001/*
002 * $Id: SolvableGroebnerBasePseudoRecSeq.java 5841 2018-05-20 21:26:13Z kredel $
003 */
004
005package edu.jas.gbufd;
006
007
008import java.util.ArrayList;
009import java.util.Collections;
010import java.util.List;
011
012import org.apache.log4j.Logger;
013
014import edu.jas.gb.OrderedPairlist;
015import edu.jas.gb.Pair;
016import edu.jas.gb.PairList;
017import edu.jas.gb.SolvableExtendedGB;
018import edu.jas.gb.SolvableGroebnerBaseAbstract;
019import edu.jas.poly.GenPolynomial;
020import edu.jas.poly.GenPolynomialRing;
021import edu.jas.poly.GenSolvablePolynomial;
022import edu.jas.poly.GenSolvablePolynomialRing;
023import edu.jas.poly.QLRSolvablePolynomialRing;
024import edu.jas.poly.PolyUtil;
025import edu.jas.poly.PolynomialList;
026import edu.jas.structure.GcdRingElem;
027import edu.jas.structure.RingFactory;
028import edu.jas.ufd.GCDFactory;
029import edu.jas.ufd.GreatestCommonDivisorAbstract;
030import edu.jas.ufd.GreatestCommonDivisorFake;
031
032
033/**
034 * Solvable Groebner Base with pseudo reduction sequential algorithm. Implements
035 * coefficient fraction free Groebner bases. Coefficients can for example be
036 * (commutative) multivariate polynomials.
037 * @param <C> coefficient type
038 * @author Heinz Kredel
039 * 
040 * @see edu.jas.application.GBAlgorithmBuilder
041 * @see edu.jas.gbufd.GBFactory
042 */
043
044public class SolvableGroebnerBasePseudoRecSeq<C extends GcdRingElem<C>> extends
045                SolvableGroebnerBaseAbstract<GenPolynomial<C>> {
046
047
048    private static final Logger logger = Logger.getLogger(SolvableGroebnerBasePseudoRecSeq.class);
049
050
051    private static final boolean debug = logger.isDebugEnabled();
052
053
054    /**
055     * Greatest common divisor engine for coefficient content and primitive
056     * parts.
057     */
058    protected final GreatestCommonDivisorAbstract<C> engine;
059
060
061    /**
062     * Pseudo reduction engine.
063     */
064    protected final SolvablePseudoReduction<C> sredRec;
065
066
067    /**
068     * Pseudo reduction engine.
069     */
070    protected final SolvablePseudoReduction<GenPolynomial<C>> sred;
071
072
073    /**
074     * Coefficient ring factory.
075     */
076    //protected final RingFactory<C> cofac;
077    protected final GenPolynomialRing<C> cofac;
078
079
080    /**
081     * Constructor.
082     * @param rf coefficient ring factory.
083     */
084    public SolvableGroebnerBasePseudoRecSeq(RingFactory<GenPolynomial<C>> rf) {
085        this(rf, new SolvablePseudoReductionSeq<C>());
086    }
087
088
089    /**
090     * Constructor.
091     * @param rf coefficient ring factory.
092     * @param pl pair selection strategy
093     */
094    public SolvableGroebnerBasePseudoRecSeq(RingFactory<GenPolynomial<C>> rf, PairList<GenPolynomial<C>> pl) {
095        this(rf, new SolvablePseudoReductionSeq<C>(), pl);
096    }
097
098
099    /**
100     * Constructor.
101     * @param rf coefficient ring factory.
102     * @param red pseudo reduction engine. <b>Note:</b> red must be an instance
103     *            of PseudoReductionSeq.
104     */
105    public SolvableGroebnerBasePseudoRecSeq(RingFactory<GenPolynomial<C>> rf, SolvablePseudoReduction<C> red) {
106        this(rf, red, new OrderedPairlist<GenPolynomial<C>>());
107    }
108
109
110    /**
111     * Constructor.
112     * @param rf coefficient ring factory.
113     * @param red pseudo reduction engine. <b>Note:</b> red must be an instance
114     *            of PseudoReductionSeq.
115     * @param pl pair selection strategy
116     */
117    @SuppressWarnings({ "cast", "unchecked" })
118    public SolvableGroebnerBasePseudoRecSeq(RingFactory<GenPolynomial<C>> rf, SolvablePseudoReduction<C> red,
119                    PairList<GenPolynomial<C>> pl) {
120        super((SolvablePseudoReduction<GenPolynomial<C>>) (SolvablePseudoReduction) red, pl);
121        this.sred = (SolvablePseudoReduction<GenPolynomial<C>>) (SolvablePseudoReduction) red;
122        sredRec = red;
123        //this.red = sred;
124        cofac = (GenPolynomialRing<C>) rf;
125        if (!cofac.isCommutative()) {
126            logger.warn("right reduction not correct for " + cofac.toScript());
127            engine = new GreatestCommonDivisorFake<C>();
128            // TODO check that also coeffTable is empty for recursive solvable poly ring
129        } else {
130            //engine = GCDFactory.<C> getImplementation(cofac.coFac);
131            engine = GCDFactory.<C> getProxy(cofac.coFac);
132        }
133    }
134
135
136    /**
137     * Left Groebner base using pairlist class.
138     * @param modv module variable number.
139     * @param F polynomial list.
140     * @return GB(F) a Groebner base of F.
141     */
142    @Override
143    public List<GenSolvablePolynomial<GenPolynomial<C>>> leftGB(int modv,
144                    List<GenSolvablePolynomial<GenPolynomial<C>>> F) {
145        List<GenSolvablePolynomial<GenPolynomial<C>>> G = normalizeZerosOnes(F);
146        G = PolynomialList.<GenPolynomial<C>> castToSolvableList(PolyUtil.<C> monicRec(engine
147                        .recursivePrimitivePart(PolynomialList.<GenPolynomial<C>> castToList(G))));
148        if (G.size() <= 1) {
149            return G;
150        }
151        GenSolvablePolynomialRing<GenPolynomial<C>> ring = G.get(0).ring;
152        if (ring.coFac.isField()) { // remove ? 
153            throw new IllegalArgumentException("coefficients from a field");
154        }
155        PairList<GenPolynomial<C>> pairlist = strategy.create(modv, ring);
156        pairlist.put(PolynomialList.<GenPolynomial<C>> castToList(G));
157        logger.info("leftGB start " + pairlist);
158
159        Pair<GenPolynomial<C>> pair;
160        GenSolvablePolynomial<GenPolynomial<C>> pi, pj, S, H;
161        while (pairlist.hasNext()) {
162            pair = pairlist.removeNext();
163            if (pair == null)
164                continue;
165
166            pi = (GenSolvablePolynomial<GenPolynomial<C>>) pair.pi;
167            pj = (GenSolvablePolynomial<GenPolynomial<C>>) pair.pj;
168            if (debug) {
169                logger.debug("pi    = " + pi);
170                logger.debug("pj    = " + pj);
171            }
172
173            S = sred.leftSPolynomial(pi, pj);
174            if (S.isZERO()) {
175                pair.setZero();
176                continue;
177            }
178            if (debug) {
179                logger.info("ht(S) = " + S.leadingExpVector());
180            }
181
182            H = sredRec.leftNormalformRecursive(G, S);
183            if (H.isZERO()) {
184                pair.setZero();
185                continue;
186            }
187            if (debug) {
188                logger.info("ht(H) = " + H.leadingExpVector() + ", #(H) = " + H.length());
189            }
190            H = (GenSolvablePolynomial<GenPolynomial<C>>) engine.recursivePrimitivePart(H);
191            H = PolyUtil.<C> monic(H);
192            if (H.isConstant()) {
193                G.clear();
194                G.add(H);
195                return G; // since no threads are activated
196            }
197            if (debug) {
198                logger.info("lc(pp(H)) = " + H.leadingBaseCoefficient().toScript());
199            }
200            if (H.length() > 0) {
201                G.add(H);
202                pairlist.put(H);
203            }
204        }
205        logger.debug("#sequential list = " + G.size());
206        G = leftMinimalGB(G);
207        logger.info("leftGB end  " + pairlist);
208        return G;
209    }
210
211
212    /**
213     * Minimal ordered Solvable Groebner basis.
214     * @param Gp a Solvable Groebner base.
215     * @return a reduced Solvable Groebner base of Gp.
216     */
217    @Override
218    public List<GenSolvablePolynomial<GenPolynomial<C>>> leftMinimalGB(
219                    List<GenSolvablePolynomial<GenPolynomial<C>>> Gp) {
220        List<GenSolvablePolynomial<GenPolynomial<C>>> G = normalizeZerosOnes(Gp);
221        if (G.size() <= 1) {
222            return G;
223        }
224        // remove top reducible polynomials
225        GenSolvablePolynomial<GenPolynomial<C>> a;
226        List<GenSolvablePolynomial<GenPolynomial<C>>> F = new ArrayList<GenSolvablePolynomial<GenPolynomial<C>>>(
227                        G.size());
228        while (G.size() > 0) {
229            a = G.remove(0);
230            if (sred.isTopReducible(G, a) || sred.isTopReducible(F, a)) {
231                // drop polynomial 
232                if (debug) {
233                    System.out.println("dropped " + a);
234                    List<GenSolvablePolynomial<GenPolynomial<C>>> ff;
235                    ff = new ArrayList<GenSolvablePolynomial<GenPolynomial<C>>>(G);
236                    ff.addAll(F);
237                    a = sredRec.leftNormalformRecursive(ff, a);
238                    if (!a.isZERO()) {
239                        System.out.println("error, nf(a) " + a);
240                    }
241                }
242            } else {
243                F.add(a);
244            }
245        }
246        G = F;
247        if (G.size() <= 1) {
248            return G;
249        }
250        Collections.reverse(G); // important for lex GB
251        // reduce remaining polynomials
252        int len = G.size();
253        int i = 0;
254        while (i < len) {
255            a = G.remove(0);
256            //System.out.println("doing " + a.length());
257            a = sredRec.leftNormalformRecursive(G, a);
258            a = (GenSolvablePolynomial<GenPolynomial<C>>) engine.recursivePrimitivePart(a); //a.monic(); not possible
259            a = PolyUtil.<C> monic(a);
260            G.add(a); // adds as last
261            i++;
262        }
263        return G;
264    }
265
266
267    /**
268     * Twosided Solvable Groebner base using pairlist class.
269     * @param modv number of module variables.
270     * @param Fp solvable polynomial list.
271     * @return tsGB(Fp) a twosided Groebner base of Fp.
272     */
273    @Override
274    public List<GenSolvablePolynomial<GenPolynomial<C>>> twosidedGB(int modv,
275                    List<GenSolvablePolynomial<GenPolynomial<C>>> Fp) {
276        List<GenSolvablePolynomial<GenPolynomial<C>>> G = normalizeZerosOnes(Fp);
277        G = PolynomialList.<GenPolynomial<C>> castToSolvableList(PolyUtil.<C> monicRec(engine
278                        .recursivePrimitivePart(PolynomialList.<GenPolynomial<C>> castToList(G))));
279        if (G.size() < 1) { // two-sided!
280            return G;
281        }
282        //System.out.println("G = " + G);
283        GenSolvablePolynomialRing<GenPolynomial<C>> ring = G.get(0).ring; // assert != null
284        if (ring.coFac.isField()) { // remove ?
285            throw new IllegalArgumentException("coefficients from a field");
286        }
287        // add also coefficient generators
288        List<GenSolvablePolynomial<GenPolynomial<C>>> X;
289        X = PolynomialList.castToSolvableList(ring.generators(modv)); 
290        logger.info("right multipliers = " + X);
291        List<GenSolvablePolynomial<GenPolynomial<C>>> F = new ArrayList<GenSolvablePolynomial<GenPolynomial<C>>>(
292                        G.size() * (1 + X.size()));
293        F.addAll(G);
294        GenSolvablePolynomial<GenPolynomial<C>> p, x, q;
295        for (int i = 0; i < F.size(); i++) { // F changes
296            p = F.get(i);
297            for (int j = 0; j < X.size(); j++) {
298                x = X.get(j);
299                if (x.isONE()) {
300                    continue;
301                }
302                q = p.multiply(x);
303                q = sredRec.leftNormalformRecursive(F, q);
304                if (!q.isZERO()) {
305                    q = (GenSolvablePolynomial<GenPolynomial<C>>) engine.recursivePrimitivePart(q);
306                    q = PolyUtil.<C> monic(q);
307                    F.add(q);
308                }
309            }
310        }
311        G = F;
312        //System.out.println("G generated = " + G);
313        PairList<GenPolynomial<C>> pairlist = strategy.create(modv, ring);
314        pairlist.put(PolynomialList.<GenPolynomial<C>> castToList(G));
315        logger.info("twosidedGB start " + pairlist);
316
317        Pair<GenPolynomial<C>> pair;
318        GenSolvablePolynomial<GenPolynomial<C>> pi, pj, S, H;
319        while (pairlist.hasNext()) {
320            pair = pairlist.removeNext();
321            if (pair == null) {
322                continue;
323            }
324
325            pi = (GenSolvablePolynomial<GenPolynomial<C>>) pair.pi;
326            pj = (GenSolvablePolynomial<GenPolynomial<C>>) pair.pj;
327            if (debug) {
328                logger.debug("pi    = " + pi);
329                logger.debug("pj    = " + pj);
330            }
331
332            S = sred.leftSPolynomial(pi, pj);
333            if (S.isZERO()) {
334                pair.setZero();
335                continue;
336            }
337            if (debug) {
338                logger.info("ht(S) = " + S.leadingExpVector());
339            }
340
341            H = sredRec.leftNormalformRecursive(G, S);
342            if (H.isZERO()) {
343                pair.setZero();
344                continue;
345            }
346            if (debug) {
347                logger.info("ht(H) = " + H.leadingExpVector());
348            }
349
350            H = (GenSolvablePolynomial<GenPolynomial<C>>) engine.recursivePrimitivePart(H);
351            H = PolyUtil.<C> monic(H);
352            if (H.isONE()) {
353                G.clear();
354                G.add(H);
355                return G; // since no threads are activated
356            }
357            if (debug) {
358                logger.info("lc(pp(H)) = " + H.leadingBaseCoefficient());
359            }
360            if (H.length() > 0) {
361                G.add(H);
362                pairlist.put(H);
363                for (int j = 0; j < X.size(); j++) {
364                    x = X.get(j);
365                    if (x.isONE()) {
366                        continue;
367                    }
368                    p = H.multiply(x);
369                    p = sredRec.leftNormalformRecursive(G, p);
370                    if (!p.isZERO()) {
371                        p = (GenSolvablePolynomial<GenPolynomial<C>>) engine.recursivePrimitivePart(p);
372                        p = PolyUtil.<C> monic(p);
373                        if (p.isONE()) {
374                            G.clear();
375                            G.add(p);
376                            return G; // since no threads are activated
377                        }
378                        G.add(p);
379                        pairlist.put(p);
380                    }
381                }
382            }
383        }
384        logger.debug("#sequential list = " + G.size());
385        G = leftMinimalGB(G);
386        logger.info("twosidedGB end  " + pairlist);
387        return G;
388    }
389
390
391    /**
392     * Left Groebner base test.
393     * @param modv number of module variables.
394     * @param F solvable polynomial list.
395     * @return true, if F is a left Groebner base, else false.
396     */
397    @Override
398    public boolean isLeftGBsimple(int modv, List<GenSolvablePolynomial<GenPolynomial<C>>> F) {
399        //System.out.println("F to left check = " + F);
400        GenSolvablePolynomial<GenPolynomial<C>> pi, pj, s, h;
401        for (int i = 0; i < F.size(); i++) {
402            pi = F.get(i);
403            for (int j = i + 1; j < F.size(); j++) {
404                pj = F.get(j);
405                if (!red.moduleCriterion(modv, pi, pj)) {
406                    continue;
407                }
408                // if ( ! red.criterion4( pi, pj ) ) { continue; }
409                s = sred.leftSPolynomial(pi, pj);
410                if (s.isZERO()) {
411                    continue;
412                }
413                h = sredRec.leftNormalformRecursive(F, s);
414                if (!h.isZERO()) {
415                    return false;
416                }
417            }
418        }
419        return true;
420    }
421
422
423    /**
424     * Left Groebner base idempotence test.
425     * @param modv module variable number.
426     * @param F solvable polynomial list.
427     * @return true, if F is equal to GB(F), else false.
428     */
429    @Override
430    public boolean isLeftGBidem(int modv, List<GenSolvablePolynomial<GenPolynomial<C>>> F) {
431        if (F == null || F.isEmpty()) {
432            return true;
433        }
434        GenSolvablePolynomialRing<GenPolynomial<C>> pring = F.get(0).ring;
435        List<GenSolvablePolynomial<GenPolynomial<C>>> G = leftGB(modv, F);
436        PolynomialList<GenPolynomial<C>> Fp = new PolynomialList<GenPolynomial<C>>(pring, F);
437        PolynomialList<GenPolynomial<C>> Gp = new PolynomialList<GenPolynomial<C>>(pring, G);
438        return Fp.compareTo(Gp) == 0;
439    }
440
441
442    /**
443     * Twosided Groebner base test.
444     * @param modv number of module variables.
445     * @param Fp solvable polynomial list.
446     * @return true, if Fp is a two-sided Groebner base, else false.
447     */
448    @Override
449    public boolean isTwosidedGB(int modv, List<GenSolvablePolynomial<GenPolynomial<C>>> Fp) {
450        //System.out.println("F to twosided check = " + Fp);
451        if (Fp == null || Fp.size() == 0) { // 0 not 1
452            return true;
453        }
454        GenSolvablePolynomialRing<GenPolynomial<C>> ring = Fp.get(0).ring; // assert != null
455        //List<GenSolvablePolynomial<C>> X = generateUnivar( modv, Fp );
456        List<GenSolvablePolynomial<GenPolynomial<C>>> X, Y;
457        X = PolynomialList.castToSolvableList(ring.generators()); // todo use modv?
458        Y = new ArrayList<GenSolvablePolynomial<GenPolynomial<C>>>();
459        for (GenSolvablePolynomial<GenPolynomial<C>> x : X) {
460             if (x.isConstant()) {
461                 Y.add(x);
462             }
463        }
464        X = Y;
465        X.addAll(ring.univariateList(modv));
466        logger.info("right multipliers = " + X);
467        List<GenSolvablePolynomial<GenPolynomial<C>>> F = new ArrayList<GenSolvablePolynomial<GenPolynomial<C>>>(
468                        Fp.size() * (1 + X.size()));
469        F.addAll(Fp);
470        GenSolvablePolynomial<GenPolynomial<C>> p, x, pi, pj, s, h;
471        for (int i = 0; i < Fp.size(); i++) {
472            p = Fp.get(i);
473            for (int j = 0; j < X.size(); j++) {
474                x = X.get(j);
475                if (x.isONE()) {
476                    continue;
477                }
478                p = p.multiply(x);
479                p = sredRec.leftNormalformRecursive(F, p);
480                if (!p.isZERO()) {
481                    return false;
482                    //F.add(p);
483                }
484            }
485        }
486        //System.out.println("F to check = " + F);
487        for (int i = 0; i < F.size(); i++) {
488            pi = F.get(i);
489            for (int j = i + 1; j < F.size(); j++) {
490                pj = F.get(j);
491                if (!red.moduleCriterion(modv, pi, pj)) {
492                    continue;
493                }
494                // if ( ! red.criterion4( pi, pj ) ) { continue; }
495                s = sred.leftSPolynomial(pi, pj);
496                if (s.isZERO()) {
497                    continue;
498                }
499                h = sredRec.leftNormalformRecursive(F, s);
500                if (!h.isZERO()) {
501                    logger.info("is not TwosidedGB: " + h);
502                    return false;
503                }
504            }
505        }
506        return true;
507    }
508
509
510    /**
511     * Solvable Extended Groebner base using critical pair class.
512     * @param modv module variable number.
513     * @param F solvable polynomial list.
514     * @return a container for an extended left Groebner base of F. <b>Note:
515     *         </b> not implemented;
516     */
517    //@SuppressWarnings("unchecked")
518    @Override
519    public SolvableExtendedGB<GenPolynomial<C>> extLeftGB(int modv,
520                    List<GenSolvablePolynomial<GenPolynomial<C>>> F) {
521        throw new UnsupportedOperationException(); // TODO
522    }
523
524}