001/*
002 * $Id: GenWordPolynomial.java 5292 2015-08-05 21:54:16Z kredel $
003 */
004
005package edu.jas.poly;
006
007
008import java.util.Collections;
009import java.util.Iterator;
010import java.util.Map;
011import java.util.SortedMap;
012import java.util.TreeMap;
013
014import org.apache.log4j.Logger;
015
016import edu.jas.kern.PreemptingException;
017import edu.jas.structure.NotInvertibleException;
018import edu.jas.structure.RingElem;
019import edu.jas.structure.UnaryFunctor;
020
021
022/**
023 * GenWordPolynomial generic polynomials implementing RingElem. Non-commutative
024 * string polynomials over C. Objects of this class are intended to be
025 * immutable. The implementation is based on TreeMap respectively SortedMap from
026 * words to coefficients. Only the coefficients are modeled with generic types,
027 * the "exponents" are fixed to Word. C can also be a non integral domain, e.g.
028 * a ModInteger, i.e. it may contain zero divisors, since multiply() does check
029 * for zeros.
030 * @param <C> coefficient type
031 * @author Heinz Kredel
032 */
033public final class GenWordPolynomial<C extends RingElem<C>> implements RingElem<GenWordPolynomial<C>>,
034                Iterable<WordMonomial<C>> {
035
036
037    /**
038     * The factory for the polynomial ring.
039     */
040    public final GenWordPolynomialRing<C> ring;
041
042
043    /**
044     * The data structure for polynomials.
045     */
046    final SortedMap<Word, C> val; // do not change to TreeMap
047
048
049    private static final Logger logger = Logger.getLogger(GenWordPolynomial.class);
050
051
052    private final boolean debug = logger.isDebugEnabled();
053
054
055    // protected GenWordPolynomial() { ring = null; val = null; } // don't use
056
057
058    /**
059     * Private constructor for GenWordPolynomial.
060     * @param r polynomial ring factory.
061     * @param t TreeMap with correct ordering.
062     */
063    private GenWordPolynomial(GenWordPolynomialRing<C> r, TreeMap<Word, C> t) {
064        ring = r;
065        val = t;
066        if (ring.checkPreempt) {
067            if (Thread.currentThread().isInterrupted()) {
068                logger.debug("throw PreemptingException");
069                throw new PreemptingException();
070            }
071        }
072    }
073
074
075    /**
076     * Constructor for zero GenWordPolynomial.
077     * @param r polynomial ring factory.
078     */
079    public GenWordPolynomial(GenWordPolynomialRing<C> r) {
080        this(r, new TreeMap<Word, C>(r.alphabet.getDescendComparator()));
081    }
082
083
084    /**
085     * Constructor for GenWordPolynomial c * x<sup>e</sup>.
086     * @param r polynomial ring factory.
087     * @param c coefficient.
088     * @param e word.
089     */
090    public GenWordPolynomial(GenWordPolynomialRing<C> r, C c, Word e) {
091        this(r);
092        if (!c.isZERO()) {
093            val.put(e, c);
094        }
095    }
096
097
098    /**
099     * Constructor for GenWordPolynomial c * x<sup>0</sup>.
100     * @param r polynomial ring factory.
101     * @param c coefficient.
102     */
103    public GenWordPolynomial(GenWordPolynomialRing<C> r, C c) {
104        this(r, c, r.wone);
105    }
106
107
108    /**
109     * Constructor for GenWordPolynomial x<sup>e</sup>.
110     * @param r polynomial ring factory.
111     * @param e word.
112     */
113    public GenWordPolynomial(GenWordPolynomialRing<C> r, Word e) {
114        this(r, r.coFac.getONE(), e);
115    }
116
117
118    /**
119     * Constructor for GenWordPolynomial x<sup>e</sup>.
120     * @param r polynomial ring factory.
121     * @param e exponent vector.
122     */
123    public GenWordPolynomial(GenWordPolynomialRing<C> r, ExpVector e) {
124        this(r, r.coFac.getONE(), r.alphabet.valueOf(e));
125    }
126
127
128    /**
129     * Constructor for GenWordPolynomial c * x<sup>e</sup>.
130     * @param r polynomial ring factory.
131     * @param c coefficient.
132     * @param e exponent vector.
133     */
134    public GenWordPolynomial(GenWordPolynomialRing<C> r, C c, ExpVector e) {
135        this(r, c, r.alphabet.valueOf(e));
136    }
137
138
139    /**
140     * Constructor for GenWordPolynomial.
141     * @param r polynomial ring factory.
142     * @param v the SortedMap of some other polynomial.
143     */
144    protected GenWordPolynomial(GenWordPolynomialRing<C> r, SortedMap<Word, C> v) {
145        this(r);
146        val.putAll(v); // assume no zero coefficients
147    }
148
149
150    /**
151     * Get the corresponding element factory.
152     * @return factory for this Element.
153     * @see edu.jas.structure.Element#factory()
154     */
155    public GenWordPolynomialRing<C> factory() {
156        return ring;
157    }
158
159
160    /**
161     * Copy this GenWordPolynomial.
162     * @return copy of this.
163     */
164    public GenWordPolynomial<C> copy() {
165        return new GenWordPolynomial<C>(ring, this.val);
166    }
167
168
169    /**
170     * Length of GenWordPolynomial.
171     * @return number of coefficients of this GenWordPolynomial.
172     */
173    public int length() {
174        return val.size();
175    }
176
177
178    /**
179     * Word to coefficient map of GenWordPolynomial.
180     * @return val as unmodifiable SortedMap.
181     */
182    public SortedMap<Word, C> getMap() {
183        // return val;
184        return Collections.<Word, C> unmodifiableSortedMap(val);
185    }
186
187
188    /**
189     * Put a Word to coefficient entry into the internal map of this
190     * GenWordPolynomial. <b>Note:</b> Do not use this method unless you are
191     * constructing a new polynomial. this is modified and breaks the
192     * immutability promise of this class.
193     * @param c coefficient.
194     * @param e word.
195     */
196    public void doPutToMap(Word e, C c) {
197        if (debug) {
198            C a = val.get(e);
199            if (a != null) {
200                logger.error("map entry exists " + e + " to " + a + " new " + c);
201            }
202        }
203        if (!c.isZERO()) {
204            val.put(e, c);
205        }
206    }
207
208
209    /**
210     * Remove a Word to coefficient entry from the internal map of this
211     * GenWordPolynomial. <b>Note:</b> Do not use this method unless you are
212     * constructing a new polynomial. this is modified and breaks the
213     * immutability promise of this class.
214     * @param e Word.
215     * @param c expected coefficient, null for ignore.
216     */
217    public void doRemoveFromMap(Word e, C c) {
218        C b = val.remove(e);
219        if (debug) {
220            if (c == null) { // ignore b
221                return;
222            }
223            if (!c.equals(b)) {
224                logger.error("map entry wrong " + e + " to " + c + " old " + b);
225            }
226        }
227    }
228
229
230    /**
231     * Put an a sorted map of words to coefficients into the internal map of
232     * this GenWordPolynomial. <b>Note:</b> Do not use this method unless you
233     * are constructing a new polynomial. this is modified and breaks the
234     * immutability promise of this class.
235     * @param vals sorted map of wordss and coefficients.
236     */
237    public void doPutToMap(SortedMap<Word, C> vals) {
238        for (Map.Entry<Word, C> me : vals.entrySet()) {
239            Word e = me.getKey();
240            if (debug) {
241                C a = val.get(e);
242                if (a != null) {
243                    logger.error("map entry exists " + e + " to " + a + " new " + me.getValue());
244                }
245            }
246            C c = me.getValue();
247            if (!c.isZERO()) {
248                val.put(e, c);
249            }
250        }
251    }
252
253
254    /**
255     * String representation of GenWordPolynomial.
256     * @see java.lang.Object#toString()
257     */
258    @Override
259    public String toString() {
260        if (isZERO()) {
261            return "0";
262        }
263        if (isONE()) {
264            return "1";
265        }
266        StringBuffer s = new StringBuffer();
267        if (val.size() > 1) {
268            s.append("( ");
269        }
270        boolean parenthesis = false;
271        boolean first = true;
272        for (Map.Entry<Word, C> m : val.entrySet()) {
273            C c = m.getValue();
274            if (first) {
275                first = false;
276            } else {
277                if (c.signum() < 0) {
278                    s.append(" - ");
279                    c = c.negate();
280                } else {
281                    s.append(" + ");
282                }
283            }
284            Word e = m.getKey();
285            if (!c.isONE() || e.isONE()) {
286                if (parenthesis) {
287                    s.append("( ");
288                }
289                String cs = c.toString();
290                if (cs.indexOf("+")>=0||cs.indexOf("-")>=0) {
291                    s.append("( " + cs + " )");
292                } else {
293                    s.append(cs);
294                }
295                if (parenthesis) {
296                    s.append(" )");
297                }
298                if (!e.isONE()) {
299                    s.append(" ");
300                }
301            }
302            s.append(e.toString());
303        }
304        if (val.size() > 1) {
305            s.append(" )");
306        }
307        return s.toString();
308    }
309
310
311    /**
312     * Get a scripting compatible string representation.
313     * @return script compatible representation for this Element.
314     * @see edu.jas.structure.Element#toScript()
315     */
316    @Override
317    public String toScript() {
318        if (isZERO()) {
319            return "0";
320        }
321        if (isONE()) {
322            return "1";
323        }
324        StringBuffer s = new StringBuffer();
325        if (val.size() > 1) {
326            s.append("( ");
327        }
328        final boolean parenthesis = false;
329        boolean first = true;
330        for (Map.Entry<Word, C> m : val.entrySet()) {
331            C c = m.getValue();
332            if (first) {
333                first = false;
334            } else {
335                if (c.signum() < 0) {
336                    s.append(" - ");
337                    c = c.negate();
338                } else {
339                    s.append(" + ");
340                }
341            }
342            Word e = m.getKey();
343            if (!c.isONE() || e.isONE()) {
344                if (parenthesis) {
345                    s.append("( ");
346                }
347                String cs = c.toScript();
348                if (cs.indexOf("+")>=0||cs.indexOf("-")>=0) {
349                    s.append("( " + cs + " )");
350                } else {
351                    s.append(cs);
352                }
353                if (parenthesis) {
354                    s.append(" )");
355                }
356                if (!e.isONE()) {
357                    s.append(" * ");
358                }
359            }
360            s.append(e.toScript());
361        }
362        if (val.size() > 1) {
363            s.append(" )");
364        }
365        return s.toString();
366    }
367
368
369    /**
370     * Get a scripting compatible string representation of the factory.
371     * @return script compatible representation for this ElemFactory.
372     * @see edu.jas.structure.Element#toScriptFactory()
373     */
374    @Override
375    public String toScriptFactory() {
376        // Python case
377        return factory().toScript();
378    }
379
380
381    /**
382     * Is GenWordPolynomial&lt;C&gt; zero.
383     * @return If this is 0 then true is returned, else false.
384     * @see edu.jas.structure.RingElem#isZERO()
385     */
386    public boolean isZERO() {
387        return (val.size() == 0);
388    }
389
390
391    /**
392     * Is GenWordPolynomial&lt;C&gt; one.
393     * @return If this is 1 then true is returned, else false.
394     * @see edu.jas.structure.RingElem#isONE()
395     */
396    public boolean isONE() {
397        if (val.size() != 1) {
398            return false;
399        }
400        C c = val.get(ring.wone);
401        if (c == null) {
402            return false;
403        }
404        return c.isONE();
405    }
406
407
408    /**
409     * Is GenWordPolynomial&lt;C&gt; a unit.
410     * @return If this is a unit then true is returned, else false.
411     * @see edu.jas.structure.RingElem#isUnit()
412     */
413    public boolean isUnit() {
414        if (val.size() != 1) {
415            return false;
416        }
417        C c = val.get(ring.wone);
418        if (c == null) {
419            return false;
420        }
421        return c.isUnit();
422    }
423
424
425    /**
426     * Is GenWordPolynomial&lt;C&gt; a constant.
427     * @return If this is a constant polynomial then true is returned, else
428     *         false.
429     */
430    public boolean isConstant() {
431        if (val.size() != 1) {
432            return false;
433        }
434        C c = val.get(ring.wone);
435        if (c == null) {
436            return false;
437        }
438        return true;
439    }
440
441
442    /**
443     * Is GenWordPolynomial&lt;C&gt; homogeneous.
444     * @return true, if this is homogeneous, else false.
445     */
446    public boolean isHomogeneous() {
447        if (val.size() <= 1) {
448            return true;
449        }
450        long deg = -1;
451        for (Word e : val.keySet()) {
452            if (deg < 0) {
453                deg = e.degree();
454            } else if (deg != e.degree()) {
455                return false;
456            }
457        }
458        return true;
459    }
460
461
462    /**
463     * Comparison with any other object.
464     * @see java.lang.Object#equals(java.lang.Object)
465     */
466    @Override
467    @SuppressWarnings("unchecked")
468    public boolean equals(Object B) {
469        if (B == null) {
470            return false;
471        }
472        if (!(B instanceof GenWordPolynomial)) {
473            return false;
474        }
475        GenWordPolynomial<C> a = (GenWordPolynomial<C>) B;
476        return this.compareTo(a) == 0;
477    }
478
479
480    /**
481     * Hash code for this polynomial.
482     * @see java.lang.Object#hashCode()
483     */
484    @Override
485    public int hashCode() {
486        int h;
487        h = (ring.hashCode() << 27);
488        h += val.hashCode();
489        return h;
490    }
491
492
493    /**
494     * GenWordPolynomial comparison.
495     * @param b GenWordPolynomial.
496     * @return sign(this-b).
497     */
498    public int compareTo(GenWordPolynomial<C> b) {
499        if (b == null) {
500            return 1;
501        }
502        SortedMap<Word, C> av = this.val;
503        SortedMap<Word, C> bv = b.val;
504        Iterator<Map.Entry<Word, C>> ai = av.entrySet().iterator();
505        Iterator<Map.Entry<Word, C>> bi = bv.entrySet().iterator();
506        int s = 0;
507        int c = 0;
508        while (ai.hasNext() && bi.hasNext()) {
509            Map.Entry<Word, C> aie = ai.next();
510            Map.Entry<Word, C> bie = bi.next();
511            Word ae = aie.getKey();
512            Word be = bie.getKey();
513            s = ae.compareTo(be);
514            //System.out.println("s = " + s + ", " + ae + ", " +be);
515            if (s != 0) {
516                return s;
517            }
518            if (c == 0) {
519                C ac = aie.getValue(); //av.get(ae);
520                C bc = bie.getValue(); //bv.get(be);
521                c = ac.compareTo(bc);
522            }
523        }
524        if (ai.hasNext()) {
525            return 1;
526        }
527        if (bi.hasNext()) {
528            return -1;
529        }
530        // now all keys are equal
531        return c;
532    }
533
534
535    /**
536     * GenWordPolynomial signum.
537     * @return sign(ldcf(this)).
538     */
539    public int signum() {
540        if (this.isZERO()) {
541            return 0;
542        }
543        Word t = val.firstKey();
544        C c = val.get(t);
545        return c.signum();
546    }
547
548
549    /**
550     * Number of variables.
551     * @return ring.alphabet.length().
552     */
553    public int numberOfVariables() {
554        return ring.alphabet.length();
555    }
556
557
558    /**
559     * Leading monomial.
560     * @return first map entry.
561     */
562    public Map.Entry<Word, C> leadingMonomial() {
563        if (val.size() == 0)
564            return null;
565        Iterator<Map.Entry<Word, C>> ai = val.entrySet().iterator();
566        return ai.next();
567    }
568
569
570    /**
571     * Leading word.
572     * @return first highest word.
573     */
574    public Word leadingWord() {
575        if (val.size() == 0) {
576            return ring.wone; // null? needs changes? 
577        }
578        return val.firstKey();
579    }
580
581
582    /**
583     * Trailing word.
584     * @return last lowest word.
585     */
586    public Word trailingWord() {
587        if (val.size() == 0) {
588            return ring.wone; // or null ?;
589        }
590        return val.lastKey();
591    }
592
593
594    /**
595     * Leading base coefficient.
596     * @return first coefficient.
597     */
598    public C leadingBaseCoefficient() {
599        if (val.size() == 0) {
600            return ring.coFac.getZERO();
601        }
602        return val.get(val.firstKey());
603    }
604
605
606    /**
607     * Trailing base coefficient.
608     * @return coefficient of constant term.
609     */
610    public C trailingBaseCoefficient() {
611        C c = val.get(ring.wone);
612        if (c == null) {
613            return ring.coFac.getZERO();
614        }
615        return c;
616    }
617
618
619    /**
620     * Coefficient.
621     * @param e word.
622     * @return coefficient for given word.
623     */
624    public C coefficient(Word e) {
625        C c = val.get(e);
626        if (c == null) {
627            c = ring.coFac.getZERO();
628        }
629        return c;
630    }
631
632
633    /**
634     * Reductum.
635     * @return this - leading monomial.
636     */
637    public GenWordPolynomial<C> reductum() {
638        if (val.size() <= 1) {
639            return ring.getZERO();
640        }
641        Iterator<Word> ai = val.keySet().iterator();
642        Word lt = ai.next();
643        lt = ai.next(); // size > 1
644        SortedMap<Word, C> red = val.tailMap(lt);
645        return new GenWordPolynomial<C>(ring, red);
646    }
647
648
649    /**
650     * Maximal degree.
651     * @return maximal degree in any variables.
652     */
653    public long degree() {
654        if (val.size() == 0) {
655            return 0; // 0 or -1 ?;
656        }
657        long deg = 0;
658        for (Word e : val.keySet()) {
659            long d = e.degree();
660            if (d > deg) {
661                deg = d;
662            }
663        }
664        return deg;
665    }
666
667
668    /**
669     * GenWordPolynomial maximum norm.
670     * @return ||this||.
671     */
672    public C maxNorm() {
673        C n = ring.getZEROCoefficient();
674        for (C c : val.values()) {
675            C x = c.abs();
676            if (n.compareTo(x) < 0) {
677                n = x;
678            }
679        }
680        return n;
681    }
682
683
684    /**
685     * GenWordPolynomial sum norm.
686     * @return sum of all absolute values of coefficients.
687     */
688    public C sumNorm() {
689        C n = ring.getZEROCoefficient();
690        for (C c : val.values()) {
691            C x = c.abs();
692            n = n.sum(x);
693        }
694        return n;
695    }
696
697
698    /**
699     * GenWordPolynomial summation.
700     * @param S GenWordPolynomial.
701     * @return this+S.
702     */
703    public GenWordPolynomial<C> sum(GenWordPolynomial<C> S) {
704        if (S == null) {
705            return this;
706        }
707        if (S.isZERO()) {
708            return this;
709        }
710        if (this.isZERO()) {
711            return S;
712        }
713        assert (ring.alphabet == S.ring.alphabet);
714        GenWordPolynomial<C> n = this.copy(); //new GenWordPolynomial<C>(ring, val); 
715        SortedMap<Word, C> nv = n.val;
716        SortedMap<Word, C> sv = S.val;
717        for (Map.Entry<Word, C> me : sv.entrySet()) {
718            Word e = me.getKey();
719            C y = me.getValue(); //sv.get(e); // assert y != null
720            C x = nv.get(e);
721            if (x != null) {
722                x = x.sum(y);
723                if (!x.isZERO()) {
724                    nv.put(e, x);
725                } else {
726                    nv.remove(e);
727                }
728            } else {
729                nv.put(e, y);
730            }
731        }
732        return n;
733    }
734
735
736    /**
737     * GenWordPolynomial addition. This method is not very efficient, since this
738     * is copied.
739     * @param a coefficient.
740     * @param e word.
741     * @return this + a e.
742     */
743    public GenWordPolynomial<C> sum(C a, Word e) {
744        if (a == null) {
745            return this;
746        }
747        if (a.isZERO()) {
748            return this;
749        }
750        GenWordPolynomial<C> n = this.copy(); //new GenWordPolynomial<C>(ring, val); 
751        SortedMap<Word, C> nv = n.val;
752        C x = nv.get(e);
753        if (x != null) {
754            x = x.sum(a);
755            if (!x.isZERO()) {
756                nv.put(e, x);
757            } else {
758                nv.remove(e);
759            }
760        } else {
761            nv.put(e, a);
762        }
763        return n;
764    }
765
766
767    /**
768     * GenWordPolynomial addition. This method is not very efficient, since this
769     * is copied.
770     * @param a coefficient.
771     * @return this + a x<sup>0</sup>.
772     */
773    public GenWordPolynomial<C> sum(C a) {
774        return sum(a, ring.wone);
775    }
776
777
778    /**
779     * GenWordPolynomial subtraction.
780     * @param S GenWordPolynomial.
781     * @return this-S.
782     */
783    public GenWordPolynomial<C> subtract(GenWordPolynomial<C> S) {
784        if (S == null) {
785            return this;
786        }
787        if (S.isZERO()) {
788            return this;
789        }
790        if (this.isZERO()) {
791            return S.negate();
792        }
793        assert (ring.alphabet == S.ring.alphabet);
794        GenWordPolynomial<C> n = this.copy(); //new GenWordPolynomial<C>(ring, val); 
795        SortedMap<Word, C> nv = n.val;
796        SortedMap<Word, C> sv = S.val;
797        for (Map.Entry<Word, C> me : sv.entrySet()) {
798            Word e = me.getKey();
799            C y = me.getValue(); //sv.get(e); // assert y != null
800            C x = nv.get(e);
801            if (x != null) {
802                x = x.subtract(y);
803                if (!x.isZERO()) {
804                    nv.put(e, x);
805                } else {
806                    nv.remove(e);
807                }
808            } else {
809                nv.put(e, y.negate());
810            }
811        }
812        return n;
813    }
814
815
816    /**
817     * GenWordPolynomial subtraction. This method is not very efficient, since
818     * this is copied.
819     * @param a coefficient.
820     * @param e word.
821     * @return this - a e.
822     */
823    public GenWordPolynomial<C> subtract(C a, Word e) {
824        if (a == null) {
825            return this;
826        }
827        if (a.isZERO()) {
828            return this;
829        }
830        GenWordPolynomial<C> n = this.copy(); //new GenWordPolynomial<C>(ring, val); 
831        SortedMap<Word, C> nv = n.val;
832        C x = nv.get(e);
833        if (x != null) {
834            x = x.subtract(a);
835            if (!x.isZERO()) {
836                nv.put(e, x);
837            } else {
838                nv.remove(e);
839            }
840        } else {
841            nv.put(e, a.negate());
842        }
843        return n;
844    }
845
846
847    /**
848     * GenWordPolynomial subtract. This method is not very efficient, since this
849     * is copied.
850     * @param a coefficient.
851     * @return this + a x<sup>0</sup>.
852     */
853    public GenWordPolynomial<C> subtract(C a) {
854        return subtract(a, ring.wone);
855    }
856
857
858    /**
859     * GenWordPolynomial negation.
860     * @return -this.
861     */
862    public GenWordPolynomial<C> negate() {
863        GenWordPolynomial<C> n = ring.getZERO().copy();
864        SortedMap<Word, C> v = n.val;
865        for (Map.Entry<Word, C> m : val.entrySet()) {
866            C x = m.getValue(); // != null, 0
867            v.put(m.getKey(), x.negate());
868        }
869        return n;
870    }
871
872
873    /**
874     * GenWordPolynomial absolute value, i.e. leadingCoefficient &gt; 0.
875     * @return abs(this).
876     */
877    public GenWordPolynomial<C> abs() {
878        if (leadingBaseCoefficient().signum() < 0) {
879            return this.negate();
880        }
881        return this;
882    }
883
884
885    /**
886     * GenWordPolynomial multiplication.
887     * @param S GenWordPolynomial.
888     * @return this*S.
889     */
890    public GenWordPolynomial<C> multiply(GenWordPolynomial<C> S) {
891        if (S == null) {
892            return ring.getZERO();
893        }
894        if (S.isZERO()) {
895            return ring.getZERO();
896        }
897        if (this.isZERO()) {
898            return this;
899        }
900        assert (ring.alphabet == S.ring.alphabet);
901        GenWordPolynomial<C> p = ring.getZERO().copy();
902        SortedMap<Word, C> pv = p.val;
903        for (Map.Entry<Word, C> m1 : val.entrySet()) {
904            C c1 = m1.getValue();
905            Word e1 = m1.getKey();
906            for (Map.Entry<Word, C> m2 : S.val.entrySet()) {
907                C c2 = m2.getValue();
908                Word e2 = m2.getKey();
909                C c = c1.multiply(c2); // check non zero if not domain
910                if (!c.isZERO()) {
911                    Word e = e1.multiply(e2);
912                    C c0 = pv.get(e);
913                    if (c0 == null) {
914                        pv.put(e, c);
915                    } else {
916                        c0 = c0.sum(c);
917                        if (!c0.isZERO()) {
918                            pv.put(e, c0);
919                        } else {
920                            pv.remove(e);
921                        }
922                    }
923                }
924            }
925        }
926        return p;
927    }
928
929
930    /**
931     * GenWordPolynomial left and right multiplication. Product with two
932     * polynomials.
933     * @param S GenWordPolynomial.
934     * @param T GenWordPolynomial.
935     * @return S*this*T.
936     */
937    public GenWordPolynomial<C> multiply(GenWordPolynomial<C> S, GenWordPolynomial<C> T) {
938        if (S.isZERO() || T.isZERO()) {
939            return ring.getZERO();
940        }
941        if (S.isONE()) {
942            return multiply(T);
943        }
944        if (T.isONE()) {
945            return S.multiply(this);
946        }
947        return S.multiply(this).multiply(T);
948    }
949
950
951    /**
952     * GenWordPolynomial multiplication. Product with coefficient ring element.
953     * @param s coefficient.
954     * @return this*s.
955     */
956    public GenWordPolynomial<C> multiply(C s) {
957        if (s == null) {
958            return ring.getZERO();
959        }
960        if (s.isZERO()) {
961            return ring.getZERO();
962        }
963        if (this.isZERO()) {
964            return this;
965        }
966        GenWordPolynomial<C> p = ring.getZERO().copy();
967        SortedMap<Word, C> pv = p.val;
968        for (Map.Entry<Word, C> m1 : val.entrySet()) {
969            C c1 = m1.getValue();
970            Word e1 = m1.getKey();
971            C c = c1.multiply(s); // check non zero if not domain
972            if (!c.isZERO()) {
973                pv.put(e1, c); // or m1.setValue( c )
974            }
975        }
976        return p;
977    }
978
979
980    /**
981     * GenWordPolynomial multiplication. Product with coefficient ring element.
982     * @param s coefficient.
983     * @param t coefficient.
984     * @return s*this*t.
985     */
986    public GenWordPolynomial<C> multiply(C s, C t) {
987        if (s == null || t == null) {
988            return ring.getZERO();
989        }
990        if (s.isZERO() || t.isZERO()) {
991            return ring.getZERO();
992        }
993        if (this.isZERO()) {
994            return this;
995        }
996        GenWordPolynomial<C> p = ring.getZERO().copy();
997        SortedMap<Word, C> pv = p.val;
998        for (Map.Entry<Word, C> m1 : val.entrySet()) {
999            C c1 = m1.getValue();
1000            Word e = m1.getKey();
1001            C c = s.multiply(c1).multiply(t); // check non zero if not domain
1002            if (!c.isZERO()) {
1003                pv.put(e, c); // or m1.setValue( c )
1004            }
1005        }
1006        return p;
1007    }
1008
1009
1010    /**
1011     * GenWordPolynomial monic, i.e. leadingCoefficient == 1. If
1012     * leadingCoefficient is not invertible returns this unmodified.
1013     * @return monic(this).
1014     */
1015    public GenWordPolynomial<C> monic() {
1016        if (this.isZERO()) {
1017            return this;
1018        }
1019        C lc = leadingBaseCoefficient();
1020        if (!lc.isUnit()) {
1021            //System.out.println("lc = "+lc);
1022            return this;
1023        }
1024        C lm = lc.inverse();
1025        return multiply(lm);
1026    }
1027
1028
1029    /**
1030     * GenWordPolynomial multiplication. Product with ring element and word.
1031     * @param s coefficient.
1032     * @param e left word.
1033     * @return this * s e.
1034     */
1035    public GenWordPolynomial<C> multiply(C s, Word e) {
1036        if (s == null) {
1037            return ring.getZERO();
1038        }
1039        if (s.isZERO()) {
1040            return ring.getZERO();
1041        }
1042        if (this.isZERO()) {
1043            return this;
1044        }
1045        GenWordPolynomial<C> p = ring.getZERO().copy();
1046        SortedMap<Word, C> pv = p.val;
1047        for (Map.Entry<Word, C> m1 : val.entrySet()) {
1048            C c1 = m1.getValue();
1049            Word e1 = m1.getKey();
1050            C c = c1.multiply(s); // check non zero if not domain
1051            if (!c.isZERO()) {
1052                Word e2 = e1.multiply(e);
1053                pv.put(e2, c);
1054            }
1055        }
1056        return p;
1057    }
1058
1059
1060    /**
1061     * GenWordPolynomial left and right multiplication. Product with ring
1062     * element and two words.
1063     * @param e left word.
1064     * @param f right word.
1065     * @return e * this * f.
1066     */
1067    public GenWordPolynomial<C> multiply(Word e, Word f) {
1068        if (this.isZERO()) {
1069            return this;
1070        }
1071        if (e.isONE()) {
1072            return multiply(f);
1073        }
1074        GenWordPolynomial<C> p = ring.getZERO().copy();
1075        SortedMap<Word, C> pv = p.val;
1076        for (Map.Entry<Word, C> m1 : val.entrySet()) {
1077            C c = m1.getValue();
1078            Word e1 = m1.getKey();
1079            Word e2 = e.multiply(e1.multiply(f));
1080            pv.put(e2, c);
1081        }
1082        return p;
1083    }
1084
1085
1086    /**
1087     * GenWordPolynomial left and right multiplication. Product with ring
1088     * element and two words.
1089     * @param s coefficient.
1090     * @param e left word.
1091     * @param f right word.
1092     * @return e * this * s * f.
1093     */
1094    public GenWordPolynomial<C> multiply(C s, Word e, Word f) {
1095        if (s == null) {
1096            return ring.getZERO();
1097        }
1098        if (s.isZERO()) {
1099            return ring.getZERO();
1100        }
1101        if (this.isZERO()) {
1102            return this;
1103        }
1104        if (e.isONE()) {
1105            return multiply(s, f);
1106        }
1107        C c = ring.coFac.getONE();
1108        return multiply(c, e, s, f); // sic, history
1109    }
1110
1111
1112    /**
1113     * GenWordPolynomial left and right multiplication. Product with ring
1114     * element and two words.
1115     * @param s coefficient.
1116     * @param e left word.
1117     * @param t coefficient.
1118     * @param f right word.
1119     * @return s * e * this * t * f.
1120     */
1121    public GenWordPolynomial<C> multiply(C s, Word e, C t, Word f) {
1122        if (s == null) {
1123            return ring.getZERO();
1124        }
1125        if (s.isZERO()) {
1126            return ring.getZERO();
1127        }
1128        if (this.isZERO()) {
1129            return this;
1130        }
1131        GenWordPolynomial<C> p = ring.getZERO().copy();
1132        SortedMap<Word, C> pv = p.val;
1133        for (Map.Entry<Word, C> m1 : val.entrySet()) {
1134            C c1 = m1.getValue();
1135            C c = s.multiply(c1).multiply(t); // check non zero if not domain
1136            if (!c.isZERO()) {
1137                Word e1 = m1.getKey();
1138                Word e2 = e.multiply(e1).multiply(f);
1139                pv.put(e2, c);
1140            }
1141        }
1142        return p;
1143    }
1144
1145
1146    /**
1147     * GenWordPolynomial multiplication. Product with word.
1148     * @param e word (!= null).
1149     * @return this * e.
1150     */
1151    public GenWordPolynomial<C> multiply(Word e) {
1152        if (this.isZERO()) {
1153            return this;
1154        }
1155        GenWordPolynomial<C> p = ring.getZERO().copy();
1156        SortedMap<Word, C> pv = p.val;
1157        for (Map.Entry<Word, C> m1 : val.entrySet()) {
1158            C c1 = m1.getValue();
1159            Word e1 = m1.getKey();
1160            Word e2 = e1.multiply(e);
1161            pv.put(e2, c1);
1162        }
1163        return p;
1164    }
1165
1166
1167    /**
1168     * GenWordPolynomial multiplication. Product with 'monomial'.
1169     * @param m 'monomial'.
1170     * @return this * m.
1171     */
1172    public GenWordPolynomial<C> multiply(Map.Entry<Word, C> m) {
1173        if (m == null) {
1174            return ring.getZERO();
1175        }
1176        return multiply(m.getValue(), m.getKey());
1177    }
1178
1179
1180    /**
1181     * GenWordPolynomial division. Division by coefficient ring element. Fails,
1182     * if exact division is not possible.
1183     * @param s coefficient.
1184     * @return this/s.
1185     */
1186    public GenWordPolynomial<C> divide(C s) {
1187        if (s == null || s.isZERO()) {
1188            throw new ArithmeticException(this.getClass().getName() + " division by zero");
1189        }
1190        if (this.isZERO()) {
1191            return this;
1192        }
1193        //C t = s.inverse();
1194        //return multiply(t);
1195        GenWordPolynomial<C> p = ring.getZERO().copy();
1196        SortedMap<Word, C> pv = p.val;
1197        for (Map.Entry<Word, C> m : val.entrySet()) {
1198            Word e = m.getKey();
1199            C c1 = m.getValue();
1200            C c = c1.divide(s); // is divideLeft
1201            if (debug) {
1202                C x = c1.remainder(s);
1203                if (!x.isZERO()) {
1204                    logger.info("divide x = " + x);
1205                    throw new ArithmeticException(this.getClass().getName() + " no exact division: " + c1
1206                                    + "/" + s);
1207                }
1208            }
1209            if (c.isZERO()) {
1210                throw new ArithmeticException(this.getClass().getName() + " no exact division: " + c1 + "/"
1211                                + s + ", in " + this);
1212            }
1213            pv.put(e, c); // or m1.setValue( c )
1214        }
1215        return p;
1216    }
1217
1218
1219    /**
1220     * GenWordPolynomial division with remainder. Fails, if exact division by
1221     * leading base coefficient is not possible. Meaningful only for univariate
1222     * polynomials over fields, but works in any case.
1223     * @param S nonzero GenWordPolynomial with invertible leading coefficient.
1224     * @return [ quotient , remainder ] with this = quotient * S + remainder and
1225     *         deg(remainder) &lt; deg(S) or remiander = 0.
1226     * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial)
1227     *      .
1228     */
1229    @SuppressWarnings("unchecked")
1230    public GenWordPolynomial<C>[] quotientRemainder(GenWordPolynomial<C> S) {
1231        if (S == null || S.isZERO()) {
1232            throw new ArithmeticException(this.getClass().getName() + " division by zero");
1233        }
1234        C c = S.leadingBaseCoefficient();
1235        if (!c.isUnit()) {
1236            throw new ArithmeticException(this.getClass().getName() + " lbcf not invertible " + c);
1237        }
1238        C ci = c.inverse();
1239        C one = ring.coFac.getONE();
1240        assert (ring.alphabet == S.ring.alphabet);
1241        WordFactory.WordComparator cmp = ring.alphabet.getDescendComparator();
1242        Word e = S.leadingWord();
1243        GenWordPolynomial<C> h;
1244        GenWordPolynomial<C> q = ring.getZERO().copy();
1245        GenWordPolynomial<C> r = this.copy();
1246        while (!r.isZERO()) {
1247            Word f = r.leadingWord();
1248            if (f.multipleOf(e)) {
1249                C a = r.leadingBaseCoefficient();
1250                Word[] g = f.divideWord(e); // divide not sufficient
1251                //logger.info("div: f = " + f + ", e = " + e + ", g = " + g[0] + ", " + g[1]);
1252                a = a.multiply(ci);
1253                q = q.sum(a, g[0].multiply(g[1]));
1254                h = S.multiply(a, g[0], one, g[1]);
1255                r = r.subtract(h);
1256                Word fr = r.leadingWord();
1257                if (cmp.compare(f, fr) > 0) { // non noetherian reduction
1258                    throw new RuntimeException("possible infinite loop: f = " + f + ", fr = " + fr);
1259                }
1260            } else {
1261                break;
1262            }
1263        }
1264        GenWordPolynomial<C>[] ret = new GenWordPolynomial[2];
1265        ret[0] = q;
1266        ret[1] = r;
1267        return ret;
1268    }
1269
1270
1271    /**
1272     * GenWordPolynomial division. Fails, if exact division by leading base
1273     * coefficient is not possible. Meaningful only for univariate polynomials
1274     * over fields, but works in any case.
1275     * @param S nonzero GenWordPolynomial with invertible leading coefficient.
1276     * @return quotient with this = quotient * S + remainder.
1277     * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial)
1278     *      .
1279     */
1280    public GenWordPolynomial<C> divide(GenWordPolynomial<C> S) {
1281        return quotientRemainder(S)[0];
1282    }
1283
1284
1285    /**
1286     * GenWordPolynomial remainder. Fails, if exact division by leading base
1287     * coefficient is not possible. Meaningful only for univariate polynomials
1288     * over fields, but works in any case.
1289     * @param S nonzero GenWordPolynomial with invertible leading coefficient.
1290     * @return remainder with this = quotient * S + remainder.
1291     * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial)
1292     *      .
1293     */
1294    public GenWordPolynomial<C> remainder(GenWordPolynomial<C> S) {
1295        if (S == null || S.isZERO()) {
1296            throw new ArithmeticException(this.getClass().getName() + " division by zero");
1297        }
1298        C c = S.leadingBaseCoefficient();
1299        if (!c.isUnit()) {
1300            throw new ArithmeticException(this.getClass().getName() + " lbc not invertible " + c);
1301        }
1302        C ci = c.inverse();
1303        C one = ring.coFac.getONE();
1304        assert (ring.alphabet == S.ring.alphabet);
1305        WordFactory.WordComparator cmp = ring.alphabet.getDescendComparator();
1306        Word e = S.leadingWord();
1307        GenWordPolynomial<C> h;
1308        GenWordPolynomial<C> r = this.copy();
1309        while (!r.isZERO()) {
1310            Word f = r.leadingWord();
1311            if (f.multipleOf(e)) {
1312                C a = r.leadingBaseCoefficient();
1313                Word[] g = f.divideWord(e); // divide not sufficient
1314                //logger.info("rem: f = " + f + ", e = " + e + ", g = " + g[0] + ", " + g[1]);
1315                a = a.multiply(ci);
1316                h = S.multiply(a, g[0], one, g[1]);
1317                r = r.subtract(h);
1318                Word fr = r.leadingWord();
1319                if (cmp.compare(f, fr) > 0) { // non noetherian reduction
1320                    throw new RuntimeException("possible infinite loop: f = " + f + ", fr = " + fr);
1321                }
1322            } else {
1323                break;
1324            }
1325        }
1326        return r;
1327    }
1328
1329
1330    /**
1331     * GenWordPolynomial greatest common divisor. Only for univariate
1332     * polynomials over fields.
1333     * @param S GenWordPolynomial.
1334     * @return gcd(this,S).
1335     */
1336    public GenWordPolynomial<C> gcd(GenWordPolynomial<C> S) {
1337        if (S == null || S.isZERO()) {
1338            return this;
1339        }
1340        if (this.isZERO()) {
1341            return S;
1342        }
1343        if (ring.alphabet.length() != 1) {
1344            throw new IllegalArgumentException("no univariate polynomial " + ring);
1345        }
1346        GenWordPolynomial<C> x;
1347        GenWordPolynomial<C> q = this;
1348        GenWordPolynomial<C> r = S;
1349        while (!r.isZERO()) {
1350            x = q.remainder(r);
1351            q = r;
1352            r = x;
1353        }
1354        return q.monic(); // normalize
1355    }
1356
1357
1358    /**
1359     * GenWordPolynomial extended greatest comon divisor. Only for univariate
1360     * polynomials over fields.
1361     * @param S GenWordPolynomial.
1362     * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S).
1363     */
1364    @SuppressWarnings("unchecked")
1365    public GenWordPolynomial<C>[] egcd(GenWordPolynomial<C> S) {
1366        GenWordPolynomial<C>[] ret = new GenWordPolynomial[3];
1367        ret[0] = null;
1368        ret[1] = null;
1369        ret[2] = null;
1370        if (S == null || S.isZERO()) {
1371            ret[0] = this;
1372            ret[1] = this.ring.getONE();
1373            ret[2] = this.ring.getZERO();
1374            return ret;
1375        }
1376        if (this.isZERO()) {
1377            ret[0] = S;
1378            ret[1] = this.ring.getZERO();
1379            ret[2] = this.ring.getONE();
1380            return ret;
1381        }
1382        if (ring.alphabet.length() != 1) {
1383            throw new IllegalArgumentException("no univariate polynomial " + ring);
1384        }
1385        if (this.isConstant() && S.isConstant()) {
1386            C t = this.leadingBaseCoefficient();
1387            C s = S.leadingBaseCoefficient();
1388            C[] gg = t.egcd(s);
1389            //System.out.println("coeff gcd = " + Arrays.toString(gg));
1390            GenWordPolynomial<C> z = this.ring.getZERO();
1391            ret[0] = z.sum(gg[0]);
1392            ret[1] = z.sum(gg[1]);
1393            ret[2] = z.sum(gg[2]);
1394            return ret;
1395        }
1396        GenWordPolynomial<C>[] qr;
1397        GenWordPolynomial<C> q = this;
1398        GenWordPolynomial<C> r = S;
1399        GenWordPolynomial<C> c1 = ring.getONE().copy();
1400        GenWordPolynomial<C> d1 = ring.getZERO().copy();
1401        GenWordPolynomial<C> c2 = ring.getZERO().copy();
1402        GenWordPolynomial<C> d2 = ring.getONE().copy();
1403        GenWordPolynomial<C> x1;
1404        GenWordPolynomial<C> x2;
1405        while (!r.isZERO()) {
1406            qr = q.quotientRemainder(r);
1407            q = qr[0];
1408            x1 = c1.subtract(q.multiply(d1));
1409            x2 = c2.subtract(q.multiply(d2));
1410            c1 = d1;
1411            c2 = d2;
1412            d1 = x1;
1413            d2 = x2;
1414            q = r;
1415            r = qr[1];
1416        }
1417        // normalize ldcf(q) to 1, i.e. make monic
1418        C g = q.leadingBaseCoefficient();
1419        if (g.isUnit()) {
1420            C h = g.inverse();
1421            q = q.multiply(h);
1422            c1 = c1.multiply(h);
1423            c2 = c2.multiply(h);
1424        }
1425        //assert ( ((c1.multiply(this)).sum( c2.multiply(S)).equals(q) )); 
1426        ret[0] = q;
1427        ret[1] = c1;
1428        ret[2] = c2;
1429        return ret;
1430    }
1431
1432
1433    /**
1434     * GenWordPolynomial half extended greatest comon divisor. Only for
1435     * univariate polynomials over fields.
1436     * @param S GenWordPolynomial.
1437     * @return [ gcd(this,S), a ] with a*this + b*S = gcd(this,S).
1438     */
1439    @SuppressWarnings("unchecked")
1440    public GenWordPolynomial<C>[] hegcd(GenWordPolynomial<C> S) {
1441        GenWordPolynomial<C>[] ret = new GenWordPolynomial[2];
1442        ret[0] = null;
1443        ret[1] = null;
1444        if (S == null || S.isZERO()) {
1445            ret[0] = this;
1446            ret[1] = this.ring.getONE();
1447            return ret;
1448        }
1449        if (this.isZERO()) {
1450            ret[0] = S;
1451            return ret;
1452        }
1453        if (ring.alphabet.length() != 1) {
1454            throw new IllegalArgumentException("no univariate polynomial " + ring);
1455        }
1456        GenWordPolynomial<C>[] qr;
1457        GenWordPolynomial<C> q = this;
1458        GenWordPolynomial<C> r = S;
1459        GenWordPolynomial<C> c1 = ring.getONE().copy();
1460        GenWordPolynomial<C> d1 = ring.getZERO().copy();
1461        GenWordPolynomial<C> x1;
1462        while (!r.isZERO()) {
1463            qr = q.quotientRemainder(r);
1464            q = qr[0];
1465            x1 = c1.subtract(q.multiply(d1));
1466            c1 = d1;
1467            d1 = x1;
1468            q = r;
1469            r = qr[1];
1470        }
1471        // normalize ldcf(q) to 1, i.e. make monic
1472        C g = q.leadingBaseCoefficient();
1473        if (g.isUnit()) {
1474            C h = g.inverse();
1475            q = q.multiply(h);
1476            c1 = c1.multiply(h);
1477        }
1478        //assert ( ((c1.multiply(this)).remainder(S).equals(q) )); 
1479        ret[0] = q;
1480        ret[1] = c1;
1481        return ret;
1482    }
1483
1484
1485    /**
1486     * GenWordPolynomial inverse. Required by RingElem. Throws not invertible
1487     * exception.
1488     */
1489    public GenWordPolynomial<C> inverse() {
1490        if (isUnit()) { // only possible if ldbcf is unit
1491            C c = leadingBaseCoefficient().inverse();
1492            return ring.getONE().multiply(c);
1493        }
1494        throw new NotInvertibleException("element not invertible " + this + " :: " + ring);
1495    }
1496
1497
1498    /**
1499     * GenWordPolynomial modular inverse. Only for univariate polynomials over
1500     * fields.
1501     * @param m GenWordPolynomial.
1502     * @return a with with a*this = 1 mod m.
1503     */
1504    public GenWordPolynomial<C> modInverse(GenWordPolynomial<C> m) {
1505        if (this.isZERO()) {
1506            throw new NotInvertibleException("zero is not invertible");
1507        }
1508        GenWordPolynomial<C>[] hegcd = this.hegcd(m);
1509        GenWordPolynomial<C> a = hegcd[0];
1510        if (!a.isUnit()) { // gcd != 1
1511            throw new NotInvertibleException("element not invertible, gcd != 1");
1512        }
1513        GenWordPolynomial<C> b = hegcd[1];
1514        if (b.isZERO()) { // when m divides this, e.g. m.isUnit()
1515            throw new NotInvertibleException("element not invertible, divisible by modul");
1516        }
1517        return b;
1518    }
1519
1520
1521    /**
1522     * Iterator over coefficients.
1523     * @return val.values().iterator().
1524     */
1525    public Iterator<C> coefficientIterator() {
1526        return val.values().iterator();
1527    }
1528
1529
1530    /**
1531     * Iterator over words.
1532     * @return val.keySet().iterator().
1533     */
1534    public Iterator<Word> wordIterator() {
1535        return val.keySet().iterator();
1536    }
1537
1538
1539    /**
1540     * Iterator over monomials.
1541     * @return a PolyIterator.
1542     */
1543    public Iterator<WordMonomial<C>> iterator() {
1544        return new WordPolyIterator<C>(val);
1545    }
1546
1547
1548    /**
1549     * Map a unary function to the coefficients.
1550     * @param f evaluation functor.
1551     * @return new polynomial with coefficients f(this(e)).
1552     */
1553    public GenWordPolynomial<C> map(final UnaryFunctor<? super C, C> f) {
1554        GenWordPolynomial<C> n = ring.getZERO().copy();
1555        SortedMap<Word, C> nv = n.val;
1556        for (WordMonomial<C> m : this) {
1557            //logger.info("m = " + m);
1558            C c = f.eval(m.c);
1559            if (c != null && !c.isZERO()) {
1560                nv.put(m.e, c);
1561            }
1562        }
1563        return n;
1564    }
1565
1566}