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