001/*
002 * $Id$
003 */
004
005package edu.jas.gb;
006
007
008import java.util.ArrayList;
009import java.util.List;
010import java.util.Map;
011
012import org.apache.logging.log4j.LogManager;
013import org.apache.logging.log4j.Logger;
014
015import edu.jas.poly.ExpVector;
016import edu.jas.poly.GenPolynomial;
017import edu.jas.poly.GenPolynomialRing;
018import edu.jas.poly.GenSolvablePolynomial;
019import edu.jas.structure.RingElem;
020
021
022/**
023 * Polynomial D-Reduction sequential use algorithm. Implements normalform.
024 * @param <C> coefficient type
025 * @author Heinz Kredel
026 */
027
028public class DReductionSeq<C extends RingElem<C>> extends ReductionAbstract<C> implements DReduction<C> {
029
030
031    private static final Logger logger = LogManager.getLogger(DReductionSeq.class);
032
033
034    //private static final boolean debug = logger.isDebugEnabled();
035
036
037    /**
038     * Constructor.
039     */
040    public DReductionSeq() {
041    }
042
043
044    /**
045     * Is top reducible.
046     * @param A polynomial.
047     * @param P polynomial list.
048     * @return true if A is top reducible with respect to P.
049     */
050    @Override
051    public boolean isTopReducible(List<GenPolynomial<C>> P, GenPolynomial<C> A) {
052        if (P == null || P.isEmpty()) {
053            return false;
054        }
055        if (A == null || A.isZERO()) {
056            return false;
057        }
058        boolean mt = false;
059        ExpVector e = A.leadingExpVector();
060        C a = A.leadingBaseCoefficient();
061        for (GenPolynomial<C> p : P) {
062            mt = e.multipleOf(p.leadingExpVector());
063            if (mt) {
064                C b = p.leadingBaseCoefficient();
065                C r = a.remainder(b);
066                mt = r.isZERO();
067                if (mt) {
068                    return true;
069                }
070            }
071        }
072        return false;
073    }
074
075
076    /**
077     * Is in Normalform.
078     * @param Ap polynomial.
079     * @param Pp polynomial list.
080     * @return true if Ap is in normalform with respect to Pp.
081     */
082    @SuppressWarnings("unchecked")
083    @Override
084    public boolean isNormalform(List<GenPolynomial<C>> Pp, GenPolynomial<C> Ap) {
085        if (Pp == null || Pp.isEmpty()) {
086            return true;
087        }
088        if (Ap == null || Ap.isZERO()) {
089            return true;
090        }
091        int l;
092        GenPolynomial<C>[] P;
093        synchronized (Pp) {
094            l = Pp.size();
095            P = new GenPolynomial[l];
096            //P = Pp.toArray();
097            for (int i = 0; i < Pp.size(); i++) {
098                P[i] = Pp.get(i);
099            }
100        }
101        ExpVector[] htl = new ExpVector[l];
102        C[] lbc = (C[]) new RingElem[l]; // want <C>
103        GenPolynomial<C>[] p = new GenPolynomial[l];
104        Map.Entry<ExpVector, C> m;
105        int i;
106        int j = 0;
107        for (i = 0; i < l; i++) {
108            p[i] = P[i];
109            m = p[i].leadingMonomial();
110            if (m != null) {
111                p[j] = p[i];
112                htl[j] = m.getKey();
113                lbc[j] = m.getValue();
114                j++;
115            }
116        }
117        l = j;
118        boolean mt = false;
119        Map<ExpVector, C> Am = Ap.getMap();
120        for (Map.Entry<ExpVector, C> me : Am.entrySet()) {
121            ExpVector e = me.getKey();
122            C a = me.getValue(); //Am.get(e);
123            for (i = 0; i < l; i++) {
124                mt = e.multipleOf(htl[i]);
125                if (mt) {
126                    C r = a.remainder(lbc[i]);
127                    mt = r.isZERO();
128                    if (mt) {
129                        return false;
130                    }
131                }
132            }
133        }
134        return true;
135    }
136
137
138    /**
139     * Normalform using d-reduction.
140     * @param Ap polynomial.
141     * @param Pp polynomial list.
142     * @return d-nf(Ap) with respect to Pp.
143     */
144    @SuppressWarnings("unchecked")
145    @Override
146    public GenPolynomial<C> normalform(List<GenPolynomial<C>> Pp, GenPolynomial<C> Ap) {
147        if (Pp == null || Pp.isEmpty()) {
148            return Ap;
149        }
150        if (Ap == null || Ap.isZERO()) {
151            return Ap;
152        }
153        int l;
154        GenPolynomial<C>[] P;
155        synchronized (Pp) {
156            l = Pp.size();
157            P = (GenPolynomial<C>[]) new GenPolynomial[l];
158            //P = Pp.toArray();
159            for (int i = 0; i < Pp.size(); i++) {
160                P[i] = Pp.get(i); //.abs();
161            }
162        }
163        //System.out.println("l = " + l);
164        Map.Entry<ExpVector, C> m;
165        ExpVector[] htl = new ExpVector[l];
166        C[] lbc = (C[]) new RingElem[l]; // want <C>
167        GenPolynomial<C>[] p = (GenPolynomial<C>[]) new GenPolynomial[l];
168        int i;
169        int j = 0;
170        for (i = 0; i < l; i++) {
171            p[i] = P[i];
172            m = p[i].leadingMonomial();
173            if (m != null) {
174                p[j] = p[i];
175                htl[j] = m.getKey();
176                lbc[j] = m.getValue();
177                j++;
178            }
179        }
180        l = j;
181        ExpVector e;
182        C a;
183        C r = null;
184        boolean mt = false;
185        GenPolynomial<C> R = Ap.ring.getZERO();
186        GenPolynomial<C> Q = null;
187        GenPolynomial<C> S = Ap;
188        while (S.length() > 0) {
189            m = S.leadingMonomial();
190            e = m.getKey();
191            a = m.getValue();
192            for (i = 0; i < l; i++) {
193                mt = e.multipleOf(htl[i]);
194                if (mt) {
195                    r = a.remainder(lbc[i]);
196                    mt = r.isZERO(); // && mt
197                }
198                if (mt)
199                    break;
200            }
201            if (!mt) {
202                //logger.debug("irred");
203                R = R.sum(a, e);
204                //S = S.subtract( a, e ); 
205                S = S.reductum();
206                //System.out.println(" S = " + S);
207            } else {
208                //logger.info("red div = {}", e);
209                ExpVector f = e.subtract(htl[i]);
210                C b = a.divide(lbc[i]);
211                // r == 0: R = R.sum(r, e);
212                Q = p[i].multiply(b, f);
213                S = S.reductum().subtract(Q.reductum()); // ok also with reductum
214            }
215        }
216        return R.abs(); // ok with d-reduction
217    }
218
219
220    /**
221     * S-Polynomial.
222     * @param Ap polynomial.
223     * @param Bp polynomial.
224     * @return spol(Ap,Bp) the S-polynomial of Ap and Bp.
225     */
226    @Override
227    public GenPolynomial<C> SPolynomial(GenPolynomial<C> Ap, GenPolynomial<C> Bp) {
228        if (logger.isInfoEnabled()) {
229            if (Bp == null || Bp.isZERO()) {
230                return Ap.ring.getZERO();
231            }
232            if (Ap == null || Ap.isZERO()) {
233                return Bp.ring.getZERO();
234            }
235            if (!Ap.ring.equals(Bp.ring)) {
236                logger.error("rings not equal");
237            }
238        }
239        Map.Entry<ExpVector, C> ma = Ap.leadingMonomial();
240        Map.Entry<ExpVector, C> mb = Bp.leadingMonomial();
241
242        ExpVector e = ma.getKey();
243        ExpVector f = mb.getKey();
244
245        ExpVector g = e.lcm(f);
246        ExpVector e1 = g.subtract(e);
247        ExpVector f1 = g.subtract(f);
248
249        C a = ma.getValue();
250        C b = mb.getValue();
251
252        //c = lcm(a,b)
253        C c = a.gcd(b);
254        C m = a.multiply(b);
255        C l = m.divide(c);
256        C a1 = l.divide(a);
257        C b1 = l.divide(b);
258
259        //Cp = a1 e1 * A - b1 f1 * B
260        GenPolynomial<C> Cp = Ap.scaleSubtractMultiple(a1, e1, b1, f1, Bp);
261        return Cp;
262    }
263
264
265    /**
266     * G-Polynomial.
267     * @param Ap polynomial.
268     * @param Bp polynomial.
269     * @return gpol(Ap,Bp) the g-polynomial of Ap and Bp.
270     */
271    @Override
272    public GenPolynomial<C> GPolynomial(GenPolynomial<C> Ap, GenPolynomial<C> Bp) {
273        if (logger.isInfoEnabled()) {
274            if (Bp == null || Bp.isZERO()) {
275                return Ap.ring.getZERO();
276            }
277            if (Ap == null || Ap.isZERO()) {
278                return Bp.ring.getZERO();
279            }
280            if (!Ap.ring.equals(Bp.ring)) {
281                logger.error("rings not equal");
282            }
283        }
284        Map.Entry<ExpVector, C> ma = Ap.leadingMonomial();
285        Map.Entry<ExpVector, C> mb = Bp.leadingMonomial();
286
287        ExpVector e = ma.getKey();
288        ExpVector f = mb.getKey();
289
290        ExpVector g = e.lcm(f);
291        ExpVector e1 = g.subtract(e);
292        ExpVector f1 = g.subtract(f);
293
294        C a = ma.getValue();
295        C b = mb.getValue();
296
297        C[] c = a.egcd(b); // c[0] = c[1] a + c[2] b
298        //System.out.println("egcd[0] " + c[0]);
299        //Cp = c[1] e1 * A + c[2] f1 * B = c[1] e1 * A - (-c[2]) f1 * B
300        GenPolynomial<C> Cp = Ap.scaleSubtractMultiple(c[1], e1, c[2].negate(), f1, Bp);
301        return Cp; // .negate() -
302    }
303
304
305    /**
306     * S-Polynomial with recording.
307     * @param row recording vector, is modified.
308     * @param i index of Ap in basis list.
309     * @param Ap a polynomial.
310     * @param j index of Bp in basis list.
311     * @param Bp a polynomial.
312     * @return spol(Ap, Bp), the s-Polynomial for Ap and Bp.
313     */
314    @Override
315    public GenPolynomial<C> SPolynomial(List<GenPolynomial<C>> row, int i, GenPolynomial<C> Ap, int j,
316                    GenPolynomial<C> Bp) {
317        if (logger.isInfoEnabled()) {
318            if (Bp == null || Bp.isZERO()) {
319                return Ap.ring.getZERO();
320            }
321            if (Ap == null || Ap.isZERO()) {
322                return Bp.ring.getZERO();
323            }
324            if (!Ap.ring.equals(Bp.ring)) {
325                logger.error("rings not equal");
326            }
327            //if ((row.get(i) != null && !row.get(i).isZERO()) || (row.get(j) != null && !row.get(j).isZERO())) {
328            //    throw new IllegalArgumentException("row(i), row(j): " + row.get(i) + ", " + row.get(j));
329            //}
330        }
331        Map.Entry<ExpVector, C> ma = Ap.leadingMonomial();
332        Map.Entry<ExpVector, C> mb = Bp.leadingMonomial();
333
334        ExpVector e = ma.getKey();
335        ExpVector f = mb.getKey();
336
337        ExpVector g = e.lcm(f);
338        ExpVector e1 = g.subtract(e);
339        ExpVector f1 = g.subtract(f);
340
341        C a = ma.getValue();
342        C b = mb.getValue();
343
344        //c = lcm(a,b)
345        C c = a.gcd(b);
346        C m = a.multiply(b);
347        C l = m.divide(c);
348        C a1 = l.divide(a);
349        C b1 = l.divide(b);
350        //Cp = a1 e1 * A - b1 f1 * B
351        GenPolynomial<C> Cp = Ap.scaleSubtractMultiple(a1, e1, b1, f1, Bp);
352
353        GenPolynomial<C> zero = Ap.ring.getZERO();
354        GenPolynomial<C> As = zero.sum(a1, e1); /*not correct .negate()*/
355        GenPolynomial<C> Bs = zero.sum(b1.negate(), f1); /*correct */
356        row.set(i, As);
357        row.set(j, Bs);
358        return Cp;
359    }
360
361
362    /**
363     * G-Polynomial with recording.
364     * @param row recording matrix, is modified.
365     * @param i index of Ap in basis list.
366     * @param Ap a polynomial.
367     * @param j index of Bp in basis list.
368     * @param Bp a polynomial.
369     * @return gpol(Ap, Bp), the g-Polynomial for Ap and Bp.
370     */
371    @Override
372    public GenPolynomial<C> GPolynomial(List<GenPolynomial<C>> row, int i, GenPolynomial<C> Ap, int j,
373                    GenPolynomial<C> Bp) {
374        if (logger.isInfoEnabled()) {
375            if (Bp == null || Bp.isZERO()) {
376                return Ap.ring.getZERO();
377            }
378            if (Ap == null || Ap.isZERO()) {
379                return Bp.ring.getZERO();
380            }
381            if (!Ap.ring.equals(Bp.ring)) {
382                logger.error("rings not equal");
383            }
384            //if ((row.get(i) != null && !row.get(i).isZERO()) || (row.get(j) != null && !row.get(j).isZERO())) {
385            //    throw new IllegalArgumentException("row(i), row(j): " + row.get(i) + ", " + row.get(j));
386            //}
387        }
388        Map.Entry<ExpVector, C> ma = Ap.leadingMonomial();
389        Map.Entry<ExpVector, C> mb = Bp.leadingMonomial();
390
391        ExpVector e = ma.getKey();
392        ExpVector f = mb.getKey();
393
394        ExpVector g = e.lcm(f);
395        ExpVector e1 = g.subtract(e);
396        ExpVector f1 = g.subtract(f);
397
398        C a = ma.getValue();
399        C b = mb.getValue();
400
401        C[] c = a.egcd(b); // c[0] = c[1] a + c[2] b
402        //System.out.println("egcd[0] " + c[0]);
403        //Cp = c[1] e1 * A + c[2] f1 * B = c[1] e1 * A - (-c[2]) f1 * B
404        GenPolynomial<C> Cp = Ap.scaleSubtractMultiple(c[1], e1, c[2].negate(), f1, Bp);
405
406        GenPolynomial<C> zero = Ap.ring.getZERO();
407        GenPolynomial<C> As = zero.sum(c[1], e1); // .negate() -
408        GenPolynomial<C> Bs = zero.sum(c[2], f1); // .negate() -
409        row.set(i, As);
410        row.set(j, Bs);
411        return Cp; // .negate() -
412    }
413
414
415    /**
416     * GB criterium 4. Use only for commutative polynomial rings. This version
417     * works also for d-Groebner bases.
418     * @param A polynomial.
419     * @param B polynomial.
420     * @param e = lcm(ht(A),ht(B))
421     * @return true if the S-polynomial(i,j) is required, else false.
422     */
423    @Override
424    public boolean criterion4(GenPolynomial<C> A, GenPolynomial<C> B, ExpVector e) {
425        if (logger.isInfoEnabled()) {
426            if (!A.ring.equals(B.ring)) {
427                logger.error("rings equal");
428            }
429            if (A instanceof GenSolvablePolynomial || B instanceof GenSolvablePolynomial) {
430                logger.error("GBCriterion4 not applicabable to SolvablePolynomials");
431                return true;
432            }
433        }
434        ExpVector ei = A.leadingExpVector();
435        ExpVector ej = B.leadingExpVector();
436        ExpVector g = ei.sum(ej);
437        // boolean t =  g == e ;
438        ExpVector h = g.subtract(e);
439        int s = h.signum();
440        if (s == 0) { // disjoint ht
441            C a = A.leadingBaseCoefficient();
442            C b = B.leadingBaseCoefficient();
443            C d = a.gcd(b);
444            if (d.isONE()) { // disjoint hc
445                //System.out.println("d1 = " + d + ", a = " + a + ", b = " + b);
446                return false; // can skip pair
447            }
448        }
449        return true; //! ( s == 0 );
450    }
451
452
453    /**
454     * GB criterium 4. Use only for commutative polynomial rings. This version
455     * works also for d-Groebner bases.
456     * @param A polynomial.
457     * @param B polynomial.
458     * @return true if the S-polynomial(i,j) is required, else false.
459     */
460    @Override
461    public boolean criterion4(GenPolynomial<C> A, GenPolynomial<C> B) {
462        if (logger.isInfoEnabled()) {
463            if (A instanceof GenSolvablePolynomial || B instanceof GenSolvablePolynomial) {
464                logger.error("GBCriterion4 not applicabable to SolvablePolynomials");
465                return true;
466            }
467        }
468        ExpVector ei = A.leadingExpVector();
469        ExpVector ej = B.leadingExpVector();
470        ExpVector g = ei.sum(ej);
471        ExpVector e = ei.lcm(ej);
472        //        boolean t =  g == e ;
473        ExpVector h = g.subtract(e);
474        int s = h.signum();
475        if (s == 0) { // disjoint ht
476            C a = A.leadingBaseCoefficient();
477            C b = B.leadingBaseCoefficient();
478            C d = a.gcd(b);
479            if (d.isONE()) { // disjoint hc
480                return false; // can skip pair
481            }
482        }
483        return true; //! ( s == 0 );
484    }
485
486
487    /**
488     * Normalform with recording.
489     * @param row recording matrix, is modified.
490     * @param Pp a polynomial list for reduction.
491     * @param Ap a polynomial.
492     * @return nf(Pp,Ap), the normal form of Ap wrt. Pp.
493     */
494    @SuppressWarnings("unchecked")
495    @Override
496    public GenPolynomial<C> normalform(List<GenPolynomial<C>> row, List<GenPolynomial<C>> Pp,
497                    GenPolynomial<C> Ap) {
498        if (Pp == null || Pp.isEmpty()) {
499            return Ap;
500        }
501        if (Ap == null || Ap.isZERO()) {
502            return Ap;
503        }
504        int l;
505        GenPolynomial<C>[] P;
506        synchronized (Pp) {
507            l = Pp.size();
508            P = (GenPolynomial<C>[]) new GenPolynomial[l];
509            //P = Pp.toArray();
510            for (int i = 0; i < Pp.size(); i++) {
511                P[i] = Pp.get(i);
512            }
513        }
514        ExpVector[] htl = new ExpVector[l];
515        C[] lbc = (C[]) new RingElem[l]; // want <C>
516        GenPolynomial<C>[] p = (GenPolynomial<C>[]) new GenPolynomial[l];
517        Map.Entry<ExpVector, C> m;
518        int j = 0;
519        int i;
520        for (i = 0; i < l; i++) {
521            p[i] = P[i];
522            m = p[i].leadingMonomial();
523            if (m != null) {
524                p[j] = p[i];
525                htl[j] = m.getKey();
526                lbc[j] = m.getValue();
527                j++;
528            }
529        }
530        l = j;
531        ExpVector e = null;
532        ExpVector f = null;
533        C a = null;
534        C b = null;
535        C r = null;
536        GenPolynomialRing<C> pfac = Ap.ring;
537        GenPolynomial<C> R = pfac.getZERO();
538        GenPolynomial<C> zero = pfac.getZERO();
539
540        GenPolynomial<C> fac = null;
541        // GenPolynomial<C> T = null;
542        GenPolynomial<C> Q = null;
543        GenPolynomial<C> S = Ap;
544        while (S.length() > 0) {
545            boolean mt = false;
546            m = S.leadingMonomial();
547            e = m.getKey();
548            a = m.getValue();
549            for (i = 0; i < l; i++) {
550                mt = e.multipleOf(htl[i]);
551                if (mt) {
552                    r = a.remainder(lbc[i]);
553                    mt = r.isZERO();
554                }
555                if (mt)
556                    break;
557            }
558            if (!mt) {
559                //logger.debug("irred");
560                R = R.sum(a, e);
561                S = S.subtract(a, e);
562                //System.out.println("a = " + a + ", e = " + e);
563            } else {
564                //logger.info("red div = {}", e);
565                f = e.subtract(htl[i]);
566                b = a.divide(lbc[i]);
567                //System.out.println("b = " + b + ", f = " + f);
568                // r == 0: R = R.sum(r, f);
569                Q = p[i].multiply(b, f);
570                S = S.reductum().subtract(Q.reductum()); // ok also with reductum
571                fac = row.get(i);
572                if (fac == null) {
573                    fac = zero.sum(b, f);
574                } else {
575                    fac = fac.sum(b, f);
576                }
577                row.set(i, fac);
578            }
579        }
580        return R;
581    }
582
583
584    /**
585     * Irreducible set.
586     * @param Pp polynomial list.
587     * @return a list P of polynomials which are in normalform wrt. P.
588     */
589    @Override
590    public List<GenPolynomial<C>> irreducibleSet(List<GenPolynomial<C>> Pp) {
591        ArrayList<GenPolynomial<C>> P = new ArrayList<GenPolynomial<C>>();
592        if (Pp == null) {
593            return null;
594        }
595        for (GenPolynomial<C> a : Pp) {
596            if (!a.isZERO()) {
597                P.add(a);
598            }
599        }
600        int l = P.size();
601        if (l <= 1)
602            return P;
603
604        int irr = 0;
605        ExpVector e;
606        ExpVector f;
607        GenPolynomial<C> a;
608        logger.debug("irr = ");
609        while (irr != l) {
610            a = P.remove(0);
611            e = a.leadingExpVector();
612            a = normalform(P, a);
613            logger.debug(String.valueOf(irr));
614            if (a.isZERO()) {
615                l--;
616                if (l <= 1) {
617                    return P;
618                }
619            } else {
620                f = a.leadingExpVector();
621                if (e.equals(f)) {
622                    irr++;
623                } else {
624                    irr = 0;
625                }
626                P.add(a);
627            }
628        }
629        //System.out.println();
630        return P;
631    }
632
633
634    // inherit is okay:
635    //public boolean isReductionNF(List<GenPolynomial<C>> row, List<GenPolynomial<C>> Pp, GenPolynomial<C> Ap,
636    //                 GenPolynomial<C> Np) {
637
638}