001/*
002 * $Id: PolyUfdUtil.java 4125 2012-08-19 19:05:22Z kredel $
003 */
004
005package edu.jas.ufd;
006
007
008import java.util.ArrayList;
009import java.util.Collection;
010import java.util.List;
011import java.util.Map;
012
013import org.apache.log4j.Logger;
014
015import edu.jas.arith.BigInteger;
016import edu.jas.poly.AlgebraicNumber;
017import edu.jas.poly.AlgebraicNumberRing;
018import edu.jas.poly.ExpVector;
019import edu.jas.poly.GenPolynomial;
020import edu.jas.poly.GenPolynomialRing;
021import edu.jas.poly.PolyUtil;
022import edu.jas.structure.GcdRingElem;
023import edu.jas.structure.RingElem;
024import edu.jas.structure.RingFactory;
025import edu.jas.structure.UnaryFunctor;
026import edu.jas.util.ListUtil;
027
028
029/**
030 * Polynomial ufd utilities, like conversion between different representations
031 * and Hensel lifting.
032 * @author Heinz Kredel
033 */
034
035public class PolyUfdUtil {
036
037
038    private static final Logger logger = Logger.getLogger(PolyUfdUtil.class);
039
040
041    private static boolean debug = logger.isDebugEnabled();
042
043
044    /**
045     * Integral polynomial from rational function coefficients. Represent as
046     * polynomial with integral polynomial coefficients by multiplication with
047     * the lcm of the numerators of the rational function coefficients.
048     * @param fac result polynomial factory.
049     * @param A polynomial with rational function coefficients to be converted.
050     * @return polynomial with integral polynomial coefficients.
051     */
052    public static <C extends GcdRingElem<C>> GenPolynomial<GenPolynomial<C>> integralFromQuotientCoefficients(
053                    GenPolynomialRing<GenPolynomial<C>> fac, GenPolynomial<Quotient<C>> A) {
054        GenPolynomial<GenPolynomial<C>> B = fac.getZERO().copy();
055        if (A == null || A.isZERO()) {
056            return B;
057        }
058        GenPolynomial<C> c = null;
059        GenPolynomial<C> d;
060        GenPolynomial<C> x;
061        GreatestCommonDivisor<C> ufd = new GreatestCommonDivisorSubres<C>();
062        int s = 0;
063        // lcm of denominators
064        for (Quotient<C> y : A.getMap().values()) {
065            x = y.den;
066            // c = lcm(c,x)
067            if (c == null) {
068                c = x;
069                s = x.signum();
070            } else {
071                d = ufd.gcd(c, x);
072                c = c.multiply(x.divide(d));
073            }
074        }
075        if (s < 0) {
076            c = c.negate();
077        }
078        for (Map.Entry<ExpVector, Quotient<C>> y : A.getMap().entrySet()) {
079            ExpVector e = y.getKey();
080            Quotient<C> a = y.getValue();
081            // p = n*(c/d)
082            GenPolynomial<C> b = c.divide(a.den);
083            GenPolynomial<C> p = a.num.multiply(b);
084            //B = B.sum( p, e ); // inefficient
085            B.doPutToMap(e, p);
086        }
087        return B;
088    }
089
090
091    /**
092     * Integral polynomial from rational function coefficients. Represent as
093     * polynomial with integral polynomial coefficients by multiplication with
094     * the lcm of the numerators of the rational function coefficients.
095     * @param fac result polynomial factory.
096     * @param L list of polynomial with rational function coefficients to be
097     *            converted.
098     * @return list of polynomials with integral polynomial coefficients.
099     */
100    public static <C extends GcdRingElem<C>> List<GenPolynomial<GenPolynomial<C>>> integralFromQuotientCoefficients(
101                    GenPolynomialRing<GenPolynomial<C>> fac, Collection<GenPolynomial<Quotient<C>>> L) {
102        if (L == null) {
103            return null;
104        }
105        List<GenPolynomial<GenPolynomial<C>>> list = new ArrayList<GenPolynomial<GenPolynomial<C>>>(L.size());
106        for (GenPolynomial<Quotient<C>> p : L) {
107            list.add(integralFromQuotientCoefficients(fac, p));
108        }
109        return list;
110    }
111
112
113    /**
114     * Rational function from integral polynomial coefficients. Represent as
115     * polynomial with type Quotient<C> coefficients.
116     * @param fac result polynomial factory.
117     * @param A polynomial with integral polynomial coefficients to be
118     *            converted.
119     * @return polynomial with type Quotient<C> coefficients.
120     */
121    public static <C extends GcdRingElem<C>> GenPolynomial<Quotient<C>> quotientFromIntegralCoefficients(
122                    GenPolynomialRing<Quotient<C>> fac, GenPolynomial<GenPolynomial<C>> A) {
123        GenPolynomial<Quotient<C>> B = fac.getZERO().copy();
124        if (A == null || A.isZERO()) {
125            return B;
126        }
127        RingFactory<Quotient<C>> cfac = fac.coFac;
128        QuotientRing<C> qfac = (QuotientRing<C>) cfac;
129        for (Map.Entry<ExpVector, GenPolynomial<C>> y : A.getMap().entrySet()) {
130            ExpVector e = y.getKey();
131            GenPolynomial<C> a = y.getValue();
132            Quotient<C> p = new Quotient<C>(qfac, a); // can not be zero
133            if (!p.isZERO()) {
134                //B = B.sum( p, e ); // inefficient
135                B.doPutToMap(e, p);
136            }
137        }
138        return B;
139    }
140
141
142    /**
143     * Rational function from integral polynomial coefficients. Represent as
144     * polynomial with type Quotient<C> coefficients.
145     * @param fac result polynomial factory.
146     * @param L list of polynomials with integral polynomial coefficients to be
147     *            converted.
148     * @return list of polynomials with type Quotient<C> coefficients.
149     */
150    public static <C extends GcdRingElem<C>> List<GenPolynomial<Quotient<C>>> quotientFromIntegralCoefficients(
151                    GenPolynomialRing<Quotient<C>> fac, Collection<GenPolynomial<GenPolynomial<C>>> L) {
152        if (L == null) {
153            return null;
154        }
155        List<GenPolynomial<Quotient<C>>> list = new ArrayList<GenPolynomial<Quotient<C>>>(L.size());
156        for (GenPolynomial<GenPolynomial<C>> p : L) {
157            list.add(quotientFromIntegralCoefficients(fac, p));
158        }
159        return list;
160    }
161
162
163    /**
164     * From BigInteger coefficients. Represent as polynomial with type
165     * GenPolynomial&lt;C&gt; coefficients, e.g. ModInteger or BigRational.
166     * @param fac result polynomial factory.
167     * @param A polynomial with GenPolynomial&lt;BigInteger&gt; coefficients to
168     *            be converted.
169     * @return polynomial with type GenPolynomial&lt;C&gt; coefficients.
170     */
171    public static <C extends RingElem<C>> GenPolynomial<GenPolynomial<C>> fromIntegerCoefficients(
172                    GenPolynomialRing<GenPolynomial<C>> fac, GenPolynomial<GenPolynomial<BigInteger>> A) {
173        GenPolynomial<GenPolynomial<C>> B = fac.getZERO().copy();
174        if (A == null || A.isZERO()) {
175            return B;
176        }
177        RingFactory<GenPolynomial<C>> cfac = fac.coFac;
178        GenPolynomialRing<C> rfac = (GenPolynomialRing<C>) cfac;
179        for (Map.Entry<ExpVector, GenPolynomial<BigInteger>> y : A.getMap().entrySet()) {
180            ExpVector e = y.getKey();
181            GenPolynomial<BigInteger> a = y.getValue();
182            GenPolynomial<C> p = PolyUtil.<C> fromIntegerCoefficients(rfac, a);
183            if (!p.isZERO()) {
184                //B = B.sum( p, e ); // inefficient
185                B.doPutToMap(e, p);
186            }
187        }
188        return B;
189    }
190
191
192    /**
193     * From BigInteger coefficients. Represent as polynomial with type
194     * GenPolynomial&lt;C&gt; coefficients, e.g. ModInteger or BigRational.
195     * @param fac result polynomial factory.
196     * @param L polynomial list with GenPolynomial&lt;BigInteger&gt;
197     *            coefficients to be converted.
198     * @return polynomial list with polynomials with type GenPolynomial&lt;C&gt;
199     *         coefficients.
200     */
201    public static <C extends RingElem<C>> List<GenPolynomial<GenPolynomial<C>>> fromIntegerCoefficients(
202                    GenPolynomialRing<GenPolynomial<C>> fac, List<GenPolynomial<GenPolynomial<BigInteger>>> L) {
203        List<GenPolynomial<GenPolynomial<C>>> K = null;
204        if (L == null) {
205            return K;
206        }
207        K = new ArrayList<GenPolynomial<GenPolynomial<C>>>(L.size());
208        if (L.size() == 0) {
209            return K;
210        }
211        for (GenPolynomial<GenPolynomial<BigInteger>> a : L) {
212            GenPolynomial<GenPolynomial<C>> b = fromIntegerCoefficients(fac, a);
213            K.add(b);
214        }
215        return K;
216    }
217
218
219    /**
220     * Introduce lower variable. Represent as polynomial with type
221     * GenPolynomial&lt;C&gt; coefficients.
222     * @param rfac result polynomial factory.
223     * @param A polynomial to be extended.
224     * @return polynomial with type GenPolynomial&lt;C&gt; coefficients.
225     */
226    public static <C extends GcdRingElem<C>> GenPolynomial<GenPolynomial<C>> introduceLowerVariable(
227                    GenPolynomialRing<GenPolynomial<C>> rfac, GenPolynomial<C> A) {
228        if (A == null || rfac == null) {
229            return null;
230        }
231        GenPolynomial<GenPolynomial<C>> Pc = rfac.getONE().multiply(A);
232        if (Pc.isZERO()) {
233            return Pc;
234        }
235        Pc = PolyUtil.<C> switchVariables(Pc);
236        return Pc;
237    }
238
239
240    /**
241     * From AlgebraicNumber coefficients. Represent as polynomial with type
242     * GenPolynomial&lt;C&gt; coefficients, e.g. ModInteger or BigRational.
243     * @param rfac result polynomial factory.
244     * @param A polynomial with AlgebraicNumber coefficients to be converted.
245     * @param k for (y-k x) substitution.
246     * @return polynomial with type GenPolynomial&lt;C&gt; coefficients.
247     */
248    public static <C extends GcdRingElem<C>> GenPolynomial<GenPolynomial<C>> substituteFromAlgebraicCoefficients(
249                    GenPolynomialRing<GenPolynomial<C>> rfac, GenPolynomial<AlgebraicNumber<C>> A, long k) {
250        if (A == null || rfac == null) {
251            return null;
252        }
253        if (A.isZERO()) {
254            return rfac.getZERO();
255        }
256        // setup x - k alpha
257        GenPolynomialRing<AlgebraicNumber<C>> apfac = A.ring;
258        GenPolynomial<AlgebraicNumber<C>> x = apfac.univariate(0);
259        AlgebraicNumberRing<C> afac = (AlgebraicNumberRing<C>) A.ring.coFac;
260        AlgebraicNumber<C> alpha = afac.getGenerator();
261        AlgebraicNumber<C> ka = afac.fromInteger(k);
262        GenPolynomial<AlgebraicNumber<C>> s = x.subtract(ka.multiply(alpha)); // x - k alpha
263        if (debug) {
264            logger.info("x - k alpha: " + s);
265        }
266        // substitute, convert and switch
267        GenPolynomial<AlgebraicNumber<C>> B = PolyUtil.<AlgebraicNumber<C>> substituteMain(A, s);
268        GenPolynomial<GenPolynomial<C>> Pc = PolyUtil.<C> fromAlgebraicCoefficients(rfac, B); // Q[alpha][x]
269        Pc = PolyUtil.<C> switchVariables(Pc); // Q[x][alpha]
270        return Pc;
271    }
272
273
274    /**
275     * Convert to AlgebraicNumber coefficients. Represent as polynomial with
276     * AlgebraicNumber<C> coefficients, C is e.g. ModInteger or BigRational.
277     * @param pfac result polynomial factory.
278     * @param A polynomial with GenPolynomial&lt;BigInteger&gt; coefficients to
279     *            be converted.
280     * @param k for (y-k x) substitution.
281     * @return polynomial with AlgebraicNumber&lt;C&gt; coefficients.
282     */
283    public static <C extends GcdRingElem<C>> GenPolynomial<AlgebraicNumber<C>> substituteConvertToAlgebraicCoefficients(
284                    GenPolynomialRing<AlgebraicNumber<C>> pfac, GenPolynomial<C> A, long k) {
285        if (A == null || pfac == null) {
286            return null;
287        }
288        if (A.isZERO()) {
289            return pfac.getZERO();
290        }
291        // convert to Q(alpha)[x]
292        GenPolynomial<AlgebraicNumber<C>> B = PolyUtil.<C> convertToAlgebraicCoefficients(pfac, A);
293        // setup x .+. k alpha for back substitution
294        GenPolynomial<AlgebraicNumber<C>> x = pfac.univariate(0);
295        AlgebraicNumberRing<C> afac = (AlgebraicNumberRing<C>) pfac.coFac;
296        AlgebraicNumber<C> alpha = afac.getGenerator();
297        AlgebraicNumber<C> ka = afac.fromInteger(k);
298        GenPolynomial<AlgebraicNumber<C>> s = x.sum(ka.multiply(alpha)); // x + k alpha
299        // substitute
300        GenPolynomial<AlgebraicNumber<C>> N = PolyUtil.<AlgebraicNumber<C>> substituteMain(B, s);
301        return N;
302    }
303
304
305    /**
306     * Norm of a polynomial with AlgebraicNumber coefficients.
307     * @param A polynomial from GenPolynomial&lt;AlgebraicNumber&lt;C&gt;&gt;.
308     * @param k for (y - k x) substitution.
309     * @return norm(A) = res_x(A(x,y),m(x)) in GenPolynomialRing&lt;C&gt;.
310     */
311    public static <C extends GcdRingElem<C>> GenPolynomial<C> norm(GenPolynomial<AlgebraicNumber<C>> A, long k) {
312        if (A == null) {
313            return null;
314        }
315        GenPolynomialRing<AlgebraicNumber<C>> pfac = A.ring; // Q(alpha)[x]
316        if (pfac.nvar > 1) {
317            throw new IllegalArgumentException("only for univariate polynomials");
318        }
319        AlgebraicNumberRing<C> afac = (AlgebraicNumberRing<C>) pfac.coFac;
320        GenPolynomial<C> agen = afac.modul;
321        GenPolynomialRing<C> cfac = afac.ring;
322        if (A.isZERO()) {
323            return cfac.getZERO();
324        }
325        AlgebraicNumber<C> ldcf = A.leadingBaseCoefficient();
326        if (!ldcf.isONE()) {
327            A = A.monic();
328        }
329        GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(cfac, pfac);
330
331        // transform minimal polynomial to bi-variate polynomial
332        GenPolynomial<GenPolynomial<C>> Ac = PolyUfdUtil.<C> introduceLowerVariable(rfac, agen);
333        //System.out.println("Ac = " + Ac.toScript());
334
335        // transform to bi-variate polynomial, 
336        // switching varaible sequence from Q[alpha][x] to Q[X][alpha]
337        GenPolynomial<GenPolynomial<C>> Pc = PolyUfdUtil.<C> substituteFromAlgebraicCoefficients(rfac, A, k);
338        Pc = PolyUtil.<C> monic(Pc);
339        //System.out.println("Pc = " + Pc.toScript());
340
341        GreatestCommonDivisorSubres<C> engine = new GreatestCommonDivisorSubres<C>( /*cfac.coFac*/);
342        // = (GreatestCommonDivisorAbstract<C>)GCDFactory.<C>getImplementation( cfac.coFac );
343
344        GenPolynomial<GenPolynomial<C>> Rc = engine.recursiveUnivariateResultant(Pc, Ac);
345        //System.out.println("Rc = " + Rc.toScript());
346        GenPolynomial<C> res = Rc.leadingBaseCoefficient();
347        res = res.monic();
348        return res;
349    }
350
351
352    /**
353     * Norm of a polynomial with AlgebraicNumber coefficients.
354     * @param A polynomial from GenPolynomial&lt;AlgebraicNumber&lt;C&gt;&gt;.
355     * @return norm(A) = resultant_x( A(x,y), m(x) ) in K[y].
356     */
357    public static <C extends GcdRingElem<C>> GenPolynomial<C> norm(GenPolynomial<AlgebraicNumber<C>> A) {
358        return norm(A, 0L);
359    }
360
361
362    /**
363     * Ensure that the field property is determined. Checks if modul is
364     * irreducible and modifies the algebraic number ring.
365     * @param afac algebraic number ring.
366     */
367    public static <C extends GcdRingElem<C>> void ensureFieldProperty(AlgebraicNumberRing<C> afac) {
368        if (afac.getField() != -1) {
369            return;
370        }
371        if (!afac.ring.coFac.isField()) {
372            afac.setField(false);
373            return;
374        }
375        Factorization<C> mf = FactorFactory.<C> getImplementation(afac.ring);
376        if (mf.isIrreducible(afac.modul)) {
377            afac.setField(true);
378        } else {
379            afac.setField(false);
380        }
381    }
382
383
384    /**
385     * Kronecker substitution. Substitute x_i by x**d**(i-1) to construct a
386     * univariate polynomial.
387     * @param A polynomial to be converted.
388     * @return a univariate polynomial.
389     */
390    public static <C extends GcdRingElem<C>> GenPolynomial<C> substituteKronecker(GenPolynomial<C> A) {
391        if (A == null) {
392            return A;
393        }
394        long d = A.degree() + 1L;
395        return substituteKronecker(A, d);
396    }
397
398
399    /**
400     * Kronecker substitution. Substitute x_i by x**d**(i-1) to construct a
401     * univariate polynomial.
402     * @param A polynomial to be converted.
403     * @return a univariate polynomial.
404     */
405    public static <C extends GcdRingElem<C>> GenPolynomial<C> substituteKronecker(GenPolynomial<C> A, long d) {
406        if (A == null) {
407            return A;
408        }
409        RingFactory<C> cfac = A.ring.coFac;
410        GenPolynomialRing<C> ufac = new GenPolynomialRing<C>(cfac, 1);
411        GenPolynomial<C> B = ufac.getZERO().copy();
412        if (A.isZERO()) {
413            return B;
414        }
415        for (Map.Entry<ExpVector, C> y : A.getMap().entrySet()) {
416            ExpVector e = y.getKey();
417            C a = y.getValue();
418            long f = 0L;
419            long h = 1L;
420            for (int i = 0; i < e.length(); i++) {
421                long j = e.getVal(i) * h;
422                f += j;
423                h *= d;
424            }
425            ExpVector g = ExpVector.create(1, 0, f);
426            B.doPutToMap(g, a);
427        }
428        return B;
429    }
430
431
432    /**
433     * Kronecker substitution. Substitute x_i by x**d**(i-1) to construct a
434     * univariate polynomials.
435     * @param A list of polynomials to be converted.
436     * @return a list of univariate polynomials.
437     */
438    public static <C extends GcdRingElem<C>> List<GenPolynomial<C>> substituteKronecker(
439                    List<GenPolynomial<C>> A, int d) {
440        if (A == null || A.get(0) == null) {
441            return null;
442        }
443        return ListUtil.<GenPolynomial<C>, GenPolynomial<C>> map(A, new SubstKronecker<C>(d));
444    }
445
446
447    /**
448     * Kronecker back substitution. Substitute x**d**(i-1) to x_i to construct a
449     * multivariate polynomial.
450     * @param A polynomial to be converted.
451     * @param fac result polynomial factory.
452     * @return a multivariate polynomial.
453     */
454    public static <C extends GcdRingElem<C>> GenPolynomial<C> backSubstituteKronecker(
455                    GenPolynomialRing<C> fac, GenPolynomial<C> A, long d) {
456        if (A == null) {
457            return A;
458        }
459        if (fac == null) {
460            throw new IllegalArgumentException("null factory not allowed ");
461        }
462        int n = fac.nvar;
463        GenPolynomial<C> B = fac.getZERO().copy();
464        if (A.isZERO()) {
465            return B;
466        }
467        for (Map.Entry<ExpVector, C> y : A.getMap().entrySet()) {
468            ExpVector e = y.getKey();
469            C a = y.getValue();
470            long f = e.getVal(0);
471            ExpVector g = ExpVector.create(n);
472            for (int i = 0; i < n; i++) {
473                long j = f % d;
474                f /= d;
475                g = g.subst(i, j);
476            }
477            B.doPutToMap(g, a);
478        }
479        return B;
480    }
481
482
483    /**
484     * Kronecker back substitution. Substitute x**d**(i-1) to x_i to construct a
485     * multivariate polynomials.
486     * @param A list of polynomials to be converted.
487     * @param fac result polynomial factory.
488     * @return a list of multivariate polynomials.
489     */
490    public static <C extends GcdRingElem<C>> List<GenPolynomial<C>> backSubstituteKronecker(
491                    GenPolynomialRing<C> fac, List<GenPolynomial<C>> A, long d) {
492        return ListUtil.<GenPolynomial<C>, GenPolynomial<C>> map(A, new BackSubstKronecker<C>(fac, d));
493    }
494
495}
496
497
498/**
499 * Kronecker substitutuion functor.
500 */
501class SubstKronecker<C extends GcdRingElem<C>> implements UnaryFunctor<GenPolynomial<C>, GenPolynomial<C>> {
502
503
504    final long d;
505
506
507    public SubstKronecker(long d) {
508        this.d = d;
509    }
510
511
512    public GenPolynomial<C> eval(GenPolynomial<C> c) {
513        if (c == null) {
514            return null;
515        }
516        return PolyUfdUtil.<C> substituteKronecker(c, d);
517    }
518}
519
520
521/**
522 * Kronecker back substitutuion functor.
523 */
524class BackSubstKronecker<C extends GcdRingElem<C>> implements
525                UnaryFunctor<GenPolynomial<C>, GenPolynomial<C>> {
526
527
528    final long d;
529
530
531    final GenPolynomialRing<C> fac;
532
533
534    public BackSubstKronecker(GenPolynomialRing<C> fac, long d) {
535        this.d = d;
536        this.fac = fac;
537    }
538
539
540    public GenPolynomial<C> eval(GenPolynomial<C> c) {
541        if (c == null) {
542            return null;
543        }
544        return PolyUfdUtil.<C> backSubstituteKronecker(fac, c, d);
545    }
546}