001/*
002 * $Id$
003 */
004
005package edu.jas.poly;
006
007
008import java.io.IOException;
009import java.lang.reflect.InvocationTargetException;
010import java.lang.reflect.Method;
011import java.util.ArrayList;
012import java.util.Collections;
013import java.util.Iterator;
014import java.util.List;
015import java.util.Map;
016import java.util.SortedMap;
017import java.util.Spliterator;
018import java.util.TreeMap;
019import java.util.function.Function;
020import java.util.regex.Pattern;
021import java.util.stream.Collectors;
022import java.util.stream.Stream;
023
024import org.apache.logging.log4j.LogManager;
025import org.apache.logging.log4j.Logger;
026
027import edu.jas.kern.PreemptingException;
028import edu.jas.kern.PrettyPrint;
029import edu.jas.structure.NotInvertibleException;
030import edu.jas.structure.RingElem;
031import edu.jas.structure.UnaryFunctor;
032import edu.jas.util.MapEntry;
033
034
035/**
036 * GenPolynomial generic polynomials implementing RingElem. n-variate ordered
037 * polynomials over coefficients C. The variables commute with each other and
038 * with the coefficients. For non-commutative coefficients some care is taken to
039 * respect the multiplication order.
040 *
041 * Objects of this class are intended to be immutable. The implementation is
042 * based on TreeMap respectively SortedMap from exponents to coefficients. Only
043 * the coefficients are modeled with generic types, the exponents are fixed to
044 * ExpVector with long entries (@see edu.jas.poly.ExpVector StorUnit). C can
045 * also be a non integral domain, e.g. a ModInteger, i.e. it may contain zero
046 * divisors, since multiply() does check for zeros. <b>Note:</b> multiply() now
047 * checks for wrong method dispatch for GenSolvablePolynomial.
048 * @param <C> coefficient type
049 * @author Heinz Kredel
050 */
051public class GenPolynomial<C extends RingElem<C>>
052                implements RingElem<GenPolynomial<C>>, /* not yet Polynomial<C> */
053                Iterable<Monomial<C>> {
054
055
056    /**
057     * The factory for the polynomial ring.
058     */
059    public final GenPolynomialRing<C> ring;
060
061
062    /**
063     * The data structure for polynomials.
064     */
065    protected final SortedMap<ExpVector, C> val; // do not change to TreeMap
066
067
068    /**
069     * Stored hash code.
070     */
071    transient protected int hash = -1;
072
073
074    /**
075     * Stored bitLength.
076     */
077    transient protected long blen = -1;
078
079
080    private static final Logger logger = LogManager.getLogger(GenPolynomial.class);
081
082
083    private static final boolean debug = logger.isDebugEnabled();
084
085
086    // protected GenPolynomial() { ring = null; val = null; } // don't use
087
088
089    /**
090     * Private constructor for GenPolynomial.
091     * @param r polynomial ring factory.
092     * @param t TreeMap with correct ordering.
093     */
094    private GenPolynomial(GenPolynomialRing<C> r, TreeMap<ExpVector, C> t) {
095        ring = r;
096        val = t;
097        if (ring.checkPreempt) {
098            if (Thread.currentThread().isInterrupted()) {
099                logger.debug("throw PreemptingException");
100                throw new PreemptingException();
101            }
102        }
103    }
104
105
106    /**
107     * Constructor for zero GenPolynomial.
108     * @param r polynomial ring factory.
109     */
110    public GenPolynomial(GenPolynomialRing<C> r) {
111        this(r, new TreeMap<ExpVector, C>(r.tord.getDescendComparator()));
112    }
113
114
115    /**
116     * Constructor for GenPolynomial c * x<sup>e</sup>.
117     * @param r polynomial ring factory.
118     * @param c coefficient.
119     * @param e exponent.
120     */
121    public GenPolynomial(GenPolynomialRing<C> r, C c, ExpVector e) {
122        this(r);
123        if (!c.isZERO()) {
124            val.put(e, c);
125        }
126    }
127
128
129    /**
130     * Constructor for GenPolynomial c * x<sup>0</sup>.
131     * @param r polynomial ring factory.
132     * @param c coefficient.
133     */
134    public GenPolynomial(GenPolynomialRing<C> r, C c) {
135        this(r, c, r.evzero);
136    }
137
138
139    /**
140     * Constructor for GenPolynomial x<sup>e</sup>.
141     * @param r polynomial ring factory.
142     * @param e exponent.
143     */
144    public GenPolynomial(GenPolynomialRing<C> r, ExpVector e) {
145        this(r, r.coFac.getONE(), e);
146    }
147
148
149    /**
150     * Constructor for GenPolynomial.
151     * @param r polynomial ring factory.
152     * @param v the SortedMap of some other polynomial.
153     */
154    protected GenPolynomial(GenPolynomialRing<C> r, SortedMap<ExpVector, C> v) {
155        this(r);
156        if (v.size() > 0) {
157            GenPolynomialRing.creations++;
158            val.putAll(v); // assume no zero coefficients and val is empty
159            assert !val.values().contains(r.coFac.getZERO()) : "illegal coefficient zero: " + v;
160        }
161    }
162
163
164    /**
165     * Constructor for GenPolynomial.
166     * @param r polynomial ring factory.
167     * @param v some Map from ExpVector to coefficients.
168     */
169    protected GenPolynomial(GenPolynomialRing<C> r, Map<ExpVector, C> v) {
170        this(r);
171        if (v.size() > 0) {
172            GenPolynomialRing.creations++;
173            val.putAll(v); // assume no zero coefficients and val is empty
174            assert !val.values().contains(r.coFac.getZERO()) : "illegal coefficient zero: " + v;
175        }
176    }
177
178
179    /**
180     * Get the corresponding element factory.
181     * @return factory for this Element.
182     * @see edu.jas.structure.Element#factory()
183     */
184    public GenPolynomialRing<C> factory() {
185        return ring;
186    }
187
188
189    /**
190     * Copy this GenPolynomial.
191     * @return copy of this.
192     */
193    public GenPolynomial<C> copy() {
194        return new GenPolynomial<C>(ring, this.val);
195    }
196
197
198    /**
199     * Length of GenPolynomial.
200     * @return number of coefficients of this GenPolynomial.
201     */
202    public int length() {
203        return val.size();
204    }
205
206
207    /**
208     * ExpVector to coefficient map of GenPolynomial.
209     * @return val as unmodifiable SortedMap.
210     */
211    public SortedMap<ExpVector, C> getMap() {
212        // return val;
213        return Collections.<ExpVector, C> unmodifiableSortedMap(val);
214    }
215
216
217    /**
218     * Put an ExpVector to coefficient entry into the internal map of this
219     * GenPolynomial. <b>Note:</b> Do not use this method unless you are
220     * constructing a new polynomial. this is modified and breaks the
221     * immutability promise of this class.
222     * @param c coefficient.
223     * @param e exponent.
224     */
225    public void doPutToMap(ExpVector e, C c) {
226        if (debug) {
227            C a = val.get(e);
228            if (a != null) {
229                logger.error("map entry exists {} to {} new {}", e, a, c);
230            }
231            hash = -1;
232            blen = -1;
233        }
234        if (!c.isZERO()) {
235            val.put(e, c);
236        }
237    }
238
239
240    /**
241     * Remove an ExpVector to coefficient entry from the internal map of this
242     * GenPolynomial. <b>Note:</b> Do not use this method unless you are
243     * constructing a new polynomial. this is modified and breaks the
244     * immutability promise of this class.
245     * @param e exponent.
246     * @param c expected coefficient, null for ignore.
247     */
248    public void doRemoveFromMap(ExpVector e, C c) {
249        C b = val.remove(e);
250        if (true) { //||debug
251            hash = -1;
252            blen = -1;
253            if (c == null) { // ignore b
254                return;
255            }
256            if (!c.equals(b)) {
257                logger.error("map entry wrong {} to {} old {}", e, c, b);
258                throw new RuntimeException("c != b");
259            }
260        }
261    }
262
263
264    /**
265     * Put an a sorted map of exponents to coefficients into the internal map of
266     * this GenPolynomial. <b>Note:</b> Do not use this method unless you are
267     * constructing a new polynomial. this is modified and breaks the
268     * immutability promise of this class.
269     * @param vals sorted map of exponents and coefficients.
270     */
271    public void doPutToMap(SortedMap<ExpVector, C> vals) {
272        for (Map.Entry<ExpVector, C> me : vals.entrySet()) {
273            ExpVector e = me.getKey();
274            if (debug) {
275                C a = val.get(e);
276                if (a != null) {
277                    logger.error("map entry exists {} to {} new {}", e, a, me.getValue());
278                }
279                hash = -1;
280                blen = -1;
281            }
282            C c = me.getValue();
283            if (!c.isZERO()) {
284                val.put(e, c);
285            }
286        }
287    }
288
289
290    /**
291     * String representation of GenPolynomial.
292     * @see java.lang.Object#toString()
293     */
294    @Override
295    public String toString() {
296        if (ring.vars != null) {
297            return toString(ring.vars);
298        }
299        StringBuffer s = new StringBuffer();
300        s.append(this.getClass().getSimpleName() + ":");
301        s.append(ring.coFac.getClass().getSimpleName());
302        if (ring.coFac.characteristic().signum() != 0) {
303            s.append("(" + ring.coFac.characteristic() + ")");
304        }
305        s.append("[ ");
306        boolean first = true;
307        for (Map.Entry<ExpVector, C> m : val.entrySet()) {
308            if (first) {
309                first = false;
310            } else {
311                s.append(", ");
312            }
313            s.append(m.getValue().toString());
314            s.append(" ");
315            s.append(m.getKey().toString());
316        }
317        s.append(" ] "); // no not use: ring.toString() );
318        return s.toString();
319    }
320
321
322    /**
323     * String representation of GenPolynomial.
324     * @param v names for variables.
325     * @see java.lang.Object#toString()
326     */
327    public String toString(String[] v) {
328        StringBuffer s = new StringBuffer();
329        if (PrettyPrint.isTrue()) {
330            if (val.isEmpty()) {
331                s.append("0");
332            } else {
333                // s.append( "( " );
334                boolean first = true;
335                for (Map.Entry<ExpVector, C> m : val.entrySet()) {
336                    C c = m.getValue();
337                    if (first) {
338                        first = false;
339                    } else {
340                        if (c.signum() < 0) {
341                            s.append(" - ");
342                            c = c.negate();
343                        } else {
344                            s.append(" + ");
345                        }
346                    }
347                    ExpVector e = m.getKey();
348                    if (!c.isONE() || e.isZERO()) {
349                        String cs = c.toString();
350                        //if (c instanceof GenPolynomial || c instanceof AlgebraicNumber) {
351                        if (cs.indexOf("-") >= 0 || cs.indexOf("+") >= 0) {
352                            s.append("( ");
353                            s.append(cs);
354                            s.append(" )");
355                        } else {
356                            s.append(cs);
357                        }
358                        s.append(" ");
359                    }
360                    if (e != null && v != null) {
361                        s.append(e.toString(v));
362                    } else {
363                        s.append(e);
364                    }
365                }
366                //s.append(" )");
367            }
368        } else {
369            s.append(this.getClass().getSimpleName() + "[ ");
370            if (val.isEmpty()) {
371                s.append("0");
372            } else {
373                boolean first = true;
374                for (Map.Entry<ExpVector, C> m : val.entrySet()) {
375                    C c = m.getValue();
376                    if (first) {
377                        first = false;
378                    } else {
379                        if (c.signum() < 0) {
380                            s.append(" - ");
381                            c = c.negate();
382                        } else {
383                            s.append(" + ");
384                        }
385                    }
386                    ExpVector e = m.getKey();
387                    if (!c.isONE() || e.isZERO()) {
388                        s.append(c.toString());
389                        s.append(" ");
390                    }
391                    s.append(e.toString(v));
392                }
393            }
394            s.append(" ] "); // no not use: ring.toString() );
395        }
396        return s.toString();
397    }
398
399
400    /**
401     * Get a scripting compatible string representation.
402     * @return script compatible representation for this Element.
403     * @see edu.jas.structure.Element#toScript()
404     */
405    @Override
406    public String toScript() {
407        // Python case
408        if (isZERO()) {
409            return "0";
410        }
411        StringBuffer s = new StringBuffer();
412        if (val.size() > 1) {
413            s.append("( ");
414        }
415        String[] v = ring.vars;
416        if (v == null) {
417            v = GenPolynomialRing.newVars("x", ring.nvar);
418        }
419        Pattern klammern = Pattern.compile("\\s*\\(.+\\)\\s*");
420        boolean first = true;
421        for (Map.Entry<ExpVector, C> m : val.entrySet()) {
422            C c = m.getValue();
423            if (first) {
424                first = false;
425            } else {
426                if (c.signum() < 0) {
427                    s.append(" - ");
428                    c = c.negate();
429                } else {
430                    s.append(" + ");
431                }
432            }
433            ExpVector e = m.getKey();
434            String cs = c.toScript();
435            boolean parenthesis = (cs.indexOf("-") >= 0 || cs.indexOf("+") >= 0)
436                            && !klammern.matcher(cs).matches();
437            if (!c.isONE() || e.isZERO()) {
438                if (parenthesis) {
439                    s.append("( ");
440                }
441                s.append(cs);
442                if (parenthesis) {
443                    s.append(" )");
444                }
445                if (!e.isZERO()) {
446                    s.append(" * ");
447                }
448            }
449            s.append(e.toScript(v));
450        }
451        if (val.size() > 1) {
452            s.append(" )");
453        }
454        return s.toString();
455    }
456
457
458    /**
459     * Get a scripting compatible string representation of the factory.
460     * @return script compatible representation for this ElemFactory.
461     * @see edu.jas.structure.Element#toScriptFactory()
462     */
463    @Override
464    public String toScriptFactory() {
465        // Python case
466        return factory().toScript();
467    }
468
469
470    /**
471     * Is GenPolynomial&lt;C&gt; zero.
472     * @return If this is 0 then true is returned, else false.
473     * @see edu.jas.structure.RingElem#isZERO()
474     */
475    public boolean isZERO() {
476        return val.isEmpty();
477    }
478
479
480    /**
481     * Is GenPolynomial&lt;C&gt; one.
482     * @return If this is 1 then true is returned, else false.
483     * @see edu.jas.structure.RingElem#isONE()
484     */
485    public boolean isONE() {
486        if (val.size() != 1) {
487            return false;
488        }
489        C c = val.get(ring.evzero);
490        if (c == null) {
491            return false;
492        }
493        return c.isONE();
494    }
495
496
497    /**
498     * Is GenPolynomial&lt;C&gt; a unit.
499     * @return If this is a unit then true is returned, else false.
500     * @see edu.jas.structure.RingElem#isUnit()
501     */
502    public boolean isUnit() {
503        if (val.size() != 1) {
504            return false;
505        }
506        C c = val.get(ring.evzero);
507        if (c == null) {
508            return false;
509        }
510        return c.isUnit();
511    }
512
513
514    /**
515     * Is GenPolynomial&lt;C&gt; a constant.
516     * @return If this is a constant polynomial then true is returned, else
517     *         false.
518     */
519    public boolean isConstant() {
520        if (val.size() != 1) {
521            return false;
522        }
523        C c = val.get(ring.evzero);
524        if (c == null) {
525            return false;
526        }
527        return true;
528    }
529
530
531    /**
532     * Is GenPolynomial&lt;C&gt; homogeneous.
533     * @return true, if this is homogeneous, else false.
534     */
535    public boolean isHomogeneous() {
536        if (val.size() <= 1) {
537            return true;
538        }
539        long deg = -1;
540        for (ExpVector e : val.keySet()) {
541            if (deg < 0) {
542                deg = e.totalDeg();
543            } else if (deg != e.totalDeg()) {
544                return false;
545            }
546        }
547        return true;
548    }
549
550
551    /**
552     * Comparison with any other object.
553     * @see java.lang.Object#equals(java.lang.Object)
554     */
555    @Override
556    @SuppressWarnings("unchecked")
557    public boolean equals(Object B) {
558        if (B == null) {
559            return false;
560        }
561        if (!(B instanceof GenPolynomial)) {
562            return false;
563        }
564        GenPolynomial<C> a = (GenPolynomial<C>) B;
565        return this.compareTo(a) == 0;
566    }
567
568
569    /**
570     * Hash code for this polynomial.
571     * @see java.lang.Object#hashCode()
572     */
573    @Override
574    public int hashCode() {
575        int h = hash;
576        if (h == -1) {
577            //not in sync with equals(): h = (ring.hashCode() << 27);
578            h = val.hashCode();
579            hash = h;
580            //System.out.println("GenPolynomial.hashCode: " + h);
581        }
582        return h;
583    }
584
585
586    /**
587     * GenPolynomial comparison.
588     * @param b GenPolynomial.
589     * @return sign(this-b).
590     */
591    public int compareTo(GenPolynomial<C> b) {
592        if (b == null) {
593            return 1;
594        }
595        SortedMap<ExpVector, C> av = this.val;
596        SortedMap<ExpVector, C> bv = b.val;
597        Iterator<Map.Entry<ExpVector, C>> ai = av.entrySet().iterator();
598        Iterator<Map.Entry<ExpVector, C>> bi = bv.entrySet().iterator();
599        int s = 0;
600        int c = 0;
601        while (ai.hasNext() && bi.hasNext()) {
602            Map.Entry<ExpVector, C> aie = ai.next();
603            Map.Entry<ExpVector, C> bie = bi.next();
604            ExpVector ae = aie.getKey();
605            ExpVector be = bie.getKey();
606            s = ae.compareTo(be);
607            if (s != 0) {
608                //System.out.println("s = " + s + ", " + ring.toScript(ae) + ", " + ring.toScript(be));
609                return s;
610            }
611            if (c == 0) {
612                C ac = aie.getValue(); //av.get(ae);
613                C bc = bie.getValue(); //bv.get(be);
614                c = ac.compareTo(bc);
615            }
616        }
617        if (ai.hasNext()) {
618            //System.out.println("ai = " + ai);
619            return 1;
620        }
621        if (bi.hasNext()) {
622            //System.out.println("bi = " + bi);
623            return -1;
624        }
625        //if (c != 0) {
626        //System.out.println("c = " + c);
627        //}
628        // now all keys are equal
629        return c;
630    }
631
632
633    /**
634     * GenPolynomial signum.
635     * @return sign(ldcf(this)).
636     */
637    public int signum() {
638        if (this.isZERO()) {
639            return 0;
640        }
641        ExpVector t = val.firstKey();
642        C c = val.get(t);
643        return c.signum();
644    }
645
646
647    /**
648     * Number of variables.
649     * @return ring.nvar.
650     */
651    public int numberOfVariables() {
652        return ring.nvar;
653    }
654
655
656    /**
657     * Leading monomial.
658     * @return first map entry.
659     */
660    public Map.Entry<ExpVector, C> leadingMonomial() {
661        if (val.isEmpty()) {
662            return null;
663        }
664        //Iterator<Map.Entry<ExpVector, C>> ai = val.entrySet().iterator();
665        //return ai.next();
666        ExpVector e = val.firstKey();
667        return new MapEntry<ExpVector, C>(e, val.get(e));
668    }
669
670
671    /**
672     * Leading exponent vector.
673     * @return first exponent.
674     */
675    public ExpVector leadingExpVector() {
676        if (val.isEmpty()) {
677            return null; // ring.evzero? needs many changes 
678        }
679        return val.firstKey();
680    }
681
682
683    /**
684     * Trailing exponent vector.
685     * @return last exponent.
686     */
687    public ExpVector trailingExpVector() {
688        if (val.isEmpty()) {
689            return null; //ring.evzero; // or null ?;
690        }
691        return val.lastKey();
692    }
693
694
695    /**
696     * Leading base coefficient.
697     * @return first coefficient.
698     */
699    public C leadingBaseCoefficient() {
700        if (val.isEmpty()) {
701            return ring.coFac.getZERO();
702        }
703        return val.get(val.firstKey());
704    }
705
706
707    /**
708     * Trailing base coefficient.
709     * @return coefficient of constant term.
710     */
711    public C trailingBaseCoefficient() {
712        C c = val.get(ring.evzero);
713        if (c == null) {
714            return ring.coFac.getZERO();
715        }
716        return c;
717    }
718
719
720    /**
721     * Coefficient.
722     * @param e exponent.
723     * @return coefficient for given exponent.
724     */
725    public C coefficient(ExpVector e) {
726        C c = val.get(e);
727        if (c == null) {
728            c = ring.coFac.getZERO();
729        }
730        return c;
731    }
732
733
734    /**
735     * Reductum.
736     * @return this - leading monomial.
737     */
738    public GenPolynomial<C> reductum() {
739        if (val.size() <= 1) {
740            return ring.getZERO();
741        }
742        Iterator<ExpVector> ai = val.keySet().iterator();
743        ExpVector lt = ai.next();
744        lt = ai.next(); // size > 1
745        SortedMap<ExpVector, C> red = val.tailMap(lt);
746        GenPolynomial<C> r = ring.getZERO().copy();
747        r.doPutToMap(red); //  new GenPolynomial<C>(ring, red);
748        return r;
749    }
750
751
752    /**
753     * Degree in variable i.
754     * @return maximal degree in the variable i.
755     */
756    public long degree(int i) {
757        if (val.isEmpty()) {
758            return -1L; // 0 or -1 ?;
759        }
760        int j;
761        if (i >= 0) {
762            j = ring.nvar - 1 - i;
763        } else { // python like -1 means main variable
764            j = ring.nvar + i;
765        }
766        long deg = 0;
767        if (j < 0) {
768            return deg;
769        }
770        for (ExpVector e : val.keySet()) {
771            long d = e.getVal(j);
772            if (d > deg) {
773                deg = d;
774            }
775        }
776        return deg;
777    }
778
779
780    /**
781     * Maximal degree.
782     * @return maximal degree in any variables.
783     */
784    public long degree() {
785        if (val.isEmpty()) {
786            return -1L; // 0 or -1 ?;
787        }
788        long deg = 0;
789        for (ExpVector e : val.keySet()) {
790            long d = e.maxDeg();
791            if (d > deg) {
792                deg = d;
793            }
794        }
795        return deg;
796    }
797
798
799    /**
800     * Minimal degree. <b>Author:</b> Youssef Elbarbary
801     * @return minimal degree in any variables.
802     */
803    public long degreeMin() {
804        if (val.isEmpty()) {
805            return -1L; // 0 or -1 ?;
806        }
807        long deg = Long.MAX_VALUE;
808        for (ExpVector e : val.keySet()) {
809            long d = e.minDeg();
810            if (d < deg) {
811                deg = d;
812            }
813        }
814        return deg;
815    }
816
817
818    /**
819     * Total degree.
820     * @return total degree in any variables.
821     */
822    public long totalDegree() {
823        if (val.isEmpty()) {
824            return -1L; // 0 or -1 ?;
825        }
826        long deg = 0;
827        for (ExpVector e : val.keySet()) {
828            long d = e.totalDeg();
829            if (d > deg) {
830                deg = d;
831            }
832        }
833        return deg;
834    }
835
836
837    /**
838     * Weight degree.
839     * @return weight degree in all variables.
840     */
841    public long weightDegree() {
842        long[][] w = ring.tord.getWeight();
843        if (w == null || w.length == 0) {
844            return totalDegree(); // assume weight 1 
845        }
846        if (val.isEmpty()) {
847            return -1L; // 0 or -1 ?;
848        }
849        long deg = 0;
850        for (ExpVector e : val.keySet()) {
851            long d = e.weightDeg(w);
852            if (d > deg) {
853                deg = d;
854            }
855        }
856        return deg;
857    }
858
859
860    /**
861     * Leading weight polynomial.
862     * @return polynomial with terms of maximal weight degree.
863     */
864    public GenPolynomial<C> leadingWeightPolynomial() {
865        if (val.isEmpty()) {
866            return ring.getZERO();
867        }
868        long[][] w = ring.tord.getWeight();
869        long maxw = weightDegree();
870        GenPolynomial<C> wp = ring.getZERO().copy();
871        for (Map.Entry<ExpVector, C> m : val.entrySet()) {
872            ExpVector e = m.getKey();
873            long d = e.weightDeg(w);
874            if (d >= maxw) {
875                wp.val.put(e, m.getValue());
876            }
877        }
878        return wp;
879    }
880
881
882    /**
883     * Leading facet normal polynomial.
884     * @param u leading exponent vector.
885     * @param uv exponent vector of facet normal.
886     * @return polynomial with terms of facet normal.
887     */
888    public GenPolynomial<C> leadingFacetPolynomial(ExpVector u, ExpVector uv) {
889        if (val.isEmpty()) {
890            return ring.getZERO();
891        }
892        long[] normal = uv.getVal();
893        GenPolynomial<C> fp = ring.getZERO().copy();
894        for (Map.Entry<ExpVector, C> m : val.entrySet()) {
895            ExpVector e = m.getKey();
896            if (u.equals(e)) {
897                fp.val.put(e, m.getValue());
898            } else {
899                ExpVector v = u.subtract(e);
900                if (v.compareTo(uv) == 0) { // || v.negate().compareTo(uv) == 0
901                    fp.val.put(e, m.getValue());
902                } else { // check for v parallel to uv
903                    long ab = v.weightDeg(normal); //scalarProduct(v, uv);
904                    long a = v.weightDeg(v.getVal()); //scalarProduct(v, v);
905                    long b = uv.weightDeg(normal); //scalarProduct(uv, uv);
906                    if (ab * ab == a * b) { // cos == 1
907                        fp.val.put(e, m.getValue());
908                        if (logger.isInfoEnabled()) {
909                            logger.info("ab = {}, a = {}, b = {}, u = {}, e = {}, v = {}", ab, a, b, u, e, v);
910                        }
911                    }
912                }
913            }
914        }
915        return fp;
916    }
917
918
919    /**
920     * Is GenPolynomial&lt;C&gt; homogeneous with respect to a weight.
921     * @return true, if this is weight homogeneous, else false.
922     */
923    public boolean isWeightHomogeneous() {
924        if (val.size() <= 1) {
925            return true;
926        }
927        long[][] w = ring.tord.getWeight();
928        if (w == null || w.length == 0) {
929            return isHomogeneous(); // assume weights = 1
930        }
931        long deg = -1;
932        for (ExpVector e : val.keySet()) {
933            if (deg < 0) {
934                deg = e.weightDeg(w);
935            } else if (deg != e.weightDeg(w)) {
936                return false;
937            }
938        }
939        return true;
940    }
941
942
943    /**
944     * Maximal degree vector.
945     * @return maximal degree vector of all variables.
946     */
947    public ExpVector degreeVector() {
948        if (val.isEmpty()) {
949            return null; //deg;
950        }
951        ExpVector deg = ring.evzero;
952        for (ExpVector e : val.keySet()) {
953            deg = deg.lcm(e);
954        }
955        return deg;
956    }
957
958
959    /**
960     * Delta of exponent vectors.
961     * @return list of u-v, where u = lt() and v != u in this.
962     */
963    public List<ExpVector> deltaExpVectors() {
964        List<ExpVector> de = new ArrayList<ExpVector>(val.size());
965        if (val.isEmpty()) {
966            return de;
967        }
968        ExpVector u = null;
969        for (ExpVector e : val.keySet()) {
970            if (u == null) {
971                u = e;
972            } else {
973                ExpVector v = u.subtract(e);
974                de.add(v);
975            }
976        }
977        return de;
978    }
979
980
981    /**
982     * Delta of exponent vectors.
983     * @param u marked ExpVector in this.expVectors
984     * @return list of u-v, where v != u in this.expVectors.
985     */
986    public List<ExpVector> deltaExpVectors(ExpVector u) {
987        List<ExpVector> de = new ArrayList<ExpVector>(val.size());
988        if (val.isEmpty()) {
989            return de;
990        }
991        for (ExpVector e : val.keySet()) {
992            ExpVector v = u.subtract(e);
993            if (v.isZERO()) {
994                continue;
995            }
996            de.add(v);
997        }
998        return de;
999    }
1000
1001
1002    /**
1003     * GenPolynomial maximum norm.
1004     * @return ||this|| the maximum of all absolute values of coefficients.
1005     */
1006    public C maxNorm() {
1007        C n = ring.getZEROCoefficient();
1008        for (C c : val.values()) {
1009            C x = c.abs();
1010            if (n.compareTo(x) < 0) {
1011                n = x;
1012            }
1013        }
1014        return n;
1015    }
1016
1017
1018    /**
1019     * GenPolynomial sum norm.
1020     * @return sum of all absolute values of coefficients.
1021     */
1022    public C sumNorm() {
1023        C n = ring.getZEROCoefficient();
1024        for (C c : val.values()) {
1025            C x = c.abs();
1026            n = n.sum(x);
1027        }
1028        return n;
1029    }
1030
1031
1032    /**
1033     * GenPolynomial square norm.
1034     * @return the sum all squared values of coefficients.
1035     */
1036    public C squareNorm() {
1037        C n = ring.getZEROCoefficient();
1038        for (C c : val.values()) {
1039            C x = c.abs();
1040            x = x.multiply(x);
1041            n = n.sum(x);
1042        }
1043        return n;
1044    }
1045
1046
1047    /**
1048     * GenPolynomial summation.
1049     * @param S GenPolynomial.
1050     * @return this+S.
1051     */
1052    //public <T extends GenPolynomial<C>> T sum(T /*GenPolynomial<C>*/ S) {
1053    public GenPolynomial<C> sum(GenPolynomial<C> S) {
1054        if (S == null || S.isZERO()) {
1055            return this;
1056        }
1057        if (this.isZERO()) {
1058            return S;
1059        }
1060        if (this.length() < (3 * S.length()) / 5) {
1061            return S.sum(this); // performance
1062        }
1063        assert (ring.nvar == S.ring.nvar);
1064        GenPolynomial<C> n = this.copy();
1065        SortedMap<ExpVector, C> nv = n.val;
1066        SortedMap<ExpVector, C> sv = S.val;
1067        for (Map.Entry<ExpVector, C> me : sv.entrySet()) {
1068            ExpVector e = me.getKey();
1069            C y = me.getValue(); // assert y != null
1070            C x = nv.get(e);
1071            if (x != null) {
1072                x = x.sum(y);
1073                if (!x.isZERO()) {
1074                    nv.put(e, x);
1075                } else {
1076                    nv.remove(e);
1077                }
1078            } else {
1079                nv.put(e, y);
1080            }
1081        }
1082        return n;
1083    }
1084
1085
1086    /**
1087     * GenPolynomial addition. This method is not very efficient, since this is
1088     * copied.
1089     * @param a coefficient.
1090     * @param e exponent.
1091     * @return this + a x<sup>e</sup>.
1092     */
1093    public GenPolynomial<C> sum(C a, ExpVector e) {
1094        if (a == null) {
1095            return this;
1096        }
1097        if (a.isZERO()) {
1098            return this;
1099        }
1100        GenPolynomial<C> n = this.copy();
1101        SortedMap<ExpVector, C> nv = n.val;
1102        //if ( nv.size() == 0 ) { nv.put(e,a); return n; }
1103        C x = nv.get(e);
1104        if (x != null) {
1105            x = x.sum(a);
1106            if (!x.isZERO()) {
1107                nv.put(e, x);
1108            } else {
1109                nv.remove(e);
1110            }
1111        } else {
1112            nv.put(e, a);
1113        }
1114        return n;
1115    }
1116
1117
1118    /**
1119     * GenPolynomial addition. This method is not very efficient, since this is
1120     * copied.
1121     * @param m monomial.
1122     * @return this + m.
1123     */
1124    public GenPolynomial<C> sum(Monomial<C> m) {
1125        return sum(m.coefficient(), m.exponent());
1126    }
1127
1128
1129    /**
1130     * GenPolynomial addition. This method is not very efficient, since this is
1131     * copied.
1132     * @param a coefficient.
1133     * @return this + a x<sup>0</sup>.
1134     */
1135    public GenPolynomial<C> sum(C a) {
1136        return sum(a, ring.evzero);
1137    }
1138
1139
1140    /**
1141     * GenPolynomial destructive summation.
1142     * @param S GenPolynomial.
1143     */
1144    public void doAddTo(GenPolynomial<C> S) {
1145        if (S == null || S.isZERO()) {
1146            return;
1147        }
1148        if (this.isZERO()) {
1149            this.val.putAll(S.val);
1150            return;
1151        }
1152        assert (ring.nvar == S.ring.nvar);
1153        SortedMap<ExpVector, C> nv = this.val;
1154        SortedMap<ExpVector, C> sv = S.val;
1155        for (Map.Entry<ExpVector, C> me : sv.entrySet()) {
1156            ExpVector e = me.getKey();
1157            C y = me.getValue(); // assert y != null
1158            C x = nv.get(e);
1159            if (x != null) {
1160                x = x.sum(y);
1161                if (!x.isZERO()) {
1162                    nv.put(e, x);
1163                } else {
1164                    nv.remove(e);
1165                }
1166            } else {
1167                nv.put(e, y);
1168            }
1169        }
1170        return;
1171    }
1172
1173
1174    /**
1175     * GenPolynomial destructive summation.
1176     * @param a coefficient.
1177     * @param e exponent.
1178     */
1179    public void doAddTo(C a, ExpVector e) {
1180        if (a == null || a.isZERO()) {
1181            return;
1182        }
1183        SortedMap<ExpVector, C> nv = this.val;
1184        C x = nv.get(e);
1185        if (x != null) {
1186            x = x.sum(a);
1187            if (!x.isZERO()) {
1188                nv.put(e, x);
1189            } else {
1190                nv.remove(e);
1191            }
1192        } else {
1193            nv.put(e, a);
1194        }
1195        return;
1196    }
1197
1198
1199    /**
1200     * GenPolynomial destructive summation.
1201     * @param a coefficient.
1202     */
1203    public void doAddTo(C a) {
1204        doAddTo(a, ring.evzero);
1205    }
1206
1207
1208    /**
1209     * GenPolynomial subtraction.
1210     * @param S GenPolynomial.
1211     * @return this-S.
1212     */
1213    public GenPolynomial<C> subtract(GenPolynomial<C> S) {
1214        if (S == null) {
1215            return this;
1216        }
1217        if (S.isZERO()) {
1218            return this;
1219        }
1220        if (this.isZERO()) {
1221            return S.negate();
1222        }
1223        assert (ring.nvar == S.ring.nvar);
1224        GenPolynomial<C> n = this.copy();
1225        SortedMap<ExpVector, C> nv = n.val;
1226        SortedMap<ExpVector, C> sv = S.val;
1227        for (Map.Entry<ExpVector, C> me : sv.entrySet()) {
1228            ExpVector e = me.getKey();
1229            C y = me.getValue(); // assert y != null
1230            C x = nv.get(e);
1231            if (x != null) {
1232                x = x.subtract(y);
1233                if (!x.isZERO()) {
1234                    nv.put(e, x);
1235                } else {
1236                    nv.remove(e);
1237                }
1238            } else {
1239                nv.put(e, y.negate());
1240            }
1241        }
1242        return n;
1243    }
1244
1245
1246    /**
1247     * GenPolynomial subtraction. This method is not very efficient, since this
1248     * is copied.
1249     * @param a coefficient.
1250     * @param e exponent.
1251     * @return this - a x<sup>e</sup>.
1252     */
1253    public GenPolynomial<C> subtract(C a, ExpVector e) {
1254        if (a == null || a.isZERO()) {
1255            return this;
1256        }
1257        GenPolynomial<C> n = this.copy();
1258        SortedMap<ExpVector, C> nv = n.val;
1259        C x = nv.get(e);
1260        if (x != null) {
1261            x = x.subtract(a);
1262            if (!x.isZERO()) {
1263                nv.put(e, x);
1264            } else {
1265                nv.remove(e);
1266            }
1267        } else {
1268            nv.put(e, a.negate());
1269        }
1270        return n;
1271    }
1272
1273
1274    /**
1275     * GenPolynomial subtraction. This method is not very efficient, since this
1276     * is copied.
1277     * @param m monomial.
1278     * @return this - m.
1279     */
1280    public GenPolynomial<C> subtract(Monomial<C> m) {
1281        return subtract(m.coefficient(), m.exponent());
1282    }
1283
1284
1285    /**
1286     * GenPolynomial subtract. This method is not very efficient, since this is
1287     * copied.
1288     * @param a coefficient.
1289     * @return this + a x<sup>0</sup>.
1290     */
1291    public GenPolynomial<C> subtract(C a) {
1292        return subtract(a, ring.evzero);
1293    }
1294
1295
1296    /**
1297     * GenPolynomial subtract a multiple.
1298     * @param a coefficient.
1299     * @param S GenPolynomial.
1300     * @return this - a S.
1301     */
1302    public GenPolynomial<C> subtractMultiple(C a, GenPolynomial<C> S) {
1303        if (a == null || a.isZERO()) {
1304            return this;
1305        }
1306        if (S == null || S.isZERO()) {
1307            return this;
1308        }
1309        if (this.isZERO()) {
1310            return S.multiply(a.negate());
1311        }
1312        assert (ring.nvar == S.ring.nvar);
1313        GenPolynomial<C> n = this.copy();
1314        SortedMap<ExpVector, C> nv = n.val;
1315        SortedMap<ExpVector, C> sv = S.val;
1316        for (Map.Entry<ExpVector, C> me : sv.entrySet()) {
1317            ExpVector f = me.getKey();
1318            C y = me.getValue(); // assert y != null
1319            y = a.multiply(y);
1320            C x = nv.get(f);
1321            if (x != null) {
1322                x = x.subtract(y);
1323                if (!x.isZERO()) {
1324                    nv.put(f, x);
1325                } else {
1326                    nv.remove(f);
1327                }
1328            } else if (!y.isZERO()) {
1329                nv.put(f, y.negate());
1330            }
1331        }
1332        return n;
1333    }
1334
1335
1336    /**
1337     * GenPolynomial subtract a multiple.
1338     * @param a coefficient.
1339     * @param e exponent.
1340     * @param S GenPolynomial.
1341     * @return this - a x<sup>e</sup> S.
1342     */
1343    public GenPolynomial<C> subtractMultiple(C a, ExpVector e, GenPolynomial<C> S) {
1344        if (a == null || a.isZERO()) {
1345            return this;
1346        }
1347        if (S == null || S.isZERO()) {
1348            return this;
1349        }
1350        if (this.isZERO()) {
1351            return S.multiply(a.negate(), e);
1352        }
1353        assert (ring.nvar == S.ring.nvar);
1354        GenPolynomial<C> n = this.copy();
1355        SortedMap<ExpVector, C> nv = n.val;
1356        SortedMap<ExpVector, C> sv = S.val;
1357        for (Map.Entry<ExpVector, C> me : sv.entrySet()) {
1358            ExpVector f = me.getKey();
1359            f = e.sum(f);
1360            C y = me.getValue(); // assert y != null
1361            y = a.multiply(y);
1362            C x = nv.get(f);
1363            if (x != null) {
1364                x = x.subtract(y);
1365                if (!x.isZERO()) {
1366                    nv.put(f, x);
1367                } else {
1368                    nv.remove(f);
1369                }
1370            } else if (!y.isZERO()) {
1371                nv.put(f, y.negate());
1372            }
1373        }
1374        return n;
1375    }
1376
1377
1378    /**
1379     * GenPolynomial scale and subtract a multiple.
1380     * @param b scale factor.
1381     * @param a coefficient.
1382     * @param S GenPolynomial.
1383     * @return this * b - a S.
1384     */
1385    public GenPolynomial<C> scaleSubtractMultiple(C b, C a, GenPolynomial<C> S) {
1386        if (a == null || S == null) {
1387            return this.multiply(b);
1388        }
1389        if (a.isZERO() || S.isZERO()) {
1390            return this.multiply(b);
1391        }
1392        if (this.isZERO() || b == null || b.isZERO()) {
1393            return S.multiply(a.negate()); //left?
1394        }
1395        if (b.isONE()) {
1396            return subtractMultiple(a, S);
1397        }
1398        assert (ring.nvar == S.ring.nvar);
1399        GenPolynomial<C> n = this.multiply(b);
1400        SortedMap<ExpVector, C> nv = n.val;
1401        SortedMap<ExpVector, C> sv = S.val;
1402        for (Map.Entry<ExpVector, C> me : sv.entrySet()) {
1403            ExpVector f = me.getKey();
1404            //f = e.sum(f);
1405            C y = me.getValue(); // assert y != null
1406            y = a.multiply(y); // now y can be zero
1407            C x = nv.get(f);
1408            if (x != null) {
1409                x = x.subtract(y);
1410                if (!x.isZERO()) {
1411                    nv.put(f, x);
1412                } else {
1413                    nv.remove(f);
1414                }
1415            } else if (!y.isZERO()) {
1416                nv.put(f, y.negate());
1417            }
1418        }
1419        return n;
1420    }
1421
1422
1423    /**
1424     * GenPolynomial scale and subtract a multiple.
1425     * @param b scale factor.
1426     * @param a coefficient.
1427     * @param e exponent.
1428     * @param S GenPolynomial.
1429     * @return this * b - a x<sup>e</sup> S.
1430     */
1431    public GenPolynomial<C> scaleSubtractMultiple(C b, C a, ExpVector e, GenPolynomial<C> S) {
1432        if (a == null || S == null) {
1433            return this.multiply(b);
1434        }
1435        if (a.isZERO() || S.isZERO()) {
1436            return this.multiply(b);
1437        }
1438        if (this.isZERO() || b == null || b.isZERO()) {
1439            return S.multiply(a.negate(), e);
1440        }
1441        if (b.isONE()) {
1442            return subtractMultiple(a, e, S);
1443        }
1444        assert (ring.nvar == S.ring.nvar);
1445        GenPolynomial<C> n = this.multiply(b);
1446        SortedMap<ExpVector, C> nv = n.val;
1447        SortedMap<ExpVector, C> sv = S.val;
1448        for (Map.Entry<ExpVector, C> me : sv.entrySet()) {
1449            ExpVector f = me.getKey();
1450            f = e.sum(f);
1451            C y = me.getValue(); // assert y != null
1452            y = a.multiply(y); // now y can be zero
1453            C x = nv.get(f);
1454            if (x != null) {
1455                x = x.subtract(y);
1456                if (!x.isZERO()) {
1457                    nv.put(f, x);
1458                } else {
1459                    nv.remove(f);
1460                }
1461            } else if (!y.isZERO()) {
1462                nv.put(f, y.negate());
1463            }
1464        }
1465        return n;
1466    }
1467
1468
1469    /**
1470     * GenPolynomial scale and subtract a multiple.
1471     * @param b scale factor.
1472     * @param g scale exponent.
1473     * @param a coefficient.
1474     * @param e exponent.
1475     * @param S GenPolynomial.
1476     * @return this * a x<sup>g</sup> - a x<sup>e</sup> S.
1477     */
1478    public GenPolynomial<C> scaleSubtractMultiple(C b, ExpVector g, C a, ExpVector e, GenPolynomial<C> S) {
1479        if (a == null || S == null) {
1480            return this.multiply(b, g);
1481        }
1482        if (a.isZERO() || S.isZERO()) {
1483            return this.multiply(b, g);
1484        }
1485        if (this.isZERO() || b == null || b.isZERO()) {
1486            return S.multiply(a.negate(), e);
1487        }
1488        if (b.isONE() && g.isZERO()) {
1489            return subtractMultiple(a, e, S);
1490        }
1491        assert (ring.nvar == S.ring.nvar);
1492        GenPolynomial<C> n = this.multiply(b, g);
1493        SortedMap<ExpVector, C> nv = n.val;
1494        SortedMap<ExpVector, C> sv = S.val;
1495        for (Map.Entry<ExpVector, C> me : sv.entrySet()) {
1496            ExpVector f = me.getKey();
1497            f = e.sum(f);
1498            C y = me.getValue(); // assert y != null
1499            y = a.multiply(y); // y can be zero now
1500            C x = nv.get(f);
1501            if (x != null) {
1502                x = x.subtract(y);
1503                if (!x.isZERO()) {
1504                    nv.put(f, x);
1505                } else {
1506                    nv.remove(f);
1507                }
1508            } else if (!y.isZERO()) {
1509                nv.put(f, y.negate());
1510            }
1511        }
1512        return n;
1513    }
1514
1515
1516    /**
1517     * GenPolynomial negation, alternative implementation.
1518     * @return -this.
1519     */
1520    public GenPolynomial<C> negateAlt() {
1521        GenPolynomial<C> n = ring.getZERO().copy();
1522        SortedMap<ExpVector, C> v = n.val;
1523        for (Map.Entry<ExpVector, C> m : val.entrySet()) {
1524            C x = m.getValue(); // != null, 0
1525            v.put(m.getKey(), x.negate());
1526        }
1527        return n;
1528    }
1529
1530
1531    /**
1532     * GenPolynomial negation.
1533     * @return -this.
1534     */
1535    public GenPolynomial<C> negate() {
1536        GenPolynomial<C> n = this.copy();
1537        SortedMap<ExpVector, C> v = n.val;
1538        for (Map.Entry<ExpVector, C> m : v.entrySet()) {
1539            C x = m.getValue(); // != null, 0
1540            m.setValue(x.negate()); // okay
1541        }
1542        return n;
1543    }
1544
1545
1546    /**
1547     * GenPolynomial absolute value, i.e. leadingCoefficient &gt; 0.
1548     * @return abs(this).
1549     */
1550    public GenPolynomial<C> abs() {
1551        if (leadingBaseCoefficient().signum() < 0) {
1552            return this.negate();
1553        }
1554        return this;
1555    }
1556
1557
1558    /**
1559     * GenPolynomial multiplication.
1560     * @param S GenPolynomial.
1561     * @return this*S.
1562     */
1563    public GenPolynomial<C> multiply(GenPolynomial<C> S) {
1564        if (S == null) {
1565            return ring.getZERO();
1566        }
1567        if (S.isZERO()) {
1568            return ring.getZERO();
1569        }
1570        if (this.isZERO()) {
1571            return this;
1572        }
1573        assert (ring.nvar == S.ring.nvar);
1574        if (this instanceof GenSolvablePolynomial && S instanceof GenSolvablePolynomial) {
1575            //throw new RuntimeException("wrong method dispatch in JRE ");
1576            logger.debug("warn: wrong method dispatch in JRE multiply(S) - trying to fix");
1577            GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this;
1578            GenSolvablePolynomial<C> Sp = (GenSolvablePolynomial<C>) S;
1579            return T.multiply(Sp);
1580        }
1581        GenPolynomial<C> p = ring.getZERO().copy();
1582        SortedMap<ExpVector, C> pv = p.val;
1583        for (Map.Entry<ExpVector, C> m1 : val.entrySet()) {
1584            C c1 = m1.getValue();
1585            ExpVector e1 = m1.getKey();
1586            for (Map.Entry<ExpVector, C> m2 : S.val.entrySet()) {
1587                C c2 = m2.getValue();
1588                ExpVector e2 = m2.getKey();
1589                C c = c1.multiply(c2); // check non zero if not domain
1590                if (!c.isZERO()) {
1591                    ExpVector e = e1.sum(e2);
1592                    C c0 = pv.get(e);
1593                    if (c0 == null) {
1594                        pv.put(e, c);
1595                    } else {
1596                        c0 = c0.sum(c);
1597                        if (!c0.isZERO()) {
1598                            pv.put(e, c0);
1599                        } else {
1600                            pv.remove(e);
1601                        }
1602                    }
1603                }
1604            }
1605        }
1606        return p;
1607    }
1608
1609
1610    /**
1611     * GenPolynomial multiplication. Product with coefficient ring element.
1612     * @param s coefficient.
1613     * @return this*s.
1614     */
1615    public GenPolynomial<C> multiply(C s) {
1616        if (s == null || s.isZERO()) {
1617            return ring.getZERO();
1618        }
1619        if (this.isZERO()) {
1620            return this;
1621        }
1622        if (this instanceof GenSolvablePolynomial) {
1623            //throw new RuntimeException("wrong method dispatch in JRE ");
1624            logger.debug("warn: wrong method dispatch in JRE multiply(s) - trying to fix");
1625            GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this;
1626            return T.multiply(s);
1627        }
1628        GenPolynomial<C> p = ring.getZERO().copy();
1629        SortedMap<ExpVector, C> pv = p.val;
1630        for (Map.Entry<ExpVector, C> m : val.entrySet()) {
1631            C a = m.getValue();
1632            ExpVector e = m.getKey();
1633            C c = a.multiply(s); // check non zero if not domain
1634            if (!c.isZERO()) {
1635                pv.put(e, c); // not m1.setValue( c )
1636            }
1637        }
1638        return p;
1639    }
1640
1641
1642    /**
1643     * GenPolynomial left multiplication. Left product with coefficient ring
1644     * element.
1645     * @param s coefficient.
1646     * @return s*this.
1647     */
1648    public GenPolynomial<C> multiplyLeft(C s) {
1649        if (s == null || s.isZERO()) {
1650            return ring.getZERO();
1651        }
1652        if (this.isZERO()) {
1653            return this;
1654        }
1655        if (this instanceof GenSolvablePolynomial) {
1656            //throw new RuntimeException("wrong method dispatch in JRE ");
1657            logger.debug("warn: wrong method dispatch in JRE multiply(s) - trying to fix");
1658            GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this;
1659            return T.multiplyLeft(s);
1660        }
1661        GenPolynomial<C> p = ring.getZERO().copy();
1662        SortedMap<ExpVector, C> pv = p.val;
1663        for (Map.Entry<ExpVector, C> m : val.entrySet()) {
1664            C a = m.getValue();
1665            ExpVector e = m.getKey();
1666            C c = s.multiply(a);
1667            if (!c.isZERO()) {
1668                pv.put(e, c);
1669            }
1670        }
1671        return p;
1672    }
1673
1674
1675    /**
1676     * GenPolynomial monic, i.e. leadingCoefficient == 1. If leadingCoefficient
1677     * is not invertible returns this unmodified.
1678     * @return monic(this).
1679     */
1680    public GenPolynomial<C> monic() {
1681        if (this.isZERO()) {
1682            return this;
1683        }
1684        C lc = leadingBaseCoefficient();
1685        if (!lc.isUnit()) {
1686            //System.out.println("lc = "+lc);
1687            return this;
1688        }
1689        C lm = lc.inverse();
1690        return multiplyLeft(lm);
1691    }
1692
1693
1694    /**
1695     * GenPolynomial multiplication. Product with ring element and exponent
1696     * vector.
1697     * @param s coefficient.
1698     * @param e exponent.
1699     * @return this * s x<sup>e</sup>.
1700     */
1701    public GenPolynomial<C> multiply(C s, ExpVector e) {
1702        if (s == null) {
1703            return ring.getZERO();
1704        }
1705        if (s.isZERO()) {
1706            return ring.getZERO();
1707        }
1708        if (this.isZERO()) {
1709            return this;
1710        }
1711        if (e == null) { // exp vector of zero polynomial
1712            return ring.getZERO();
1713        }
1714        if (this instanceof GenSolvablePolynomial) {
1715            //throw new RuntimeException("wrong method dispatch in JRE ");
1716            logger.debug("warn: wrong method dispatch in JRE multiply(s,e) - trying to fix");
1717            GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this;
1718            return T.multiply(s, e);
1719        }
1720        GenPolynomial<C> p = ring.getZERO().copy();
1721        SortedMap<ExpVector, C> pv = p.val;
1722        for (Map.Entry<ExpVector, C> m1 : val.entrySet()) {
1723            C c1 = m1.getValue();
1724            ExpVector e1 = m1.getKey();
1725            C c = c1.multiply(s); // check non zero if not domain
1726            if (!c.isZERO()) {
1727                ExpVector e2 = e1.sum(e);
1728                pv.put(e2, c);
1729            }
1730        }
1731        return p;
1732    }
1733
1734
1735    /**
1736     * GenPolynomial multiplication. Product with exponent vector.
1737     * @param e exponent (!= null).
1738     * @return this * x<sup>e</sup>.
1739     */
1740    public GenPolynomial<C> multiply(ExpVector e) {
1741        if (e == null) { // exp vector of zero polynomial
1742            return ring.getZERO();
1743        }
1744        // assert e != null. This is seldom allowed.
1745        if (this.isZERO()) {
1746            return this;
1747        }
1748        if (this instanceof GenSolvablePolynomial) {
1749            //throw new RuntimeException("wrong method dispatch in JRE ");
1750            logger.debug("warn: wrong method dispatch in JRE multiply(e) - trying to fix");
1751            GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this;
1752            return T.multiply(e);
1753        }
1754        GenPolynomial<C> p = ring.getZERO().copy();
1755        SortedMap<ExpVector, C> pv = p.val;
1756        for (Map.Entry<ExpVector, C> m1 : val.entrySet()) {
1757            C c1 = m1.getValue();
1758            ExpVector e1 = m1.getKey();
1759            ExpVector e2 = e1.sum(e);
1760            pv.put(e2, c1);
1761        }
1762        return p;
1763    }
1764
1765
1766    /**
1767     * GenPolynomial multiplication. Product with 'monomial'.
1768     * @param m 'monomial'.
1769     * @return this * m.
1770     */
1771    public GenPolynomial<C> multiply(Map.Entry<ExpVector, C> m) {
1772        if (m == null) {
1773            return ring.getZERO();
1774        }
1775        return multiply(m.getValue(), m.getKey());
1776    }
1777
1778
1779    /**
1780     * GenPolynomial division. Division by coefficient ring element. Fails, if
1781     * exact division is not possible.
1782     * @param s coefficient.
1783     * @return s**(-1) * this.
1784     */
1785    public GenPolynomial<C> divide(C s) {
1786        if (s == null || s.isZERO()) {
1787            throw new ArithmeticException("division by zero");
1788        }
1789        if (this.isZERO()) {
1790            return this;
1791        }
1792        //C t = s.inverse();
1793        //return multiply(t);
1794        GenPolynomial<C> p = ring.getZERO().copy();
1795        SortedMap<ExpVector, C> pv = p.val;
1796        for (Map.Entry<ExpVector, C> m : val.entrySet()) {
1797            ExpVector e = m.getKey();
1798            C c1 = m.getValue();
1799            C c = c1.divide(s);
1800            if (debug) {
1801                C x = c1.remainder(s);
1802                if (!x.isZERO()) {
1803                    logger.info("divide x = {}", x);
1804                    throw new ArithmeticException("no exact division: " + c1 + "/" + s);
1805                }
1806            }
1807            if (c.isZERO()) {
1808                throw new ArithmeticException("no exact division: " + c1 + "/" + s + ", in " + this);
1809            }
1810            pv.put(e, c); // not m1.setValue( c )
1811        }
1812        return p;
1813    }
1814
1815
1816    /**
1817     * GenPolynomial right division. Right division by coefficient ring element.
1818     * Fails, if exact division is not possible.
1819     * @param s coefficient.
1820     * @return this * s**(-1).
1821     */
1822    public GenPolynomial<C> rightDivideCoeff(C s) {
1823        if (s == null || s.isZERO()) {
1824            throw new ArithmeticException("division by zero");
1825        }
1826        if (this.isZERO()) {
1827            return this;
1828        }
1829        //C t = s.inverse();
1830        //return multiply(t);
1831        GenPolynomial<C> p = ring.getZERO().copy();
1832        SortedMap<ExpVector, C> pv = p.val;
1833        for (Map.Entry<ExpVector, C> m : val.entrySet()) {
1834            ExpVector e = m.getKey();
1835            C c1 = m.getValue();
1836            C c = c1.rightDivide(s);
1837            if (debug) {
1838                C x = c1.rightRemainder(s);
1839                if (!x.isZERO()) {
1840                    logger.info("divide x = {}", x);
1841                    throw new ArithmeticException("no exact division: " + c1 + "/" + s);
1842                }
1843            }
1844            if (c.isZERO()) {
1845                throw new ArithmeticException("no exact division: " + c1 + "/" + s + ", in " + this);
1846            }
1847            pv.put(e, c); // not m1.setValue( c )
1848        }
1849        return p;
1850    }
1851
1852
1853    /**
1854     * GenPolynomial left division. Left division by coefficient ring element.
1855     * Fails, if exact division is not possible.
1856     * @param s coefficient.
1857     * @return s**(-1) * this.
1858     */
1859    public GenPolynomial<C> leftDivideCoeff(C s) {
1860        if (s == null || s.isZERO()) {
1861            throw new ArithmeticException("division by zero");
1862        }
1863        if (this.isZERO()) {
1864            return this;
1865        }
1866        //C t = s.inverse();
1867        //return multiply(t);
1868        GenPolynomial<C> p = ring.getZERO().copy();
1869        SortedMap<ExpVector, C> pv = p.val;
1870        for (Map.Entry<ExpVector, C> m : val.entrySet()) {
1871            ExpVector e = m.getKey();
1872            C c1 = m.getValue();
1873            C c = c1.leftDivide(s);
1874            if (debug) {
1875                C x = c1.leftRemainder(s);
1876                if (!x.isZERO()) {
1877                    logger.info("divide x = {}", x);
1878                    throw new ArithmeticException("no exact division: " + c1 + "/" + s);
1879                }
1880            }
1881            if (c.isZERO()) {
1882                throw new ArithmeticException("no exact division: " + c1 + "/" + s + ", in " + this);
1883            }
1884            pv.put(e, c); // not m1.setValue( c )
1885        }
1886        return p;
1887    }
1888
1889
1890    /**
1891     * GenPolynomial division with remainder. Fails, if exact division by
1892     * leading base coefficient is not possible. Meaningful only for univariate
1893     * polynomials over fields, but works in any case.
1894     * @param S nonzero GenPolynomial with invertible leading coefficient.
1895     * @return [ quotient , remainder ] with this = quotient * S + remainder and
1896     *         deg(remainder) &lt; deg(S) or remiander = 0.
1897     * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial)
1898     */
1899    @SuppressWarnings("unchecked")
1900    public GenPolynomial<C>[] quotientRemainder(GenPolynomial<C> S) {
1901        if (S == null || S.isZERO()) {
1902            throw new ArithmeticException("division by zero");
1903        }
1904        C c = S.leadingBaseCoefficient();
1905        if (!c.isUnit()) {
1906            throw new ArithmeticException("lbcf not invertible " + c);
1907        }
1908        C ci = c.inverse();
1909        assert (ring.nvar == S.ring.nvar);
1910        ExpVector e = S.leadingExpVector();
1911        GenPolynomial<C> h;
1912        GenPolynomial<C> q = ring.getZERO().copy();
1913        GenPolynomial<C> r = this.copy();
1914        while (!r.isZERO()) {
1915            ExpVector f = r.leadingExpVector();
1916            if (f.multipleOf(e)) {
1917                C a = r.leadingBaseCoefficient();
1918                ExpVector g = f.subtract(e);
1919                a = a.multiply(ci);
1920                q = q.sum(a, g);
1921                h = S.multiply(a, g);
1922                r = r.subtract(h);
1923                assert (!f.equals(r.leadingExpVector())) : "leadingExpVector not descending: " + f;
1924            } else {
1925                break;
1926            }
1927        }
1928        GenPolynomial<C>[] ret = new GenPolynomial[2];
1929        ret[0] = q;
1930        ret[1] = r;
1931        return ret;
1932    }
1933
1934
1935    /**
1936     * GenPolynomial division. Fails, if exact division by leading base
1937     * coefficient is not possible. Meaningful only for univariate polynomials
1938     * over fields, but works in any case.
1939     * @param S nonzero GenPolynomial with invertible leading coefficient.
1940     * @return quotient with this = quotient * S + remainder.
1941     * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial)
1942     */
1943    public GenPolynomial<C> divide(GenPolynomial<C> S) {
1944        if (this instanceof GenSolvablePolynomial || S instanceof GenSolvablePolynomial) {
1945            //throw new RuntimeException("wrong method dispatch in JRE ");
1946            //logger.debug("warn: wrong method dispatch in JRE multiply(S) - trying to fix");
1947            GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this;
1948            GenSolvablePolynomial<C> Sp = (GenSolvablePolynomial<C>) S;
1949            return T.quotientRemainder(Sp)[0];
1950        }
1951        return quotientRemainder(S)[0];
1952    }
1953
1954
1955    /**
1956     * GenPolynomial remainder. Fails, if exact division by leading base
1957     * coefficient is not possible. Meaningful only for univariate polynomials
1958     * over fields, but works in any case.
1959     * @param S nonzero GenPolynomial with invertible leading coefficient.
1960     * @return remainder with this = quotient * S + remainder.
1961     * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial)
1962     */
1963    public GenPolynomial<C> remainder(GenPolynomial<C> S) {
1964        if (this instanceof GenSolvablePolynomial || S instanceof GenSolvablePolynomial) {
1965            //throw new RuntimeException("wrong method dispatch in JRE ");
1966            //logger.debug("warn: wrong method dispatch in JRE multiply(S) - trying to fix");
1967            GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this;
1968            GenSolvablePolynomial<C> Sp = (GenSolvablePolynomial<C>) S;
1969            return T.quotientRemainder(Sp)[1];
1970        }
1971        if (S == null || S.isZERO()) {
1972            throw new ArithmeticException("division by zero");
1973        }
1974        C c = S.leadingBaseCoefficient();
1975        if (!c.isUnit()) {
1976            throw new ArithmeticException("lbc not invertible " + c);
1977        }
1978        C ci = c.inverse();
1979        assert (ring.nvar == S.ring.nvar);
1980        ExpVector e = S.leadingExpVector();
1981        GenPolynomial<C> h;
1982        GenPolynomial<C> r = this.copy();
1983        while (!r.isZERO()) {
1984            ExpVector f = r.leadingExpVector();
1985            if (f.multipleOf(e)) {
1986                C a = r.leadingBaseCoefficient();
1987                ExpVector g = f.subtract(e);
1988                //logger.info("red div = {}", e);
1989                a = a.multiply(ci);
1990                h = S.multiply(a, g);
1991                r = r.subtract(h);
1992                assert (!f.equals(r.leadingExpVector())) : "leadingExpVector not descending: " + f;
1993            } else {
1994                break;
1995            }
1996        }
1997        return r;
1998    }
1999
2000
2001    /**
2002     * GenPolynomial greatest common divisor. Only for univariate polynomials
2003     * over fields.
2004     * @param S GenPolynomial.
2005     * @return gcd(this,S).
2006     */
2007    public GenPolynomial<C> gcd(GenPolynomial<C> S) {
2008        if (S == null || S.isZERO()) {
2009            return this;
2010        }
2011        if (this.isZERO()) {
2012            return S;
2013        }
2014        if (ring.nvar != 1) {
2015            throw new IllegalArgumentException("not univariate polynomials" + ring);
2016        }
2017        GenPolynomial<C> x;
2018        GenPolynomial<C> q = this;
2019        GenPolynomial<C> r = S;
2020        while (!r.isZERO()) {
2021            x = q.remainder(r);
2022            q = r;
2023            r = x;
2024        }
2025        return q.monic(); // normalize
2026    }
2027
2028
2029    /**
2030     * GenPolynomial extended greatest comon divisor. Only for univariate
2031     * polynomials over fields.
2032     * @param S GenPolynomial.
2033     * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S).
2034     */
2035    @SuppressWarnings("unchecked")
2036    public GenPolynomial<C>[] egcd(GenPolynomial<C> S) {
2037        GenPolynomial<C>[] ret = new GenPolynomial[3];
2038        ret[0] = null;
2039        ret[1] = null;
2040        ret[2] = null;
2041        if (S == null || S.isZERO()) {
2042            ret[0] = this;
2043            ret[1] = this.ring.getONE();
2044            ret[2] = this.ring.getZERO();
2045            return ret;
2046        }
2047        if (this.isZERO()) {
2048            ret[0] = S;
2049            ret[1] = this.ring.getZERO();
2050            ret[2] = this.ring.getONE();
2051            return ret;
2052        }
2053        if (ring.nvar != 1) {
2054            throw new IllegalArgumentException(
2055                            this.getClass().getName() + " not univariate polynomials" + ring);
2056        }
2057        if (this.isConstant() && S.isConstant()) {
2058            C t = this.leadingBaseCoefficient();
2059            C s = S.leadingBaseCoefficient();
2060            C[] gg = t.egcd(s);
2061            //System.out.println("coeff gcd = " + Arrays.toString(gg));
2062            GenPolynomial<C> z = this.ring.getZERO();
2063            ret[0] = z.sum(gg[0]);
2064            ret[1] = z.sum(gg[1]);
2065            ret[2] = z.sum(gg[2]);
2066            return ret;
2067        }
2068        GenPolynomial<C>[] qr;
2069        GenPolynomial<C> q = this;
2070        GenPolynomial<C> r = S;
2071        GenPolynomial<C> c1 = ring.getONE().copy();
2072        GenPolynomial<C> d1 = ring.getZERO().copy();
2073        GenPolynomial<C> c2 = ring.getZERO().copy();
2074        GenPolynomial<C> d2 = ring.getONE().copy();
2075        GenPolynomial<C> x1;
2076        GenPolynomial<C> x2;
2077        while (!r.isZERO()) {
2078            qr = q.quotientRemainder(r);
2079            q = qr[0];
2080            x1 = c1.subtract(q.multiply(d1));
2081            x2 = c2.subtract(q.multiply(d2));
2082            c1 = d1;
2083            c2 = d2;
2084            d1 = x1;
2085            d2 = x2;
2086            q = r;
2087            r = qr[1];
2088        }
2089        // normalize ldcf(q) to 1, i.e. make monic
2090        C g = q.leadingBaseCoefficient();
2091        if (g.isUnit()) {
2092            C h = g.inverse();
2093            q = q.multiply(h);
2094            c1 = c1.multiply(h);
2095            c2 = c2.multiply(h);
2096        }
2097        //assert ( ((c1.multiply(this)).sum( c2.multiply(S)).equals(q) )); 
2098        ret[0] = q;
2099        ret[1] = c1;
2100        ret[2] = c2;
2101        return ret;
2102    }
2103
2104
2105    /**
2106     * GenPolynomial half extended greatest comon divisor. Only for univariate
2107     * polynomials over fields.
2108     * @param S GenPolynomial.
2109     * @return [ gcd(this,S), a ] with a*this + b*S = gcd(this,S).
2110     */
2111    @SuppressWarnings("unchecked")
2112    public GenPolynomial<C>[] hegcd(GenPolynomial<C> S) {
2113        GenPolynomial<C>[] ret = new GenPolynomial[2];
2114        ret[0] = null;
2115        ret[1] = null;
2116        if (S == null || S.isZERO()) {
2117            ret[0] = this;
2118            ret[1] = this.ring.getONE();
2119            return ret;
2120        }
2121        if (this.isZERO()) {
2122            ret[0] = S;
2123            return ret;
2124        }
2125        if (ring.nvar != 1) {
2126            throw new IllegalArgumentException(
2127                            this.getClass().getName() + " not univariate polynomials" + ring);
2128        }
2129        GenPolynomial<C>[] qr;
2130        GenPolynomial<C> q = this;
2131        GenPolynomial<C> r = S;
2132        GenPolynomial<C> c1 = ring.getONE().copy();
2133        GenPolynomial<C> d1 = ring.getZERO().copy();
2134        GenPolynomial<C> x1;
2135        while (!r.isZERO()) {
2136            qr = q.quotientRemainder(r);
2137            q = qr[0];
2138            x1 = c1.subtract(q.multiply(d1));
2139            c1 = d1;
2140            d1 = x1;
2141            q = r;
2142            r = qr[1];
2143        }
2144        // normalize ldcf(q) to 1, i.e. make monic
2145        C g = q.leadingBaseCoefficient();
2146        if (g.isUnit()) {
2147            C h = g.inverse();
2148            q = q.multiply(h);
2149            c1 = c1.multiply(h);
2150        }
2151        //assert ( ((c1.multiply(this)).remainder(S).equals(q) )); 
2152        ret[0] = q;
2153        ret[1] = c1;
2154        return ret;
2155    }
2156
2157
2158    /**
2159     * GenPolynomial inverse. Required by RingElem. Throws not invertible
2160     * exception.
2161     */
2162    public GenPolynomial<C> inverse() {
2163        if (isUnit()) { // only possible if ldbcf is unit
2164            C c = leadingBaseCoefficient().inverse();
2165            return ring.getONE().multiply(c);
2166        }
2167        throw new NotInvertibleException("element not invertible " + this + " :: " + ring);
2168    }
2169
2170
2171    /**
2172     * GenPolynomial modular inverse. Only for univariate polynomials over
2173     * fields.
2174     * @param m GenPolynomial.
2175     * @return a with with a*this = 1 mod m.
2176     */
2177    public GenPolynomial<C> modInverse(GenPolynomial<C> m) {
2178        if (this.isZERO()) {
2179            throw new NotInvertibleException("zero is not invertible");
2180        }
2181        GenPolynomial<C>[] hegcd = this.hegcd(m);
2182        GenPolynomial<C> a = hegcd[0];
2183        if (!a.isUnit()) { // gcd != 1
2184            throw new AlgebraicNotInvertibleException("element not invertible, gcd != 1", m, a, m.divide(a));
2185        }
2186        GenPolynomial<C> b = hegcd[1];
2187        if (b.isZERO()) { // when m divides this, e.g. m.isUnit()
2188            throw new NotInvertibleException("element not invertible, divisible by modul");
2189        }
2190        return b;
2191    }
2192
2193
2194    /**
2195     * Extend variables. Used e.g. in module embedding. Extend all ExpVectors by
2196     * i elements and multiply by x_j^k.
2197     * @param pfac extended polynomial ring factory (by i variables).
2198     * @param j index of variable to be used for multiplication.
2199     * @param k exponent for x_j.
2200     * @return extended polynomial.
2201     */
2202    public GenPolynomial<C> extend(GenPolynomialRing<C> pfac, int j, long k) {
2203        if (ring.equals(pfac)) { // nothing to do
2204            return this;
2205        }
2206        GenPolynomial<C> Cp = pfac.getZERO().copy();
2207        if (this.isZERO()) {
2208            return Cp;
2209        }
2210        int i = pfac.nvar - ring.nvar;
2211        Map<ExpVector, C> C = Cp.val; //getMap();
2212        Map<ExpVector, C> A = val;
2213        for (Map.Entry<ExpVector, C> y : A.entrySet()) {
2214            ExpVector e = y.getKey();
2215            C a = y.getValue();
2216            ExpVector f = e.extend(i, j, k);
2217            C.put(f, a);
2218        }
2219        return Cp;
2220    }
2221
2222
2223    /**
2224     * Extend lower variables. Used e.g. in module embedding. Extend all
2225     * ExpVectors by i lower elements and multiply by x_j^k.
2226     * @param pfac extended polynomial ring factory (by i variables).
2227     * @param j index of variable to be used for multiplication.
2228     * @param k exponent for x_j.
2229     * @return extended polynomial.
2230     */
2231    public GenPolynomial<C> extendLower(GenPolynomialRing<C> pfac, int j, long k) {
2232        if (ring.equals(pfac)) { // nothing to do
2233            return this;
2234        }
2235        GenPolynomial<C> Cp = pfac.getZERO().copy();
2236        if (this.isZERO()) {
2237            return Cp;
2238        }
2239        int i = pfac.nvar - ring.nvar;
2240        Map<ExpVector, C> C = Cp.val; //getMap();
2241        Map<ExpVector, C> A = val;
2242        for (Map.Entry<ExpVector, C> y : A.entrySet()) {
2243            ExpVector e = y.getKey();
2244            C a = y.getValue();
2245            ExpVector f = e.extendLower(i, j, k);
2246            C.put(f, a);
2247        }
2248        return Cp;
2249    }
2250
2251
2252    /**
2253     * Contract variables. Used e.g. in module embedding. Remove i elements of
2254     * each ExpVector.
2255     * @param pfac contracted polynomial ring factory (by i variables).
2256     * @return Map of exponents and contracted polynomials. <b>Note:</b> could
2257     *         return SortedMap
2258     */
2259    public Map<ExpVector, GenPolynomial<C>> contract(GenPolynomialRing<C> pfac) {
2260        GenPolynomial<C> zero = pfac.getZERO(); //not pfac.coFac;
2261        TermOrder t = new TermOrder(TermOrder.INVLEX);
2262        Map<ExpVector, GenPolynomial<C>> B = new TreeMap<ExpVector, GenPolynomial<C>>(
2263                        t.getAscendComparator());
2264        if (this.isZERO()) {
2265            return B;
2266        }
2267        int i = ring.nvar - pfac.nvar;
2268        Map<ExpVector, C> A = val;
2269        for (Map.Entry<ExpVector, C> y : A.entrySet()) {
2270            ExpVector e = y.getKey();
2271            C a = y.getValue();
2272            ExpVector f = e.contract(0, i);
2273            ExpVector g = e.contract(i, e.length() - i);
2274            GenPolynomial<C> p = B.get(f);
2275            if (p == null) {
2276                p = zero;
2277            }
2278            p = p.sum(a, g);
2279            B.put(f, p);
2280        }
2281        return B;
2282    }
2283
2284
2285    /**
2286     * Contract variables to coefficient polynomial. Remove i elements of each
2287     * ExpVector, removed elements must be zero.
2288     * @param pfac contracted polynomial ring factory (by i variables).
2289     * @return contracted coefficient polynomial.
2290     */
2291    public GenPolynomial<C> contractCoeff(GenPolynomialRing<C> pfac) {
2292        Map<ExpVector, GenPolynomial<C>> ms = contract(pfac);
2293        GenPolynomial<C> c = pfac.getZERO();
2294        for (Map.Entry<ExpVector, GenPolynomial<C>> m : ms.entrySet()) {
2295            if (m.getKey().isZERO()) {
2296                c = m.getValue();
2297            } else {
2298                throw new RuntimeException("wrong coefficient contraction " + m + ", pol =  " + c);
2299            }
2300        }
2301        return c;
2302    }
2303
2304
2305    /**
2306     * Extend univariate to multivariate polynomial. This is an univariate
2307     * polynomial in variable i of the polynomial ring, it is extended to the
2308     * given polynomial ring.
2309     * @param pfac extended polynomial ring factory.
2310     * @param i index of the variable of this polynomial in pfac.
2311     * @return extended multivariate polynomial.
2312     */
2313    public GenPolynomial<C> extendUnivariate(GenPolynomialRing<C> pfac, int i) {
2314        if (i < 0 || pfac.nvar < i) {
2315            throw new IllegalArgumentException("index " + i + "out of range " + pfac.nvar);
2316        }
2317        if (ring.nvar != 1) {
2318            throw new IllegalArgumentException("polynomial not univariate " + ring.nvar);
2319        }
2320        if (this.isONE()) {
2321            return pfac.getONE();
2322        }
2323        int j = pfac.nvar - 1 - i;
2324        GenPolynomial<C> Cp = pfac.getZERO().copy();
2325        if (this.isZERO()) {
2326            return Cp;
2327        }
2328        Map<ExpVector, C> C = Cp.val; //getMap();
2329        Map<ExpVector, C> A = val;
2330        for (Map.Entry<ExpVector, C> y : A.entrySet()) {
2331            ExpVector e = y.getKey();
2332            long n = e.getVal(0);
2333            C a = y.getValue();
2334            ExpVector f = ExpVector.create(pfac.nvar, j, n);
2335            C.put(f, a); // assert not contained
2336        }
2337        return Cp;
2338    }
2339
2340
2341    /**
2342     * Make homogeneous.
2343     * @param pfac extended polynomial ring factory (by 1 variable).
2344     * @return homogeneous polynomial.
2345     */
2346    public GenPolynomial<C> homogenize(GenPolynomialRing<C> pfac) {
2347        if (ring.equals(pfac)) { // not implemented
2348            throw new UnsupportedOperationException("case with same ring not implemented");
2349        }
2350        GenPolynomial<C> Cp = pfac.getZERO().copy();
2351        if (this.isZERO()) {
2352            return Cp;
2353        }
2354        long deg = totalDegree();
2355        //int i = pfac.nvar - ring.nvar;
2356        Map<ExpVector, C> C = Cp.val; //getMap();
2357        Map<ExpVector, C> A = val;
2358        for (Map.Entry<ExpVector, C> y : A.entrySet()) {
2359            ExpVector e = y.getKey();
2360            C a = y.getValue();
2361            long d = deg - e.totalDeg();
2362            ExpVector f = e.extend(1, 0, d);
2363            C.put(f, a);
2364        }
2365        return Cp;
2366    }
2367
2368
2369    /**
2370     * Dehomogenize.
2371     * @param pfac contracted polynomial ring factory (by 1 variable).
2372     * @return in homogeneous polynomial.
2373     */
2374    public GenPolynomial<C> deHomogenize(GenPolynomialRing<C> pfac) {
2375        if (ring.equals(pfac)) { // not implemented
2376            throw new UnsupportedOperationException("case with same ring not implemented");
2377        }
2378        GenPolynomial<C> Cp = pfac.getZERO().copy();
2379        if (this.isZERO()) {
2380            return Cp;
2381        }
2382        Map<ExpVector, C> C = Cp.val; //getMap();
2383        Map<ExpVector, C> A = val;
2384        for (Map.Entry<ExpVector, C> y : A.entrySet()) {
2385            ExpVector e = y.getKey();
2386            C a = y.getValue();
2387            ExpVector f = e.contract(1, pfac.nvar);
2388            C.put(f, a);
2389        }
2390        return Cp;
2391    }
2392
2393
2394    /**
2395     * Reverse variables. Used e.g. in opposite rings.
2396     * @return polynomial with reversed variables.
2397     */
2398    public GenPolynomial<C> reverse(GenPolynomialRing<C> oring) {
2399        GenPolynomial<C> Cp = oring.getZERO().copy();
2400        if (this.isZERO()) {
2401            return Cp;
2402        }
2403        int k = -1;
2404        if (oring.tord.getEvord2() != 0 && oring.partial) {
2405            k = oring.tord.getSplit();
2406        }
2407
2408        Map<ExpVector, C> C = Cp.val; //getMap();
2409        Map<ExpVector, C> A = val;
2410        ExpVector f;
2411        for (Map.Entry<ExpVector, C> y : A.entrySet()) {
2412            ExpVector e = y.getKey();
2413            if (k >= 0) {
2414                f = e.reverse(k);
2415            } else {
2416                f = e.reverse();
2417            }
2418            C a = y.getValue();
2419            C.put(f, a);
2420        }
2421        return Cp;
2422    }
2423
2424
2425    /**
2426     * GenPolynomial inflate. Only for univariate polynomials over fields.
2427     * @param e exponent.
2428     * @return this(x**e)
2429     */
2430    public GenPolynomial<C> inflate(long e) {
2431        if (e == 1) {
2432            return this;
2433        }
2434        if (this.isZERO()) {
2435            return this;
2436        }
2437        if (ring.nvar != 1) {
2438            throw new IllegalArgumentException(
2439                            this.getClass().getName() + " not univariate polynomial" + ring);
2440        }
2441        GenPolynomial<C> Cp = ring.getZERO().copy();
2442        Map<ExpVector, C> C = Cp.val; //getMap();
2443        Map<ExpVector, C> A = val;
2444        ExpVector f;
2445        for (Map.Entry<ExpVector, C> y : A.entrySet()) {
2446            ExpVector g = y.getKey();
2447            f = g.scalarMultiply(e);
2448            C a = y.getValue();
2449            C.put(f, a);
2450        }
2451        return Cp;
2452    }
2453
2454
2455    /**
2456     * Iterator over coefficients.
2457     * @return val.values().iterator().
2458     */
2459    public Iterator<C> coefficientIterator() {
2460        return val.values().iterator();
2461    }
2462
2463
2464    /**
2465     * Iterator over exponents.
2466     * @return val.keySet().iterator().
2467     */
2468    public Iterator<ExpVector> exponentIterator() {
2469        return val.keySet().iterator();
2470    }
2471
2472
2473    /**
2474     * Iterator over monomials.
2475     * @return a PolyIterator.
2476     */
2477    public Iterator<Monomial<C>> iterator() {
2478        return new PolyIterator<C>(val);
2479    }
2480
2481
2482    /**
2483     * Spliterator over monomials.
2484     * @return a PolySpliterator.
2485     */
2486    public Spliterator<Monomial<C>> spliterator() {
2487        return new PolySpliterator<C>(val);
2488    }
2489
2490
2491    /**
2492     * Map a unary function to the coefficients.
2493     * @param f evaluation functor.
2494     * @return new polynomial with coefficients f(this.coefficients).
2495     */
2496    public GenPolynomial<C> map(final UnaryFunctor<? super C, C> f) {
2497        GenPolynomial<C> n = ring.getZERO().copy();
2498        SortedMap<ExpVector, C> nv = n.val;
2499        for (Map.Entry<ExpVector, C> m : this.val.entrySet()) {
2500            //logger.info("m = {}", m);
2501            C c = f.eval(m.getValue());
2502            if (c != null && !c.isZERO()) {
2503                nv.put(m.getKey(), c);
2504            }
2505        }
2506        return n;
2507    }
2508
2509
2510    /*
2511     * Map a unary function to the coefficients.
2512     * @param f evaluation functor.
2513     * @return new polynomial with coefficients f(this.coefficients).
2514     */
2515    GenPolynomial<C> mapWrong(final UnaryFunctor<? super C, C> f) {
2516        GenPolynomial<C> n = this.copy();
2517        SortedMap<ExpVector, C> nv = n.val;
2518        for (Map.Entry<ExpVector, C> m : nv.entrySet()) {
2519            //logger.info("m = {}", m);
2520            C c = f.eval(m.getValue());
2521            if (c != null && !c.isZERO()) {
2522                m.setValue(c); // not okay
2523            } else {
2524                // not possible nv.remove(m.getKey());
2525            }
2526        }
2527        return n;
2528    }
2529
2530
2531    /**
2532     * Map a function to the polynomial stream entries.
2533     * @param f evaluation functor.
2534     * @return new polynomial with f(this.entries).
2535     */
2536    public GenPolynomial<C> mapOnStream(
2537                    final Function<? super Map.Entry<ExpVector, C>, ? extends Map.Entry<ExpVector, C>> f) {
2538        return mapOnStream(f, false);
2539    }
2540
2541
2542    /**
2543     * Map a function to the polynomial stream entries.
2544     * @param f evaluation functor.
2545     * @return new polynomial with f(this.entries).
2546     */
2547    public GenPolynomial<C> mapOnStream(
2548                    final Function<? super Map.Entry<ExpVector, C>, ? extends Map.Entry<ExpVector, C>> f,
2549                    boolean parallel) {
2550        Stream<Map.Entry<ExpVector, C>> st;
2551        if (parallel) {
2552            st = val.entrySet().parallelStream();
2553        } else {
2554            st = val.entrySet().stream();
2555        }
2556        Map<ExpVector, C> m = st.map(f).filter(me -> !me.getValue().isZERO())
2557                        .collect(Collectors.toMap(me -> me.getKey(), me -> me.getValue()));
2558        //Stream<Map.Entry<ExpVector,C>> stp = st.map(f);
2559        //Stream<Map.Entry<ExpVector,C>> stf = stp.filter(me -> !me.getValue().isZERO());
2560        //Map<ExpVector,C> m = stf.collect(Collectors.toMap(me -> me.getKey(), me -> me.getValue()));
2561        return new GenPolynomial<C>(ring, m);
2562    }
2563
2564
2565    /**
2566     * Returns the number of bits in the representation of this polynomial.
2567     * @return number of bits in the representation of this polynomial,
2568     *         including sign bits.
2569     */
2570    public long bitLength() {
2571        if (blen < 0L) {
2572            long n = 0L;
2573            for (Monomial<C> m : this) {
2574                n += m.e.bitLength();
2575                //n += m.c.bitLength(); // todo add bitLength to Element
2576                try { // hack
2577                    Method method = m.c.getClass().getMethod("bitLength", (Class<?>[]) null);
2578                    n += (Long) method.invoke(m.c, (Object[]) null);
2579                } catch (NoSuchMethodException e) {
2580                    logger.error("Exception, class: {}", m.c.getClass());
2581                    throw new RuntimeException(e);
2582                } catch (IllegalAccessException e) {
2583                    logger.error("Exception, class: {}", m.c.getClass());
2584                    throw new RuntimeException(e);
2585                } catch (InvocationTargetException e) {
2586                    logger.error("Exception, class: {}", m.c.getClass());
2587                    throw new RuntimeException(e);
2588                }
2589            }
2590            blen = n;
2591            //System.out.println("bitLength(poly) = " + blen);
2592        }
2593        return blen;
2594    }
2595
2596    //private void writeObject(java.io.ObjectOutputStream out) throws IOException {
2597    //    out.defaultWriteObject();
2598    //}
2599
2600
2601    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
2602        in.defaultReadObject();
2603        blen = -1;
2604        hash = -1;
2605    }
2606}