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