001/*
002 * $Id: GCDFactory.java 5871 2018-07-20 15:58:45Z kredel $
003 */
004
005package edu.jas.ufd;
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.kern.ComputerThreads;
018import edu.jas.structure.GcdRingElem;
019import edu.jas.structure.RingFactory;
020
021
022/**
023 * Greatest common divisor algorithms factory. Select appropriate GCD engine
024 * based on the coefficient types.
025 * @author Heinz Kredel
026 * @usage To create objects that implement the
027 *        <code>GreatestCommonDivisor</code> interface use the
028 *        <code>GCDFactory</code>. It will select an appropriate implementation
029 *        based on the types of polynomial coefficients C. There are two methods
030 *        to obtain an implementation: <code>getProxy()</code> and
031 *        <code>getImplementation()</code>. <code>getImplementation()</code>
032 *        returns an object of a class which implements the
033 *        <code>GreatestCommonDivisor</code> interface. <code>getProxy()</code>
034 *        returns a proxy object of a class which implements the
035 *        <code>GreatestCommonDivisor</code>r interface. The proxy will run two
036 *        implementations in parallel, return the first computed result and
037 *        cancel the second running task. On systems with one CPU the computing
038 *        time will be two times the time of the fastest algorithm
039 *        implmentation. On systems with more than two CPUs the computing time
040 *        will be the time of the fastest algorithm implmentation.
041 * 
042 *        <pre>
043 * GreatestCommonDivisor&lt;CT&gt; engine;
044 * engine = GCDFactory.&lt;CT&gt; getImplementation(cofac);
045 * or engine = GCDFactory.&lt;CT&gt; getProxy(cofac);
046 * c = engine.gcd(a, b);
047 * </pre>
048 * 
049 *        For example, if the coefficient type is
050 *        <code>BigInteger</code>, the usage looks like
051 * 
052 *        <pre>
053 * BigInteger cofac = new BigInteger();
054 * GreatestCommonDivisor&lt;BigInteger&gt; engine;
055 * engine = GCDFactory.getImplementation(cofac);
056 * or engine = GCDFactory.getProxy(cofac);
057 * c = engine.gcd(a, b);
058 * </pre>
059 *
060 * <b>Todo:</b> Base decision also on degree vectors and number of
061 * variables of polynomials. Incorporate also number of CPUs / threads
062 * available (done with <code>GCDProxy</code>).
063 * 
064 * @see edu.jas.ufd.GreatestCommonDivisor#gcd(edu.jas.poly.GenPolynomial P,
065 *      edu.jas.poly.GenPolynomial S)
066 */
067
068public class GCDFactory {
069
070
071    private static final Logger logger = LogManager.getLogger(GCDFactory.class);
072
073
074    /**
075     * Protected factory constructor.
076     */
077    protected GCDFactory() {
078    }
079
080
081    /**
082     * Determine suitable implementation of gcd algorithms, case ModLong.
083     * @param fac ModLongRing.
084     * @return gcd algorithm implementation.
085     */
086    public static GreatestCommonDivisorAbstract<ModLong> getImplementation(ModLongRing fac) {
087        GreatestCommonDivisorAbstract<ModLong> ufd;
088        if (fac.isField()) {
089            ufd = new GreatestCommonDivisorModEval<ModLong>();
090            //ufd = new GreatestCommonDivisorSimple<ModLong>();
091            return ufd;
092        }
093        ufd = new GreatestCommonDivisorSubres<ModLong>();
094        return ufd;
095    }
096
097
098    /**
099     * Determine suitable proxy for gcd algorithms, case ModLong.
100     * @param fac ModLongRing.
101     * @return gcd algorithm implementation.
102     */
103    public static GreatestCommonDivisorAbstract<ModLong> getProxy(ModLongRing fac) {
104        GreatestCommonDivisorAbstract<ModLong> ufd1, ufd2;
105        ufd1 = new GreatestCommonDivisorSubres<ModLong>();
106        if (fac.isField()) {
107            ufd2 = new GreatestCommonDivisorModEval<ModLong>();
108        } else {
109            ufd2 = new GreatestCommonDivisorSimple<ModLong>();
110        }
111        return new GCDProxy<ModLong>(ufd1, ufd2);
112    }
113
114
115    /**
116     * Determine suitable implementation of gcd algorithms, case ModInteger.
117     * @param fac ModIntegerRing.
118     * @return gcd algorithm implementation.
119     */
120    public static GreatestCommonDivisorAbstract<ModInteger> getImplementation(ModIntegerRing fac) {
121        GreatestCommonDivisorAbstract<ModInteger> ufd;
122        if (fac.isField()) {
123            ufd = new GreatestCommonDivisorModEval<ModInteger>();
124            //ufd = new GreatestCommonDivisorSimple<ModInteger>();
125            return ufd;
126        }
127        ufd = new GreatestCommonDivisorSubres<ModInteger>();
128        return ufd;
129    }
130
131
132    /**
133     * Determine suitable proxy for gcd algorithms, case ModInteger.
134     * @param fac ModIntegerRing.
135     * @return gcd algorithm implementation.
136     */
137    public static GreatestCommonDivisorAbstract<ModInteger> getProxy(ModIntegerRing fac) {
138        GreatestCommonDivisorAbstract<ModInteger> ufd1, ufd2;
139        ufd1 = new GreatestCommonDivisorSubres<ModInteger>();
140        if (fac.isField()) {
141            ufd2 = new GreatestCommonDivisorModEval<ModInteger>();
142        } else {
143            ufd2 = new GreatestCommonDivisorSimple<ModInteger>();
144        }
145        return new GCDProxy<ModInteger>(ufd1, ufd2);
146    }
147
148
149    /**
150     * Determine suitable implementation of gcd algorithms, case BigInteger.
151     * @param fac BigInteger.
152     * @return gcd algorithm implementation.
153     */
154    @SuppressWarnings("unused")
155    public static GreatestCommonDivisorAbstract<BigInteger> getImplementation(BigInteger fac) {
156        GreatestCommonDivisorAbstract<BigInteger> ufd;
157        if (true) {
158            ufd = new GreatestCommonDivisorModular<ModLong>(); // dummy type
159        } else {
160            ufd = new GreatestCommonDivisorSubres<BigInteger>();
161            //ufd = new GreatestCommonDivisorPrimitive<BigInteger>();
162        }
163        return ufd;
164    }
165
166
167    /**
168     * Determine suitable procy for gcd algorithms, case BigInteger.
169     * @param fac BigInteger.
170     * @return gcd algorithm implementation.
171     */
172    public static GreatestCommonDivisorAbstract<BigInteger> getProxy(BigInteger fac) {
173        if (fac == null) {
174            throw new IllegalArgumentException("fac == null not supported");
175        }
176        GreatestCommonDivisorAbstract<BigInteger> ufd1, ufd2;
177        ufd1 = new GreatestCommonDivisorSubres<BigInteger>();
178        ufd2 = new GreatestCommonDivisorModular<ModLong>(); // dummy type
179        return new GCDProxy<BigInteger>(ufd1, ufd2);
180    }
181
182
183    /**
184     * Determine suitable implementation of gcd algorithms, case BigRational.
185     * @param fac BigRational.
186     * @return gcd algorithm implementation.
187     */
188    public static GreatestCommonDivisorAbstract<BigRational> getImplementation(BigRational fac) {
189        if (fac == null) {
190            throw new IllegalArgumentException("fac == null not supported");
191        }
192        GreatestCommonDivisorAbstract<BigRational> ufd;
193        ufd = new GreatestCommonDivisorPrimitive<BigRational>();
194        return ufd;
195    }
196
197
198    /**
199     * Determine suitable proxy for gcd algorithms, case BigRational.
200     * @param fac BigRational.
201     * @return gcd algorithm implementation.
202     */
203    public static GreatestCommonDivisorAbstract<BigRational> getProxy(BigRational fac) {
204        if (fac == null) {
205            throw new IllegalArgumentException("fac == null not supported");
206        }
207        GreatestCommonDivisorAbstract<BigRational> ufd1, ufd2;
208        ufd1 = new GreatestCommonDivisorSubres<BigRational>();
209        ufd2 = new GreatestCommonDivisorSimple<BigRational>();
210        return new GCDProxy<BigRational>(ufd1, ufd2);
211    }
212
213
214    /**
215     * Determine suitable implementation of gcd algorithms, other cases.
216     * @param fac RingFactory&lt;C&gt;.
217     * @return gcd algorithm implementation.
218     */
219    @SuppressWarnings("unchecked")
220    public static <C extends GcdRingElem<C>> GreatestCommonDivisorAbstract<C> getImplementation(
221                    RingFactory<C> fac) {
222        GreatestCommonDivisorAbstract/*raw type<C>*/ufd;
223        logger.debug("fac = " + fac.getClass().getName());
224        Object ofac = fac;
225        if (ofac instanceof BigInteger) {
226            ufd = new GreatestCommonDivisorModular<ModInteger>();
227            //ufd = new GreatestCommonDivisorSubres<BigInteger>();
228            //ufd = new GreatestCommonDivisorModular<ModInteger>(true);
229        } else if (ofac instanceof ModIntegerRing) {
230            ufd = new GreatestCommonDivisorModEval<ModInteger>();
231            //ufd = new GreatestCommonDivisorSimple<ModInteger>();
232        } else if (ofac instanceof ModLongRing) {
233            ufd = new GreatestCommonDivisorModEval<ModLong>();
234            //ufd = new GreatestCommonDivisorSimple<ModLong>();
235        } else if (ofac instanceof BigRational) {
236            ufd = new GreatestCommonDivisorSubres<BigRational>();
237        } else {
238            if (fac.isField()) {
239                ufd = new GreatestCommonDivisorSimple<C>();
240            } else {
241                ufd = new GreatestCommonDivisorSubres<C>();
242            }
243        }
244        logger.debug("implementation = " + ufd);
245        return ufd;
246    }
247
248
249    /**
250     * Determine suitable proxy for gcd algorithms, other cases.
251     * @param fac RingFactory&lt;C&gt;.
252     * @return gcd algorithm implementation. <b>Note:</b> This method contains a
253     *         hack for Google app engine to not use threads.
254     * @see edu.jas.kern.ComputerThreads#NO_THREADS
255     */
256    @SuppressWarnings("unchecked")
257    public static <C extends GcdRingElem<C>> GreatestCommonDivisorAbstract<C> getProxy(RingFactory<C> fac) {
258        if (ComputerThreads.NO_THREADS) { // hack for Google app engine
259            return GCDFactory.<C> getImplementation(fac);
260        }
261        GreatestCommonDivisorAbstract/*raw type<C>*/ufd;
262        logger.debug("fac = " + fac.getClass().getName());
263        Object ofac = fac;
264        if (ofac instanceof BigInteger) {
265            ufd = new GCDProxy<BigInteger>(new GreatestCommonDivisorSubres<BigInteger>(),
266                            new GreatestCommonDivisorModular<ModInteger>());
267        } else if (ofac instanceof ModIntegerRing) {
268            ufd = new GCDProxy<ModInteger>(new GreatestCommonDivisorSimple<ModInteger>(), // Subres
269                            new GreatestCommonDivisorModEval<ModInteger>());
270        } else if (ofac instanceof ModLongRing) {
271            ufd = new GCDProxy<ModLong>(new GreatestCommonDivisorSimple<ModLong>(), // Subres
272                            new GreatestCommonDivisorModEval<ModLong>());
273        } else if (ofac instanceof BigRational) {
274            ufd = new GCDProxy<BigRational>(new GreatestCommonDivisorSubres<BigRational>(),
275                            new GreatestCommonDivisorPrimitive<BigRational>()); //Simple
276        } else {
277            if (fac.isField()) {
278                ufd = new GCDProxy<C>(new GreatestCommonDivisorSimple<C>(),
279                                new GreatestCommonDivisorSubres<C>());
280            } else {
281                ufd = new GCDProxy<C>(new GreatestCommonDivisorSubres<C>(),
282                                new GreatestCommonDivisorPrimitive<C>()); // no resultant
283            }
284        }
285        logger.debug("ufd = " + ufd);
286        return ufd;
287    }
288
289}