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