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