001/*
002 * $Id$
003 */
004
005package edu.jas.ufd;
006
007
008import java.util.ArrayList;
009import java.util.Collection;
010import java.util.List;
011import java.util.Map;
012import java.util.SortedMap;
013import java.util.TreeMap;
014
015import org.apache.logging.log4j.LogManager;
016import org.apache.logging.log4j.Logger;
017
018import edu.jas.arith.BigInteger;
019import edu.jas.arith.BigRational;
020import edu.jas.poly.AlgebraicNumber;
021import edu.jas.poly.AlgebraicNumberRing;
022import edu.jas.poly.ExpVector;
023import edu.jas.poly.GenPolynomial;
024import edu.jas.poly.GenPolynomialRing;
025import edu.jas.poly.PolyUtil;
026import edu.jas.poly.TermOrderByName;
027import edu.jas.structure.GcdRingElem;
028import edu.jas.structure.RingElem;
029import edu.jas.structure.RingFactory;
030import edu.jas.structure.UnaryFunctor;
031import edu.jas.util.ListUtil;
032
033
034/**
035 * Polynomial ufd utilities. For example conversion between different
036 * representations and Kronecker substitution.
037 * @author Heinz Kredel
038 */
039
040public class PolyUfdUtil {
041
042
043    private static final Logger logger = LogManager.getLogger(PolyUfdUtil.class);
044
045
046    private static final boolean debug = logger.isDebugEnabled();
047
048
049    /**
050     * Factors of Quotient rational function.
051     * @param A rational function to be factored.
052     * @return list of irreducible rational function parts.
053     */
054    public static <C extends GcdRingElem<C>> SortedMap<Quotient<C>, Long> factors(Quotient<C> A) {
055        SortedMap<Quotient<C>, Long> factors = new TreeMap<Quotient<C>, Long>();
056        if (A == null || A.isZERO()) {
057            return factors;
058        }
059        if (A.abs().isONE()) {
060            factors.put(A, 1L);
061            return factors;
062        }
063        QuotientRing<C> qfac = A.ring;
064        GenPolynomialRing<C> fac = qfac.ring;
065        FactorAbstract<C> eng = FactorFactory.<C> getImplementation(fac.coFac);
066        GenPolynomial<C> n = A.num;
067        SortedMap<GenPolynomial<C>, Long> numfactors = eng.factors(n);
068        for (Map.Entry<GenPolynomial<C>, Long> me : numfactors.entrySet()) {
069            GenPolynomial<C> f = me.getKey();
070            Long e = me.getValue();
071            Quotient<C> q = new Quotient<C>(qfac, f);
072            factors.put(q, e);
073        }
074        GenPolynomial<C> d = A.den;
075        if (d.isONE()) {
076            return factors;
077        }
078        GenPolynomial<C> one = fac.getONE();
079        SortedMap<GenPolynomial<C>, Long> denfactors = eng.factors(d);
080        for (Map.Entry<GenPolynomial<C>, Long> me : denfactors.entrySet()) {
081            GenPolynomial<C> f = me.getKey();
082            Long e = me.getValue();
083            Quotient<C> q = new Quotient<C>(qfac, one, f);
084            factors.put(q, e);
085        }
086        return factors;
087    }
088
089
090    /**
091     * Quotient is (squarefree) factorization.
092     * @param P Quotient.
093     * @param F = [p_1 -&gt; e_1, ..., p_k -&gt; e_k].
094     * @return true if P = prod_{i=1,...,k} p_i**e_i, else false.
095     */
096    public static <C extends GcdRingElem<C>> boolean isFactorization(Quotient<C> P,
097                    SortedMap<Quotient<C>, Long> F) {
098        if (P == null || F == null) {
099            throw new IllegalArgumentException("P and F may not be null");
100        }
101        if (P.isZERO() && F.size() == 0) {
102            return true;
103        }
104        Quotient<C> t = P.ring.getONE();
105        for (Map.Entry<Quotient<C>, Long> me : F.entrySet()) {
106            Quotient<C> f = me.getKey();
107            Long E = me.getValue();
108            long e = E.longValue();
109            Quotient<C> g = f.power(e);
110            t = t.multiply(g);
111        }
112        boolean f = P.equals(t) || P.equals(t.negate());
113        if (!f) {
114            P = P.monic();
115            t = t.monic();
116            f = P.equals(t) || P.equals(t.negate());
117            if (f) {
118                return f;
119            }
120            logger.info("no factorization(map): F = " + F + ", P = " + P + ", t = " + t);
121        }
122        return f;
123    }
124
125
126    /**
127     * Integral polynomial from rational function coefficients. Represent as
128     * polynomial with integral polynomial coefficients by multiplication with
129     * the lcm of the numerators of the rational function coefficients.
130     * @param fac result polynomial factory.
131     * @param A polynomial with rational function coefficients to be converted.
132     * @return polynomial with integral polynomial coefficients.
133     */
134    public static <C extends GcdRingElem<C>> GenPolynomial<GenPolynomial<C>> integralFromQuotientCoefficients(
135                    GenPolynomialRing<GenPolynomial<C>> fac, GenPolynomial<Quotient<C>> A) {
136        GenPolynomial<GenPolynomial<C>> B = fac.getZERO().copy();
137        if (A == null || A.isZERO()) {
138            return B;
139        }
140        GenPolynomial<C> c = null;
141        GenPolynomial<C> d;
142        GenPolynomial<C> x;
143        GreatestCommonDivisor<C> ufd = new GreatestCommonDivisorSubres<C>();
144        int s = 0;
145        // lcm of denominators
146        for (Quotient<C> y : A.getMap().values()) {
147            x = y.den;
148            // c = lcm(c,x)
149            if (c == null) {
150                c = x;
151                s = x.signum();
152            } else {
153                d = ufd.gcd(c, x);
154                c = c.multiply(x.divide(d));
155            }
156        }
157        if (s < 0) {
158            c = c.negate();
159        }
160        for (Map.Entry<ExpVector, Quotient<C>> y : A.getMap().entrySet()) {
161            ExpVector e = y.getKey();
162            Quotient<C> a = y.getValue();
163            // p = n*(c/d)
164            GenPolynomial<C> b = c.divide(a.den);
165            GenPolynomial<C> p = a.num.multiply(b);
166            //B = B.sum( p, e ); // inefficient
167            B.doPutToMap(e, p);
168        }
169        return B;
170    }
171
172
173    /**
174     * Integral polynomial from rational function coefficients. Represent as
175     * polynomial with integral polynomial coefficients by multiplication with
176     * the lcm of the numerators of the rational function coefficients.
177     * @param fac result polynomial factory.
178     * @param L list of polynomial with rational function coefficients to be
179     *            converted.
180     * @return list of polynomials with integral polynomial coefficients.
181     */
182    public static <C extends GcdRingElem<C>> List<GenPolynomial<GenPolynomial<C>>> integralFromQuotientCoefficients(
183                    GenPolynomialRing<GenPolynomial<C>> fac, Collection<GenPolynomial<Quotient<C>>> L) {
184        if (L == null) {
185            return null;
186        }
187        List<GenPolynomial<GenPolynomial<C>>> list = new ArrayList<GenPolynomial<GenPolynomial<C>>>(L.size());
188        for (GenPolynomial<Quotient<C>> p : L) {
189            list.add(integralFromQuotientCoefficients(fac, p));
190        }
191        return list;
192    }
193
194
195    /**
196     * Rational function from integral polynomial coefficients. Represent as
197     * polynomial with type Quotient<C> coefficients.
198     * @param fac result polynomial factory.
199     * @param A polynomial with integral polynomial coefficients to be
200     *            converted.
201     * @return polynomial with type Quotient<C> coefficients.
202     */
203    public static <C extends GcdRingElem<C>> GenPolynomial<Quotient<C>> quotientFromIntegralCoefficients(
204                    GenPolynomialRing<Quotient<C>> fac, GenPolynomial<GenPolynomial<C>> A) {
205        GenPolynomial<Quotient<C>> B = fac.getZERO().copy();
206        if (A == null || A.isZERO()) {
207            return B;
208        }
209        RingFactory<Quotient<C>> cfac = fac.coFac;
210        QuotientRing<C> qfac = (QuotientRing<C>) cfac;
211        for (Map.Entry<ExpVector, GenPolynomial<C>> y : A.getMap().entrySet()) {
212            ExpVector e = y.getKey();
213            GenPolynomial<C> a = y.getValue();
214            Quotient<C> p = new Quotient<C>(qfac, a); // can not be zero
215            if (!p.isZERO()) {
216                //B = B.sum( p, e ); // inefficient
217                B.doPutToMap(e, p);
218            }
219        }
220        return B;
221    }
222
223
224    /**
225     * Rational function from integral polynomial coefficients. Represent as
226     * polynomial with type Quotient<C> coefficients.
227     * @param fac result polynomial factory.
228     * @param L list of polynomials with integral polynomial coefficients to be
229     *            converted.
230     * @return list of polynomials with type Quotient<C> coefficients.
231     */
232    public static <C extends GcdRingElem<C>> List<GenPolynomial<Quotient<C>>> quotientFromIntegralCoefficients(
233                    GenPolynomialRing<Quotient<C>> fac, Collection<GenPolynomial<GenPolynomial<C>>> L) {
234        if (L == null) {
235            return null;
236        }
237        List<GenPolynomial<Quotient<C>>> list = new ArrayList<GenPolynomial<Quotient<C>>>(L.size());
238        for (GenPolynomial<GenPolynomial<C>> p : L) {
239            list.add(quotientFromIntegralCoefficients(fac, p));
240        }
241        return list;
242    }
243
244
245    /**
246     * From BigInteger coefficients. Represent as polynomial with type
247     * GenPolynomial&lt;C&gt; coefficients, e.g. ModInteger or BigRational.
248     * @param fac result polynomial factory.
249     * @param A polynomial with GenPolynomial&lt;BigInteger&gt; coefficients to
250     *            be converted.
251     * @return polynomial with type GenPolynomial&lt;C&gt; coefficients.
252     */
253    public static <C extends RingElem<C>> GenPolynomial<GenPolynomial<C>> fromIntegerCoefficients(
254                    GenPolynomialRing<GenPolynomial<C>> fac, GenPolynomial<GenPolynomial<BigInteger>> A) {
255        GenPolynomial<GenPolynomial<C>> B = fac.getZERO().copy();
256        if (A == null || A.isZERO()) {
257            return B;
258        }
259        RingFactory<GenPolynomial<C>> cfac = fac.coFac;
260        GenPolynomialRing<C> rfac = (GenPolynomialRing<C>) cfac;
261        for (Map.Entry<ExpVector, GenPolynomial<BigInteger>> y : A.getMap().entrySet()) {
262            ExpVector e = y.getKey();
263            GenPolynomial<BigInteger> a = y.getValue();
264            GenPolynomial<C> p = PolyUtil.<C> fromIntegerCoefficients(rfac, a);
265            if (!p.isZERO()) {
266                //B = B.sum( p, e ); // inefficient
267                B.doPutToMap(e, p);
268            }
269        }
270        return B;
271    }
272
273
274    /**
275     * From BigInteger coefficients. Represent as polynomial with type
276     * GenPolynomial&lt;C&gt; coefficients, e.g. ModInteger or BigRational.
277     * @param fac result polynomial factory.
278     * @param L polynomial list with GenPolynomial&lt;BigInteger&gt;
279     *            coefficients to be converted.
280     * @return polynomial list with polynomials with type GenPolynomial&lt;C&gt;
281     *         coefficients.
282     */
283    public static <C extends RingElem<C>> List<GenPolynomial<GenPolynomial<C>>> fromIntegerCoefficients(
284                    GenPolynomialRing<GenPolynomial<C>> fac,
285                    List<GenPolynomial<GenPolynomial<BigInteger>>> L) {
286        List<GenPolynomial<GenPolynomial<C>>> K = null;
287        if (L == null) {
288            return K;
289        }
290        K = new ArrayList<GenPolynomial<GenPolynomial<C>>>(L.size());
291        if (L.size() == 0) {
292            return K;
293        }
294        for (GenPolynomial<GenPolynomial<BigInteger>> a : L) {
295            GenPolynomial<GenPolynomial<C>> b = fromIntegerCoefficients(fac, a);
296            K.add(b);
297        }
298        return K;
299    }
300
301
302    //------------------------------
303
304    /**
305     * BigInteger from BigRational coefficients. Represent as polynomial with
306     * type GenPolynomial&lt;BigInteger&gt; coefficients.
307     * @param fac result polynomial factory.
308     * @param A polynomial with GenPolynomial&lt;BigRational&gt; coefficients to
309     *            be converted.
310     * @return polynomial with type GenPolynomial&lt;BigInteger&gt;
311     *         coefficients.
312     */
313    public static GenPolynomial<GenPolynomial<BigInteger>> integerFromRationalCoefficients(
314                    GenPolynomialRing<GenPolynomial<BigInteger>> fac,
315                    GenPolynomial<GenPolynomial<BigRational>> A) {
316        GenPolynomial<GenPolynomial<BigInteger>> B = fac.getZERO().copy();
317        if (A == null || A.isZERO()) {
318            return B;
319        }
320        java.math.BigInteger gcd = null;
321        java.math.BigInteger lcm = null;
322        int sLCM = 0;
323        int sGCD = 0;
324        // lcm of all denominators
325        for (GenPolynomial<BigRational> av : A.getMap().values()) {
326            for (BigRational y : av.getMap().values()) {
327                java.math.BigInteger numerator = y.numerator();
328                java.math.BigInteger denominator = y.denominator();
329                // lcm = lcm(lcm,x)
330                if (lcm == null) {
331                    lcm = denominator;
332                    sLCM = denominator.signum();
333                } else {
334                    java.math.BigInteger d = lcm.gcd(denominator);
335                    lcm = lcm.multiply(denominator.divide(d));
336                }
337                // gcd = gcd(gcd,x)
338                if (gcd == null) {
339                    gcd = numerator;
340                    sGCD = numerator.signum();
341                } else {
342                    gcd = gcd.gcd(numerator);
343                }
344            }
345            //System.out.println("gcd = " + gcd + ", lcm = " + lcm);
346        }
347        if (sLCM < 0) {
348            lcm = lcm.negate();
349        }
350        if (sGCD < 0) {
351            gcd = gcd.negate();
352        }
353        //System.out.println("gcd** = " + gcd + ", lcm = " + lcm);
354        RingFactory<GenPolynomial<BigInteger>> cfac = fac.coFac;
355        GenPolynomialRing<BigInteger> rfac = (GenPolynomialRing<BigInteger>) cfac;
356        for (Map.Entry<ExpVector, GenPolynomial<BigRational>> y : A.getMap().entrySet()) {
357            ExpVector e = y.getKey();
358            GenPolynomial<BigRational> a = y.getValue();
359            // common denominator over all coefficients
360            GenPolynomial<BigInteger> p = PolyUtil.integerFromRationalCoefficients(rfac, gcd, lcm, a);
361            if (!p.isZERO()) {
362                //B = B.sum( p, e ); // inefficient
363                B.doPutToMap(e, p);
364            }
365        }
366        return B;
367    }
368
369
370    /**
371     * BigInteger from BigRational coefficients. Represent as polynomial with
372     * type GenPolynomial&lt;BigInteger&gt; coefficients.
373     * @param fac result polynomial factory.
374     * @param L polynomial list with GenPolynomial&lt;BigRational&gt;
375     *            coefficients to be converted.
376     * @return polynomial list with polynomials with type
377     *         GenPolynomial&lt;BigInteger&gt; coefficients.
378     */
379    public static List<GenPolynomial<GenPolynomial<BigInteger>>> integerFromRationalCoefficients(
380                    GenPolynomialRing<GenPolynomial<BigInteger>> fac,
381                    List<GenPolynomial<GenPolynomial<BigRational>>> L) {
382        List<GenPolynomial<GenPolynomial<BigInteger>>> K = null;
383        if (L == null) {
384            return K;
385        }
386        K = new ArrayList<GenPolynomial<GenPolynomial<BigInteger>>>(L.size());
387        if (L.isEmpty()) {
388            return K;
389        }
390        for (GenPolynomial<GenPolynomial<BigRational>> a : L) {
391            GenPolynomial<GenPolynomial<BigInteger>> b = integerFromRationalCoefficients(fac, a);
392            K.add(b);
393        }
394        return K;
395    }
396
397
398    /**
399     * Introduce lower variable. Represent as polynomial with type
400     * GenPolynomial&lt;C&gt; coefficients.
401     * @param rfac result polynomial factory.
402     * @param A polynomial to be extended.
403     * @return polynomial with type GenPolynomial&lt;C&gt; coefficients.
404     */
405    public static <C extends GcdRingElem<C>> GenPolynomial<GenPolynomial<C>> introduceLowerVariable(
406                    GenPolynomialRing<GenPolynomial<C>> rfac, GenPolynomial<C> A) {
407        if (A == null || rfac == null) {
408            return null;
409        }
410        GenPolynomial<GenPolynomial<C>> Pc = rfac.getONE().multiply(A);
411        if (Pc.isZERO()) {
412            return Pc;
413        }
414        Pc = PolyUtil.<C> switchVariables(Pc);
415        return Pc;
416    }
417
418
419    /**
420     * From AlgebraicNumber coefficients. Represent as polynomial with type
421     * GenPolynomial&lt;C&gt; coefficients, e.g. ModInteger or BigRational.
422     * @param rfac result polynomial factory.
423     * @param A polynomial with AlgebraicNumber coefficients to be converted.
424     * @param k for (y-k x) substitution.
425     * @return polynomial with type GenPolynomial&lt;C&gt; coefficients.
426     */
427    public static <C extends GcdRingElem<C>> GenPolynomial<GenPolynomial<C>> substituteFromAlgebraicCoefficients(
428                    GenPolynomialRing<GenPolynomial<C>> rfac, GenPolynomial<AlgebraicNumber<C>> A, long k) {
429        if (A == null || rfac == null) {
430            return null;
431        }
432        if (A.isZERO()) {
433            return rfac.getZERO();
434        }
435        // setup x - k alpha
436        GenPolynomialRing<AlgebraicNumber<C>> apfac = A.ring;
437        GenPolynomial<AlgebraicNumber<C>> x = apfac.univariate(0);
438        AlgebraicNumberRing<C> afac = (AlgebraicNumberRing<C>) A.ring.coFac;
439        AlgebraicNumber<C> alpha = afac.getGenerator();
440        AlgebraicNumber<C> ka = afac.fromInteger(k);
441        GenPolynomial<AlgebraicNumber<C>> s = x.subtract(ka.multiply(alpha)); // x - k alpha
442        //System.out.println("x - k alpha = " + s);
443        //System.out.println("s.ring = " + s.ring.toScript());
444        if (debug) {
445            logger.info("x - k alpha: " + s);
446        }
447        // substitute, convert and switch
448        //System.out.println("Asubs = " + A);
449        GenPolynomial<AlgebraicNumber<C>> B;
450        if (s.ring.nvar <= 1) {
451            B = PolyUtil.<AlgebraicNumber<C>> substituteMain(A, s);
452        } else {
453            B = PolyUtil.<AlgebraicNumber<C>> substituteUnivariateMult(A, s);
454        }
455        //System.out.println("Bsubs = " + B);
456        GenPolynomial<GenPolynomial<C>> Pc = PolyUtil.<C> fromAlgebraicCoefficients(rfac, B); // Q[alpha][x]
457        //System.out.println("Pc[a,x] = " + Pc);
458        Pc = PolyUtil.<C> switchVariables(Pc); // Q[x][alpha]
459        //System.out.println("Pc[x,a] = " + Pc);
460        return Pc;
461    }
462
463
464    /**
465     * Convert to AlgebraicNumber coefficients. Represent as polynomial with
466     * AlgebraicNumber<C> coefficients, C is e.g. ModInteger or BigRational.
467     * @param pfac result polynomial factory.
468     * @param A polynomial with GenPolynomial&lt;BigInteger&gt; coefficients to
469     *            be converted.
470     * @param k for (y-k x) substitution.
471     * @return polynomial with AlgebraicNumber&lt;C&gt; coefficients.
472     */
473    public static <C extends GcdRingElem<C>> GenPolynomial<AlgebraicNumber<C>> substituteConvertToAlgebraicCoefficients(
474                    GenPolynomialRing<AlgebraicNumber<C>> pfac, GenPolynomial<C> A, long k) {
475        if (A == null || pfac == null) {
476            return null;
477        }
478        if (A.isZERO()) {
479            return pfac.getZERO();
480        }
481        // convert to Q(alpha)[x]
482        GenPolynomial<AlgebraicNumber<C>> B = PolyUtil.<C> convertToAlgebraicCoefficients(pfac, A);
483        // setup x .+. k alpha for back substitution
484        GenPolynomial<AlgebraicNumber<C>> x = pfac.univariate(0);
485        AlgebraicNumberRing<C> afac = (AlgebraicNumberRing<C>) pfac.coFac;
486        AlgebraicNumber<C> alpha = afac.getGenerator();
487        AlgebraicNumber<C> ka = afac.fromInteger(k);
488        GenPolynomial<AlgebraicNumber<C>> s = x.sum(ka.multiply(alpha)); // x + k alpha
489        // substitute
490        //System.out.println("s.ring = " + s.ring.toScript());
491        GenPolynomial<AlgebraicNumber<C>> N;
492        if (s.ring.nvar <= 1) {
493            N = PolyUtil.<AlgebraicNumber<C>> substituteMain(B, s);
494        } else {
495            N = PolyUtil.<AlgebraicNumber<C>> substituteUnivariateMult(B, s);
496        }
497        return N;
498    }
499
500
501    /**
502     * Norm of a polynomial with AlgebraicNumber coefficients.
503     * @param A uni or multivariate polynomial from
504     *            GenPolynomial&lt;AlgebraicNumber&lt;C&gt;&gt;.
505     * @param k for (y - k x) substitution.
506     * @return norm(A) = res_x(A(x,y),m(x)) in GenPolynomialRing&lt;C&gt;.
507     */
508    public static <C extends GcdRingElem<C>> GenPolynomial<C> norm(GenPolynomial<AlgebraicNumber<C>> A,
509                    long k) {
510        if (A == null) {
511            return null;
512        }
513        GenPolynomialRing<AlgebraicNumber<C>> pfac = A.ring; // Q(alpha)[x]
514        //if (pfac.nvar > 1) {
515        //    throw new IllegalArgumentException("only for univariate polynomials");
516        //}
517        AlgebraicNumberRing<C> afac = (AlgebraicNumberRing<C>) pfac.coFac;
518        GenPolynomial<C> agen = afac.modul;
519        GenPolynomialRing<C> cfac = afac.ring;
520        if (A.isZERO()) {
521            return cfac.getZERO();
522        }
523        AlgebraicNumber<C> ldcf = A.leadingBaseCoefficient();
524        if (!ldcf.isONE()) {
525            A = A.monic();
526        }
527        GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(cfac, pfac);
528        //System.out.println("rfac = " + rfac.toScript());
529
530        // transform minimal polynomial to bi-variate polynomial
531        GenPolynomial<GenPolynomial<C>> Ac = PolyUfdUtil.<C> introduceLowerVariable(rfac, agen);
532
533        // transform to bi-variate polynomial, 
534        // switching varaible sequence from Q[alpha][x] to Q[X][alpha]
535        GenPolynomial<GenPolynomial<C>> Pc = PolyUfdUtil.<C> substituteFromAlgebraicCoefficients(rfac, A, k);
536        Pc = PolyUtil.<C> monic(Pc);
537        //System.out.println("Pc = " + Pc.toScript() + " :: " + Pc.ring.toScript());
538
539        GreatestCommonDivisorSubres<C> engine = new GreatestCommonDivisorSubres<C>( /*cfac.coFac*/);
540        // = (GreatestCommonDivisorAbstract<C>)GCDFactory.<C>getImplementation( cfac.coFac );
541
542        GenPolynomial<GenPolynomial<C>> Rc = engine.recursiveUnivariateResultant(Pc, Ac);
543        //System.out.println("Rc = " + Rc.toScript());
544        GenPolynomial<C> res = Rc.leadingBaseCoefficient();
545        res = res.monic();
546        return res;
547    }
548
549
550    /**
551     * Norm of a polynomial with AlgebraicNumber coefficients.
552     * @param A polynomial from GenPolynomial&lt;AlgebraicNumber&lt;C&gt;&gt;.
553     * @return norm(A) = resultant_x( A(x,y), m(x) ) in K[y].
554     */
555    public static <C extends GcdRingElem<C>> GenPolynomial<C> norm(GenPolynomial<AlgebraicNumber<C>> A) {
556        return norm(A, 0L);
557    }
558
559
560    /**
561     * Ensure that the field property is determined. Checks if modul is
562     * irreducible and modifies the algebraic number ring.
563     * @param afac algebraic number ring.
564     */
565    public static <C extends GcdRingElem<C>> void ensureFieldProperty(AlgebraicNumberRing<C> afac) {
566        if (afac.getField() != -1) {
567            return;
568        }
569        if (!afac.ring.coFac.isField()) {
570            afac.setField(false);
571            return;
572        }
573        Factorization<C> mf = FactorFactory.<C> getImplementation(afac.ring);
574        if (mf.isIrreducible(afac.modul)) {
575            afac.setField(true);
576        } else {
577            afac.setField(false);
578        }
579    }
580
581
582    /**
583     * Construct a random irreducible univariate polynomial of degree d.
584     * @param cfac coefficient ring.
585     * @param degree of random polynomial.
586     * @return irreducible univariate polynomial.
587     */
588    public static <C extends GcdRingElem<C>> GenPolynomial<C> randomIrreduciblePolynomial(RingFactory<C> cfac,
589                    int degree) {
590        if (!cfac.isField()) {
591            throw new IllegalArgumentException("coefficient ring must be a field " + cfac);
592        }
593        GenPolynomialRing<C> ring = new GenPolynomialRing<C>(cfac, 1, TermOrderByName.INVLEX);
594        Factorization<C> eng = FactorFactory.<C> getImplementation(ring);
595        GenPolynomial<C> mod = ring.getZERO();
596        int k = cfac.characteristic().bitLength(); // log
597        if (k < 3) {
598            k = 7;
599        }
600        int l = degree / 2 + 2;
601        int d = degree + 1;
602        float q = 0.55f;
603        for (;;) {
604            mod = ring.random(k, l, d, q).monic();
605            if (mod.degree() != degree) {
606                mod = mod.sum(ring.univariate(0, degree));
607            }
608            if (mod.trailingBaseCoefficient().isZERO()) {
609                mod = mod.sum(ring.getONE());
610            }
611            //System.out.println("algebriacNumberField: mod = " + mod + ", k = " + k);
612            if (eng.isIrreducible(mod)) {
613                break;
614            }
615        }
616        return mod;
617    }
618
619
620    /**
621     * Construct an algebraic number field of degree d. Uses a random
622     * irreducible polynomial of degree d as modulus of the algebraic number
623     * ring.
624     * @param cfac coefficient ring.
625     * @param degree of random polynomial.
626     * @return algebraic number field.
627     */
628    public static <C extends GcdRingElem<C>> AlgebraicNumberRing<C> algebraicNumberField(RingFactory<C> cfac,
629                    int degree) {
630        GenPolynomial<C> mod = randomIrreduciblePolynomial(cfac, degree);
631        AlgebraicNumberRing<C> afac = new AlgebraicNumberRing<C>(mod, true);
632        return afac;
633    }
634
635
636    /**
637     * Kronecker substitution. Substitute x_i by x**d**(i-1) to construct a
638     * univariate polynomial.
639     * @param A polynomial to be converted.
640     * @return a univariate polynomial.
641     */
642    public static <C extends GcdRingElem<C>> GenPolynomial<C> substituteKronecker(GenPolynomial<C> A) {
643        if (A == null) {
644            return A;
645        }
646        long d = A.degree() + 1L;
647        return substituteKronecker(A, d);
648    }
649
650
651    /**
652     * Kronecker substitution. Substitute x_i by x**d**(i-1) to construct a
653     * univariate polynomial.
654     * @param A polynomial to be converted.
655     * @return a univariate polynomial.
656     */
657    public static <C extends GcdRingElem<C>> GenPolynomial<C> substituteKronecker(GenPolynomial<C> A,
658                    long d) {
659        if (A == null) {
660            return A;
661        }
662        RingFactory<C> cfac = A.ring.coFac;
663        GenPolynomialRing<C> ufac = new GenPolynomialRing<C>(cfac, 1);
664        GenPolynomial<C> B = ufac.getZERO().copy();
665        if (A.isZERO()) {
666            return B;
667        }
668        for (Map.Entry<ExpVector, C> y : A.getMap().entrySet()) {
669            ExpVector e = y.getKey();
670            C a = y.getValue();
671            long f = 0L;
672            long h = 1L;
673            for (int i = 0; i < e.length(); i++) {
674                long j = e.getVal(i) * h;
675                f += j;
676                h *= d;
677            }
678            ExpVector g = ExpVector.create(1, 0, f);
679            B.doPutToMap(g, a);
680        }
681        return B;
682    }
683
684
685    /**
686     * Kronecker substitution. Substitute x_i by x**d**(i-1) to construct
687     * univariate polynomials.
688     * @param A list of polynomials to be converted.
689     * @return a list of univariate polynomials.
690     */
691    public static <C extends GcdRingElem<C>> List<GenPolynomial<C>> substituteKronecker(
692                    List<GenPolynomial<C>> A, int d) {
693        if (A == null || A.get(0) == null) {
694            return null;
695        }
696        return ListUtil.<GenPolynomial<C>, GenPolynomial<C>> map(A, new SubstKronecker<C>(d));
697    }
698
699
700    /**
701     * Kronecker back substitution. Substitute x**d**(i-1) to x_i to construct a
702     * multivariate polynomial.
703     * @param A polynomial to be converted.
704     * @param fac result polynomial factory.
705     * @return a multivariate polynomial.
706     */
707    public static <C extends GcdRingElem<C>> GenPolynomial<C> backSubstituteKronecker(
708                    GenPolynomialRing<C> fac, GenPolynomial<C> A, long d) {
709        if (A == null) {
710            return A;
711        }
712        if (fac == null) {
713            throw new IllegalArgumentException("null factory not allowed ");
714        }
715        int n = fac.nvar;
716        GenPolynomial<C> B = fac.getZERO().copy();
717        if (A.isZERO()) {
718            return B;
719        }
720        for (Map.Entry<ExpVector, C> y : A.getMap().entrySet()) {
721            ExpVector e = y.getKey();
722            C a = y.getValue();
723            long f = e.getVal(0);
724            ExpVector g = ExpVector.create(n);
725            for (int i = 0; i < n; i++) {
726                long j = f % d;
727                f /= d;
728                g = g.subst(i, j);
729            }
730            B.doPutToMap(g, a);
731        }
732        return B;
733    }
734
735
736    /**
737     * Kronecker back substitution. Substitute x**d**(i-1) to x_i to construct
738     * multivariate polynomials.
739     * @param A list of polynomials to be converted.
740     * @param fac result polynomial factory.
741     * @return a list of multivariate polynomials.
742     */
743    public static <C extends GcdRingElem<C>> List<GenPolynomial<C>> backSubstituteKronecker(
744                    GenPolynomialRing<C> fac, List<GenPolynomial<C>> A, long d) {
745        return ListUtil.<GenPolynomial<C>, GenPolynomial<C>> map(A, new BackSubstKronecker<C>(fac, d));
746    }
747
748}
749
750
751/**
752 * Kronecker substitutuion functor.
753 */
754class SubstKronecker<C extends GcdRingElem<C>> implements UnaryFunctor<GenPolynomial<C>, GenPolynomial<C>> {
755
756
757    final long d;
758
759
760    public SubstKronecker(long d) {
761        this.d = d;
762    }
763
764
765    public GenPolynomial<C> eval(GenPolynomial<C> c) {
766        if (c == null) {
767            return null;
768        }
769        return PolyUfdUtil.<C> substituteKronecker(c, d);
770    }
771}
772
773
774/**
775 * Kronecker back substitutuion functor.
776 */
777class BackSubstKronecker<C extends GcdRingElem<C>>
778                implements UnaryFunctor<GenPolynomial<C>, GenPolynomial<C>> {
779
780
781    final long d;
782
783
784    final GenPolynomialRing<C> fac;
785
786
787    public BackSubstKronecker(GenPolynomialRing<C> fac, long d) {
788        this.d = d;
789        this.fac = fac;
790    }
791
792
793    public GenPolynomial<C> eval(GenPolynomial<C> c) {
794        if (c == null) {
795            return null;
796        }
797        return PolyUfdUtil.<C> backSubstituteKronecker(fac, c, d);
798    }
799}