001/*
002 * $Id: GBAlgorithmBuilder.java 5773 2017-11-05 15:10:09Z kredel $
003 */
004
005package edu.jas.application;
006
007
008import java.io.Serializable;
009
010import org.apache.log4j.Logger;
011
012import edu.jas.arith.BigInteger;
013import edu.jas.arith.BigRational;
014import edu.jas.gb.GBOptimized;
015import edu.jas.gb.GBProxy;
016import edu.jas.gb.GroebnerBaseAbstract;
017import edu.jas.gb.GroebnerBaseParallel;
018import edu.jas.gb.GroebnerBaseSeqIter;
019import edu.jas.gb.GroebnerBaseF5zSigSeqIter;
020import edu.jas.gb.GroebnerBaseGGVSigSeqIter;
021import edu.jas.gb.GroebnerBaseArriSigSeqIter;
022import edu.jas.gb.GroebnerBaseParIter;
023import edu.jas.gb.OrderedMinPairlist;
024import edu.jas.gb.OrderedPairlist;
025import edu.jas.gb.OrderedSyzPairlist;
026import edu.jas.gb.PairList;
027import edu.jas.gbufd.GBFactory;
028import edu.jas.gbufd.GroebnerBaseFGLM;
029import edu.jas.gbufd.GroebnerBaseWalk;
030import edu.jas.gbufd.GroebnerBasePseudoParallel;
031import edu.jas.gbufd.GroebnerBaseQuotient;
032import edu.jas.gbufd.GroebnerBaseRational;
033import edu.jas.kern.ComputerThreads;
034import edu.jas.poly.GenPolynomial;
035import edu.jas.poly.GenPolynomialRing;
036import edu.jas.structure.GcdRingElem;
037import edu.jas.structure.RingFactory;
038import edu.jas.ufd.Quotient;
039import edu.jas.ufd.QuotientRing;
040
041
042/**
043 * Builder for commutative Gröbner bases algorithm implementations.
044 * @author Heinz Kredel
045 * @usage To create objects that implement the <code>GroebnerBase</code>
046 *        interface one can use the <code>GBFactory</code> or this
047 *        <code>GBAlgorithmBuilder</code>. This class will select and compose an
048 *        appropriate implementation based on the types of polynomial
049 *        coefficients C and the desired properties. To build an implementation
050 *        start with the static method <code>polynomialRing()</code> to define
051 *        the polynomial ring. Then continue to construct the algorithm with the
052 *        methods
053 *        <ul>
054 *        <li><code>optimize()</code> or <code>optimize(boolean)</code> for term
055 *        order (variable order) optimization (true for return of permuted
056 *        polynomials),</li>
057 *        <li><code>normalPairlist()</code> (default),
058 *        <code>syzygyPairlist()</code> or <code>simplePairlist()</code> for
059 *        pair-list selection strategies,</li>
060 *        <li><code>fractionFree()</code> for clearing denominators and
061 *        computing with pseudo reduction,</li>
062 *        <li><code>graded()</code> for using the FGLM algorithm to first
063 *        compute a Gr&ouml;bner base with respect to a graded term order and
064 *        then constructing a Gr&ouml;bner base wrt. a lexicographical term
065 *        order,</li>
066 *        <li><code>walk()</code> for using the Gr&ouml;bner walk algorithm to first
067 *        compute a Gr&ouml;bner base with respect to a graded term order and
068 *        then constructing a Gr&ouml;bner base wrt. a lexicographical term
069 *        order,</li>
070 *        <li><code>iterated()</code> for using the iterative GB algorithm to 
071 *        compute a Gr&ouml;bner base adding one polynomial after another,</li>
072 *        <li><code>F5()</code>, <code>GGV()</code> and <code>Arri()</code> for using 
073 *        the respective iterative signature based GB algorithm (over field coefficients) to 
074 *        compute a Gr&ouml;bner base adding one polynomial after another,</li>
075 *        <li><code>parallel()</code> additionaly compute a Gr&ouml;bner base
076 *        over a field or integral domain in parallel,</li>
077 *        <li><code>euclideanDomain()</code> for computing a e-Gr&ouml;bner
078 *        base,</li>
079 *        <li><code>domainAlgorithm(Algo)</code> for computing a d- or
080 *        e-Gr&ouml;bner base,</li>
081 *        </ul>
082 *        Finally call the method <code>build()</code> to obtain an
083 *        implementaton of class <code>GroebnerBaseAbstract</code>. For example
084 * 
085 *        <pre>
086 * 
087 * GenPolynomialRing&lt;C&gt; pf = new GenPolynomialRing&lt;C&gt;(cofac, vars);
088 * GroebnerBaseAbstract&lt;C&gt; engine;
089 * engine = GBAlgorithmBuilder.&lt;C&gt; polynomialRing(pf).fractionFree().parallel().optimize().build();
090 * c = engine.GB(A);
091 * </pre>
092 * 
093 *        For example, if the coefficient type is BigRational, the usage looks
094 *        like
095 * 
096 *        <pre>
097 * 
098 * GenPolynomialRing&lt;BigRational&gt; pf = new GenPolynomialRing&lt;BigRational&gt;(cofac, vars);
099 * GroebnerBaseAbstract&lt;BigRational&gt; engine;
100 * engine = GBAlgorithmBuilder.&lt;BigRational&gt; polynomialRing(pf).fractionFree().parallel().optimize().build();
101 * c = engine.GB(A);
102 * </pre>
103 * 
104 *        <b>Note:</b> Not all combinations are meanigful
105 * 
106 * @see edu.jas.gb.GroebnerBase
107 * @see edu.jas.gbufd.GBFactory
108 */
109
110public class GBAlgorithmBuilder<C extends GcdRingElem<C>> implements Serializable {
111
112
113    private static final Logger logger = Logger.getLogger(GBAlgorithmBuilder.class);
114
115
116    /**
117     * The current GB algorithm implementation.
118     */
119    private GroebnerBaseAbstract<C> algo;
120
121
122    /**
123     * The current polynomial ring.
124     */
125    public final GenPolynomialRing<C> ring;
126
127
128    /**
129     * Requested pairlist strategy.
130     */
131    public final PairList<C> strategy;
132
133
134    /**
135     * Constructor not for use.
136     */
137    protected GBAlgorithmBuilder() {
138        throw new IllegalArgumentException("do not use this constructor");
139    }
140
141
142    /**
143     * Constructor.
144     * @param ring the polynomial ring.
145     */
146    public GBAlgorithmBuilder(GenPolynomialRing<C> ring) {
147        this(ring, null);
148    }
149
150
151    /**
152     * Constructor.
153     * @param ring the polynomial ring.
154     * @param algo already determined algorithm.
155     */
156    public GBAlgorithmBuilder(GenPolynomialRing<C> ring, GroebnerBaseAbstract<C> algo) {
157        this(ring, algo, null);
158    }
159
160
161    /**
162     * Constructor.
163     * @param ring the polynomial ring.
164     * @param algo already determined algorithm.
165     * @param strategy pairlist strategy.
166     */
167    public GBAlgorithmBuilder(GenPolynomialRing<C> ring, GroebnerBaseAbstract<C> algo, PairList<C> strategy) {
168        if (ring == null) {
169            throw new IllegalArgumentException("ring may not be null");
170        }
171        this.ring = ring;
172        if (strategy == null) {
173            strategy = new OrderedPairlist<C>();
174        } else {
175            if (algo == null) { // or overwrite?
176                algo = GBFactory.<C> getImplementation(ring.coFac, strategy);
177            }
178        }
179        this.algo = algo; // null accepted
180        this.strategy = strategy;
181    }
182
183
184    /**
185     * Build the GB algorithm implementaton.
186     * @return GB algorithm implementaton as GroebnerBaseAbstract object.
187     */
188    public GroebnerBaseAbstract<C> build() {
189        if (algo == null) {
190            if (strategy == null) { // should not happen
191                algo = GBFactory.<C> getImplementation(ring.coFac);
192            } else {
193                algo = GBFactory.<C> getImplementation(ring.coFac, strategy);
194            }
195        }
196        return algo;
197    }
198
199
200    /**
201     * Define polynomial ring.
202     * @param fac the commutative polynomial ring.
203     * @return GBAlgorithmBuilder object.
204     */
205    public static <C extends GcdRingElem<C>> GBAlgorithmBuilder<C> polynomialRing(GenPolynomialRing<C> fac) {
206        return new GBAlgorithmBuilder<C>(fac);
207    }
208
209
210    /**
211     * Select syzygy critical pair-list strategy. Gebauer and M&ouml;ller
212     * algorithm.
213     * @return GBAlgorithmBuilder object.
214     */
215    public GBAlgorithmBuilder<C> syzygyPairlist() {
216        return new GBAlgorithmBuilder<C>(ring, algo, new OrderedSyzPairlist<C>());
217    }
218
219
220    /**
221     * Select normal critical pair-list strategy. Buchberger, Winkler and Kredel
222     * algorithm.
223     * @return GBAlgorithmBuilder object.
224     */
225    public GBAlgorithmBuilder<C> normalPairlist() {
226        return new GBAlgorithmBuilder<C>(ring, algo, new OrderedPairlist<C>());
227    }
228
229
230    /**
231     * Select simple critical pair-list strategy. Original Buchberger algorithm.
232     * @return GBAlgorithmBuilder object.
233     */
234    public GBAlgorithmBuilder<C> simplePairlist() {
235        return new GBAlgorithmBuilder<C>(ring, algo, new OrderedMinPairlist<C>());
236    }
237
238
239    /**
240     * Request term order optimization. Call optimize(true) for return of
241     * permuted polynomials.
242     * @return GBAlgorithmBuilder object.
243     */
244    public GBAlgorithmBuilder<C> optimize() {
245        return optimize(true);
246    }
247
248
249    /**
250     * Request term order optimization.
251     * @param rP true for return of permuted polynomials, false for inverse
252     *            permuted polynomials and new GB computation.
253     * @return GBAlgorithmBuilder object.
254     */
255    public GBAlgorithmBuilder<C> optimize(boolean rP) {
256        if (algo == null) {
257            algo = GBFactory.<C> getImplementation(ring.coFac, strategy);
258        }
259        GroebnerBaseAbstract<C> bb = new GBOptimized<C>(algo, rP);
260        return new GBAlgorithmBuilder<C>(ring, bb, strategy);
261    }
262
263
264    /**
265     * Request fraction free algorithm. For BigRational and Quotient
266     * coefficients denominators are cleared and pseudo reduction is used.
267     * @return GBAlgorithmBuilder object.
268     */
269    @SuppressWarnings({"cast", "unchecked"})
270    public GBAlgorithmBuilder<C> fractionFree() {
271        if (algo != null) {
272            logger.warn("selected algorithm ignored: " + algo + ", use fractionFree before");
273        }
274        if (((Object) ring.coFac) instanceof BigRational) {
275            BigRational cf = (BigRational) (Object) ring.coFac;
276            PairList<BigRational> sty = (PairList) strategy;
277            GroebnerBaseAbstract<BigRational> bb = GBFactory.getImplementation(cf, GBFactory.Algo.ffgb, sty);
278            GroebnerBaseAbstract<C> cbb = (GroebnerBaseAbstract<C>) (GroebnerBaseAbstract) bb;
279            return new GBAlgorithmBuilder<C>(ring, cbb, strategy);
280        }
281        if (((Object) ring.coFac) instanceof QuotientRing) {
282            QuotientRing<C> cf = (QuotientRing<C>) (Object) ring.coFac;
283            PairList<Quotient<C>> sty = (PairList) strategy;
284            GroebnerBaseAbstract<Quotient<C>> bb = GBFactory.<C> getImplementation(cf, GBFactory.Algo.ffgb,
285                            sty);
286            GroebnerBaseAbstract<C> cbb = (GroebnerBaseAbstract<C>) (GroebnerBaseAbstract) bb;
287            return new GBAlgorithmBuilder<C>(ring, cbb, strategy);
288        }
289        logger.warn("no fraction free algorithm implemented for " + ring);
290        return this;
291    }
292
293
294    /**
295     * Request e-GB algorithm.
296     * @return GBAlgorithmBuilder object.
297     */
298    public GBAlgorithmBuilder<C> euclideanDomain() {
299        return domainAlgorithm(GBFactory.Algo.egb);
300    }
301
302
303    /**
304     * Request d-, e- or i-GB algorithm.
305     * @param a algorithm from GBFactory.Algo.
306     * @return GBAlgorithmBuilder object.
307     */
308    @SuppressWarnings({"cast", "unchecked"})
309    public GBAlgorithmBuilder<C> domainAlgorithm(GBFactory.Algo a) {
310        if (strategy != null) {
311            logger.warn("strategy " + strategy + " ignored for algorithm " + a);
312        }
313        if (((Object) ring.coFac) instanceof BigInteger) {
314            BigInteger cf = (BigInteger) (Object) ring.coFac;
315            GroebnerBaseAbstract<BigInteger> bb = GBFactory.getImplementation(cf, a);
316            GroebnerBaseAbstract<C> cbb = (GroebnerBaseAbstract<C>) (GroebnerBaseAbstract) bb;
317            return new GBAlgorithmBuilder<C>(ring, cbb);
318        }
319        if (((Object) ring.coFac) instanceof GenPolynomial) {
320            GenPolynomialRing<C> cf = (GenPolynomialRing) (Object) ring.coFac;
321            GroebnerBaseAbstract<GenPolynomial<C>> bb = GBFactory.<C> getImplementation(cf, a);
322            GroebnerBaseAbstract<C> cbb = (GroebnerBaseAbstract<C>) (GroebnerBaseAbstract) bb;
323            return new GBAlgorithmBuilder<C>(ring, cbb);
324        }
325        logger.warn("no domain algorithm implemented for " + ring);
326        return this;
327    }
328
329
330    /**
331     * Request parallel algorithm. Additionaly run a parallel algorithm via
332     * GBProxy.
333     * @return GBAlgorithmBuilder object.
334     */
335    @SuppressWarnings("unchecked")
336    public GBAlgorithmBuilder<C> parallel() {
337        return parallel(ComputerThreads.N_CPUS);
338    }
339
340
341    /**
342     * Request parallel algorithm. Additionaly run a parallel algorithm via
343     * GBProxy.
344     * @param threads number of threads requested.
345     * @return GBAlgorithmBuilder object.
346     */
347    @SuppressWarnings({"cast", "unchecked"})
348    public GBAlgorithmBuilder<C> parallel(int threads) {
349        if (ComputerThreads.NO_THREADS) {
350            logger.warn("parallel algorithms disabled");
351            return this;
352        }
353        if (algo == null) {
354            algo = GBFactory.<C> getImplementation(ring.coFac, strategy);
355        }
356        if (algo instanceof GroebnerBaseSeqIter) { // iterative requested
357            GroebnerBaseAbstract<C> bb;
358            bb = (GroebnerBaseAbstract) new GroebnerBaseParIter<C>(threads, strategy);
359            GroebnerBaseAbstract<C> pbb = new GBProxy<C>(algo, bb);
360            return new GBAlgorithmBuilder<C>(ring, pbb, strategy);
361        } else if (((RingFactory) ring.coFac) instanceof BigRational) {
362            GroebnerBaseAbstract<C> bb;
363            if (algo instanceof GroebnerBaseRational) { // fraction free requested
364                PairList<BigInteger> pli;
365                if (strategy instanceof OrderedMinPairlist) {
366                    pli = new OrderedMinPairlist<BigInteger>();
367                } else if (strategy instanceof OrderedSyzPairlist) {
368                    pli = new OrderedSyzPairlist<BigInteger>();
369                } else {
370                    pli = new OrderedPairlist<BigInteger>();
371                }
372                bb = (GroebnerBaseAbstract) new GroebnerBaseRational<BigRational>(threads, pli);
373            } else {
374                bb = (GroebnerBaseAbstract) new GroebnerBaseParallel<C>(threads, strategy);
375            }
376            GroebnerBaseAbstract<C> pbb = new GBProxy<C>(algo, bb);
377            return new GBAlgorithmBuilder<C>(ring, pbb, strategy);
378        } else if (((RingFactory) ring.coFac) instanceof QuotientRing) {
379            GroebnerBaseAbstract<C> bb;
380            if (algo instanceof GroebnerBaseQuotient) { // fraction free requested
381                PairList<GenPolynomial<C>> pli;
382                if (strategy instanceof OrderedMinPairlist) {
383                    pli = new OrderedMinPairlist<GenPolynomial<C>>();
384                } else if (strategy instanceof OrderedSyzPairlist) {
385                    pli = new OrderedSyzPairlist<GenPolynomial<C>>();
386                } else {
387                    pli = new OrderedPairlist<GenPolynomial<C>>();
388                }
389                QuotientRing<C> fac = (QuotientRing) ring.coFac;
390                bb = (GroebnerBaseAbstract) new GroebnerBaseQuotient<C>(threads, fac, pli); // pl not possible
391            } else {
392                bb = (GroebnerBaseAbstract) new GroebnerBaseParallel<C>(threads, strategy);
393            }
394            GroebnerBaseAbstract<C> pbb = new GBProxy<C>(algo, bb);
395            return new GBAlgorithmBuilder<C>(ring, pbb);
396        } else if (ring.coFac.isField()) {
397            GroebnerBaseAbstract<C> bb = new GroebnerBaseParallel<C>(threads, strategy);
398            GroebnerBaseAbstract<C> pbb = new GBProxy<C>(algo, bb);
399            return new GBAlgorithmBuilder<C>(ring, pbb, strategy);
400        } else if (ring.coFac.getONE() instanceof GcdRingElem) {
401            GroebnerBaseAbstract<C> bb = new GroebnerBasePseudoParallel<C>(threads, ring.coFac, strategy);
402            GroebnerBaseAbstract<C> pbb = new GBProxy<C>(algo, bb);
403            return new GBAlgorithmBuilder<C>(ring, pbb, strategy);
404        }
405        logger.warn("no parallel algorithm implemented for " + ring);
406        return this;
407    }
408
409
410    /**
411     * Request FGLM algorithm.
412     * @return GBAlgorithmBuilder object.
413     */
414    @SuppressWarnings("unchecked")
415    public GBAlgorithmBuilder<C> graded() {
416        if (ring.coFac.isField()) {
417            GroebnerBaseAbstract<C> bb;
418            if (algo == null) {
419                bb = new GroebnerBaseFGLM<C>();
420            } else {
421                bb = new GroebnerBaseFGLM<C>(algo);
422            }
423            return new GBAlgorithmBuilder<C>(ring, bb, strategy);
424        }
425        logger.warn("no FGLM algorithm implemented for " + ring);
426        return this;
427    }
428
429
430    /**
431     * Request Groebner walk algorithm.
432     * @return GBAlgorithmBuilder object.
433     */
434    @SuppressWarnings("unchecked")
435    public GBAlgorithmBuilder<C> walk() {
436        if (ring.coFac.isField()) {
437            GroebnerBaseAbstract<C> bb;
438            if (algo == null) {
439                bb = new GroebnerBaseWalk<C>();
440            } else {
441                bb = new GroebnerBaseWalk<C>(algo);
442            }
443            return new GBAlgorithmBuilder<C>(ring, bb, strategy);
444        }
445        logger.warn("no Groebner walk algorithm implemented for " + ring);
446        return this;
447    }
448
449
450    /**
451     * Request iterated GB algorithm.
452     * @return GBAlgorithmBuilder object.
453     */
454    @SuppressWarnings("unchecked")
455    public GBAlgorithmBuilder<C> iterated() {
456        if (ring.coFac.isField()) {
457            GroebnerBaseAbstract<C> bb;
458            bb = new GroebnerBaseSeqIter<C>(strategy); 
459            // if (algo instanceof GBProxy) ... assemble parallel todo
460            if (algo != null) {
461                logger.warn("algorithm " + algo + " ignored for " + bb);
462            }
463            return new GBAlgorithmBuilder<C>(ring, bb, strategy);
464        }
465        logger.warn("no iterated GB algorithm implemented for " + ring);
466        return this;
467    }
468
469
470    /**
471     * Request iterated F5 signature based GB algorithm.
472     * @return GBAlgorithmBuilder object.
473     */
474    @SuppressWarnings("unchecked")
475    public GBAlgorithmBuilder<C> F5() {
476        if (ring.coFac.isField()) {
477            GroebnerBaseAbstract<C> bb;
478            bb = new GroebnerBaseF5zSigSeqIter<C>(); 
479            // if (algo instanceof GBProxy) ... assemble parallel todo
480            if (algo != null) {
481                logger.warn("algorithm " + algo + " ignored for " + bb);
482            }
483            if (strategy != null) {
484                logger.warn("strategy " + strategy + " ignored for " + bb);
485            }
486            return new GBAlgorithmBuilder<C>(ring, bb, strategy);
487        }
488        logger.warn("no iterated F5 GB algorithm implemented for " + ring);
489        return this;
490    }
491
492
493    /**
494     * Request iterated GGV signature based GB algorithm.
495     * @return GBAlgorithmBuilder object.
496     */
497    @SuppressWarnings("unchecked")
498    public GBAlgorithmBuilder<C> GGV() {
499        if (ring.coFac.isField()) {
500            GroebnerBaseAbstract<C> bb;
501            bb = new GroebnerBaseGGVSigSeqIter<C>(); 
502            // if (algo instanceof GBProxy) ... assemble parallel todo
503            if (algo != null) {
504                logger.warn("algorithm " + algo + " ignored for " + bb);
505            }
506            if (strategy != null) {
507                logger.warn("strategy " + strategy + " ignored for " + bb);
508            }
509            return new GBAlgorithmBuilder<C>(ring, bb, strategy);
510        }
511        logger.warn("no iterated GGV GB algorithm implemented for " + ring);
512        return this;
513    }
514
515
516    /**
517     * Request iterated Arri signature based GB algorithm.
518     * @return GBAlgorithmBuilder object.
519     */
520    @SuppressWarnings("unchecked")
521    public GBAlgorithmBuilder<C> Arri() {
522        if (ring.coFac.isField()) {
523            GroebnerBaseAbstract<C> bb;
524            bb = new GroebnerBaseArriSigSeqIter<C>(); 
525            // if (algo instanceof GBProxy) ... assemble parallel todo
526            if (algo != null) {
527                logger.warn("algorithm " + algo + " ignored for " + bb);
528            }
529            if (strategy != null) {
530                logger.warn("strategy " + strategy + " ignored for " + bb);
531            }
532            return new GBAlgorithmBuilder<C>(ring, bb, strategy);
533        }
534        logger.warn("no iterated Arri GB algorithm implemented for " + ring);
535        return this;
536    }
537
538
539    /**
540     * String representation of the GB algorithm implementation.
541     * @see java.lang.Object#toString()
542     */
543    @Override
544    public String toString() {
545        StringBuffer s = new StringBuffer(" ");
546        if (algo != null) {
547            s.append(algo.toString());
548            s.append(" for ");
549        }
550        s.append(ring.toString());
551        if (strategy != null) {
552            s.append(" strategy=");
553            s.append(strategy.toString());
554        }
555        return s.toString();
556    }
557
558
559    /**
560     * Get a scripting compatible string representation.
561     * @return script compatible representation for this Element.
562     * @see edu.jas.structure.Element#toScript()
563     */
564    public String toScript() {
565        // Python case
566        StringBuffer s = new StringBuffer(" ");
567        if (algo != null) {
568            s.append(algo.toString()); // nonsense
569            s.append(" ");
570        }
571        s.append(ring.toScript());
572        if (strategy != null) {
573            s.append(",strategy=");
574            s.append(strategy.toString());
575        }
576        return s.toString();
577    }
578
579}