001/*
002 * $Id: GenSolvablePolynomial.java 5282 2015-07-31 12:01:44Z kredel $
003 */
004
005package edu.jas.poly;
006
007
008import java.util.Map;
009import java.util.Set;
010import java.util.SortedMap;
011
012import org.apache.log4j.Logger;
013
014import edu.jas.structure.NotInvertibleException;
015import edu.jas.structure.RingElem;
016
017
018// import edu.jas.application.ResidueSolvablePolynomial;
019
020
021/**
022 * GenSolvablePolynomial generic solvable polynomials implementing RingElem.
023 * n-variate ordered solvable polynomials over C. Objects of this class are
024 * intended to be immutable. The implementation is based on TreeMap respectively
025 * SortedMap from exponents to coefficients by extension of GenPolybomial. Only
026 * the coefficients are modeled with generic types, the exponents are fixed to
027 * ExpVector with long entries (this will eventually be changed in the future).
028 * @param <C> coefficient type
029 * @author Heinz Kredel
030 */
031
032public class GenSolvablePolynomial<C extends RingElem<C>> extends GenPolynomial<C> {
033
034
035    //not possible: implements RingElem< GenSolvablePolynomial<C> > {
036
037
038    /**
039     * The factory for the solvable polynomial ring. Hides super.ring.
040     */
041    public final GenSolvablePolynomialRing<C> ring;
042
043
044    private static final Logger logger = Logger.getLogger(GenSolvablePolynomial.class);
045
046
047    private final boolean debug = false; //logger.isDebugEnabled();
048
049
050    /**
051     * Constructor for zero GenSolvablePolynomial.
052     * @param r solvable polynomial ring factory.
053     */
054    public GenSolvablePolynomial(GenSolvablePolynomialRing<C> r) {
055        super(r);
056        ring = r;
057    }
058
059
060    /**
061     * Constructor for GenSolvablePolynomial.
062     * @param r solvable polynomial ring factory.
063     * @param c coefficient.
064     * @param e exponent.
065     */
066    public GenSolvablePolynomial(GenSolvablePolynomialRing<C> r, C c, ExpVector e) {
067        this(r);
068        if (c != null && !c.isZERO()) {
069            val.put(e, c);
070        }
071    }
072
073
074    /**
075     * Constructor for GenSolvablePolynomial.
076     * @param r solvable polynomial ring factory.
077     * @param c coefficient.
078     */
079    public GenSolvablePolynomial(GenSolvablePolynomialRing<C> r, C c) {
080        this(r, c, r.evzero);
081    }
082
083
084    /**
085     * Constructor for GenSolvablePolynomial.
086     * @param r solvable polynomial ring factory.
087     * @param v the SortedMap of some other (solvable) polynomial.
088     */
089    protected GenSolvablePolynomial(GenSolvablePolynomialRing<C> r, SortedMap<ExpVector, C> v) {
090        this(r);
091        if (v.size() > 0) {
092            GenPolynomialRing.creations++;
093            val.putAll(v); // assume val is empty and no zero coefficients in v
094        }
095    }
096
097
098    /**
099     * Get the corresponding element factory.
100     * @return factory for this Element.
101     * @see edu.jas.structure.Element#factory()
102     */
103    @Override
104    public GenSolvablePolynomialRing<C> factory() {
105        return ring;
106    }
107
108
109    /**
110     * Clone this GenSolvablePolynomial.
111     * @see java.lang.Object#clone()
112     */
113    @Override
114    public GenSolvablePolynomial<C> copy() {
115        return new GenSolvablePolynomial<C>(ring, this.val);
116    }
117
118
119    /**
120     * Comparison with any other object.
121     * @see java.lang.Object#equals(java.lang.Object)
122     */
123    @Override
124    public boolean equals(Object B) {
125        if (!(B instanceof GenSolvablePolynomial)) {
126            return false;
127        }
128        return super.equals(B);
129    }
130
131
132    /**
133     * GenSolvablePolynomial multiplication.
134     * @param Bp GenSolvablePolynomial.
135     * @return this*Bp, where * denotes solvable multiplication.
136     */
137    // cannot @Override, @NoOverride
138    @SuppressWarnings({ "cast", "unchecked" })
139    public GenSolvablePolynomial<C> multiply(GenSolvablePolynomial<C> Bp) {
140        if (Bp == null || Bp.isZERO()) {
141            return ring.getZERO();
142        }
143        if (this.isZERO()) {
144            return this;
145        }
146        assert (ring.nvar == Bp.ring.nvar);
147        if (debug) {
148            logger.debug("ring = " + ring);
149        }
150        if (this instanceof RecSolvablePolynomial && Bp instanceof RecSolvablePolynomial) {
151            //throw new RuntimeException("wrong method dispatch in JRE ");
152            logger.info("warn: wrong method dispatch in JRE Rec.multiply(Rec Bp) - trying to fix");
153            RecSolvablePolynomial T = (RecSolvablePolynomial) this; // no <C>
154            RecSolvablePolynomial Sp = (RecSolvablePolynomial) Bp;
155            return (GenSolvablePolynomial<C>) T.multiply(Sp);
156        }
157        if (this instanceof QLRSolvablePolynomial && Bp instanceof QLRSolvablePolynomial) {
158            //throw new RuntimeException("wrong method dispatch in JRE ");
159            logger.info("warn: wrong method dispatch in JRE QLR.multiply(QLR Bp) - trying to fix");
160            QLRSolvablePolynomial T = (QLRSolvablePolynomial) this; // no <C>
161            QLRSolvablePolynomial Sp = (QLRSolvablePolynomial) Bp;
162            return (GenSolvablePolynomial<C>) T.multiply(Sp);
163        }
164        // if (this instanceof ResidueSolvablePolynomial && Bp instanceof ResidueSolvablePolynomial) {
165        //     //throw new RuntimeException("wrong method dispatch in JRE ");
166        //     logger.info("warn: wrong method dispatch in JRE multiply(Bp) - trying to fix");
167        //     ResidueSolvablePolynomial T = (ResidueSolvablePolynomial) this; // no <C>
168        //     ResidueSolvablePolynomial Sp = (ResidueSolvablePolynomial) Bp;
169        //     return (GenSolvablePolynomial<C>) T.multiply(Sp);
170        // }
171        final boolean commute = ring.table.isEmpty();
172        GenSolvablePolynomial<C> Cp = ring.getZERO().copy(); // needed for doPutToMap and doAddTo
173        //GenSolvablePolynomial<C> zero = ring.getZERO(); //.copy(); // copy not needed
174        //C one = ring.getONECoefficient();
175        ExpVector Z = ring.evzero;
176
177        GenSolvablePolynomial<C> C1 = null;
178        GenSolvablePolynomial<C> C2 = null;
179        Map<ExpVector, C> A = val;
180        Map<ExpVector, C> B = Bp.val;
181        Set<Map.Entry<ExpVector, C>> Bk = B.entrySet();
182        for (Map.Entry<ExpVector, C> y : A.entrySet()) {
183            C a = y.getValue();
184            ExpVector e = y.getKey();
185            if (debug)
186                logger.debug("e = " + e);
187            int[] ep = e.dependencyOnVariables();
188            int el1 = ring.nvar + 1;
189            if (ep.length > 0) {
190                el1 = ep[0];
191            }
192            int el1s = ring.nvar + 1 - el1;
193            for (Map.Entry<ExpVector, C> x : Bk) {
194                C b = x.getValue();
195                ExpVector f = x.getKey();
196                if (debug)
197                    logger.debug("f = " + f);
198                int[] fp = f.dependencyOnVariables();
199                int fl1 = 0;
200                if (fp.length > 0) {
201                    fl1 = fp[fp.length - 1];
202                }
203                int fl1s = ring.nvar + 1 - fl1;
204                if (debug) {
205                    logger.debug("el1s = " + el1s + " fl1s = " + fl1s);
206                }
207                GenSolvablePolynomial<C> Cs = null;
208                if (commute || el1s <= fl1s) { // symmetric
209                    ExpVector g = e.sum(f);
210                    //if ( debug ) logger.debug("g = " + g);
211                    Cs = ring.valueOf(g); // symmetric! //(GenSolvablePolynomial<C>) zero.sum(one, g); 
212                    //no: Cs = new GenSolvablePolynomial<C>(ring, one, g); 
213                    //System.out.println("Cs(sym) = " + Cs + ", g = " + g);
214                } else { // unsymmetric
215                    // split e = e1 * e2, f = f1 * f2
216                    ExpVector e1 = e.subst(el1, 0);
217                    ExpVector e2 = Z.subst(el1, e.getVal(el1));
218                    ExpVector e4;
219                    ExpVector f1 = f.subst(fl1, 0);
220                    ExpVector f2 = Z.subst(fl1, f.getVal(fl1));
221                    //if ( debug ) logger.debug("e1 = " + e1 + " e2 = " + e2);
222                    //if ( debug ) logger.debug("f1 = " + f1 + " f2 = " + f2);
223                    TableRelation<C> rel = ring.table.lookup(e2, f2);
224                    //logger.info("relation = " + rel);
225                    Cs = rel.p; //ring.copy( rel.p ); // do not clone() 
226                    if (rel.f != null) {
227                        C2 = ring.valueOf(rel.f); //(GenSolvablePolynomial<C>) zero.sum(one, rel.f);
228                        Cs = Cs.multiply(C2);
229                        if (rel.e == null) {
230                            e4 = e2;
231                        } else {
232                            e4 = e2.subtract(rel.e);
233                        }
234                        ring.table.update(e4, f2, Cs);
235                    }
236                    if (rel.e != null) {
237                        C1 = ring.valueOf(rel.e); //(GenSolvablePolynomial<C>) zero.sum(one, rel.e);
238                        Cs = C1.multiply(Cs);
239                        ring.table.update(e2, f2, Cs);
240                    }
241                    if (!f1.isZERO()) {
242                        C2 = ring.valueOf(f1); //(GenSolvablePolynomial<C>) zero.sum(one, f1);
243                        Cs = Cs.multiply(C2);
244                        //ring.table.update(?,f1,Cs)
245                    }
246                    if (!e1.isZERO()) {
247                        C1 = ring.valueOf(e1); //(GenSolvablePolynomial<C>) zero.sum(one, e1);
248                        Cs = C1.multiply(Cs);
249                        //ring.table.update(e1,?,Cs)
250                    }
251                }
252                //System.out.println("Cs = " + Cs + ", a = " + a + ", b = " + b);
253                //C c = a.multiply(b);
254                Cs = Cs.multiply(a, b); // now non-symmetric // Cs.multiply(c); is symmetric!
255                //if ( debug ) logger.debug("Cs = " + Cs);
256                //Cp = (GenSolvablePolynomial<C>) Cp.sum(Cs);
257                Cp.doAddTo(Cs);
258            }
259        }
260        return Cp;
261    }
262
263
264    /**
265     * GenSolvablePolynomial left and right multiplication. Product with two
266     * polynomials.
267     * @param S GenSolvablePolynomial.
268     * @param T GenSolvablePolynomial.
269     * @return S*this*T.
270     */
271    // new method, @NoOverride
272    public GenSolvablePolynomial<C> multiply(GenSolvablePolynomial<C> S, GenSolvablePolynomial<C> T) {
273        if (S.isZERO() || T.isZERO() || this.isZERO()) {
274            return ring.getZERO();
275        }
276        if (S.isONE()) {
277            return multiply(T);
278        }
279        if (T.isONE()) {
280            return S.multiply(this);
281        }
282        return S.multiply(this).multiply(T);
283    }
284
285
286    /**
287     * GenSolvablePolynomial multiplication. Product with coefficient ring
288     * element.
289     * @param b coefficient.
290     * @return this*b, where * is coefficient multiplication.
291     */
292    @Override
293    @SuppressWarnings({ "cast", "unchecked" })
294    public GenSolvablePolynomial<C> multiply(C b) {
295        GenSolvablePolynomial<C> Cp = ring.getZERO();
296        if (b == null || b.isZERO()) {
297            return Cp;
298        }
299        if (this instanceof RecSolvablePolynomial && b instanceof GenSolvablePolynomial) {
300            //throw new RuntimeException("wrong method dispatch in JRE ");
301            logger.info("warn: wrong method dispatch in JRE Rec.multiply(b) - trying to fix");
302            RecSolvablePolynomial T = (RecSolvablePolynomial) this; // no <C>
303            GenSolvablePolynomial Sp = (GenSolvablePolynomial) b;
304            return (GenSolvablePolynomial<C>) T.recMultiply(Sp);
305        }
306        if (this instanceof QLRSolvablePolynomial && b instanceof GenSolvablePolynomial) {
307            //throw new RuntimeException("wrong method dispatch in JRE ");
308            logger.info("warn: wrong method dispatch in JRE QLR.multiply(Bp) - trying to fix");
309            QLRSolvablePolynomial T = (QLRSolvablePolynomial) this; // no <C>
310            GenSolvablePolynomial Sp = (GenSolvablePolynomial) b;
311            return (GenSolvablePolynomial<C>) T.multiply(Sp);
312        }
313        // if (this instanceof ResidueSolvablePolynomial && b instanceof GenSolvablePolynomial) {
314        //     //throw new RuntimeException("wrong method dispatch in JRE ");
315        //     logger.info("warn: wrong method dispatch in JRE multiply(Bp) - trying to fix");
316        //     ResidueSolvablePolynomial T = (ResidueSolvablePolynomial) this; // no <C>
317        //     GenSolvablePolynomial Sp = (GenSolvablePolynomial) b;
318        //     return (GenSolvablePolynomial<C>) T.multiply(Sp);
319        // }
320        Cp = Cp.copy();
321        Map<ExpVector, C> Cm = Cp.val; //getMap();
322        Map<ExpVector, C> Am = val;
323        for (Map.Entry<ExpVector, C> y : Am.entrySet()) {
324            ExpVector e = y.getKey();
325            C a = y.getValue();
326            C c = a.multiply(b);
327            if (!c.isZERO()) {
328                Cm.put(e, c);
329            }
330        }
331        return Cp;
332    }
333
334
335    /**
336     * GenSolvablePolynomial left and right multiplication. Product with
337     * coefficient ring element.
338     * @param b coefficient.
339     * @param c coefficient.
340     * @return b*this*c, where * is coefficient multiplication.
341     */
342    // new method, @NoOverride
343    @SuppressWarnings({ "cast", "unchecked" })
344    public GenSolvablePolynomial<C> multiply(C b, C c) {
345        GenSolvablePolynomial<C> Cp = ring.getZERO();
346        if (b == null || b.isZERO()) {
347            return Cp;
348        }
349        if (c == null || c.isZERO()) {
350            return Cp;
351        }
352        if (this instanceof RecSolvablePolynomial && b instanceof GenSolvablePolynomial
353                        && c instanceof GenSolvablePolynomial) {
354            //throw new RuntimeException("wrong method dispatch in JRE ");
355            logger.info("warn: wrong method dispatch in JRE Rec.multiply(b,c) - trying to fix");
356            RecSolvablePolynomial T = (RecSolvablePolynomial) this; // no <C>
357            GenSolvablePolynomial Bp = (GenSolvablePolynomial) b;
358            GenSolvablePolynomial Dp = (GenSolvablePolynomial) c;
359            return (GenSolvablePolynomial<C>) T.multiply(Bp, Dp);
360        }
361        if (this instanceof QLRSolvablePolynomial && b instanceof GenSolvablePolynomial
362                        && c instanceof GenSolvablePolynomial) {
363            //throw new RuntimeException("wrong method dispatch in JRE ");
364            logger.info("warn: wrong method dispatch in JRE QLR.multiply(b,c) - trying to fix");
365            QLRSolvablePolynomial T = (QLRSolvablePolynomial) this; // no <C>
366            GenSolvablePolynomial Bp = (GenSolvablePolynomial) b;
367            GenSolvablePolynomial Dp = (GenSolvablePolynomial) c;
368            return (GenSolvablePolynomial<C>) T.multiply(Bp, Dp);
369        }
370        // if (this instanceof ResidueSolvablePolynomial && b instanceof GenSolvablePolynomial
371        //                 && c instanceof GenSolvablePolynomial) {
372        //     //throw new RuntimeException("wrong method dispatch in JRE ");
373        //     logger.info("warn: wrong method dispatch in JRE multiply(b,c) - trying to fix");
374        //     ResidueSolvablePolynomial T = (ResidueSolvablePolynomial) this; // no <C>
375        //     GenSolvablePolynomial Bp = (GenSolvablePolynomial) b;
376        //     GenSolvablePolynomial Dp = (GenSolvablePolynomial) c;
377        //     return (GenSolvablePolynomial<C>) T.multiply(Bp, Dp);
378        // }
379        Cp = Cp.copy();
380        Map<ExpVector, C> Cm = Cp.val; //getMap();
381        Map<ExpVector, C> Am = val;
382        for (Map.Entry<ExpVector, C> y : Am.entrySet()) {
383            ExpVector e = y.getKey();
384            C a = y.getValue();
385            C d = b.multiply(a).multiply(c);
386            if (!d.isZERO()) {
387                Cm.put(e, d);
388            }
389        }
390        return Cp;
391    }
392
393
394    /**
395     * GenSolvablePolynomial multiplication. Product with exponent vector.
396     * @param e exponent.
397     * @return this * x<sup>e</sup>, where * denotes solvable multiplication.
398     */
399    @Override
400    public GenSolvablePolynomial<C> multiply(ExpVector e) {
401        if (e == null || e.isZERO()) {
402            return this;
403        }
404        C b = ring.getONECoefficient();
405        return multiply(b, e);
406    }
407
408
409    /**
410     * GenSolvablePolynomial left and right multiplication. Product with
411     * exponent vector.
412     * @param e exponent.
413     * @param f exponent.
414     * @return x<sup>e</sup> * this * x<sup>f</sup>, where * denotes solvable
415     *         multiplication.
416     */
417    // new method, @NoOverride
418    public GenSolvablePolynomial<C> multiply(ExpVector e, ExpVector f) {
419        if (e == null || e.isZERO()) {
420            return this;
421        }
422        if (f == null || f.isZERO()) {
423            return this;
424        }
425        C b = ring.getONECoefficient();
426        return multiply(b, e, b, f);
427    }
428
429
430    /**
431     * GenSolvablePolynomial multiplication. Product with ring element and
432     * exponent vector.
433     * @param b coefficient.
434     * @param e exponent.
435     * @return this * b x<sup>e</sup>, where * denotes solvable multiplication.
436     */
437    @Override
438    public GenSolvablePolynomial<C> multiply(C b, ExpVector e) {
439        if (b == null || b.isZERO()) {
440            return ring.getZERO();
441        }
442        GenSolvablePolynomial<C> Cp = ring.valueOf(b, e); //new GenSolvablePolynomial<C>(ring, b, e);
443        return multiply(Cp);
444    }
445
446
447    /**
448     * GenSolvablePolynomial left and right multiplication. Product with ring
449     * element and exponent vector.
450     * @param b coefficient.
451     * @param e exponent.
452     * @param c coefficient.
453     * @param f exponent.
454     * @return b x<sup>e</sup> * this * c x<sup>f</sup>, where * denotes
455     *         solvable multiplication.
456     */
457    // new method, @NoOverride
458    public GenSolvablePolynomial<C> multiply(C b, ExpVector e, C c, ExpVector f) {
459        if (b == null || b.isZERO()) {
460            return ring.getZERO();
461        }
462        if (c == null || c.isZERO()) {
463            return ring.getZERO();
464        }
465        GenSolvablePolynomial<C> Cp = ring.valueOf(b, e); //new GenSolvablePolynomial<C>(ring, b, e);
466        GenSolvablePolynomial<C> Dp = ring.valueOf(c, f); //new GenSolvablePolynomial<C>(ring, c, f);
467        return multiply(Cp, Dp);
468    }
469
470
471    /**
472     * GenSolvablePolynomial multiplication. Left product with ring element and
473     * exponent vector.
474     * @param b coefficient.
475     * @param e exponent.
476     * @return b x<sup>e</sup> * this, where * denotes solvable multiplication.
477     */
478    // new method, @NoOverride
479    public GenSolvablePolynomial<C> multiplyLeft(C b, ExpVector e) {
480        if (b == null || b.isZERO()) {
481            return ring.getZERO();
482        }
483        GenSolvablePolynomial<C> Cp = ring.valueOf(b, e); //new GenSolvablePolynomial<C>(ring, b, e);
484        return Cp.multiply(this);
485    }
486
487
488    /**
489     * GenSolvablePolynomial multiplication. Left product with exponent vector.
490     * @param e exponent.
491     * @return x<sup>e</sup> * this, where * denotes solvable multiplication.
492     */
493    // new method, @NoOverride
494    public GenSolvablePolynomial<C> multiplyLeft(ExpVector e) {
495        if (e == null || e.isZERO()) {
496            return this;
497        }
498        C b = ring.getONECoefficient();
499        return multiplyLeft(b, e);
500    }
501
502
503    /**
504     * GenSolvablePolynomial multiplication. Left product with coefficient ring
505     * element.
506     * @param b coefficient.
507     * @return b*this, where * is coefficient multiplication.
508     */
509    // new method, @NoOverride
510    public GenSolvablePolynomial<C> multiplyLeft(C b) {
511        GenSolvablePolynomial<C> Cp = ring.getZERO();
512        if (b == null || b.isZERO()) {
513            return Cp;
514        }
515        Cp = Cp.copy();
516        Map<ExpVector, C> Cm = Cp.val; //getMap();
517        Map<ExpVector, C> Am = val;
518        for (Map.Entry<ExpVector, C> y : Am.entrySet()) {
519            ExpVector e = y.getKey();
520            C a = y.getValue();
521            C c = b.multiply(a);
522            if (!c.isZERO()) {
523                Cm.put(e, c);
524            }
525        }
526        return Cp;
527    }
528
529
530    /**
531     * GenSolvablePolynomial multiplication. Left product with 'monomial'.
532     * @param m 'monomial'.
533     * @return m * this, where * denotes solvable multiplication.
534     */
535    // new method, @NoOverride
536    public GenSolvablePolynomial<C> multiplyLeft(Map.Entry<ExpVector, C> m) {
537        if (m == null) {
538            return ring.getZERO();
539        }
540        return multiplyLeft(m.getValue(), m.getKey());
541    }
542
543
544    /**
545     * GenSolvablePolynomial multiplication. Product with 'monomial'.
546     * @param m 'monomial'.
547     * @return this * m, where * denotes solvable multiplication.
548     */
549    @Override
550    public GenSolvablePolynomial<C> multiply(Map.Entry<ExpVector, C> m) {
551        if (m == null) {
552            return ring.getZERO();
553        }
554        return multiply(m.getValue(), m.getKey());
555    }
556
557
558    /**
559     * GenSolvablePolynomial subtract a multiple.
560     * @param a coefficient.
561     * @param S GenSolvablePolynomial.
562     * @return this - a * S.
563     */
564    public GenSolvablePolynomial<C> subtractMultiple(C a, GenSolvablePolynomial<C> S) {
565        if (a == null || a.isZERO()) {
566            return this;
567        }
568        if (S == null || S.isZERO()) {
569            return this;
570        }
571        if (this.isZERO()) {
572            return S.multiplyLeft(a.negate());
573        }
574        assert (ring.nvar == S.ring.nvar);
575        GenSolvablePolynomial<C> n = this.copy();
576        SortedMap<ExpVector, C> nv = n.val;
577        SortedMap<ExpVector, C> sv = S.val;
578        for (Map.Entry<ExpVector, C> me : sv.entrySet()) {
579            ExpVector f = me.getKey();
580            C y = me.getValue(); // assert y != null
581            y = a.multiply(y);
582            C x = nv.get(f);
583            if (x != null) {
584                x = x.subtract(y);
585                if (!x.isZERO()) {
586                    nv.put(f, x);
587                } else {
588                    nv.remove(f);
589                }
590            } else if (!y.isZERO()) {
591                nv.put(f, y.negate());
592            }
593        }
594        return n;
595    }
596
597
598    /**
599     * GenSolvablePolynomial subtract a multiple.
600     * @param a coefficient.
601     * @param e exponent.
602     * @param S GenSolvablePolynomial.
603     * @return this - a * x<sup>e</sup> * S.
604     */
605    public GenSolvablePolynomial<C> subtractMultiple(C a, ExpVector e, GenSolvablePolynomial<C> S) {
606        if (a == null || a.isZERO()) {
607            return this;
608        }
609        if (S == null || S.isZERO()) {
610            return this;
611        }
612        if (this.isZERO()) {
613            return S.multiplyLeft(a.negate(), e);
614        }
615        assert (ring.nvar == S.ring.nvar);
616        GenSolvablePolynomial<C> n = this.copy();
617        SortedMap<ExpVector, C> nv = n.val;
618        GenSolvablePolynomial<C> s = S.multiplyLeft(e);
619        SortedMap<ExpVector, C> sv = s.val;
620        for (Map.Entry<ExpVector, C> me : sv.entrySet()) {
621            ExpVector f = me.getKey();
622            //f = e.sum(f);
623            C y = me.getValue(); // assert y != null
624            y = a.multiply(y);
625            C x = nv.get(f);
626            if (x != null) {
627                x = x.subtract(y);
628                if (!x.isZERO()) {
629                    nv.put(f, x);
630                } else {
631                    nv.remove(f);
632                }
633            } else if (!y.isZERO()) {
634                nv.put(f, y.negate());
635            }
636        }
637        return n;
638    }
639
640
641    /**
642     * GenSolvablePolynomial scale and subtract a multiple.
643     * @param b scale factor.
644     * @param a coefficient.
645     * @param S GenSolvablePolynomial.
646     * @return b * this - a * S.
647     */
648    //@Override
649    public GenSolvablePolynomial<C> scaleSubtractMultiple(C b, C a, GenSolvablePolynomial<C> S) {
650        if (a == null || S == null) {
651            return this.multiplyLeft(b);
652        }
653        if (a.isZERO() || S.isZERO()) {
654            return this.multiplyLeft(b);
655        }
656        if (this.isZERO() || b == null || b.isZERO()) {
657            return S.multiplyLeft(a.negate());
658        }
659        if (b.isONE()) {
660            return subtractMultiple(a, S);
661        }
662        assert (ring.nvar == S.ring.nvar);
663        GenSolvablePolynomial<C> n = this.multiplyLeft(b);
664        SortedMap<ExpVector, C> nv = n.val;
665        SortedMap<ExpVector, C> sv = S.val;
666        for (Map.Entry<ExpVector, C> me : sv.entrySet()) {
667            ExpVector f = me.getKey();
668            //f = e.sum(f);
669            C y = me.getValue(); // assert y != null
670            y = a.multiply(y); // now y can be zero
671            C x = nv.get(f);
672            if (x != null) {
673                x = x.subtract(y);
674                if (!x.isZERO()) {
675                    nv.put(f, x);
676                } else {
677                    nv.remove(f);
678                }
679            } else if (!y.isZERO()) {
680                nv.put(f, y.negate());
681            }
682        }
683        return n;
684    }
685
686
687    /**
688     * GenSolvablePolynomial scale and subtract a multiple.
689     * @param b scale factor.
690     * @param a coefficient.
691     * @param e exponent.
692     * @param S GenSolvablePolynomial.
693     * @return b * this - a * x<sup>e</sup> * S.
694     */
695    public GenSolvablePolynomial<C> scaleSubtractMultiple(C b, C a, ExpVector e, GenSolvablePolynomial<C> S) {
696        if (a == null || S == null) {
697            return this.multiplyLeft(b);
698        }
699        if (a.isZERO() || S.isZERO()) {
700            return this.multiplyLeft(b);
701        }
702        if (this.isZERO() || b == null || b.isZERO()) {
703            return S.multiplyLeft(a.negate(), e);
704        }
705        if (b.isONE()) {
706            return subtractMultiple(a, e, S);
707        }
708        assert (ring.nvar == S.ring.nvar);
709        GenSolvablePolynomial<C> n = this.multiplyLeft(b);
710        SortedMap<ExpVector, C> nv = n.val;
711        GenSolvablePolynomial<C> s = S.multiplyLeft(e);
712        SortedMap<ExpVector, C> sv = s.val;
713        for (Map.Entry<ExpVector, C> me : sv.entrySet()) {
714            ExpVector f = me.getKey();
715            //f = e.sum(f);
716            C y = me.getValue(); // assert y != null
717            y = a.multiply(y); // now y can be zero
718            C x = nv.get(f);
719            if (x != null) {
720                x = x.subtract(y);
721                if (!x.isZERO()) {
722                    nv.put(f, x);
723                } else {
724                    nv.remove(f);
725                }
726            } else if (!y.isZERO()) {
727                nv.put(f, y.negate());
728            }
729        }
730        return n;
731    }
732
733
734    /**
735     * GenSolvablePolynomial scale and subtract a multiple.
736     * @param b scale factor.
737     * @param g scale exponent.
738     * @param a coefficient.
739     * @param e exponent.
740     * @param S GenSolvablePolynomial.
741     * @return a * x<sup>g</sup> * this - a * x<sup>e</sup> * S.
742     */
743    public GenSolvablePolynomial<C> scaleSubtractMultiple(C b, ExpVector g, C a, ExpVector e,
744                    GenSolvablePolynomial<C> S) {
745        if (a == null || S == null) {
746            return this.multiplyLeft(b, g);
747        }
748        if (a.isZERO() || S.isZERO()) {
749            return this.multiplyLeft(b, g);
750        }
751        if (this.isZERO() || b == null || b.isZERO()) {
752            return S.multiplyLeft(a.negate(), e);
753        }
754        if (b.isONE() && g.isZERO()) {
755            return subtractMultiple(a, e, S);
756        }
757        assert (ring.nvar == S.ring.nvar);
758        GenSolvablePolynomial<C> n = this.multiplyLeft(b, g);
759        SortedMap<ExpVector, C> nv = n.val;
760        GenSolvablePolynomial<C> s = S.multiplyLeft(e);
761        SortedMap<ExpVector, C> sv = s.val;
762        for (Map.Entry<ExpVector, C> me : sv.entrySet()) {
763            ExpVector f = me.getKey();
764            //f = e.sum(f);
765            C y = me.getValue(); // assert y != null
766            y = a.multiply(y); // y can be zero now
767            C x = nv.get(f);
768            if (x != null) {
769                x = x.subtract(y);
770                if (!x.isZERO()) {
771                    nv.put(f, x);
772                } else {
773                    nv.remove(f);
774                }
775            } else if (!y.isZERO()) {
776                nv.put(f, y.negate());
777            }
778        }
779        return n;
780    }
781
782
783    /**
784     * GenSolvablePolynomial left monic, i.e. leadingCoefficient == 1. If
785     * leadingCoefficient is not invertible returns this abs value.
786     * @return monic(this).
787     */
788    @Override
789    public GenSolvablePolynomial<C> monic() {
790        if (this.isZERO()) {
791            return this;
792        }
793        C lc = leadingBaseCoefficient();
794        if (!lc.isUnit()) {
795            return (GenSolvablePolynomial<C>)this.abs();
796        }
797        try {
798            C lm = lc.inverse();
799            //System.out.println("lm = "+lm);
800            return (GenSolvablePolynomial<C>)multiplyLeft(lm).abs();
801        } catch (NotInvertibleException e) {
802            logger.info("monic not invertible " + lc);
803            //e.printStackTrace();
804        }
805        return this;
806    }
807
808
809    /**
810     * GenSolvablePolynomial left division with remainder. Fails, if exact
811     * division by leading base coefficient is not possible. Meaningful only for
812     * univariate polynomials over fields, but works in any case.
813     * @param S nonzero GenSolvablePolynomial with invertible leading
814     *            coefficient.
815     * @return [ quotient , remainder ] with this = quotient * S + remainder and
816     *         deg(remainder) &lt; deg(S) or remiander = 0.
817     * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial)
818     */
819    // cannot @Override, @NoOverride
820    @SuppressWarnings({ "unchecked" })
821    public GenSolvablePolynomial<C>[] quotientRemainder(GenSolvablePolynomial<C> S) {
822        if (S == null || S.isZERO()) {
823            throw new ArithmeticException("division by zero");
824        }
825        C c = S.leadingBaseCoefficient();
826        if (!c.isUnit()) {
827            throw new ArithmeticException("lbcf not invertible " + c);
828        }
829        C ci = c.inverse();
830        assert (ring.nvar == S.ring.nvar);
831        ExpVector e = S.leadingExpVector();
832        GenSolvablePolynomial<C> h;
833        GenSolvablePolynomial<C> q = ring.getZERO().copy();
834        GenSolvablePolynomial<C> r = this.copy();
835        while (!r.isZERO()) {
836            ExpVector f = r.leadingExpVector();
837            if (f.multipleOf(e)) {
838                C a = r.leadingBaseCoefficient();
839                //System.out.println("FDQR: f = " + f + ", a = " + a);
840                f = f.subtract(e);
841                //a = ci.multiply(a); // multiplyLeft
842                a = a.multiply(ci); // this is correct!
843                q = (GenSolvablePolynomial<C>) q.sum(a, f);
844                h = S.multiplyLeft(a, f);
845                if (!h.leadingBaseCoefficient().equals(r.leadingBaseCoefficient())) {
846                    throw new RuntimeException("something is wrong: r = " + r + ", h = " + h);
847                }
848                r = (GenSolvablePolynomial<C>) r.subtract(h);
849            } else {
850                break;
851            }
852        }
853        GenSolvablePolynomial<C>[] ret = new GenSolvablePolynomial[2];
854        ret[0] = q;
855        ret[1] = r;
856        return ret;
857    }
858
859
860    /**
861     * RecSolvablePolynomial right coefficients from left coefficients.
862     * <b>Note:</b> R is represented as a polynomial with left coefficients, the
863     * implementation can at the moment not distinguish between left and right
864     * coefficients.
865     * @return R = sum( X<sup>i</sup> b<sub>i</sub> ), with P =
866     *         sum(a<sub>i</sub> X<sup>i</sup> ) and eval(sum(X<sup>i</sup>
867     *         b<sub>i</sub>)) == sum(a<sub>i</sub> X<sup>i</sup>)
868     */
869    @SuppressWarnings({ "unchecked" })
870    public GenSolvablePolynomial<C> rightRecursivePolynomial() {
871        if (this.isONE() || this.isZERO()) {
872            return this;
873        }
874        if (!(this instanceof RecSolvablePolynomial)) {
875            return this;
876        }
877        RecSolvablePolynomialRing<C> rfac = (RecSolvablePolynomialRing<C>) ring;
878        if (rfac.coeffTable.isEmpty()) {
879            return this;
880        }
881        RecSolvablePolynomial<C> p = (RecSolvablePolynomial<C>) this;
882        RecSolvablePolynomial<C> R = (RecSolvablePolynomial<C>) p.rightRecursivePolynomial();
883        return (GenSolvablePolynomial<C>) R;
884    }
885
886
887    /**
888     * Evaluate RecSolvablePolynomial as right coefficients polynomial.
889     * <b>Note:</b> R is represented as a polynomial with left coefficients, the
890     * implementation can at the moment not distinguish between left and right
891     * coefficients.
892     * @return this as evaluated polynomial R. R = sum( X<sup>i</sup>
893     *         b<sub>i</sub> ), this = sum(a<sub>i</sub> X<sup>i</sup> ) =
894     *         eval(sum(X<sup>i</sup> b<sub>i</sub>))
895     */
896    @SuppressWarnings({ "unchecked" })
897    public GenSolvablePolynomial<C> evalAsRightRecursivePolynomial() {
898        if (this.isONE() || this.isZERO()) {
899            return this;
900        }
901        if (!(this instanceof RecSolvablePolynomial)) {
902            return this;
903        }
904        RecSolvablePolynomialRing<C> rfac = (RecSolvablePolynomialRing<C>) ring;
905        if (rfac.coeffTable.isEmpty()) {
906            return this;
907        }
908        RecSolvablePolynomial<C> p = (RecSolvablePolynomial<C>) this;
909        RecSolvablePolynomial<C> R = (RecSolvablePolynomial<C>) p.evalAsRightRecursivePolynomial();
910        return (GenSolvablePolynomial<C>) R;
911    }
912
913
914    /**
915     * Test RecSolvablePolynomial right coefficients polynomial. <b>Note:</b> R
916     * is represented as a polynomial with left coefficients, the implementation
917     * can at the moment not distinguish between left and right coefficients.
918     * @param R GenSolvablePolynomial with right coefficients.
919     * @return true, if R is polynomial with right coefficients of this. R =
920     *         sum( X<sup>i</sup> b<sub>i</sub> ), with this = sum(a<sub>i</sub>
921     *         X<sup>i</sup> ) and eval(sum(X<sup>i</sup> b<sub>i</sub>)) ==
922     *         sum(a<sub>i</sub> X<sup>i</sup>)
923     */
924    @SuppressWarnings({ "unchecked" })
925    public boolean isRightRecursivePolynomial(GenSolvablePolynomial<C> R) {
926        if (this.isZERO()) {
927            return R.isZERO();
928        }
929        if (this.isONE()) {
930            return R.isONE();
931        }
932        if (!(this instanceof RecSolvablePolynomial)) {
933            return !(R instanceof RecSolvablePolynomial);
934        }
935        if (!(R instanceof RecSolvablePolynomial)) {
936            return false;
937        }
938        RecSolvablePolynomialRing<C> rfac = (RecSolvablePolynomialRing<C>) ring;
939        if (rfac.coeffTable.isEmpty()) {
940            RecSolvablePolynomialRing<C> rf = (RecSolvablePolynomialRing<C>) R.ring;
941            return rf.coeffTable.isEmpty();
942        }
943        RecSolvablePolynomial<C> p = (RecSolvablePolynomial<C>) this;
944        RecSolvablePolynomial<C> q = (RecSolvablePolynomial<C>) R;
945        return p.isRightRecursivePolynomial(q);
946    }
947
948}