001/*
002 * $Id$
003 */
004
005package edu.jas.gbufd;
006
007
008import org.apache.logging.log4j.LogManager;
009import org.apache.logging.log4j.Logger;
010
011import edu.jas.arith.BigInteger;
012import edu.jas.arith.BigRational;
013import edu.jas.arith.ModInt;
014import edu.jas.arith.ModIntRing;
015import edu.jas.arith.ModInteger;
016import edu.jas.arith.ModIntegerRing;
017import edu.jas.arith.ModLong;
018import edu.jas.arith.ModLongRing;
019import edu.jas.arith.Product;
020import edu.jas.arith.ProductRing;
021import edu.jas.gb.DGroebnerBaseSeq;
022import edu.jas.gb.EGroebnerBaseSeq;
023import edu.jas.gb.GBProxy;
024import edu.jas.gb.GroebnerBaseAbstract;
025import edu.jas.gb.GroebnerBaseParallel;
026import edu.jas.gb.GroebnerBaseSeq;
027import edu.jas.gb.OrderedMinPairlist;
028import edu.jas.gb.OrderedPairlist;
029import edu.jas.gb.OrderedSyzPairlist;
030import edu.jas.gb.PairList;
031import edu.jas.gb.ReductionSeq;
032import edu.jas.kern.ComputerThreads;
033import edu.jas.poly.GenPolynomial;
034import edu.jas.poly.GenPolynomialRing;
035import edu.jas.structure.GcdRingElem;
036import edu.jas.structure.RingElem;
037import edu.jas.structure.RingFactory;
038import edu.jas.ufd.Quotient;
039import edu.jas.ufd.QuotientRing;
040
041
042/**
043 * Groebner bases algorithms factory. Select appropriate Groebner bases engine
044 * based on the coefficient types.
045 * <p>
046 * <b>Usage:</b> To create objects that implement the <code>GroebnerBase</code>
047 * interface use the <code>GBFactory</code>. It will select an appropriate
048 * implementation based on the types of polynomial coefficients C. The method to
049 * obtain an implementation is <code>getImplementation()</code>.
050 * <code>getImplementation()</code> returns an object of a class which
051 * implements the <code>GroebnerBase</code> interface, more precisely an object
052 * of abstract class <code>GroebnerBaseAbstract</code>.
053 * 
054 * <pre>
055 * GroebnerBase&lt;CT&gt; engine;
056 * engine = GBFactory.&lt;CT&gt; getImplementation(cofac);
057 * c = engine.GB(A);
058 * </pre>
059 * <p>
060 * For example, if the coefficient type is BigInteger, the usage looks like
061 * 
062 * <pre>
063 * BigInteger cofac = new BigInteger();
064 * GroebnerBase&lt;BigInteger&gt; engine;
065 * engine = GBFactory.getImplementation(cofac);
066 * c = engine.GB(A);
067 * </pre>
068 * 
069 * @author Heinz Kredel
070 *
071 * @see edu.jas.gb.GroebnerBase
072 * @see edu.jas.application.GBAlgorithmBuilder
073 */
074
075public class GBFactory {
076
077
078    private static final Logger logger = LogManager.getLogger(GBFactory.class);
079
080
081    /**
082     * Algorithm indicators: igb = integerGB, egb = e-GB, dgb = d-GB, qgb =
083     * fraction coefficients GB, ffgb = fraction free GB.
084     */
085    public static enum Algo {
086        igb, egb, dgb, qgb, ffgb
087    };
088
089
090    /**
091     * Protected factory constructor.
092     */
093    protected GBFactory() {
094    }
095
096
097    /**
098     * Determine suitable implementation of GB algorithms, no factory case.
099     * @return GB algorithm implementation for field coefficients.
100     */
101    public static <C extends GcdRingElem<C>> GroebnerBaseAbstract<C> getImplementation() {
102        logger.warn("no coefficient factory given, assuming field coefficients");
103        GroebnerBaseAbstract<C> bba = new GroebnerBaseSeq<C>();
104        return bba;
105    }
106
107
108    /**
109     * Determine suitable implementation of GB algorithms, case ModLong.
110     * @param fac ModLongRing.
111     * @return GB algorithm implementation.
112     */
113    public static GroebnerBaseAbstract<ModLong> getImplementation(ModLongRing fac) {
114        return getImplementation(fac, new OrderedPairlist<ModLong>());
115    }
116
117
118    /**
119     * Determine suitable implementation of GB algorithms, case ModLong.
120     * @param fac ModLongRing.
121     * @param pl pair selection strategy
122     * @return GB algorithm implementation.
123     */
124    public static GroebnerBaseAbstract<ModLong> getImplementation(ModLongRing fac, PairList<ModLong> pl) {
125        GroebnerBaseAbstract<ModLong> bba;
126        if (fac.isField()) {
127            bba = new GroebnerBaseSeq<ModLong>(pl);
128        } else {
129            bba = new GroebnerBasePseudoSeq<ModLong>(fac, pl);
130        }
131        return bba;
132    }
133
134
135    /**
136     * Determine suitable implementation of GB algorithms, case ModInt.
137     * @param fac ModIntRing.
138     * @return GB algorithm implementation.
139     */
140    public static GroebnerBaseAbstract<ModInt> getImplementation(ModIntRing fac) {
141        return getImplementation(fac, new OrderedPairlist<ModInt>());
142    }
143
144
145    /**
146     * Determine suitable implementation of GB algorithms, case ModInt.
147     * @param fac ModIntRing.
148     * @param pl pair selection strategy
149     * @return GB algorithm implementation.
150     */
151    public static GroebnerBaseAbstract<ModInt> getImplementation(ModIntRing fac, PairList<ModInt> pl) {
152        GroebnerBaseAbstract<ModInt> bba;
153        if (fac.isField()) {
154            bba = new GroebnerBaseSeq<ModInt>(pl);
155        } else {
156            bba = new GroebnerBasePseudoSeq<ModInt>(fac, pl);
157        }
158        return bba;
159    }
160
161
162    /**
163     * Determine suitable implementation of GB algorithms, case ModInteger.
164     * @param fac ModIntegerRing.
165     * @return GB algorithm implementation.
166     */
167    public static GroebnerBaseAbstract<ModInteger> getImplementation(ModIntegerRing fac) {
168        return getImplementation(fac, new OrderedPairlist<ModInteger>());
169    }
170
171
172    /**
173     * Determine suitable implementation of GB algorithms, case ModInteger.
174     * @param fac ModIntegerRing.
175     * @param pl pair selection strategy
176     * @return GB algorithm implementation.
177     */
178    public static GroebnerBaseAbstract<ModInteger> getImplementation(ModIntegerRing fac,
179                    PairList<ModInteger> pl) {
180        GroebnerBaseAbstract<ModInteger> bba;
181        if (fac.isField()) {
182            bba = new GroebnerBaseSeq<ModInteger>(pl);
183        } else {
184            bba = new GroebnerBasePseudoSeq<ModInteger>(fac, pl);
185        }
186        return bba;
187    }
188
189
190    /**
191     * Determine suitable implementation of GB algorithms, case BigInteger.
192     * @param fac BigInteger.
193     * @return GB algorithm implementation.
194     */
195    public static GroebnerBaseAbstract<BigInteger> getImplementation(BigInteger fac) {
196        return getImplementation(fac, Algo.igb);
197    }
198
199
200    /**
201     * Determine suitable implementation of GB algorithms, case BigInteger.
202     * @param fac BigInteger.
203     * @param a algorithm, a = igb, egb, dgb.
204     * @return GB algorithm implementation.
205     */
206    public static GroebnerBaseAbstract<BigInteger> getImplementation(BigInteger fac, Algo a) {
207        return getImplementation(fac, a, new OrderedPairlist<BigInteger>());
208    }
209
210
211    /**
212     * Determine suitable implementation of GB algorithms, case BigInteger.
213     * @param fac BigInteger.
214     * @param pl pair selection strategy
215     * @return GB algorithm implementation.
216     */
217    public static GroebnerBaseAbstract<BigInteger> getImplementation(BigInteger fac,
218                    PairList<BigInteger> pl) {
219        return getImplementation(fac, Algo.igb, pl);
220    }
221
222
223    /**
224     * Determine suitable implementation of GB algorithms, case BigInteger.
225     * @param fac BigInteger.
226     * @param a algorithm, a = igb, egb, dgb.
227     * @param pl pair selection strategy
228     * @return GB algorithm implementation.
229     */
230    public static GroebnerBaseAbstract<BigInteger> getImplementation(BigInteger fac, Algo a,
231                    PairList<BigInteger> pl) {
232        GroebnerBaseAbstract<BigInteger> bba;
233        switch (a) {
234        case igb:
235            bba = new GroebnerBasePseudoSeq<BigInteger>(fac, pl);
236            break;
237        case egb:
238            bba = new EGroebnerBaseSeq<BigInteger>(); // pl not suitable
239            break;
240        case dgb:
241            bba = new DGroebnerBaseSeq<BigInteger>(); // pl not suitable
242            break;
243        default:
244            throw new IllegalArgumentException("algorithm not available for BigInteger " + a);
245        }
246        return bba;
247    }
248
249
250    /**
251     * Determine suitable implementation of GB algorithms, case BigRational.
252     * @param fac BigRational.
253     * @return GB algorithm implementation.
254     */
255    public static GroebnerBaseAbstract<BigRational> getImplementation(BigRational fac) {
256        return getImplementation(fac, Algo.qgb);
257    }
258
259
260    /**
261     * Determine suitable implementation of GB algorithms, case BigRational.
262     * @param fac BigRational.
263     * @param a algorithm, a = qgb, ffgb.
264     * @return GB algorithm implementation.
265     */
266    public static GroebnerBaseAbstract<BigRational> getImplementation(BigRational fac, Algo a) {
267        return getImplementation(fac, a, new OrderedPairlist<BigRational>());
268    }
269
270
271    /**
272     * Determine suitable implementation of GB algorithms, case BigRational.
273     * @param fac BigRational.
274     * @param pl pair selection strategy
275     * @return GB algorithm implementation.
276     */
277    public static GroebnerBaseAbstract<BigRational> getImplementation(BigRational fac,
278                    PairList<BigRational> pl) {
279        return getImplementation(fac, Algo.qgb, pl);
280    }
281
282
283    /**
284     * Determine suitable implementation of GB algorithms, case BigRational.
285     * @param fac BigRational.
286     * @param a algorithm, a = qgb, ffgb.
287     * @param pl pair selection strategy
288     * @return GB algorithm implementation.
289     */
290    public static GroebnerBaseAbstract<BigRational> getImplementation(BigRational fac, Algo a,
291                    PairList<BigRational> pl) {
292        GroebnerBaseAbstract<BigRational> bba;
293        switch (a) {
294        case qgb:
295            bba = new GroebnerBaseSeq<BigRational>(pl);
296            break;
297        case ffgb:
298            PairList<BigInteger> pli;
299            if (pl instanceof OrderedMinPairlist) {
300                pli = new OrderedMinPairlist<BigInteger>();
301            } else if (pl instanceof OrderedSyzPairlist) {
302                pli = new OrderedSyzPairlist<BigInteger>();
303            } else {
304                pli = new OrderedPairlist<BigInteger>();
305            }
306            bba = new GroebnerBaseRational<BigRational>(pli); // pl not possible
307            break;
308        default:
309            throw new IllegalArgumentException(
310                            "algorithm not available for " + fac.toScriptFactory() + ", Algo = " + a);
311        }
312        return bba;
313    }
314
315
316    /**
317     * Determine suitable implementation of GB algorithms, case Quotient
318     * coefficients.
319     * @param fac QuotientRing.
320     * @return GB algorithm implementation.
321     */
322    public static <C extends GcdRingElem<C>> GroebnerBaseAbstract<Quotient<C>> getImplementation(
323                    QuotientRing<C> fac) {
324        return getImplementation(fac, Algo.qgb);
325    }
326
327
328    /**
329     * Determine suitable implementation of GB algorithms, case Quotient
330     * coefficients.
331     * @param fac QuotientRing.
332     * @param a algorithm, a = qgb, ffgb.
333     * @return GB algorithm implementation.
334     */
335    public static <C extends GcdRingElem<C>> GroebnerBaseAbstract<Quotient<C>> getImplementation(
336                    QuotientRing<C> fac, Algo a) {
337        return getImplementation(fac, a, new OrderedPairlist<Quotient<C>>());
338    }
339
340
341    /**
342     * Determine suitable implementation of GB algorithms, case Quotient
343     * coefficients.
344     * @param fac QuotientRing.
345     * @param pl pair selection strategy
346     * @return GB algorithm implementation.
347     */
348    public static <C extends GcdRingElem<C>> GroebnerBaseAbstract<Quotient<C>> getImplementation(
349                    QuotientRing<C> fac, PairList<Quotient<C>> pl) {
350        return getImplementation(fac, Algo.qgb, pl);
351    }
352
353
354    /**
355     * Determine suitable implementation of GB algorithms, case Quotient
356     * coefficients.
357     * @param fac QuotientRing.
358     * @param a algorithm, a = qgb, ffgb.
359     * @param pl pair selection strategy
360     * @return GB algorithm implementation.
361     */
362    public static <C extends GcdRingElem<C>> GroebnerBaseAbstract<Quotient<C>> getImplementation(
363                    QuotientRing<C> fac, Algo a, PairList<Quotient<C>> pl) {
364        GroebnerBaseAbstract<Quotient<C>> bba;
365        switch (a) {
366        case qgb:
367            bba = new GroebnerBaseSeq<Quotient<C>>(new ReductionSeq<Quotient<C>>(), pl);
368            break;
369        case ffgb:
370            PairList<GenPolynomial<C>> pli;
371            if (pl instanceof OrderedMinPairlist) {
372                pli = new OrderedMinPairlist<GenPolynomial<C>>();
373            } else if (pl instanceof OrderedSyzPairlist) {
374                pli = new OrderedSyzPairlist<GenPolynomial<C>>();
375            } else {
376                pli = new OrderedPairlist<GenPolynomial<C>>();
377            }
378            bba = new GroebnerBaseQuotient<C>(fac, pli); // pl not possible
379            break;
380        default:
381            throw new IllegalArgumentException("algorithm not available for Quotient " + a);
382        }
383        return bba;
384    }
385
386
387    /**
388     * Determine suitable implementation of GB algorithms, case (recursive)
389     * polynomial.
390     * @param fac GenPolynomialRing&lt;C&gt;.
391     * @return GB algorithm implementation.
392     */
393    public static <C extends GcdRingElem<C>> GroebnerBaseAbstract<GenPolynomial<C>> getImplementation(
394                    GenPolynomialRing<C> fac) {
395        return getImplementation(fac, Algo.igb);
396    }
397
398
399    /**
400     * Determine suitable implementation of GB algorithms, case (recursive)
401     * polynomial.
402     * @param fac GenPolynomialRing&lt;C&gt;.
403     * @param a algorithm, a = igb or egb, dgb if fac is univariate over a
404     *            field.
405     * @return GB algorithm implementation.
406     */
407    public static <C extends GcdRingElem<C>> GroebnerBaseAbstract<GenPolynomial<C>> getImplementation(
408                    GenPolynomialRing<C> fac, Algo a) {
409        return getImplementation(fac, a, new OrderedPairlist<GenPolynomial<C>>());
410    }
411
412
413    /**
414     * Determine suitable implementation of GB algorithms, case (recursive)
415     * polynomial.
416     * @param fac GenPolynomialRing&lt;C&gt;.
417     * @param pl pair selection strategy
418     * @return GB algorithm implementation.
419     */
420    public static <C extends GcdRingElem<C>> GroebnerBaseAbstract<GenPolynomial<C>> getImplementation(
421                    GenPolynomialRing<C> fac, PairList<GenPolynomial<C>> pl) {
422        return getImplementation(fac, Algo.igb, pl);
423    }
424
425
426    /**
427     * Determine suitable implementation of GB algorithms, case (recursive)
428     * polynomial.
429     * @param fac GenPolynomialRing&lt;C&gt;.
430     * @param a algorithm, a = igb or egb, dgb if fac is univariate over a
431     *            field.
432     * @param pl pair selection strategy
433     * @return GB algorithm implementation.
434     */
435    public static <C extends GcdRingElem<C>> GroebnerBaseAbstract<GenPolynomial<C>> getImplementation(
436                    GenPolynomialRing<C> fac, Algo a, PairList<GenPolynomial<C>> pl) {
437        GroebnerBaseAbstract<GenPolynomial<C>> bba;
438        switch (a) {
439        case igb:
440            bba = new GroebnerBasePseudoRecSeq<C>(fac, pl);
441            break;
442        case egb:
443            if (fac.nvar > 1 || !fac.coFac.isField()) {
444                throw new IllegalArgumentException("coefficients not univariate or not over a field" + fac);
445            }
446            bba = new EGroebnerBaseSeq<GenPolynomial<C>>(); // pl not suitable
447            break;
448        case dgb:
449            if (fac.nvar > 1 || !fac.coFac.isField()) {
450                throw new IllegalArgumentException("coefficients not univariate or not over a field" + fac);
451            }
452            bba = new DGroebnerBaseSeq<GenPolynomial<C>>(); // pl not suitable
453            break;
454        default:
455            throw new IllegalArgumentException("algorithm not available for GenPolynomial<C> " + a);
456        }
457        return bba;
458    }
459
460
461    /**
462     * Determine suitable implementation of GB algorithms, case regular rings.
463     * @param fac RegularRing.
464     * @return GB algorithm implementation.
465     */
466    public static <C extends RingElem<C>> GroebnerBaseAbstract<Product<C>> getImplementation(
467                    ProductRing<C> fac) {
468        GroebnerBaseAbstract<Product<C>> bba;
469        if (fac.onlyFields()) {
470            bba = new RGroebnerBaseSeq<Product<C>>();
471        } else {
472            bba = new RGroebnerBasePseudoSeq<Product<C>>(fac);
473        }
474        return bba;
475    }
476
477
478    /**
479     * Determine suitable implementation of GB algorithms, other cases.
480     * @param fac RingFactory&lt;C&gt;.
481     * @return GB algorithm implementation.
482     */
483    public static <C extends GcdRingElem<C>> // interface RingElem not sufficient 
484    GroebnerBaseAbstract<C> getImplementation(RingFactory<C> fac) {
485        return getImplementation(fac, new OrderedPairlist<C>());
486    }
487
488
489    /**
490     * Determine suitable implementation of GB algorithms, other cases.
491     * @param fac RingFactory&lt;C&gt;.
492     * @param pl pair selection strategy
493     * @return GB algorithm implementation.
494     */
495    @SuppressWarnings("unchecked")
496    public static <C extends GcdRingElem<C>> // interface RingElem not sufficient 
497    GroebnerBaseAbstract<C> getImplementation(RingFactory<C> fac, PairList<C> pl) {
498        logger.debug("fac = {}", fac.getClass().getName());
499        if (fac.isField()) {
500            return new GroebnerBaseSeq<C>(pl);
501        }
502        GroebnerBaseAbstract bba = null;
503        Object ofac = fac;
504        if (ofac instanceof GenPolynomialRing) {
505            PairList<GenPolynomial<C>> pli;
506            if (pl instanceof OrderedMinPairlist) {
507                pli = new OrderedMinPairlist<GenPolynomial<C>>();
508            } else if (pl instanceof OrderedSyzPairlist) {
509                pli = new OrderedSyzPairlist<GenPolynomial<C>>();
510            } else {
511                pli = new OrderedPairlist<GenPolynomial<C>>();
512            }
513            GenPolynomialRing<C> rofac = (GenPolynomialRing<C>) ofac;
514            GroebnerBaseAbstract<GenPolynomial<C>> bbr = new GroebnerBasePseudoRecSeq<C>(rofac, pli); // not pl
515            bba = (GroebnerBaseAbstract) bbr;
516        } else if (ofac instanceof ProductRing) {
517            ProductRing pfac = (ProductRing) ofac;
518            if (pfac.onlyFields()) {
519                bba = new RGroebnerBaseSeq<Product<C>>();
520            } else {
521                bba = new RGroebnerBasePseudoSeq<Product<C>>(pfac);
522            }
523        } else {
524            bba = new GroebnerBasePseudoSeq<C>(fac, pl);
525        }
526        logger.debug("bba = {}", bba.getClass().getName());
527        return bba;
528    }
529
530
531    /**
532     * Determine suitable parallel/concurrent implementation of GB algorithms if
533     * possible.
534     * @param fac RingFactory&lt;C&gt;.
535     * @return GB proxy algorithm implementation.
536     */
537    public static <C extends GcdRingElem<C>> // interface RingElem not sufficient 
538    GroebnerBaseAbstract<C> getProxy(RingFactory<C> fac) {
539        return getProxy(fac, new OrderedPairlist<C>());
540    }
541
542
543    /**
544     * Determine suitable parallel/concurrent implementation of GB algorithms if
545     * possible.
546     * @param fac RingFactory&lt;C&gt;.
547     * @param pl pair selection strategy
548     * @return GB proxy algorithm implementation.
549     */
550    @SuppressWarnings("unchecked")
551    public static <C extends GcdRingElem<C>> // interface RingElem not sufficient 
552    GroebnerBaseAbstract<C> getProxy(RingFactory<C> fac, PairList<C> pl) {
553        if (ComputerThreads.NO_THREADS) {
554            return GBFactory.<C> getImplementation(fac, pl);
555        }
556        logger.debug("fac = {}", fac.getClass().getName());
557        int th = (ComputerThreads.N_CPUS > 2 ? ComputerThreads.N_CPUS - 1 : 2);
558        if (fac.isField()) {
559            GroebnerBaseAbstract<C> e1 = new GroebnerBaseSeq<C>(pl);
560            GroebnerBaseAbstract<C> e2 = new GroebnerBaseParallel<C>(th, pl);
561            return new GBProxy<C>(e1, e2);
562        } else if (fac.characteristic().signum() == 0) {
563            if (fac instanceof GenPolynomialRing) {
564                GenPolynomialRing pfac = (GenPolynomialRing) fac;
565                OrderedPairlist ppl = new OrderedPairlist<GenPolynomial<C>>();
566                GroebnerBaseAbstract e1 = new GroebnerBasePseudoRecSeq<C>(pfac, ppl);
567                GroebnerBaseAbstract e2 = new GroebnerBasePseudoRecParallel<C>(th, pfac, ppl);
568                return new GBProxy<C>(e1, e2);
569            }
570            GroebnerBaseAbstract<C> e1 = new GroebnerBasePseudoSeq<C>(fac, pl);
571            GroebnerBaseAbstract<C> e2 = new GroebnerBasePseudoParallel<C>(th, fac, pl);
572            return new GBProxy<C>(e1, e2);
573        }
574        return getImplementation(fac, pl);
575    }
576
577
578    /**
579     * Determine suitable parallel/concurrent implementation of GB algorithms if
580     * possible.
581     * @param fac RingFactory&lt;C&gt;.
582     * @return GB proxy algorithm implementation.
583     */
584    @SuppressWarnings("unchecked")
585    public static <C extends GcdRingElem<C>> // interface RingElem not sufficient 
586    GroebnerBaseAbstract<GenPolynomial<C>> getProxy(GenPolynomialRing<C> fac) {
587        if (ComputerThreads.NO_THREADS) {
588            //return GBFactory.<GenPolynomial<C>> getImplementation(fac);
589            return GBFactory.getImplementation(fac);
590        }
591        logger.debug("fac = {}", fac.getClass().getName());
592        int th = (ComputerThreads.N_CPUS > 2 ? ComputerThreads.N_CPUS - 1 : 2);
593        OrderedPairlist<GenPolynomial<C>> ppl = new OrderedPairlist<GenPolynomial<C>>();
594        GroebnerBaseAbstract<GenPolynomial<C>> e1 = new GroebnerBasePseudoRecSeq<C>(fac, ppl);
595        GroebnerBaseAbstract<GenPolynomial<C>> e2 = new GroebnerBasePseudoRecParallel<C>(th, fac, ppl);
596        //return new GBProxy<GenPolynomial<C>>(e1, e2);
597        return new GBProxy(e1, e2);
598    }
599
600}