001    /*
002     * $Id: PolyUfdUtil.java 3634 2011-05-15 18:48:04Z kredel $
003     */
004    
005    package edu.jas.ufd;
006    
007    
008    import java.util.ArrayList;
009    import java.util.Collection;
010    import java.util.List;
011    import java.util.Map;
012    
013    import org.apache.log4j.Logger;
014    
015    import edu.jas.arith.BigInteger;
016    import edu.jas.poly.AlgebraicNumber;
017    import edu.jas.poly.AlgebraicNumberRing;
018    import edu.jas.poly.ExpVector;
019    import edu.jas.poly.GenPolynomial;
020    import edu.jas.poly.GenPolynomialRing;
021    import edu.jas.poly.PolyUtil;
022    import edu.jas.structure.GcdRingElem;
023    import edu.jas.structure.RingElem;
024    import edu.jas.structure.RingFactory;
025    import edu.jas.structure.UnaryFunctor;
026    import 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    
035    public 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().clone();
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().clone();
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 != null && !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().clone();
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 != null && !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            // substitute, convert and switch
264            GenPolynomial<AlgebraicNumber<C>> B = PolyUtil.<AlgebraicNumber<C>> substituteMain(A, s);
265            GenPolynomial<GenPolynomial<C>> Pc = PolyUtil.<C> fromAlgebraicCoefficients(rfac, B); // Q[alpha][x]
266            Pc = PolyUtil.<C> switchVariables(Pc); // Q[x][alpha]
267            return Pc;
268        }
269    
270    
271        /**
272         * Convert to AlgebraicNumber coefficients. Represent as polynomial with
273         * AlgebraicNumber<C> coefficients, C is e.g. ModInteger or BigRational.
274         * @param pfac result polynomial factory.
275         * @param A polynomial with GenPolynomial&lt;BigInteger&gt; coefficients to
276         *            be converted.
277         * @param k for (y-k x) substitution.
278         * @return polynomial with AlgebraicNumber&lt;C&gt; coefficients.
279         */
280        public static <C extends GcdRingElem<C>> GenPolynomial<AlgebraicNumber<C>> substituteConvertToAlgebraicCoefficients(
281                GenPolynomialRing<AlgebraicNumber<C>> pfac, GenPolynomial<C> A, long k) {
282            if (A == null || pfac == null) {
283                return null;
284            }
285            if (A.isZERO()) {
286                return pfac.getZERO();
287            }
288            // convert to Q(alpha)[x]
289            GenPolynomial<AlgebraicNumber<C>> B = PolyUtil.<C> convertToAlgebraicCoefficients(pfac, A);
290            // setup x .+. k alpha for back substitution
291            GenPolynomial<AlgebraicNumber<C>> x = pfac.univariate(0);
292            AlgebraicNumberRing<C> afac = (AlgebraicNumberRing<C>) pfac.coFac;
293            AlgebraicNumber<C> alpha = afac.getGenerator();
294            AlgebraicNumber<C> ka = afac.fromInteger(k);
295            GenPolynomial<AlgebraicNumber<C>> s = x.sum(ka.multiply(alpha)); // x + k alpha
296            // substitute
297            GenPolynomial<AlgebraicNumber<C>> N = PolyUtil.<AlgebraicNumber<C>> substituteMain(B, s);
298            return N;
299        }
300    
301    
302        /**
303         * Norm of a polynomial with AlgebraicNumber coefficients.
304         * @param A polynomial from GenPolynomial&lt;AlgebraicNumber&lt;C&gt;&gt;.
305         * @param k for (y - k x) substitution.
306         * @return norm(A) = res_x(A(x,y),m(x)) in GenPolynomialRing&lt;C&gt;.
307         */
308        public static <C extends GcdRingElem<C>> GenPolynomial<C> norm(GenPolynomial<AlgebraicNumber<C>> A, long k) {
309            if (A == null) {
310                return null;
311            }
312            GenPolynomialRing<AlgebraicNumber<C>> pfac = A.ring; // Q(alpha)[x]
313            if (pfac.nvar > 1) {
314                throw new IllegalArgumentException("only for univariate polynomials");
315            }
316            AlgebraicNumberRing<C> afac = (AlgebraicNumberRing<C>) pfac.coFac;
317            GenPolynomial<C> agen = afac.modul;
318            GenPolynomialRing<C> cfac = afac.ring;
319            if (A.isZERO()) {
320                return cfac.getZERO();
321            }
322            AlgebraicNumber<C> ldcf = A.leadingBaseCoefficient();
323            if (!ldcf.isONE()) {
324                A = A.monic();
325            }
326            GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(cfac, pfac);
327    
328            // transform minimal polynomial to bi-variate polynomial
329            GenPolynomial<GenPolynomial<C>> Ac = PolyUfdUtil.<C> introduceLowerVariable(rfac, agen);
330            //System.out.println("Ac = " + Ac.toScript());
331    
332            // transform to bi-variate polynomial, 
333            // switching varaible sequence from Q[alpha][x] to Q[X][alpha]
334            GenPolynomial<GenPolynomial<C>> Pc = PolyUfdUtil.<C> substituteFromAlgebraicCoefficients(rfac, A, k);
335            Pc = PolyUtil.<C> monic(Pc);
336            //System.out.println("Pc = " + Pc.toScript());
337    
338            GreatestCommonDivisorSubres<C> engine = new GreatestCommonDivisorSubres<C>( /*cfac.coFac*/);
339            // = (GreatestCommonDivisorAbstract<C>)GCDFactory.<C>getImplementation( cfac.coFac );
340    
341            GenPolynomial<GenPolynomial<C>> Rc = engine.recursiveResultant(Pc, Ac);
342            //System.out.println("Rc = " + Rc.toScript());
343            GenPolynomial<C> res = Rc.leadingBaseCoefficient();
344            res = res.monic();
345            return res;
346        }
347    
348    
349        /**
350         * Norm of a polynomial with AlgebraicNumber coefficients.
351         * @param A polynomial from GenPolynomial&lt;AlgebraicNumber&lt;C&gt;&gt;.
352         * @return norm(A) = resultant_x( A(x,y), m(x) ) in K[y].
353         */
354        public static <C extends GcdRingElem<C>> GenPolynomial<C> norm(GenPolynomial<AlgebraicNumber<C>> A) {
355            return norm(A, 0L);
356        }
357    
358    
359        /**
360         * Ensure that the field property is determined. Checks if modul is
361         * irreducible and modifies the algebraic number ring.
362         * @param afac algebraic number ring.
363         */
364        public static <C extends GcdRingElem<C>> void ensureFieldProperty(AlgebraicNumberRing<C> afac) {
365            if (afac.getField() != -1) {
366                return;
367            }
368            if (!afac.ring.coFac.isField()) {
369                afac.setField(false);
370                return;
371            }
372            Factorization<C> mf = FactorFactory.<C> getImplementation(afac.ring);
373            if (mf.isIrreducible(afac.modul)) {
374                afac.setField(true);
375            } else {
376                afac.setField(false);
377            }
378        }
379    
380    
381        /**
382         * Kronecker substitution. Substitute x_i by x**d**(i-1) to construct a
383         * univariate polynomial.
384         * @param A polynomial to be converted.
385         * @return a univariate polynomial.
386         */
387        public static <C extends GcdRingElem<C>> GenPolynomial<C> substituteKronecker(GenPolynomial<C> A) {
388            if (A == null) {
389                return A;
390            }
391            long d = A.degree() + 1L;
392            return substituteKronecker(A, d);
393        }
394    
395    
396        /**
397         * Kronecker substitution. Substitute x_i by x**d**(i-1) to construct a
398         * univariate polynomial.
399         * @param A polynomial to be converted.
400         * @return a univariate polynomial.
401         */
402        public static <C extends GcdRingElem<C>> GenPolynomial<C> substituteKronecker(GenPolynomial<C> A, long d) {
403            if (A == null) {
404                return A;
405            }
406            RingFactory<C> cfac = A.ring.coFac;
407            GenPolynomialRing<C> ufac = new GenPolynomialRing<C>(cfac, 1);
408            GenPolynomial<C> B = ufac.getZERO().clone();
409            if (A.isZERO()) {
410                return B;
411            }
412            for (Map.Entry<ExpVector, C> y : A.getMap().entrySet()) {
413                ExpVector e = y.getKey();
414                C a = y.getValue();
415                long f = 0L;
416                long h = 1L;
417                for (int i = 0; i < e.length(); i++) {
418                    long j = e.getVal(i) * h;
419                    f += j;
420                    h *= d;
421                }
422                ExpVector g = ExpVector.create(1, 0, f);
423                B.doPutToMap(g, a);
424            }
425            return B;
426        }
427    
428    
429        /**
430         * Kronecker substitution. Substitute x_i by x**d**(i-1) to construct a
431         * univariate polynomials.
432         * @param A list of polynomials to be converted.
433         * @return a list of univariate polynomials.
434         */
435        public static <C extends GcdRingElem<C>> List<GenPolynomial<C>> substituteKronecker(
436                List<GenPolynomial<C>> A, int d) {
437            if (A == null || A.get(0) == null) {
438                return null;
439            }
440            return ListUtil.<GenPolynomial<C>, GenPolynomial<C>> map(A, new SubstKronecker<C>(d));
441        }
442    
443    
444        /**
445         * Kronecker back substitution. Substitute x**d**(i-1) to x_i to construct a
446         * multivariate polynomial.
447         * @param A polynomial to be converted.
448         * @param fac result polynomial factory.
449         * @return a multivariate polynomial.
450         */
451        public static <C extends GcdRingElem<C>> GenPolynomial<C> backSubstituteKronecker(
452                GenPolynomialRing<C> fac, GenPolynomial<C> A, long d) {
453            if (A == null) {
454                return A;
455            }
456            if (fac == null) {
457                throw new IllegalArgumentException("null factory not allowed ");
458            }
459            int n = fac.nvar;
460            GenPolynomial<C> B = fac.getZERO().clone();
461            if (A.isZERO()) {
462                return B;
463            }
464            for (Map.Entry<ExpVector, C> y : A.getMap().entrySet()) {
465                ExpVector e = y.getKey();
466                C a = y.getValue();
467                long f = e.getVal(0);
468                ExpVector g = ExpVector.create(n);
469                for (int i = 0; i < n; i++) {
470                    long j = f % d;
471                    f /= d;
472                    g = g.subst(i, j);
473                }
474                B.doPutToMap(g, a);
475            }
476            return B;
477        }
478    
479    
480        /**
481         * Kronecker back substitution. Substitute x**d**(i-1) to x_i to construct a
482         * multivariate polynomials.
483         * @param A list of polynomials to be converted.
484         * @param fac result polynomial factory.
485         * @return a list of multivariate polynomials.
486         */
487        public static <C extends GcdRingElem<C>> List<GenPolynomial<C>> backSubstituteKronecker(
488                GenPolynomialRing<C> fac, List<GenPolynomial<C>> A, long d) {
489            return ListUtil.<GenPolynomial<C>, GenPolynomial<C>> map(A, new BackSubstKronecker<C>(fac, d));
490        }
491    
492    }
493    
494    
495    /**
496     * Kronecker substitutuion functor.
497     */
498    class SubstKronecker<C extends GcdRingElem<C>> implements UnaryFunctor<GenPolynomial<C>, GenPolynomial<C>> {
499    
500    
501        final long d;
502    
503    
504        public SubstKronecker(long d) {
505            this.d = d;
506        }
507    
508    
509        public GenPolynomial<C> eval(GenPolynomial<C> c) {
510            if (c == null) {
511                return null;
512            } else {
513                return PolyUfdUtil.<C> substituteKronecker(c, d);
514            }
515        }
516    }
517    
518    
519    /**
520     * Kronecker back substitutuion functor.
521     */
522    class BackSubstKronecker<C extends GcdRingElem<C>> implements
523            UnaryFunctor<GenPolynomial<C>, GenPolynomial<C>> {
524    
525    
526        final long d;
527    
528    
529        final GenPolynomialRing<C> fac;
530    
531    
532        public BackSubstKronecker(GenPolynomialRing<C> fac, long d) {
533            this.d = d;
534            this.fac = fac;
535        }
536    
537    
538        public GenPolynomial<C> eval(GenPolynomial<C> c) {
539            if (c == null) {
540                return null;
541            } else {
542                return PolyUfdUtil.<C> backSubstituteKronecker(fac, c, d);
543            }
544        }
545    }