001/*
002 * $Id: WordIdeal.java 5303 2015-08-16 17:11:07Z kredel $
003 */
004
005package edu.jas.application;
006
007
008import java.io.Serializable;
009import java.util.ArrayList;
010import java.util.Collections;
011import java.util.Comparator;
012import java.util.List;
013import java.util.SortedSet;
014import java.util.TreeSet;
015
016import org.apache.log4j.Logger;
017
018import edu.jas.gb.WordGroebnerBaseAbstract;
019import edu.jas.gb.WordGroebnerBaseSeq;
020import edu.jas.gb.WordReduction;
021import edu.jas.gb.WordReductionSeq;
022import edu.jas.kern.Scripting;
023import edu.jas.poly.GenWordPolynomial;
024import edu.jas.poly.GenWordPolynomialRing;
025import edu.jas.poly.Word;
026import edu.jas.structure.GcdRingElem;
027import edu.jas.structure.NotInvertibleException;
028
029
030/**
031 * Word Ideal implements some methods for ideal arithmetic, for example
032 * containment, sum or product. <b>Note:</b> only two-sided ideals.
033 * @author Heinz Kredel
034 */
035public class WordIdeal<C extends GcdRingElem<C>> implements Comparable<WordIdeal<C>>, Serializable {
036
037
038    private static final Logger logger = Logger.getLogger(WordIdeal.class);
039
040
041    private final boolean debug = logger.isDebugEnabled();
042
043
044    /**
045     * The data structure is a list of word polynomials.
046     */
047    protected List<GenWordPolynomial<C>> list;
048
049
050    /**
051     * Reference to the word polynomial ring.
052     */
053    protected GenWordPolynomialRing<C> ring;
054
055
056    /**
057     * Indicator if list is a Groebner Base.
058     */
059    protected boolean isGB;
060
061
062    /**
063     * Indicator if test has been performed if this is a Groebner Base.
064     */
065    protected boolean testGB;
066
067
068    /**
069     * Groebner base engine.
070     */
071    protected final WordGroebnerBaseAbstract<C> bb;
072
073
074    /**
075     * Reduction engine.
076     */
077    protected final WordReduction<C> red;
078
079
080    /**
081     * Constructor.
082     * @param ring solvable polynomial ring
083     */
084    public WordIdeal(GenWordPolynomialRing<C> ring) {
085        this(ring, new ArrayList<GenWordPolynomial<C>>());
086    }
087
088
089    /**
090     * Constructor.
091     * @param ring word polynomial ring
092     * @param list word polynomial list
093     */
094    public WordIdeal(GenWordPolynomialRing<C> ring, List<GenWordPolynomial<C>> list) {
095        this(ring, list, false);
096    }
097
098
099    /**
100     * Constructor.
101     * @param ring word polynomial ring
102     * @param list word polynomial list
103     * @param bb Groebner Base engine
104     * @param red Reduction engine
105     */
106    public WordIdeal(GenWordPolynomialRing<C> ring, List<GenWordPolynomial<C>> list,
107                    WordGroebnerBaseAbstract<C> bb, WordReduction<C> red) {
108        this(ring, list, false, bb, red);
109    }
110
111
112    /**
113     * Constructor.
114     * @param ring word polynomial ring
115     * @param list word polynomial list
116     * @param gb true if list is known to be a Groebner Base, else false
117     */
118    public WordIdeal(GenWordPolynomialRing<C> ring, List<GenWordPolynomial<C>> list, boolean gb) {
119        this(ring, list, gb, new WordGroebnerBaseSeq<C>(), new WordReductionSeq<C>());
120        //this(list, gb, topt, GBFactory.getImplementation(list.ring.coFac));
121    }
122
123
124    /**
125     * Constructor.
126     * @param ring word polynomial ring
127     * @param list word polynomial list
128     * @param gb true if list is known to be a Groebner Base, else false
129     * @param bb Groebner Base engine
130     */
131    public WordIdeal(GenWordPolynomialRing<C> ring, List<GenWordPolynomial<C>> list, boolean gb,
132                    WordGroebnerBaseAbstract<C> bb) {
133        this(ring, list, gb, bb, bb.red);
134    }
135
136
137    /**
138     * Constructor.
139     * @param ring word polynomial ring
140     * @param list word polynomial list
141     * @param gb true if list is known to be a Groebner Base, else false
142     * @param bb Groebner Base engine
143     * @param red Reduction engine
144     */
145    public WordIdeal(GenWordPolynomialRing<C> ring, List<GenWordPolynomial<C>> list, boolean gb,
146                    WordGroebnerBaseAbstract<C> bb, WordReduction<C> red) {
147        if (ring == null) {
148            throw new IllegalArgumentException("ring may not be null");
149        }
150        if (list == null) {
151            throw new IllegalArgumentException("list may not be null");
152        }
153        this.ring = ring;
154        this.list = list;
155        this.isGB = gb;
156        this.testGB = (gb ? true : false); // ??
157        this.bb = bb;
158        this.red = red;
159        if (debug) {
160            logger.info("constructed: " + this);
161        }
162    }
163
164
165    /**
166     * Clone this.
167     * @return a copy of this.
168     */
169    public WordIdeal<C> copy() {
170        return new WordIdeal<C>(ring, new ArrayList<GenWordPolynomial<C>>(list), isGB, bb, red);
171    }
172
173
174    /**
175     * Get the List of GenWordPolynomials.
176     * @return (cast) list.list
177     */
178    public List<GenWordPolynomial<C>> getList() {
179        return list;
180    }
181
182
183    /**
184     * Get the GenWordPolynomialRing.
185     * @return (cast) list.ring
186     */
187    public GenWordPolynomialRing<C> getRing() {
188        return ring;
189    }
190
191
192    /**
193     * Get the zero ideal.
194     * @return ideal(0)
195     */
196    public WordIdeal<C> getZERO() {
197        List<GenWordPolynomial<C>> z = new ArrayList<GenWordPolynomial<C>>(0);
198        return new WordIdeal<C>(ring, z, true, bb, red);
199    }
200
201
202    /**
203     * Get the one ideal.
204     * @return ideal(1)
205     */
206    public WordIdeal<C> getONE() {
207        List<GenWordPolynomial<C>> one = new ArrayList<GenWordPolynomial<C>>(1);
208        one.add(getRing().getONE());
209        return new WordIdeal<C>(ring, one, true, bb, red);
210    }
211
212
213    /**
214     * String representation of the solvable ideal.
215     * @see java.lang.Object#toString()
216     */
217    @Override
218    public String toString() {
219        StringBuffer sb = new StringBuffer("(");
220        boolean first = true;
221        for (GenWordPolynomial<C> p : list) {
222            if (!first) {
223                sb.append(",");
224            } else {
225                first = false;
226            }
227            sb.append(p.toString());
228        }
229        sb.append(")");
230        return sb.toString();
231    }
232
233
234    /**
235     * Get a scripting compatible string representation.
236     * @return script compatible representation for this Element.
237     * @see edu.jas.structure.Element#toScript()
238     */
239    public String toScript() {
240        StringBuffer s = new StringBuffer();
241        switch (Scripting.getLang()) {
242        case Ruby:
243            s.append("WordPolyIdeal.new(");
244            break;
245        case Python:
246        default:
247            s.append("WordIdeal(");
248        }
249        if (ring != null) {
250            s.append(ring.toScript());
251        }
252        if (list == null) {
253            s.append(")");
254            return s.toString();
255        }
256        switch (Scripting.getLang()) {
257        case Ruby:
258            s.append(",\"\",[");
259            break;
260        case Python:
261        default:
262            s.append(",list=[");
263        }
264        boolean first = true;
265        String sa = null;
266        for (GenWordPolynomial<C> oa : list) {
267            sa = oa.toScript();
268            if (first) {
269                first = false;
270            } else {
271                s.append(", ");
272            }
273            //s.append("( " + sa + " )");
274            s.append(sa);
275        }
276        s.append("])");
277        return s.toString();
278    }
279
280
281    /**
282     * Comparison with any other object. <b>Note:</b> If not both ideals are
283     * Groebner Bases, then false may be returned even the ideals are equal.
284     * @see java.lang.Object#equals(java.lang.Object)
285     */
286    @Override
287    @SuppressWarnings("unchecked")
288    public boolean equals(Object b) {
289        if (!(b instanceof WordIdeal)) {
290            logger.warn("equals no Ideal");
291            return false;
292        }
293        WordIdeal<C> B = null;
294        try {
295            B = (WordIdeal<C>) b;
296        } catch (ClassCastException ignored) {
297            return false;
298        }
299        SortedSet<GenWordPolynomial<C>> s = new TreeSet<GenWordPolynomial<C>>(list);
300        SortedSet<GenWordPolynomial<C>> t = new TreeSet<GenWordPolynomial<C>>(B.list);
301        if (isGB && B.isGB) { //requires also monic polys
302            return s.equals(t);
303        }
304        if (s.equals(t)) {
305            return true;
306        }
307        //System.out.println("no GBs contains");
308        return this.contains(B) && B.contains(this);
309    }
310
311
312    /**
313     * WordIdeal comparison.
314     * @param L other solvable ideal.
315     * @return compareTo() of polynomial lists.
316     */
317    public int compareTo(WordIdeal<C> L) {
318        int si = Math.min(L.list.size(), list.size());
319        int s = 0;
320        final Comparator<Word> wc = ring.alphabet.getAscendComparator();
321        Comparator<GenWordPolynomial<C>> cmp = new Comparator<GenWordPolynomial<C>>() {
322
323
324            public int compare(GenWordPolynomial<C> p1, GenWordPolynomial<C> p2) {
325                Word w1 = p1.leadingWord();
326                Word w2 = p2.leadingWord();
327                if (w1 == null) {
328                    return -1; // dont care
329                }
330                if (w2 == null) {
331                    return 1; // dont care
332                }
333                if (w1.length() != w2.length()) {
334                    if (w1.length() > w2.length()) {
335                        return 1; // dont care
336                    }
337                    return -1; // dont care
338                }
339                return wc.compare(w1, w2);
340            }
341        };
342
343        List<GenWordPolynomial<C>> l1 = new ArrayList<GenWordPolynomial<C>>(list);
344        List<GenWordPolynomial<C>> l2 = new ArrayList<GenWordPolynomial<C>>(L.list);
345        //Collections.sort(l1);
346        //Collections.sort(l2);
347        Collections.sort(l1, cmp);
348        Collections.sort(l2, cmp);
349        for (int i = 0; i < si; i++) {
350            GenWordPolynomial<C> a = l1.get(i);
351            GenWordPolynomial<C> b = l2.get(i);
352            s = a.compareTo(b);
353            if (s != 0) {
354                return s;
355            }
356        }
357        if (list.size() > si) {
358            return 1;
359        }
360        if (L.list.size() > si) {
361            return -1;
362        }
363        return s;
364    }
365
366
367    /**
368     * Hash code for this solvable ideal.
369     * @see java.lang.Object#hashCode()
370     */
371    @Override
372    public int hashCode() {
373        int h;
374        h = list.hashCode();
375        if (isGB) {
376            h = h << 1;
377        }
378        if (testGB) {
379            h += 1;
380        }
381        return h;
382    }
383
384
385    /**
386     * Test if ZERO ideal.
387     * @return true, if this is the 0 ideal, else false
388     */
389    public boolean isZERO() {
390        //return list.isZERO();
391        if (list == null) { // never true
392            return true;
393        }
394        for (GenWordPolynomial<C> p : list) {
395            if (p == null) {
396                continue;
397            }
398            if (!p.isZERO()) {
399                return false;
400            }
401        }
402        return true;
403    }
404
405
406    /**
407     * Test if ONE is contained in the ideal. To test for a proper ideal use
408     * <code>! id.isONE()</code>.
409     * @return true, if this is the 1 ideal, else false
410     */
411    public boolean isONE() {
412        //return list.isONE();
413        if (list == null) {
414            return false;
415        }
416        for (GenWordPolynomial<C> p : list) {
417            if (p == null) {
418                continue;
419            }
420            if (p.isONE()) {
421                return true;
422            }
423        }
424        return false;
425    }
426
427
428    /**
429     * Test if this is a twosided Groebner base.
430     * @return true, if this is a twosided Groebner base, else false
431     */
432    public boolean isGB() {
433        if (testGB) {
434            return isGB;
435        }
436        logger.warn("isGB computing");
437        isGB = bb.isGB(getList());
438        testGB = true;
439        return isGB;
440    }
441
442
443    /**
444     * Do Groebner Base. Compute the Groebner Base for this ideal.
445     */
446    @SuppressWarnings("unchecked")
447    public void doGB() {
448        if (isGB && testGB) {
449            return;
450        }
451        List<GenWordPolynomial<C>> G = getList();
452        logger.info("GB computing = " + G);
453        list = bb.GB(G);
454        isGB = true;
455        testGB = true;
456        return;
457    }
458
459
460    /**
461     * Groebner Base. Get a Groebner Base for this ideal.
462     * @return twosidedGB(this)
463     */
464    public WordIdeal<C> GB() {
465        if (isGB) {
466            return this;
467        }
468        doGB();
469        return this;
470    }
471
472
473    /**
474     * Word ideal containment. Test if B is contained in this ideal. Note: this
475     * is eventually modified to become a Groebner Base.
476     * @param B solvable ideal
477     * @return true, if B is contained in this, else false
478     */
479    public boolean contains(WordIdeal<C> B) {
480        if (B == null || B.isZERO()) {
481            return true;
482        }
483        return contains(B.getList());
484    }
485
486
487    /**
488     * Word ideal containment. Test if b is contained in this ideal. Note: this
489     * is eventually modified to become a Groebner Base.
490     * @param b solvable polynomial
491     * @return true, if b is contained in this, else false
492     */
493    public boolean contains(GenWordPolynomial<C> b) {
494        if (b == null || b.isZERO()) {
495            return true;
496        }
497        if (this.isONE()) {
498            return true;
499        }
500        if (this.isZERO()) {
501            return false;
502        }
503        if (!isGB) {
504            doGB();
505        }
506        GenWordPolynomial<C> z = red.normalform(getList(), b);
507        if (z == null || z.isZERO()) {
508            return true;
509        }
510        return false;
511    }
512
513
514    /**
515     * Word ideal containment. Test if each b in B is contained in this ideal.
516     * Note: this is eventually modified to become a Groebner Base.
517     * @param B list of solvable polynomials
518     * @return true, if each b in B is contained in this, else false
519     */
520    public boolean contains(List<GenWordPolynomial<C>> B) {
521        if (B == null || B.size() == 0) {
522            return true;
523        }
524        if (this.isONE()) {
525            return true;
526        }
527        if (!isGB) {
528            doGB();
529        }
530        List<GenWordPolynomial<C>> si = getList();
531        for (GenWordPolynomial<C> b : B) {
532            if (b == null) {
533                continue;
534            }
535            GenWordPolynomial<C> z = red.normalform(si, b);
536            if (!z.isZERO()) {
537                System.out.println("contains nf(b) != 0: " + b + ", z = " + z);
538                //System.out.println("contains nf(b) != 0: si = " + si);
539                return false;
540            }
541        }
542        return true;
543    }
544
545
546    /**
547     * Word ideal summation. Generators for the sum of ideals. Note: if both
548     * ideals are Groebner bases, a Groebner base is returned.
549     * @param B solvable ideal
550     * @return ideal(this+B)
551     */
552    public WordIdeal<C> sum(WordIdeal<C> B) {
553        if (B == null || B.isZERO()) {
554            return this;
555        }
556        if (this.isZERO()) {
557            return B;
558        }
559        int s = getList().size() + B.getList().size();
560        List<GenWordPolynomial<C>> c;
561        c = new ArrayList<GenWordPolynomial<C>>(s);
562        c.addAll(getList());
563        c.addAll(B.getList());
564        WordIdeal<C> I = new WordIdeal<C>(getRing(), c, false);
565        if (isGB && B.isGB) {
566            I.doGB();
567        }
568        return I;
569    }
570
571
572    /**
573     * Word summation. Generators for the sum of ideal and a polynomial. Note:
574     * if this ideal is a Groebner base, a Groebner base is returned.
575     * @param b solvable polynomial
576     * @return ideal(this+{b})
577     */
578    public WordIdeal<C> sum(GenWordPolynomial<C> b) {
579        if (b == null || b.isZERO()) {
580            return this;
581        }
582        int s = getList().size() + 1;
583        List<GenWordPolynomial<C>> c;
584        c = new ArrayList<GenWordPolynomial<C>>(s);
585        c.addAll(getList());
586        c.add(b);
587        WordIdeal<C> I = new WordIdeal<C>(getRing(), c, false);
588        if (isGB) {
589            I.doGB();
590        }
591        return I;
592    }
593
594
595    /**
596     * Word summation. Generators for the sum of this ideal and a list of
597     * polynomials. Note: if this ideal is a Groebner base, a Groebner base is
598     * returned.
599     * @param L list of solvable polynomials
600     * @return ideal(this+L)
601     */
602    public WordIdeal<C> sum(List<GenWordPolynomial<C>> L) {
603        if (L == null || L.isEmpty()) {
604            return this;
605        }
606        int s = getList().size() + L.size();
607        List<GenWordPolynomial<C>> c = new ArrayList<GenWordPolynomial<C>>(s);
608        c.addAll(getList());
609        c.addAll(L);
610        WordIdeal<C> I = new WordIdeal<C>(getRing(), c, false);
611        if (isGB) {
612            I.doGB();
613        }
614        return I;
615    }
616
617
618    /**
619     * Product. Generators for the product of ideals. Note: if both ideals are
620     * Groebner bases, a Groebner base is returned.
621     * @param B solvable ideal
622     * @return ideal(this*B)
623     */
624    public WordIdeal<C> product(WordIdeal<C> B) {
625        if (B == null || B.isZERO()) {
626            return B;
627        }
628        if (this.isZERO()) {
629            return this;
630        }
631        int s = getList().size() * B.getList().size();
632        List<GenWordPolynomial<C>> c;
633        c = new ArrayList<GenWordPolynomial<C>>(s);
634        for (GenWordPolynomial<C> p : getList()) {
635            for (GenWordPolynomial<C> q : B.getList()) {
636                q = p.multiply(q);
637                c.add(q);
638            }
639        }
640        WordIdeal<C> I = new WordIdeal<C>(getRing(), c, false);
641        if (isGB && B.isGB) {
642            I.doGB();
643        }
644        return I;
645    }
646
647
648    /**
649     * Left product. Generators for the product this by a polynomial.
650     * @param b solvable polynomial
651     * @return ideal(this*b)
652     */
653    public WordIdeal<C> product(GenWordPolynomial<C> b) {
654        if (b == null || b.isZERO()) {
655            return getZERO();
656        }
657        if (this.isZERO()) {
658            return this;
659        }
660        List<GenWordPolynomial<C>> c;
661        c = new ArrayList<GenWordPolynomial<C>>(getList().size());
662        for (GenWordPolynomial<C> p : getList()) {
663            GenWordPolynomial<C> q = p.multiply(b);
664            c.add(q);
665        }
666        WordIdeal<C> I = new WordIdeal<C>(getRing(), c, false);
667        if (isGB) {
668            I.doGB();
669        }
670        return I;
671    }
672
673
674    /*
675     * Intersection. Generators for the intersection of ideals. Using an
676     * iterative algorithm.
677     * @param Bl list of solvable ideals
678     * @return ideal(cap_i B_i), a Groebner base
679    public WordIdeal<C> intersect(List<WordIdeal<C>> Bl) {
680        if (Bl == null || Bl.size() == 0) {
681            return getZERO();
682        }
683        WordIdeal<C> I = null;
684        for (WordIdeal<C> B : Bl) {
685            if (I == null) {
686                I = B;
687                continue;
688            }
689            if (I.isONE()) {
690                return I;
691            }
692            I = I.intersect(B);
693        }
694        return I;
695    }
696     */
697
698
699    /*
700     * Intersection. Generators for the intersection of ideals.
701     * @param B solvable ideal
702     * @return ideal(this \cap B), a Groebner base
703    public WordIdeal<C> intersect(WordIdeal<C> B) {
704        if (B == null || B.isZERO()) { // (0)
705            return B;
706        }
707        if (this.isZERO()) {
708            return this;
709        }
710        List<GenWordPolynomial<C>> c = PolyGBUtil.<C> intersect(getRing(),getList(),B.getList());
711        WordIdeal<C> I = new WordIdeal<C>(getRing(), c, true);
712        return I;
713    }
714     */
715
716
717    /*
718     * Intersection. Generators for the intersection of a ideal with a
719     * polynomial ring. The polynomial ring of this ideal must be a contraction
720     * of R and the TermOrder must be an elimination order.
721     * @param R solvable polynomial ring
722     * @return ideal(this \cap R)
723    public WordIdeal<C> intersect(GenWordPolynomialRing<C> R) {
724        if (R == null) {
725            throw new IllegalArgumentException("R may not be null");
726        }
727        List<GenWordPolynomial<C>> H = PolyUtil.<C> intersect(R,getList());
728        return new WordIdeal<C>(R, H, isGB, isTopt);
729    }
730     */
731
732
733    /*
734     * Eliminate. Generators for the intersection of this ideal with a solvable
735     * polynomial ring. The solvable polynomial ring of this ideal must be a
736     * contraction of R and the TermOrder must be an elimination order.
737     * @param R solvable polynomial ring
738     * @return ideal(this \cap R)
739    public WordIdeal<C> eliminate(GenWordPolynomialRing<C> R) {
740        if (R == null) {
741            throw new IllegalArgumentException("R may not be null");
742        }
743        if (getRing().equals(R)) {
744            return this;
745        }
746        return intersect(R);
747    }
748     */
749
750
751    /*
752     * Quotient. Generators for the solvable ideal quotient.
753     * @param h solvable polynomial
754     * @return ideal(this : h), a Groebner base
755    public WordIdeal<C> quotient(GenWordPolynomial<C> h) {
756        if (h == null) { // == (0)
757            return this;
758        }
759        if (h.isZERO()) {
760            return this;
761        }
762        if (this.isZERO()) {
763            return this;
764        }
765        List<GenWordPolynomial<C>> H;
766        H = new ArrayList<GenWordPolynomial<C>>(1);
767        H.add(h);
768        WordIdeal<C> Hi = new WordIdeal<C>(getRing(), H, true);
769
770        WordIdeal<C> I = this.intersect(Hi);
771
772        List<GenWordPolynomial<C>> Q;
773        Q = new ArrayList<GenWordPolynomial<C>>(I.getList().size());
774        for (GenWordPolynomial<C> q : I.getList()) {
775            q = (GenWordPolynomial<C>) q.divide(h); // remainder == 0
776            Q.add(q);
777        }
778        return new WordIdeal<C>(getRing(), Q, true);
779    }
780     */
781
782
783    /*
784     * Quotient. Generators for the solvable ideal quotient.
785     * @param H solvable ideal
786     * @return ideal(this : H), a Groebner base
787    public WordIdeal<C> quotient(WordIdeal<C> H) {
788        if (H == null || H.isZERO()) { // == (0)
789            return this;
790        }
791        if (this.isZERO()) {
792            return this;
793        }
794        WordIdeal<C> Q = null;
795        for (GenWordPolynomial<C> h : H.getList()) {
796            WordIdeal<C> Hi = this.quotient(h);
797            if (Q == null) {
798                Q = Hi;
799            } else {
800                Q = Q.intersect(Hi);
801            }
802        }
803        return Q;
804    }
805     */
806
807
808    /**
809     * Power. Generators for the power of this solvable ideal. Note: if this
810     * ideal is a Groebner base, a Groebner base is returned.
811     * @param d integer
812     * @return ideal(this^d)
813     */
814    public WordIdeal<C> power(int d) {
815        if (d <= 0) {
816            return getONE();
817        }
818        if (this.isZERO() || this.isONE()) {
819            return this;
820        }
821        WordIdeal<C> c = this;
822        for (int i = 1; i < d; i++) {
823            c = c.product(this);
824        }
825        return c;
826    }
827
828
829    /**
830     * Normalform for element.
831     * @param h solvable polynomial
832     * @return left normalform of h with respect to this
833     */
834    public GenWordPolynomial<C> normalform(GenWordPolynomial<C> h) {
835        if (h == null) {
836            return h;
837        }
838        if (h.isZERO()) {
839            return h;
840        }
841        if (this.isZERO()) {
842            return h;
843        }
844        GenWordPolynomial<C> r;
845        r = red.normalform(getList(), h);
846        return r;
847    }
848
849
850    /**
851     * Normalform for list of solvable elements.
852     * @param L solvable polynomial list
853     * @return list of left normalforms of the elements of L with respect to
854     *         this
855     */
856    public List<GenWordPolynomial<C>> normalform(List<GenWordPolynomial<C>> L) {
857        if (L == null) {
858            return L;
859        }
860        if (L.size() == 0) {
861            return L;
862        }
863        if (this.isZERO()) {
864            return L;
865        }
866        List<GenWordPolynomial<C>> M = new ArrayList<GenWordPolynomial<C>>(L.size());
867        for (GenWordPolynomial<C> h : L) {
868            GenWordPolynomial<C> r = normalform(h);
869            if (r != null && !r.isZERO()) {
870                M.add(r);
871            }
872        }
873        return M;
874    }
875
876
877    /**
878     * Inverse for element modulo this ideal.
879     * @param h word polynomial
880     * @return inverse of h with respect to this, if defined
881     */
882    public GenWordPolynomial<C> inverse(GenWordPolynomial<C> h) {
883        if (h == null || h.isZERO()) {
884            throw new NotInvertibleException("zero not invertible");
885        }
886        if (this.isZERO()) {
887            throw new NotInvertibleException("zero ideal");
888        }
889        if (h.isUnit()) {
890            return h.inverse();
891        }
892        throw new UnsupportedOperationException("inverse of " + h);
893        /*
894        doGB();
895        List<GenWordPolynomial<C>> F = new ArrayList<GenWordPolynomial<C>>(1 + list.list.size());
896        F.add(h);
897        F.addAll(getList());
898        //System.out.println("F = " + F);
899        WordExtendedGB<C> x = bb.extLeftGB(F);
900        List<GenWordPolynomial<C>> G = x.G;
901        //System.out.println("G = " + G);
902        GenWordPolynomial<C> one = null;
903        int i = -1;
904        for (GenWordPolynomial<C> p : G) {
905            i++;
906            if (p == null) {
907                continue;
908            }
909            if (p.isUnit()) {
910                one = p;
911                break;
912            }
913        }
914        if (one == null) {
915            throw new NotInvertibleException("one == null: h = " + h);
916        }
917        List<GenWordPolynomial<C>> row = x.G2F.get(i); // != -1
918        //System.out.println("row = " + row);
919        GenWordPolynomial<C> g = row.get(0);
920        if (g == null || g.isZERO()) {
921            throw new NotInvertibleException("g == 0: h = " + h);
922        }
923        GenWordPolynomial<C> gp = red.leftNormalform(getList(), g);
924        if (gp.isZERO()) { // can happen with solvable rings
925            throw new NotInvertibleException("solv|gp == 0: h = " + h + ", g = " + g);
926        }
927        // adjust leading coefficient of g to get g*h == 1
928        GenWordPolynomial<C> f = g.multiply(h);
929        //System.out.println("f = " + f);
930        GenWordPolynomial<C> k = red.leftNormalform(getList(), f);
931        //System.out.println("k = " + k);
932        if (!k.isONE()) {
933            C lbc = k.leadingBaseCoefficient();
934            lbc = lbc.inverse();
935            g = g.multiply(lbc);
936        }
937        if (debug) {
938            //logger.info("inv G = " + G);
939            //logger.info("inv G2F = " + x.G2F);
940            //logger.info("inv row "+i+" = " + row);
941            //logger.info("inv h = " + h);
942            //logger.info("inv g = " + g);
943            //logger.info("inv f = " + f);
944            f = g.multiply(h);
945            k = red.leftNormalform(getList(), f);
946            logger.debug("inv k = " + k);
947            if (!k.isUnit()) {
948                throw new NotInvertibleException(" k = " + k);
949            }
950        }
951        return g;
952        */
953    }
954
955
956    /**
957     * Test if element is a unit modulo this ideal.
958     * @param h solvable polynomial
959     * @return true if h is a unit with respect to this, else false
960     */
961    public boolean isUnit(GenWordPolynomial<C> h) {
962        if (h == null || h.isZERO()) {
963            return false;
964        }
965        if (this.isZERO()) {
966            return false;
967        }
968        if (h.isUnit()) {
969            return true;
970        }
971        /* TODO together wit inverse
972        List<GenWordPolynomial<C>> F = new ArrayList<GenWordPolynomial<C>>(1 + list.size());
973        F.add(h);
974        F.addAll(getList());
975        List<GenWordPolynomial<C>> G = bb.GB(F);
976        if (debug) {
977            logger.info("isUnit GB = " + G);
978        }
979        for (GenWordPolynomial<C> p : G) {
980            if (p == null) {
981                continue;
982            }
983            if (p.isUnit()) {
984                return true;
985            }
986        }
987        */
988        return false;
989    }
990
991
992    /**
993     * Ideal common zero test.
994     * @return -1, 0 or 1 if dimension(this) &eq; -1, 0 or &ge; 1.
995     */
996    public int commonZeroTest() {
997        if (this.isZERO()) {
998            return 1;
999        }
1000        if (!isGB) {
1001            doGB();
1002        }
1003        if (this.isONE()) {
1004            return -1;
1005        }
1006        return bb.commonZeroTest(getList());
1007    }
1008
1009
1010    /**
1011     * Test if this ideal is maximal.
1012     * @return true, if this is maximal and not one, else false.
1013     */
1014    public boolean isMaximal() {
1015        if (commonZeroTest() != 0) {
1016            return false;
1017        }
1018        for (Long d : univariateDegrees()) {
1019            if (d > 1L) {
1020                // todo: test if irreducible
1021                return false;
1022            }
1023        }
1024        return true;
1025    }
1026
1027
1028    /**
1029     * Univariate head term degrees.
1030     * @return a list of the degrees of univariate head terms.
1031     */
1032    public List<Long> univariateDegrees() {
1033        List<Long> ud = new ArrayList<Long>();
1034        if (this.isZERO()) {
1035            return ud;
1036        }
1037        if (!isGB) {
1038            doGB();
1039        }
1040        if (this.isONE()) {
1041            return ud;
1042        }
1043        return bb.univariateDegrees(getList());
1044    }
1045
1046
1047    /*
1048     * Construct univariate polynomials of minimal degree in all variables in
1049     * zero dimensional ideal(G).
1050     * @return list of univariate solvable polynomial of minimal degree in each
1051     *         variable in ideal(G)
1052    public List<GenWordPolynomial<C>> constructUnivariate() {
1053        List<GenWordPolynomial<C>> univs = new ArrayList<GenWordPolynomial<C>>();
1054        for (int i = ring.alphabet.length() - 1; i >= 0; i--) {
1055            GenWordPolynomial<C> u = constructUnivariate(i);
1056            univs.add(u);
1057        }
1058        return univs;
1059    }
1060     */
1061
1062
1063    /*
1064     * Construct univariate polynomial of minimal degree in variable i in zero
1065     * dimensional ideal(G).
1066     * @param i variable index.
1067     * @return univariate solvable polynomial of minimal degree in variable i in
1068     *         ideal(G)
1069    public GenWordPolynomial<C> constructUnivariate(int i) {
1070        doGB();
1071        return bb.constructUnivariate(i, getList());
1072    }
1073     */
1074
1075}