001/*
002 * $Id: GBAlgorithmBuilder.java 4296 2012-11-11 18:09:53Z 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.gbufd.GBFactory;
019import edu.jas.gbufd.GroebnerBaseFGLM;
020import edu.jas.gbufd.GroebnerBasePseudoParallel;
021import edu.jas.gbufd.GroebnerBaseRational;
022import edu.jas.kern.ComputerThreads;
023import edu.jas.poly.GenPolynomialRing;
024import edu.jas.structure.GcdRingElem;
025import edu.jas.ufd.Quotient;
026import edu.jas.ufd.QuotientRing;
027
028
029/**
030 * Builder for commutative Gröbner bases algorithm implementations.
031 * @author Heinz Kredel
032 * @usage To create objects that implement the <code>GroebnerBase</code>
033 *        interface one can use the <code>GBFactory</code> or this <code>GBAlgorithmBuilder</code>. 
034 *        This class will select and compose an
035 *        appropriate implementation based on the types of polynomial
036 *        coefficients C and the desired properties. To build an implementation start with
037 *        the static method <code>polynomialRing()</code> to define the polynomial ring. 
038 *        Then continue to construct the algorithm with the methods 
039 *        <ul>
040 *        <li><code>optimize()</code> or <code>optimize(boolean)</code> for term order (variable order) 
041 *            optimization,
042 *        </li>
043 *        <li><code>fractionFree()</code> for clearing denominators and computing with pseudo reduction,
044 *        </li>
045 *        <li><code>graded()</code> for using the FGLM algorithm to first compute with a graded term order and 
046 *            then constructing a lexicographical Gr&ouml;bner base,
047 *        </li>
048 *        <li><code>parallel()</code> additionaly compute a Gr&ouml;bner base over a field in parallel,
049 *        </li>
050 *        <li><code>euclideanDomain()</code> for computing a e-Gr&ouml;bner base,
051 *        </li>
052 *        <li><code>domainAlgorithm(Algo)</code> for computing a d- or e-Gr&ouml;bner base,
053 *        </li>
054 *        </ul>
055 *        Finaly call the method <code>build()</code> to obtain an implementaton of
056 *        class <code>GroebnerBaseAbstract</code>. For example 
057 * 
058 *        <pre>
059 *
060 * GenPolynomialRing&lt;C&gt; pf = new GenPolynomialRing&lt;C&gt;(cofac, vars);
061 * GroebnerBaseAbstract&lt;C&gt; engine;
062 * engine = GBAlgorithmBuilder.&lt;C&gt; polynomialRing(pf).fractionFree().parallel().optimize().build();
063 * c = engine.GB(A);
064 * </pre>
065 * 
066 *        For example, if the coefficient type is BigRational, the usage looks
067 *        like
068 * 
069 *        <pre>
070 *
071 * GenPolynomialRing&lt;BigRational&gt; pf = new GenPolynomialRing&lt;BigRational&gt;(cofac, vars);
072 * GroebnerBaseAbstract&lt;BigRational&gt; engine;
073 * engine = GBAlgorithmBuilder.&lt;BigRational&gt; polynomialRing(pf).fractionFree().parallel().optimize().build();
074 * c = engine.GB(A);
075 * </pre>
076 * 
077 * <b>Note:</b> Not all combinations are meanigful  
078 * 
079 * @see edu.jas.gb.GroebnerBase
080 * @see edu.jas.gbufd.GBFactory
081 */
082
083public class GBAlgorithmBuilder<C extends GcdRingElem<C>> implements Serializable {
084
085
086    private static final Logger logger = Logger.getLogger(GBAlgorithmBuilder.class);
087
088
089    /**
090     * The current GB algorithm implementation.
091     */
092    private GroebnerBaseAbstract<C> algo;
093
094
095    /**
096     * The current polynomial ring.
097     */
098    public final GenPolynomialRing<C> ring;
099
100
101    /**
102     * Constructor not for use.
103     */
104    protected GBAlgorithmBuilder() {
105        throw new IllegalArgumentException("do not use this constructor");
106    }
107
108
109    /**
110     * Constructor.
111     * @param ring the polynomial ring.
112     */
113    public GBAlgorithmBuilder(GenPolynomialRing<C> ring) {
114        this(ring, null);
115    }
116
117
118    /**
119     * Constructor.
120     * @param ring the polynomial ring.
121     * @param algo already determined algorithm.
122     */
123    public GBAlgorithmBuilder(GenPolynomialRing<C> ring, GroebnerBaseAbstract<C> algo) {
124        this.ring = ring;
125        this.algo = algo;
126    }
127
128
129    /**
130     * Build the GB algorithm implementaton.
131     * @return GB algorithm implementaton as GroebnerBaseAbstract object.
132     */
133    public GroebnerBaseAbstract<C> build() {
134        if (algo == null) {
135            algo = GBFactory.<C> getImplementation(ring.coFac);
136        }
137        return algo;
138    }
139
140
141    /**
142     * Define polynomial ring.
143     * @param fac the commutative polynomial ring.
144     * @return GBAlgorithmBuilder object.
145     */
146    public static <C extends GcdRingElem<C>> GBAlgorithmBuilder<C> polynomialRing(GenPolynomialRing<C> fac) {
147        return new GBAlgorithmBuilder<C>(fac);
148    }
149
150
151    /**
152     * Request term order optimization.
153     * Call optimize(true) for return of permuted polynomials.
154     * @return GBAlgorithmBuilder object.
155     */
156    public GBAlgorithmBuilder<C> optimize() {
157        return optimize(true);
158    }
159
160
161    /**
162     * Request term order optimization.
163     * @param rP true for return of permuted polynomials, false for inverse
164     *            permuted polynomials and new GB computation.
165     * @return GBAlgorithmBuilder object.
166     */
167    public GBAlgorithmBuilder<C> optimize(boolean rP) {
168        if (algo == null) {
169           algo = GBFactory.<C> getImplementation(ring.coFac);
170        }
171        GroebnerBaseAbstract<C> bb = new GBOptimized<C>(algo, rP);
172        return new GBAlgorithmBuilder<C>(ring, bb);
173    }
174
175
176    /**
177     * Request fraction free algorithm.  For BigRational and Quotient
178     * coefficients denominators are cleared and pseudo reduction is
179     * used.
180     * @return GBAlgorithmBuilder object.
181     */
182    @SuppressWarnings("unchecked")
183    public GBAlgorithmBuilder<C> fractionFree() {
184        if (algo != null) {
185           logger.warn("selected algorithm ignored: " + algo + ", use fractionFree before");
186        }
187        if (((Object)ring.coFac) instanceof BigRational) {
188            BigRational cf = (BigRational) (Object) ring.coFac;
189            GroebnerBaseAbstract<BigRational> bb = GBFactory.getImplementation(cf, GBFactory.Algo.ffgb);
190            GroebnerBaseAbstract<C> cbb = (GroebnerBaseAbstract<C>) (GroebnerBaseAbstract) bb;
191            return new GBAlgorithmBuilder<C>(ring, cbb);
192        }
193        if (((Object)ring.coFac) instanceof QuotientRing) {
194            QuotientRing<C> cf = (QuotientRing<C>) (Object) ring.coFac;
195            GroebnerBaseAbstract<Quotient<C>> bb = GBFactory.<C> getImplementation(cf, GBFactory.Algo.ffgb);
196            GroebnerBaseAbstract<C> cbb = (GroebnerBaseAbstract<C>) (GroebnerBaseAbstract) bb;
197            return new GBAlgorithmBuilder<C>(ring, cbb);
198        }
199        logger.warn("no fraction free algorithm implemented for " + ring);
200        return this;
201    }
202
203
204    /**
205     * Request e-GB algorithm.
206     * @return GBAlgorithmBuilder object.
207     */
208    public GBAlgorithmBuilder<C> euclideanDomain() {
209        return domainAlgorithm(GBFactory.Algo.egb);
210    }
211
212
213    /**
214     * Request d- or e-GB algorithm.
215     * @param a algorithm from GBFactory.Algo.
216     * @return GBAlgorithmBuilder object.
217     */
218    @SuppressWarnings("unchecked")
219    public GBAlgorithmBuilder<C> domainAlgorithm(GBFactory.Algo a) {
220        if (((Object)ring.coFac) instanceof BigInteger) {
221            BigInteger cf = (BigInteger) (Object) ring.coFac;
222            GroebnerBaseAbstract<BigInteger> bb = GBFactory.getImplementation(cf, a);
223            GroebnerBaseAbstract<C> cbb = (GroebnerBaseAbstract<C>) (GroebnerBaseAbstract) bb;
224            return new GBAlgorithmBuilder<C>(ring, cbb);
225        }
226        logger.warn("no domain algorithm implemented for " + ring);
227        return this;
228    }
229
230
231    /**
232     * Request parallel algorithm.
233     * Additionaly run a parallel algorithm via GBProxy.
234     * @return GBAlgorithmBuilder object.
235     */
236    @SuppressWarnings("unchecked")
237    public GBAlgorithmBuilder<C> parallel() {
238        return parallel(ComputerThreads.N_CPUS);
239    }
240
241
242    /**
243     * Request parallel algorithm.
244     * Additionaly run a parallel algorithm via GBProxy.
245     * @param threads number of threads requested.
246     * @return GBAlgorithmBuilder object.
247     */
248    @SuppressWarnings("unchecked")
249    public GBAlgorithmBuilder<C> parallel(int threads) {
250        if (ComputerThreads.NO_THREADS) {
251            logger.warn("parallel algorithms disabled");
252            return this;
253        }
254        if (algo == null) {
255            algo = GBFactory.<C> getImplementation(ring.coFac);
256        }
257        if (ring.coFac instanceof BigRational) {
258            GroebnerBaseAbstract<C> bb;
259            if (algo instanceof GroebnerBaseRational) { // fraction free requested
260                bb = (GroebnerBaseAbstract) new GroebnerBaseRational<BigRational>(threads);
261            } else {
262                bb = (GroebnerBaseAbstract) new GroebnerBaseParallel<C>(threads);
263            }
264            GroebnerBaseAbstract<C> pbb = new GBProxy<C>(algo, bb);
265            return new GBAlgorithmBuilder<C>(ring, pbb);
266        } else if (ring.coFac.isField()) {
267            GroebnerBaseAbstract<C> bb = new GroebnerBaseParallel<C>(threads);
268            GroebnerBaseAbstract<C> pbb = new GBProxy<C>(algo, bb);
269            return new GBAlgorithmBuilder<C>(ring, pbb);
270        } else if (ring.coFac.getONE() instanceof GcdRingElem) {
271            GroebnerBaseAbstract<C> bb = new GroebnerBasePseudoParallel<C>(threads,ring.coFac);
272            GroebnerBaseAbstract<C> pbb = new GBProxy<C>(algo, bb);
273            return new GBAlgorithmBuilder<C>(ring, pbb);
274        }
275        logger.warn("no parallel algorithm implemented for " + ring);
276        return this;
277    }
278
279
280    /**
281     * Request FGLM algorithm.
282     * @return GBAlgorithmBuilder object.
283     */
284    @SuppressWarnings("unchecked")
285    public GBAlgorithmBuilder<C> graded() {
286        if (ring.coFac.isField()) {
287            GroebnerBaseAbstract<C> bb;
288            if (algo == null) {
289                bb = new GroebnerBaseFGLM<C>();
290            } else {
291                bb = new GroebnerBaseFGLM<C>(algo);
292            }
293            return new GBAlgorithmBuilder<C>(ring, bb);
294        }
295        logger.warn("no FGLM algorithm implemented for " + ring);
296        return this;
297    }
298
299
300    /**
301     * String representation of the GB algorithm implementation.
302     * @see java.lang.Object#toString()
303     */
304    @Override
305    public String toString() {
306        StringBuffer s = new StringBuffer(" ");
307        if ( algo != null ) {
308            s.append(algo.toString());
309            s.append(" for ");
310        }
311        s.append(ring.toString());
312        return s.toString();
313    }
314
315
316    /**
317     * Get a scripting compatible string representation.
318     * @return script compatible representation for this Element.
319     * @see edu.jas.structure.Element#toScript()
320     */
321    public String toScript() {
322        // Python case
323        StringBuffer s = new StringBuffer(" ");
324        if ( algo != null ) {
325            s.append(algo.toString()); // nonsense
326            s.append(" ");
327        }
328        s.append(ring.toScript());
329        return s.toString();
330    }
331
332}