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