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