001/*
002 * $Id$
003 */
004
005package edu.jas.gb;
006
007
008import java.util.ArrayList;
009import java.util.Iterator;
010import java.util.List;
011import java.util.Map;
012
013import org.apache.logging.log4j.LogManager;
014import org.apache.logging.log4j.Logger;
015
016import edu.jas.poly.ExpVector;
017import edu.jas.poly.Monomial;
018import edu.jas.poly.GenSolvablePolynomial;
019import edu.jas.poly.GenSolvablePolynomialRing;
020import edu.jas.poly.ModuleList;
021import edu.jas.poly.PolynomialList;
022import edu.jas.structure.RingElem;
023
024
025/**
026 * Solvable polynomial Reduction abstract class. Implements common left, right
027 * S-Polynomial, left normalform and left irreducible set.
028 * @param <C> coefficient type
029 * @author Heinz Kredel
030 */
031
032public abstract class SolvableReductionAbstract<C extends RingElem<C>> implements SolvableReduction<C> {
033
034
035    private static final Logger logger = LogManager.getLogger(SolvableReductionAbstract.class);
036
037
038    private static final boolean debug = logger.isDebugEnabled();
039
040
041    /**
042     * Constructor.
043     */
044    public SolvableReductionAbstract() {
045    }
046
047
048    /**
049     * Left S-Polynomial.
050     * @param Ap solvable polynomial.
051     * @param Bp solvable polynomial.
052     * @return left-spol(Ap,Bp) the left S-polynomial of Ap and Bp.
053     */
054    public GenSolvablePolynomial<C> leftSPolynomial(GenSolvablePolynomial<C> Ap,
055                    GenSolvablePolynomial<C> Bp) {
056        if (logger.isInfoEnabled()) {
057            if (Bp == null || Bp.isZERO()) {
058                if (Ap != null) {
059                    return Ap.ring.getZERO();
060                }
061                return null;
062            }
063            if (Ap == null || Ap.isZERO()) {
064                return Bp.ring.getZERO();
065            }
066            if (!Ap.ring.equals(Bp.ring)) {
067                logger.error("rings not equal");
068            }
069        }
070        Map.Entry<ExpVector, C> ma = Ap.leadingMonomial();
071        Map.Entry<ExpVector, C> mb = Bp.leadingMonomial();
072
073        ExpVector e = ma.getKey();
074        ExpVector f = mb.getKey();
075
076        ExpVector g = e.lcm(f);
077        ExpVector e1 = g.subtract(e);
078        ExpVector f1 = g.subtract(f);
079
080        C a = ma.getValue();
081        C b = mb.getValue();
082
083        GenSolvablePolynomial<C> App = Ap.multiplyLeft(b, e1);
084        GenSolvablePolynomial<C> Bpp = Bp.multiplyLeft(a, f1);
085        GenSolvablePolynomial<C> Cp = (GenSolvablePolynomial<C>) App.subtract(Bpp);
086        return Cp;
087    }
088
089
090    /**
091     * S-Polynomial with recording.
092     * @param S recording matrix, is modified.
093     * @param i index of Ap in basis list.
094     * @param Ap a polynomial.
095     * @param j index of Bp in basis list.
096     * @param Bp a polynomial.
097     * @return leftSpol(Ap, Bp), the left S-Polynomial for Ap and Bp.
098     */
099    public GenSolvablePolynomial<C> leftSPolynomial(List<GenSolvablePolynomial<C>> S, int i,
100                    GenSolvablePolynomial<C> Ap, int j, GenSolvablePolynomial<C> Bp) {
101        if (debug /*logger.isInfoEnabled()*/) {
102            if (Bp == null || Bp.isZERO()) {
103                throw new ArithmeticException("Spol B is zero");
104            }
105            if (Ap == null || Ap.isZERO()) {
106                throw new ArithmeticException("Spol A is zero");
107            }
108            if (!Ap.ring.equals(Bp.ring)) {
109                logger.error("rings not equal");
110            }
111        }
112        Map.Entry<ExpVector, C> ma = Ap.leadingMonomial();
113        Map.Entry<ExpVector, C> mb = Bp.leadingMonomial();
114
115        ExpVector e = ma.getKey();
116        ExpVector f = mb.getKey();
117
118        ExpVector g = e.lcm(f);
119        ExpVector e1 = g.subtract(e);
120        ExpVector f1 = g.subtract(f);
121
122        C a = ma.getValue();
123        C b = mb.getValue();
124
125        GenSolvablePolynomial<C> App = Ap.multiplyLeft(b, e1);
126        GenSolvablePolynomial<C> Bpp = Bp.multiplyLeft(a, f1);
127        GenSolvablePolynomial<C> Cp = (GenSolvablePolynomial<C>) App.subtract(Bpp);
128
129        GenSolvablePolynomial<C> zero = Ap.ring.getZERO();
130        GenSolvablePolynomial<C> As = (GenSolvablePolynomial<C>) zero.sum(b.negate(), e1);
131        GenSolvablePolynomial<C> Bs = (GenSolvablePolynomial<C>) zero.sum(a, f1);
132        S.set(i, As);
133        S.set(j, Bs);
134        return Cp;
135    }
136
137
138    /**
139     * Left Normalform Set.
140     * @param Ap solvable polynomial list.
141     * @param Pp solvable polynomial list.
142     * @return list of left-nf(a) with respect to Pp for all a in Ap.
143     */
144    public List<GenSolvablePolynomial<C>> leftNormalform(List<GenSolvablePolynomial<C>> Pp,
145                    List<GenSolvablePolynomial<C>> Ap) {
146        if (Pp == null || Pp.isEmpty()) {
147            return Ap;
148        }
149        if (Ap == null || Ap.isEmpty()) {
150            return Ap;
151        }
152        ArrayList<GenSolvablePolynomial<C>> red = new ArrayList<GenSolvablePolynomial<C>>();
153        for (GenSolvablePolynomial<C> A : Ap) {
154            A = leftNormalform(Pp, A);
155            red.add(A);
156        }
157        return red;
158    }
159
160
161    /**
162     * Module left normalform set.
163     * @param Ap module list.
164     * @param Pp module list.
165     * @return list of left-nf(a) with respect to Pp for all a in Ap.
166     */
167    public ModuleList<C> leftNormalform(ModuleList<C> Pp, ModuleList<C> Ap) {
168        return leftNormalform(Pp, Ap, false);
169    }
170
171
172    /**
173     * Module left normalform set.
174     * @param Ap module list.
175     * @param Pp module list.
176     * @param top true for TOP term order, false for POT term order.
177     * @return list of left-nf(a) with respect to Pp for all a in Ap.
178     */
179    public ModuleList<C> leftNormalform(ModuleList<C> Pp, ModuleList<C> Ap, boolean top) {
180        if (Pp == null || Pp.isEmpty()) {
181            return Ap;
182        }
183        if (Ap == null || Ap.isEmpty()) {
184            return Ap;
185        }
186        GenSolvablePolynomialRing<C> sring = (GenSolvablePolynomialRing<C>) Pp.ring;
187        int modv = Pp.cols;
188        GenSolvablePolynomialRing<C> pfac = sring.extend(modv, top);
189        logger.debug("extended ring = {}", pfac.toScript());
190        //System.out.println("extended ring = " + pfac.toScript());
191        PolynomialList<C> P = Pp.getPolynomialList(pfac);
192        PolynomialList<C> A = Ap.getPolynomialList(pfac);
193        //System.out.println("P = " + P.toScript());
194
195        List<GenSolvablePolynomial<C>> red = leftNormalform(P.castToSolvableList(), A.castToSolvableList());
196        PolynomialList<C> Fr = new PolynomialList<C>(pfac, red);
197        ModuleList<C> Nr = Fr.getModuleList(modv);
198        return Nr;
199    }
200
201
202    /**
203     * Left irreducible set.
204     * @param Pp solvable polynomial list.
205     * @return a list P of solvable polynomials which are in normalform wrt. P.
206     */
207    public List<GenSolvablePolynomial<C>> leftIrreducibleSet(List<GenSolvablePolynomial<C>> Pp) {
208        ArrayList<GenSolvablePolynomial<C>> P = new ArrayList<GenSolvablePolynomial<C>>();
209        for (GenSolvablePolynomial<C> a : Pp) {
210            if (a.length() != 0) {
211                a = a.monic();
212                P.add(a);
213            }
214        }
215        int l = P.size();
216        if (l <= 1)
217            return P;
218
219        int irr = 0;
220        ExpVector e;
221        ExpVector f;
222        GenSolvablePolynomial<C> a;
223        Iterator<GenSolvablePolynomial<C>> it;
224        logger.debug("irr = ");
225        while (irr != l) {
226            it = P.listIterator();
227            a = it.next();
228            P.remove(0);
229            e = a.leadingExpVector();
230            a = leftNormalform(P, a);
231            logger.debug(String.valueOf(irr));
232            if (a.length() == 0) {
233                l--;
234                if (l <= 1) {
235                    return P;
236                }
237            } else {
238                f = a.leadingExpVector();
239                if (f.signum() == 0) {
240                    P = new ArrayList<GenSolvablePolynomial<C>>();
241                    P.add(a.monic());
242                    return P;
243                }
244                if (e.equals(f)) {
245                    irr++;
246                } else {
247                    irr = 0;
248                    a = a.monic();
249                }
250                P.add(a);
251            }
252        }
253        //System.out.println();
254        return P;
255    }
256
257
258    /**
259     * Is reduction of normal form.
260     * @param row recording matrix.
261     * @param Pp a solvable polynomial list for reduction.
262     * @param Ap a solvable polynomial.
263     * @param Np nf(Pp,Ap), a left normal form of Ap wrt. Pp.
264     * @return true, if Np + sum( row[i]*Pp[i] ) == Ap, else false.
265     */
266    @SuppressWarnings("unchecked")
267    public boolean isLeftReductionNF(List<GenSolvablePolynomial<C>> row, List<GenSolvablePolynomial<C>> Pp,
268                    GenSolvablePolynomial<C> Ap, GenSolvablePolynomial<C> Np) {
269        if (row == null && Pp == null) {
270            if (Ap == null) {
271                return Np == null;
272            }
273            return Ap.equals(Np);
274        }
275        if (row == null || Pp == null) {
276            return false;
277        }
278        if (row.size() != Pp.size()) {
279            return false;
280        }
281        GenSolvablePolynomial<C> t = Np;
282        GenSolvablePolynomial<C> r;
283        GenSolvablePolynomial<C> p;
284        for (int m = 0; m < Pp.size(); m++) {
285            r = row.get(m);
286            p = Pp.get(m);
287            if (r != null && p != null) {
288                if (t == null) {
289                    t = r.multiply(p);
290                } else {
291                    t = (GenSolvablePolynomial<C>) t.sum(r.multiply(p));
292                }
293            }
294            //System.out.println("r = " + r );
295            //System.out.println("p = " + p );
296        }
297        if (debug) {
298            logger.info("t = {}", t);
299            logger.info("a = {}", Ap);
300        }
301        if (t == null) {
302            if (Ap == null) {
303                return true;
304            }
305            return Ap.isZERO();
306        }
307        t = (GenSolvablePolynomial<C>) t.subtract(Ap);
308        return t.isZERO();
309    }
310
311
312    /**
313     * Right S-Polynomial.
314     * @param Ap solvable polynomial.
315     * @param Bp solvable polynomial.
316     * @return right-spol(Ap,Bp) the right S-polynomial of Ap and Bp.
317     */
318    @SuppressWarnings("unchecked")
319    public GenSolvablePolynomial<C> rightSPolynomial(GenSolvablePolynomial<C> Ap,
320                    GenSolvablePolynomial<C> Bp) {
321        if (logger.isInfoEnabled()) {
322            if (Bp == null || Bp.isZERO()) {
323                if (Ap != null) {
324                    return Ap.ring.getZERO();
325                }
326                return null;
327            }
328            if (Ap == null || Ap.isZERO()) {
329                return Bp.ring.getZERO();
330            }
331            if (!Ap.ring.equals(Bp.ring)) {
332                logger.error("rings not equal");
333            }
334        }
335        ExpVector e = Ap.leadingExpVector();
336        ExpVector f = Bp.leadingExpVector();
337
338        ExpVector g = e.lcm(f);
339        ExpVector e1 = g.subtract(e);
340        ExpVector f1 = g.subtract(f);
341
342        C a = Ap.leadingBaseCoefficient();
343        C b = Bp.leadingBaseCoefficient();
344
345        GenSolvablePolynomial<C> App = Ap.multiply(b,e1);
346        GenSolvablePolynomial<C> Bpp = Bp.multiply(a,f1);
347
348        // App = App.multiply(b);
349        // Bpp = Bpp.multiply(a);
350
351        if (!App.leadingMonomial().equals(Bpp.leadingMonomial()) ) {
352            logger.info("lm(A) = " + new Monomial(App.leadingMonomial()) + ", lm(B) = " + new Monomial(Bpp.leadingMonomial()));
353            logger.info("right S-polynomial with unequal leading monomials: " + Ap.ring.toScript());
354            //throw new UnsupportedOperationException("right S-polynomial with error");
355        }
356        GenSolvablePolynomial<C> Cp = (GenSolvablePolynomial<C>) App.subtract(Bpp);
357        return Cp;
358    }
359
360
361    /**
362     * S-Polynomial with recording.
363     * @param S recording matrix, is modified.
364     * @param i index of Ap in basis list.
365     * @param Ap a polynomial.
366     * @param j index of Bp in basis list.
367     * @param Bp a polynomial.
368     * @return rightSpol(Ap, Bp), the right S-Polynomial for Ap and Bp.
369     */
370    public GenSolvablePolynomial<C> rightSPolynomial(List<GenSolvablePolynomial<C>> S, int i,
371                    GenSolvablePolynomial<C> Ap, int j, GenSolvablePolynomial<C> Bp) {
372        if (debug /*logger.isInfoEnabled()*/) {
373            if (Bp == null || Bp.isZERO()) {
374                throw new ArithmeticException("Spol B is zero");
375            }
376            if (Ap == null || Ap.isZERO()) {
377                throw new ArithmeticException("Spol A is zero");
378            }
379            if (!Ap.ring.equals(Bp.ring)) {
380                logger.error("rings not equal");
381            }
382        }
383        Map.Entry<ExpVector, C> ma = Ap.leadingMonomial();
384        Map.Entry<ExpVector, C> mb = Bp.leadingMonomial();
385
386        ExpVector e = ma.getKey();
387        ExpVector f = mb.getKey();
388
389        ExpVector g = e.lcm(f);
390        ExpVector e1 = g.subtract(e);
391        ExpVector f1 = g.subtract(f);
392
393        C a = ma.getValue();
394        C b = mb.getValue();
395
396        GenSolvablePolynomial<C> App = Ap.multiply(b, e1);
397        GenSolvablePolynomial<C> Bpp = Bp.multiply(a, f1);
398
399        if (!App.leadingMonomial().equals(Bpp.leadingMonomial()) ) {
400            System.out.println("lm(A) = " + App.leadingMonomial() + ", lm(B) = " + Bpp.leadingMonomial());
401            throw new UnsupportedOperationException("right S-polynomial undefined ");
402        }
403        GenSolvablePolynomial<C> Cp = (GenSolvablePolynomial<C>) App.subtract(Bpp);
404
405        GenSolvablePolynomial<C> zero = Ap.ring.getZERO();
406        GenSolvablePolynomial<C> As = (GenSolvablePolynomial<C>) zero.sum(b.negate(), e1);
407        GenSolvablePolynomial<C> Bs = (GenSolvablePolynomial<C>) zero.sum(a, f1);
408        S.set(i, As);
409        S.set(j, Bs);
410        return Cp;
411    }
412
413
414    /**
415     * Is top reducible. Is left right symmetric.
416     * @param A solvable polynomial.
417     * @param P solvable polynomial list.
418     * @return true if A is top reducible with respect to P.
419     */
420    public boolean isTopReducible(List<GenSolvablePolynomial<C>> P, GenSolvablePolynomial<C> A) {
421        if (P == null || P.isEmpty()) {
422            return false;
423        }
424        if (A == null || A.isZERO()) {
425            return false;
426        }
427        boolean mt = false;
428        ExpVector e = A.leadingExpVector();
429        for (GenSolvablePolynomial<C> p : P) {
430            mt = e.multipleOf(p.leadingExpVector());
431            if (mt) {
432                return true;
433            }
434        }
435        return false;
436    }
437
438
439    /**
440     * Is reducible. Is left right symmetric.
441     * @param Ap solvable polynomial.
442     * @param Pp solvable polynomial list.
443     * @return true if Ap is reducible with respect to Pp.
444     */
445    public boolean isReducible(List<GenSolvablePolynomial<C>> Pp, GenSolvablePolynomial<C> Ap) {
446        return !isNormalform(Pp, Ap);
447    }
448
449
450    /**
451     * Is in Normalform. Is left right symmetric.
452     * @param Ap polynomial.
453     * @param Pp polynomial list.
454     * @return true if Ap is in normalform with respect to Pp.
455     */
456    @SuppressWarnings("unchecked")
457    public boolean isNormalform(List<GenSolvablePolynomial<C>> Pp, GenSolvablePolynomial<C> Ap) {
458        if (Pp == null || Pp.isEmpty()) {
459            return true;
460        }
461        if (Ap == null || Ap.isZERO()) {
462            return true;
463        }
464        GenSolvablePolynomial<C>[] P = new GenSolvablePolynomial[0];
465        synchronized (Pp) {
466            P = Pp.toArray(P);
467        }
468        int l = P.length;
469        ExpVector[] htl = new ExpVector[l];
470        GenSolvablePolynomial<C>[] p = new GenSolvablePolynomial[l];
471        ExpVector f;
472        int i;
473        int j = 0;
474        for (i = 0; i < l; i++) {
475            p[i] = P[i];
476            f = p[i].leadingExpVector();
477            if (f != null) {
478                p[j] = p[i];
479                htl[j] = f;
480                j++;
481            }
482        }
483        l = j;
484        boolean mt = false;
485        for (ExpVector e : Ap.getMap().keySet()) {
486            for (i = 0; i < l; i++) {
487                mt = e.multipleOf(htl[i]);
488                if (mt) {
489                    return false;
490                }
491            }
492        }
493        return true;
494    }
495
496
497    /**
498     * Is right reduction of normal form.
499     * @param row recording matrix.
500     * @param Pp a solvable polynomial list for reduction.
501     * @param Ap a solvable polynomial.
502     * @param Np nf(Pp,Ap), a left normal form of Ap wrt. Pp.
503     * @return true, if Np + sum( Pp[i]*row[i] ) == Ap, else false.
504     */
505    @SuppressWarnings("unchecked")
506    public boolean isRightReductionNF(List<GenSolvablePolynomial<C>> row, List<GenSolvablePolynomial<C>> Pp,
507                    GenSolvablePolynomial<C> Ap, GenSolvablePolynomial<C> Np) {
508        if (row == null && Pp == null) {
509            if (Ap == null) {
510                return Np == null;
511            }
512            return Ap.equals(Np);
513        }
514        if (row == null || Pp == null) {
515            return false;
516        }
517        if (row.size() != Pp.size()) {
518            return false;
519        }
520        GenSolvablePolynomial<C> t = Np;
521        GenSolvablePolynomial<C> r;
522        GenSolvablePolynomial<C> p;
523        for (int m = 0; m < Pp.size(); m++) {
524            r = row.get(m);
525            p = Pp.get(m);
526            if (r != null && p != null) {
527                if (t == null) {
528                    t = p.multiply(r); //right
529                } else {
530                    t = (GenSolvablePolynomial<C>) t.sum(p.multiply(r)); //right
531                }
532            }
533            //System.out.println("r = " + r );
534            //System.out.println("p = " + p );
535        }
536        if (debug) {
537            logger.info("t = {}", t);
538            logger.info("a = {}", Ap);
539        }
540        if (t == null) {
541            if (Ap == null) {
542                return true;
543            }
544            return Ap.isZERO();
545        }
546        t = (GenSolvablePolynomial<C>) t.subtract(Ap);
547        return t.isZERO();
548    }
549
550
551    /**
552     * Two-sided Normalform.
553     * @param Ap solvable polynomial.
554     * @param Pp solvable polynomial list.
555     * @return two-sided-nf(Ap) with respect to Pp.
556     */
557    public GenSolvablePolynomial<C> normalform(List<GenSolvablePolynomial<C>> Pp,
558                    GenSolvablePolynomial<C> Ap) {
559        throw new UnsupportedOperationException("two-sided normalform not implemented");
560    }
561
562}