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