001/*
002 * $Id: HenselUtil.java 5842 2018-05-21 13:23:49Z kredel $
003 */
004
005package edu.jas.ufd;
006
007
008import java.util.ArrayList;
009import java.util.List;
010
011import org.apache.log4j.Logger;
012
013import edu.jas.arith.BigInteger;
014import edu.jas.arith.ModInteger;
015import edu.jas.arith.ModIntegerRing;
016import edu.jas.arith.ModLongRing;
017import edu.jas.arith.Modular;
018import edu.jas.arith.ModularRingFactory;
019import edu.jas.poly.ExpVector;
020import edu.jas.poly.GenPolynomial;
021import edu.jas.poly.GenPolynomialRing;
022import edu.jas.poly.Monomial;
023import edu.jas.poly.PolyUtil;
024import edu.jas.structure.GcdRingElem;
025import edu.jas.structure.RingFactory;
026
027
028/**
029 * Hensel utilities for ufd.
030 * @author Heinz Kredel
031 */
032
033public class HenselUtil {
034
035
036    private static final Logger logger = Logger.getLogger(HenselUtil.class);
037
038
039    private static final boolean debug = logger.isDebugEnabled();
040
041
042    /**
043     * Modular Hensel lifting algorithm on coefficients. Let p =
044     * A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p
045     * with gcd(A,B) == 1 mod p and S A + T B == 1 mod p. See Algorithm 6.1. in
046     * Geddes et.al.. Linear version, as it does not lift S A + T B == 1 mod
047     * p^{e+1}.
048     * @param C GenPolynomial
049     * @param A GenPolynomial
050     * @param B other GenPolynomial
051     * @param S GenPolynomial
052     * @param T GenPolynomial
053     * @param M bound on the coefficients of A1 and B1 as factors of C.
054     * @return [A1,B1,Am,Bm] = lift(C,A,B), with C = A1 * B1 mod p^e, Am = A1
055     *         mod p^e, Bm = B1 mod p^e .
056     */
057    @SuppressWarnings("unchecked")
058    public static <MOD extends GcdRingElem<MOD> & Modular> HenselApprox<MOD> liftHensel(
059                    GenPolynomial<BigInteger> C, BigInteger M, GenPolynomial<MOD> A, GenPolynomial<MOD> B,
060                    GenPolynomial<MOD> S, GenPolynomial<MOD> T) throws NoLiftingException {
061        if (C == null || C.isZERO()) {
062            return new HenselApprox<MOD>(C, C, A, B);
063        }
064        if (A == null || A.isZERO() || B == null || B.isZERO()) {
065            throw new IllegalArgumentException("A and B must be nonzero");
066        }
067        GenPolynomialRing<BigInteger> fac = C.ring;
068        if (fac.nvar != 1) { // assert ?
069            throw new IllegalArgumentException("polynomial ring not univariate");
070        }
071        // setup factories
072        GenPolynomialRing<MOD> pfac = A.ring;
073        RingFactory<MOD> p = pfac.coFac;
074        RingFactory<MOD> q = p;
075        ModularRingFactory<MOD> P = (ModularRingFactory<MOD>) p;
076        ModularRingFactory<MOD> Q = (ModularRingFactory<MOD>) q;
077        BigInteger Qi = Q.getIntegerModul();
078        BigInteger M2 = M.multiply(M.fromInteger(2));
079        BigInteger Mq = Qi;
080
081        // normalize c and a, b factors, assert p is prime
082        GenPolynomial<BigInteger> Ai;
083        GenPolynomial<BigInteger> Bi;
084        BigInteger c = C.leadingBaseCoefficient();
085        C = C.multiply(c); // sic
086        MOD a = A.leadingBaseCoefficient();
087        if (!a.isONE()) { // A = A.monic();
088            A = A.divide(a);
089            S = S.multiply(a);
090        }
091        MOD b = B.leadingBaseCoefficient();
092        if (!b.isONE()) { // B = B.monic();
093            B = B.divide(b);
094            T = T.multiply(b);
095        }
096        MOD cm = P.fromInteger(c.getVal());
097        A = A.multiply(cm);
098        B = B.multiply(cm);
099        T = T.divide(cm);
100        S = S.divide(cm);
101        Ai = PolyUtil.integerFromModularCoefficients(fac, A);
102        Bi = PolyUtil.integerFromModularCoefficients(fac, B);
103        // replace leading base coefficients
104        ExpVector ea = Ai.leadingExpVector();
105        ExpVector eb = Bi.leadingExpVector();
106        Ai.doPutToMap(ea, c);
107        Bi.doPutToMap(eb, c);
108
109        // polynomials mod p
110        GenPolynomial<MOD> Ap;
111        GenPolynomial<MOD> Bp;
112        GenPolynomial<MOD> A1p = A;
113        GenPolynomial<MOD> B1p = B;
114        GenPolynomial<MOD> Ep;
115
116        // polynomials over the integers
117        GenPolynomial<BigInteger> E;
118        GenPolynomial<BigInteger> Ea;
119        GenPolynomial<BigInteger> Eb;
120        GenPolynomial<BigInteger> Ea1;
121        GenPolynomial<BigInteger> Eb1;
122
123        while (Mq.compareTo(M2) < 0) {
124            // compute E=(C-AB)/q over the integers
125            E = C.subtract(Ai.multiply(Bi));
126            if (E.isZERO()) {
127                logger.info("leaving on zero E");
128                break;
129            }
130            try {
131                E = E.divide(Qi);
132            } catch (RuntimeException e) {
133                // useful in debuging
134                //System.out.println("C  = " + C );
135                //System.out.println("Ai = " + Ai );
136                //System.out.println("Bi = " + Bi );
137                //System.out.println("E  = " + E );
138                //System.out.println("Qi = " + Qi );
139                throw e;
140            }
141            // E mod p
142            Ep = PolyUtil.<MOD> fromIntegerCoefficients(pfac, E);
143            //logger.info("Ep = " + Ep);
144
145            // construct approximation mod p
146            Ap = S.multiply(Ep); // S,T ++ T,S
147            Bp = T.multiply(Ep);
148            GenPolynomial<MOD>[] QR;
149            QR = Ap.quotientRemainder(B);
150            GenPolynomial<MOD> Qp;
151            GenPolynomial<MOD> Rp;
152            Qp = QR[0];
153            Rp = QR[1];
154            A1p = Rp;
155            B1p = Bp.sum(A.multiply(Qp));
156
157            // construct q-adic approximation, convert to integer
158            Ea = PolyUtil.integerFromModularCoefficients(fac, A1p);
159            Eb = PolyUtil.integerFromModularCoefficients(fac, B1p);
160            Ea1 = Ea.multiply(Qi);
161            Eb1 = Eb.multiply(Qi);
162
163            Ea = Ai.sum(Eb1); // Eb1 and Ea1 are required
164            Eb = Bi.sum(Ea1); //--------------------------
165            assert (Ea.degree(0) + Eb.degree(0) <= C.degree(0));
166            //if ( Ea.degree(0)+Eb.degree(0) > C.degree(0) ) { // debug
167            //   throw new RuntimeException("deg(A)+deg(B) > deg(C)");
168            //}
169
170            // prepare for next iteration
171            Mq = Qi;
172            Qi = Q.getIntegerModul().multiply(P.getIntegerModul());
173            // Q = new ModIntegerRing(Qi.getVal());
174            if (ModLongRing.MAX_LONG.compareTo(Qi.getVal()) > 0) {
175                Q = (ModularRingFactory) new ModLongRing(Qi.getVal());
176            } else {
177                Q = (ModularRingFactory) new ModIntegerRing(Qi.getVal());
178            }
179            Ai = Ea;
180            Bi = Eb;
181        }
182        GreatestCommonDivisorAbstract<BigInteger> ufd = new GreatestCommonDivisorPrimitive<BigInteger>();
183
184        // remove normalization
185        BigInteger ai = ufd.baseContent(Ai);
186        Ai = Ai.divide(ai);
187        BigInteger bi = null;
188        try {
189            bi = c.divide(ai);
190            Bi = Bi.divide(bi); // divide( c/a )
191        } catch (RuntimeException e) {
192            //System.out.println("C  = " + C );
193            //System.out.println("Ai = " + Ai );
194            //System.out.println("Bi = " + Bi );
195            //System.out.println("c  = " + c );
196            //System.out.println("ai = " + ai );
197            //System.out.println("bi = " + bi );
198            //System.out.println("no exact lifting possible " + e);
199            throw new NoLiftingException("no exact lifting possible " + e);
200        }
201        return new HenselApprox<MOD>(Ai, Bi, A1p, B1p);
202    }
203
204
205    /**
206     * Modular Hensel lifting algorithm on coefficients. Let p =
207     * A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p
208     * with gcd(A,B) == 1 mod p. See algorithm 6.1. in Geddes et.al. and
209     * algorithms 3.5.{5,6} in Cohen.
210     * @param C GenPolynomial
211     * @param A GenPolynomial
212     * @param B other GenPolynomial
213     * @param M bound on the coefficients of A1 and B1 as factors of C.
214     * @return [A1,B1] = lift(C,A,B), with C = A1 * B1.
215     */
216    @SuppressWarnings("unchecked")
217    public static <MOD extends GcdRingElem<MOD> & Modular> HenselApprox<MOD> liftHensel(
218                    GenPolynomial<BigInteger> C, BigInteger M, GenPolynomial<MOD> A, GenPolynomial<MOD> B)
219                    throws NoLiftingException {
220        if (C == null || C.isZERO()) {
221            return new HenselApprox<MOD>(C, C, A, B);
222        }
223        if (A == null || A.isZERO() || B == null || B.isZERO()) {
224            throw new IllegalArgumentException("A and B must be nonzero");
225        }
226        GenPolynomialRing<BigInteger> fac = C.ring;
227        if (fac.nvar != 1) { // assert ?
228            throw new IllegalArgumentException("polynomial ring not univariate");
229        }
230        // one Hensel step on part polynomials
231        try {
232            GenPolynomial<MOD>[] gst = A.egcd(B);
233            if (!gst[0].isONE()) {
234                throw new NoLiftingException(
235                                "A and B not coprime, gcd = " + gst[0] + ", A = " + A + ", B = " + B);
236            }
237            GenPolynomial<MOD> s = gst[1];
238            GenPolynomial<MOD> t = gst[2];
239            HenselApprox<MOD> ab = HenselUtil.<MOD> liftHensel(C, M, A, B, s, t);
240            return ab;
241        } catch (ArithmeticException e) {
242            throw new NoLiftingException("coefficient error " + e);
243        }
244    }
245
246
247    /**
248     * Modular quadratic Hensel lifting algorithm on coefficients. Let p =
249     * A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p
250     * with gcd(A,B) == 1 mod p and S A + T B == 1 mod p. See algorithm 6.1. in
251     * Geddes et.al. and algorithms 3.5.{5,6} in Cohen. Quadratic version, as it
252     * also lifts S A + T B == 1 mod p^{e+1}.
253     * @param C GenPolynomial
254     * @param A GenPolynomial
255     * @param B other GenPolynomial
256     * @param S GenPolynomial
257     * @param T GenPolynomial
258     * @param M bound on the coefficients of A1 and B1 as factors of C.
259     * @return [A1,B1] = lift(C,A,B), with C = A1 * B1.
260     */
261    @SuppressWarnings("unchecked")
262    public static <MOD extends GcdRingElem<MOD> & Modular> HenselApprox<MOD> liftHenselQuadratic(
263                    GenPolynomial<BigInteger> C, BigInteger M, GenPolynomial<MOD> A, GenPolynomial<MOD> B,
264                    GenPolynomial<MOD> S, GenPolynomial<MOD> T) throws NoLiftingException {
265        if (C == null || C.isZERO()) {
266            return new HenselApprox<MOD>(C, C, A, B);
267        }
268        if (A == null || A.isZERO() || B == null || B.isZERO()) {
269            throw new IllegalArgumentException("A and B must be nonzero");
270        }
271        GenPolynomialRing<BigInteger> fac = C.ring;
272        if (fac.nvar != 1) { // assert ?
273            throw new IllegalArgumentException("polynomial ring not univariate");
274        }
275        // setup factories
276        GenPolynomialRing<MOD> pfac = A.ring;
277        RingFactory<MOD> p = pfac.coFac;
278        RingFactory<MOD> q = p;
279        ModularRingFactory<MOD> P = (ModularRingFactory<MOD>) p;
280        ModularRingFactory<MOD> Q = (ModularRingFactory<MOD>) q;
281        BigInteger Qi = Q.getIntegerModul();
282        BigInteger M2 = M.multiply(M.fromInteger(2));
283        BigInteger Mq = Qi;
284        GenPolynomialRing<MOD> qfac;
285        qfac = new GenPolynomialRing<MOD>(Q, pfac);
286
287        // normalize c and a, b factors, assert p is prime
288        GenPolynomial<BigInteger> Ai;
289        GenPolynomial<BigInteger> Bi;
290        BigInteger c = C.leadingBaseCoefficient();
291        C = C.multiply(c); // sic
292        MOD a = A.leadingBaseCoefficient();
293        if (!a.isONE()) { // A = A.monic();
294            A = A.divide(a);
295            S = S.multiply(a);
296        }
297        MOD b = B.leadingBaseCoefficient();
298        if (!b.isONE()) { // B = B.monic();
299            B = B.divide(b);
300            T = T.multiply(b);
301        }
302        MOD cm = P.fromInteger(c.getVal());
303        A = A.multiply(cm);
304        B = B.multiply(cm);
305        T = T.divide(cm);
306        S = S.divide(cm);
307        Ai = PolyUtil.integerFromModularCoefficients(fac, A);
308        Bi = PolyUtil.integerFromModularCoefficients(fac, B);
309        // replace leading base coefficients
310        ExpVector ea = Ai.leadingExpVector();
311        ExpVector eb = Bi.leadingExpVector();
312        Ai.doPutToMap(ea, c);
313        Bi.doPutToMap(eb, c);
314
315        // polynomials mod p
316        GenPolynomial<MOD> Ap;
317        GenPolynomial<MOD> Bp;
318        GenPolynomial<MOD> A1p = A;
319        GenPolynomial<MOD> B1p = B;
320        GenPolynomial<MOD> Ep;
321        GenPolynomial<MOD> Sp = S;
322        GenPolynomial<MOD> Tp = T;
323
324        // polynomials mod q
325        GenPolynomial<MOD> Aq;
326        GenPolynomial<MOD> Bq;
327        //GenPolynomial<MOD> Eq;
328
329        // polynomials over the integers
330        GenPolynomial<BigInteger> E;
331        GenPolynomial<BigInteger> Ea;
332        GenPolynomial<BigInteger> Eb;
333        GenPolynomial<BigInteger> Ea1;
334        GenPolynomial<BigInteger> Eb1;
335        GenPolynomial<BigInteger> Si;
336        GenPolynomial<BigInteger> Ti;
337
338        Si = PolyUtil.integerFromModularCoefficients(fac, S);
339        Ti = PolyUtil.integerFromModularCoefficients(fac, T);
340
341        Aq = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Ai);
342        Bq = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Bi);
343
344        while (Mq.compareTo(M2) < 0) {
345            // compute E=(C-AB)/q over the integers
346            E = C.subtract(Ai.multiply(Bi));
347            if (E.isZERO()) {
348                logger.info("leaving on zero E");
349                break;
350            }
351            E = E.divide(Qi);
352            // E mod p
353            Ep = PolyUtil.<MOD> fromIntegerCoefficients(qfac, E);
354            //logger.info("Ep = " + Ep + ", qfac = " + qfac);
355            //if (Ep.isZERO()) {
356            //System.out.println("leaving on zero error");
357            //??logger.info("leaving on zero Ep");
358            //??break;
359            //}
360
361            // construct approximation mod p
362            Ap = Sp.multiply(Ep); // S,T ++ T,S
363            Bp = Tp.multiply(Ep);
364            GenPolynomial<MOD>[] QR;
365            //logger.info("Ap = " + Ap + ", Bp = " + Bp + ", fac(Ap) = " + Ap.ring);
366            QR = Ap.quotientRemainder(Bq);
367            GenPolynomial<MOD> Qp;
368            GenPolynomial<MOD> Rp;
369            Qp = QR[0];
370            Rp = QR[1];
371            //logger.info("Qp = " + Qp + ", Rp = " + Rp);
372            A1p = Rp;
373            B1p = Bp.sum(Aq.multiply(Qp));
374
375            // construct q-adic approximation, convert to integer
376            Ea = PolyUtil.integerFromModularCoefficients(fac, A1p);
377            Eb = PolyUtil.integerFromModularCoefficients(fac, B1p);
378            Ea1 = Ea.multiply(Qi);
379            Eb1 = Eb.multiply(Qi);
380            Ea = Ai.sum(Eb1); // Eb1 and Ea1 are required
381            Eb = Bi.sum(Ea1); //--------------------------
382            assert (Ea.degree(0) + Eb.degree(0) <= C.degree(0));
383            //if ( Ea.degree(0)+Eb.degree(0) > C.degree(0) ) { // debug
384            //   throw new RuntimeException("deg(A)+deg(B) > deg(C)");
385            //}
386            Ai = Ea;
387            Bi = Eb;
388
389            // gcd representation factors error --------------------------------
390            // compute E=(1-SA-TB)/q over the integers
391            E = fac.getONE();
392            E = E.subtract(Si.multiply(Ai)).subtract(Ti.multiply(Bi));
393            E = E.divide(Qi);
394            // E mod q
395            Ep = PolyUtil.<MOD> fromIntegerCoefficients(qfac, E);
396            //logger.info("Ep2 = " + Ep);
397
398            // construct approximation mod q
399            Ap = Sp.multiply(Ep); // S,T ++ T,S
400            Bp = Tp.multiply(Ep);
401            QR = Bp.quotientRemainder(Aq); // Ai == A mod p ?
402            Qp = QR[0];
403            Rp = QR[1];
404            B1p = Rp;
405            A1p = Ap.sum(Bq.multiply(Qp));
406
407            //if (debug) {
408            //    Eq = A1p.multiply(Aq).sum(B1p.multiply(Bq)).subtract(Ep);
409            //    if (!Eq.isZERO()) {
410            //        System.out.println("A*A1p+B*B1p-Ep2 != 0 " + Eq);
411            //        throw new RuntimeException("A*A1p+B*B1p-Ep2 != 0 mod " + Q.getIntegerModul());
412            //    }
413            //}
414
415            // construct q-adic approximation, convert to integer
416            Ea = PolyUtil.integerFromModularCoefficients(fac, A1p);
417            Eb = PolyUtil.integerFromModularCoefficients(fac, B1p);
418            Ea1 = Ea.multiply(Qi);
419            Eb1 = Eb.multiply(Qi);
420            Ea = Si.sum(Ea1); // Eb1 and Ea1 are required
421            Eb = Ti.sum(Eb1); //--------------------------
422            Si = Ea;
423            Ti = Eb;
424
425            // prepare for next iteration
426            Mq = Qi;
427            Qi = Q.getIntegerModul().multiply(Q.getIntegerModul());
428            if (ModLongRing.MAX_LONG.compareTo(Qi.getVal()) > 0) {
429                Q = (ModularRingFactory) new ModLongRing(Qi.getVal());
430            } else {
431                Q = (ModularRingFactory) new ModIntegerRing(Qi.getVal());
432            }
433            //Q = new ModIntegerRing(Qi.getVal());
434            //System.out.println("Q = " + Q + ", from Q = " + Mq);
435
436            qfac = new GenPolynomialRing<MOD>(Q, pfac);
437
438            Aq = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Ai);
439            Bq = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Bi);
440            Sp = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Si);
441            Tp = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Ti);
442            //if (debug) {
443            //    E = Ai.multiply(Si).sum(Bi.multiply(Ti));
444            //    Eq = PolyUtil.<MOD> fromIntegerCoefficients(qfac, E);
445            //    if (!Eq.isONE()) {
446            //        System.out.println("Ai*Si+Bi*Ti=1 " + Eq);
447            //        throw new RuntimeException("Ai*Si+Bi*Ti != 1 mod " + Q.getIntegerModul());
448            //    }
449            //}
450        }
451        GreatestCommonDivisorAbstract<BigInteger> ufd = new GreatestCommonDivisorPrimitive<BigInteger>();
452
453        // remove normalization if possible
454        BigInteger ai = ufd.baseContent(Ai);
455        Ai = Ai.divide(ai);
456        BigInteger bi = null;
457        try {
458            bi = c.divide(ai);
459            Bi = Bi.divide(bi); // divide( c/a )
460        } catch (RuntimeException e) {
461            //System.out.println("C  = " + C );
462            //System.out.println("Ai = " + Ai );
463            //System.out.println("Bi = " + Bi );
464            //System.out.println("c  = " + c );
465            //System.out.println("ai = " + ai );
466            //System.out.println("bi = " + bi );
467            //System.out.println("no exact lifting possible " + e);
468            throw new NoLiftingException("no exact lifting possible " + e);
469        }
470        return new HenselApprox<MOD>(Ai, Bi, A1p, B1p);
471    }
472
473
474    /**
475     * Modular quadratic Hensel lifting algorithm on coefficients. Let p =
476     * A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p
477     * with gcd(A,B) == 1 mod p. See algorithm 6.1. in Geddes et.al. and
478     * algorithms 3.5.{5,6} in Cohen. Quadratic version.
479     * @param C GenPolynomial
480     * @param A GenPolynomial
481     * @param B other GenPolynomial
482     * @param M bound on the coefficients of A1 and B1 as factors of C.
483     * @return [A1,B1] = lift(C,A,B), with C = A1 * B1.
484     */
485    @SuppressWarnings("unchecked")
486    public static <MOD extends GcdRingElem<MOD> & Modular> HenselApprox<MOD> liftHenselQuadratic(
487                    GenPolynomial<BigInteger> C, BigInteger M, GenPolynomial<MOD> A, GenPolynomial<MOD> B)
488                    throws NoLiftingException {
489        if (C == null || C.isZERO()) {
490            return new HenselApprox<MOD>(C, C, A, B);
491        }
492        if (A == null || A.isZERO() || B == null || B.isZERO()) {
493            throw new IllegalArgumentException("A and B must be nonzero");
494        }
495        GenPolynomialRing<BigInteger> fac = C.ring;
496        if (fac.nvar != 1) { // assert ?
497            throw new IllegalArgumentException("polynomial ring not univariate");
498        }
499        // one Hensel step on part polynomials
500        try {
501            GenPolynomial<MOD>[] gst = A.egcd(B);
502            if (!gst[0].isONE()) {
503                throw new NoLiftingException(
504                                "A and B not coprime, gcd = " + gst[0] + ", A = " + A + ", B = " + B);
505            }
506            GenPolynomial<MOD> s = gst[1];
507            GenPolynomial<MOD> t = gst[2];
508            HenselApprox<MOD> ab = HenselUtil.<MOD> liftHenselQuadratic(C, M, A, B, s, t);
509            return ab;
510        } catch (ArithmeticException e) {
511            throw new NoLiftingException("coefficient error " + e);
512        }
513    }
514
515
516    /**
517     * Modular Hensel lifting algorithm on coefficients. Let p =
518     * A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p
519     * with gcd(A,B) == 1 mod p. See algorithm 6.1. in Geddes et.al. and
520     * algorithms 3.5.{5,6} in Cohen. Quadratic version.
521     * @param C GenPolynomial
522     * @param A GenPolynomial
523     * @param B other GenPolynomial
524     * @param M bound on the coefficients of A1 and B1 as factors of C.
525     * @return [A1,B1] = lift(C,A,B), with C = A1 * B1.
526     */
527    @SuppressWarnings("unchecked")
528    public static <MOD extends GcdRingElem<MOD> & Modular> HenselApprox<MOD> liftHenselQuadraticFac(
529                    GenPolynomial<BigInteger> C, BigInteger M, GenPolynomial<MOD> A, GenPolynomial<MOD> B)
530                    throws NoLiftingException {
531        if (C == null || C.isZERO()) {
532            throw new IllegalArgumentException("C must be nonzero");
533        }
534        if (A == null || A.isZERO() || B == null || B.isZERO()) {
535            throw new IllegalArgumentException("A and B must be nonzero");
536        }
537        GenPolynomialRing<BigInteger> fac = C.ring;
538        if (fac.nvar != 1) { // assert ?
539            throw new IllegalArgumentException("polynomial ring not univariate");
540        }
541        // one Hensel step on part polynomials
542        try {
543            GenPolynomial<MOD>[] gst = A.egcd(B);
544            if (!gst[0].isONE()) {
545                throw new NoLiftingException(
546                                "A and B not coprime, gcd = " + gst[0] + ", A = " + A + ", B = " + B);
547            }
548            GenPolynomial<MOD> s = gst[1];
549            GenPolynomial<MOD> t = gst[2];
550            HenselApprox<MOD> ab = HenselUtil.<MOD> liftHenselQuadraticFac(C, M, A, B, s, t);
551            return ab;
552        } catch (ArithmeticException e) {
553            throw new NoLiftingException("coefficient error " + e);
554        }
555    }
556
557
558    /**
559     * Modular Hensel lifting algorithm on coefficients. Let p =
560     * A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p
561     * with gcd(A,B) == 1 mod p and S A + T B == 1 mod p. See algorithm 6.1. in
562     * Geddes et.al. and algorithms 3.5.{5,6} in Cohen. Quadratic version, as it
563     * also lifts S A + T B == 1 mod p^{e+1}.
564     * @param C primitive GenPolynomial
565     * @param A GenPolynomial
566     * @param B other GenPolynomial
567     * @param S GenPolynomial
568     * @param T GenPolynomial
569     * @param M bound on the coefficients of A1 and B1 as factors of C.
570     * @return [A1,B1] = lift(C,A,B), with C = A1 * B1.
571     */
572    @SuppressWarnings("unchecked")
573    public static <MOD extends GcdRingElem<MOD> & Modular> HenselApprox<MOD> liftHenselQuadraticFac(
574                    GenPolynomial<BigInteger> C, BigInteger M, GenPolynomial<MOD> A, GenPolynomial<MOD> B,
575                    GenPolynomial<MOD> S, GenPolynomial<MOD> T) throws NoLiftingException {
576        //System.out.println("*** version for factorization *** ");
577        //GenPolynomial<BigInteger>[] AB = new GenPolynomial[2];
578        if (C == null || C.isZERO()) {
579            throw new IllegalArgumentException("C must be nonzero");
580        }
581        if (A == null || A.isZERO() || B == null || B.isZERO()) {
582            throw new IllegalArgumentException("A and B must be nonzero");
583        }
584        GenPolynomialRing<BigInteger> fac = C.ring;
585        if (fac.nvar != 1) { // assert ?
586            throw new IllegalArgumentException("polynomial ring not univariate");
587        }
588        // setup factories
589        GenPolynomialRing<MOD> pfac = A.ring;
590        RingFactory<MOD> p = pfac.coFac;
591        RingFactory<MOD> q = p;
592        ModularRingFactory<MOD> P = (ModularRingFactory<MOD>) p;
593        ModularRingFactory<MOD> Q = (ModularRingFactory<MOD>) q;
594        BigInteger PP = Q.getIntegerModul();
595        BigInteger Qi = PP;
596        BigInteger M2 = M.multiply(M.fromInteger(2));
597        if (debug) {
598            //System.out.println("M2 =  " + M2);
599            logger.debug("M2 =  " + M2);
600        }
601        BigInteger Mq = Qi;
602        GenPolynomialRing<MOD> qfac;
603        qfac = new GenPolynomialRing<MOD>(Q, pfac); // mod p
604        GenPolynomialRing<MOD> mfac;
605        BigInteger Mi = Q.getIntegerModul().multiply(Q.getIntegerModul());
606        ModularRingFactory<MOD> Qmm;
607        // = new ModIntegerRing(Mi.getVal());
608        if (ModLongRing.MAX_LONG.compareTo(Mi.getVal()) > 0) {
609            Qmm = (ModularRingFactory) new ModLongRing(Mi.getVal());
610        } else {
611            Qmm = (ModularRingFactory) new ModIntegerRing(Mi.getVal());
612        }
613        mfac = new GenPolynomialRing<MOD>(Qmm, qfac); // mod p^e
614        MOD Qm = Qmm.fromInteger(Qi.getVal());
615
616        // partly normalize c and a, b factors, assert p is prime
617        GenPolynomial<BigInteger> Ai;
618        GenPolynomial<BigInteger> Bi;
619        BigInteger c = C.leadingBaseCoefficient();
620        C = C.multiply(c); // sic
621        MOD a = A.leadingBaseCoefficient();
622        if (!a.isONE()) { // A = A.monic();
623            A = A.divide(a);
624            S = S.multiply(a);
625        }
626        MOD b = B.leadingBaseCoefficient();
627        if (!b.isONE()) { // B = B.monic();
628            B = B.divide(b);
629            T = T.multiply(b);
630        }
631        MOD cm = P.fromInteger(c.getVal());
632        if (cm.isZERO()) {
633            System.out.println("c =  " + c);
634            System.out.println("P =  " + P);
635            throw new ArithmeticException("c mod p == 0 not meaningful");
636        }
637        // mod p
638        A = A.multiply(cm);
639        S = S.divide(cm);
640        B = B.multiply(cm);
641        T = T.divide(cm);
642        Ai = PolyUtil.integerFromModularCoefficients(fac, A);
643        Bi = PolyUtil.integerFromModularCoefficients(fac, B);
644        // replace leading base coefficients
645        ExpVector ea = Ai.leadingExpVector();
646        ExpVector eb = Bi.leadingExpVector();
647        Ai.doPutToMap(ea, c);
648        Bi.doPutToMap(eb, c);
649
650        // polynomials mod p
651        GenPolynomial<MOD> Ap;
652        GenPolynomial<MOD> Bp;
653        GenPolynomial<MOD> A1p = A;
654        GenPolynomial<MOD> B1p = B;
655        GenPolynomial<MOD> Sp = S;
656        GenPolynomial<MOD> Tp = T;
657
658        // polynomials mod q
659        GenPolynomial<MOD> Aq;
660        GenPolynomial<MOD> Bq;
661
662        // polynomials mod p^e
663        GenPolynomial<MOD> Cm;
664        GenPolynomial<MOD> Am;
665        GenPolynomial<MOD> Bm;
666        GenPolynomial<MOD> Em;
667        GenPolynomial<MOD> Emp;
668        GenPolynomial<MOD> Sm;
669        GenPolynomial<MOD> Tm;
670        GenPolynomial<MOD> Ema;
671        GenPolynomial<MOD> Emb;
672        GenPolynomial<MOD> Ema1;
673        GenPolynomial<MOD> Emb1;
674
675        // polynomials over the integers
676        GenPolynomial<BigInteger> Ei;
677        GenPolynomial<BigInteger> Si;
678        GenPolynomial<BigInteger> Ti;
679
680        Si = PolyUtil.integerFromModularCoefficients(fac, S);
681        Ti = PolyUtil.integerFromModularCoefficients(fac, T);
682
683        Aq = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Ai);
684        Bq = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Bi);
685
686        // polynomials mod p^e
687        Cm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, C);
688        Am = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Ai);
689        Bm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Bi);
690        Sm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Si);
691        Tm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Ti);
692        //System.out.println("Cm =  " + Cm);
693        //System.out.println("Am =  " + Am);
694        //System.out.println("Bm =  " + Bm);
695        //System.out.println("Ai =  " + Ai);
696        //System.out.println("Bi =  " + Bi);
697        //System.out.println("mfac =  " + mfac);
698
699        while (Mq.compareTo(M2) < 0) {
700            // compute E=(C-AB)/p mod p^e
701            if (debug) {
702                //System.out.println("mfac =  " + Cm.ring);
703                logger.debug("mfac =  " + Cm.ring);
704            }
705            Em = Cm.subtract(Am.multiply(Bm));
706            //System.out.println("Em =  " + Em);
707            if (Em.isZERO()) {
708                if (C.subtract(Ai.multiply(Bi)).isZERO()) {
709                    logger.info("leaving on zero E");
710                    break;
711                }
712            }
713            // Em = Em.divide( Qm );
714            Ei = PolyUtil.integerFromModularCoefficients(fac, Em);
715            Ei = Ei.divide(Qi);
716            //System.out.println("Ei =  " + Ei);
717
718            // Ei mod p
719            Emp = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Ei);
720            //            Emp = PolyUtil.<MOD>fromIntegerCoefficients(qfac,
721            //               PolyUtil.integerFromModularCoefficients(fac,Em) ); 
722            //System.out.println("Emp =  " + Emp);
723            //logger.info("Emp = " + Emp);
724            if (Emp.isZERO()) {
725                if (C.subtract(Ai.multiply(Bi)).isZERO()) {
726                    logger.info("leaving on zero Emp");
727                    break;
728                }
729            }
730
731            // construct approximation mod p
732            Ap = Sp.multiply(Emp); // S,T ++ T,S 
733            Bp = Tp.multiply(Emp);
734            GenPolynomial<MOD>[] QR = null;
735            QR = Ap.quotientRemainder(Bq); // Bq !
736            GenPolynomial<MOD> Qp = QR[0];
737            GenPolynomial<MOD> Rp = QR[1];
738            A1p = Rp;
739            B1p = Bp.sum(Aq.multiply(Qp)); // Aq !
740            //System.out.println("A1p =  " + A1p);
741            //System.out.println("B1p =  " + B1p);
742
743            // construct q-adic approximation
744            Ema = PolyUtil.<MOD> fromIntegerCoefficients(mfac,
745                            PolyUtil.integerFromModularCoefficients(fac, A1p));
746            Emb = PolyUtil.<MOD> fromIntegerCoefficients(mfac,
747                            PolyUtil.integerFromModularCoefficients(fac, B1p));
748            //System.out.println("Ema =  " + Ema);
749            //System.out.println("Emb =  " + Emb);
750            Ema1 = Ema.multiply(Qm);
751            Emb1 = Emb.multiply(Qm);
752            Ema = Am.sum(Emb1); // Eb1 and Ea1 are required
753            Emb = Bm.sum(Ema1); //--------------------------
754            assert (Ema.degree(0) + Emb.degree(0) <= Cm.degree(0));
755            //if ( Ema.degree(0)+Emb.degree(0) > Cm.degree(0) ) { // debug
756            //   throw new RuntimeException("deg(A)+deg(B) > deg(C)");
757            //}
758            Am = Ema;
759            Bm = Emb;
760            Ai = PolyUtil.integerFromModularCoefficients(fac, Am);
761            Bi = PolyUtil.integerFromModularCoefficients(fac, Bm);
762            //System.out.println("Am =  " + Am);
763            //System.out.println("Bm =  " + Bm);
764            //System.out.println("Ai =  " + Ai);
765            //System.out.println("Bi =  " + Bi + "\n");
766
767            // gcd representation factors error --------------------------------
768            // compute E=(1-SA-TB)/p mod p^e
769            Em = mfac.getONE();
770            Em = Em.subtract(Sm.multiply(Am)).subtract(Tm.multiply(Bm));
771            //System.out.println("Em  =  " + Em);
772            // Em = Em.divide( Pm );
773
774            Ei = PolyUtil.integerFromModularCoefficients(fac, Em);
775            Ei = Ei.divide(Qi);
776            //System.out.println("Ei =  " + Ei);
777            // Ei mod p
778            Emp = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Ei);
779            //Emp = PolyUtil.<MOD>fromIntegerCoefficients(qfac,
780            //               PolyUtil.integerFromModularCoefficients(fac,Em) );
781            //System.out.println("Emp =  " + Emp);
782
783            // construct approximation mod p
784            Ap = Sp.multiply(Emp); // S,T ++ T,S // Ep Eqp
785            Bp = Tp.multiply(Emp); // Ep Eqp
786            QR = Bp.quotientRemainder(Aq); // Ap Aq ! // Ai == A mod p ?
787            Qp = QR[0];
788            Rp = QR[1];
789            B1p = Rp;
790            A1p = Ap.sum(Bq.multiply(Qp));
791            //System.out.println("A1p =  " + A1p);
792            //System.out.println("B1p =  " + B1p);
793
794            // construct p^e-adic approximation
795            Ema = PolyUtil.<MOD> fromIntegerCoefficients(mfac,
796                            PolyUtil.integerFromModularCoefficients(fac, A1p));
797            Emb = PolyUtil.<MOD> fromIntegerCoefficients(mfac,
798                            PolyUtil.integerFromModularCoefficients(fac, B1p));
799            Ema1 = Ema.multiply(Qm);
800            Emb1 = Emb.multiply(Qm);
801            Ema = Sm.sum(Ema1); // Emb1 and Ema1 are required
802            Emb = Tm.sum(Emb1); //--------------------------
803            Sm = Ema;
804            Tm = Emb;
805            Si = PolyUtil.integerFromModularCoefficients(fac, Sm);
806            Ti = PolyUtil.integerFromModularCoefficients(fac, Tm);
807            //System.out.println("Sm =  " + Sm);
808            //System.out.println("Tm =  " + Tm);
809            //System.out.println("Si =  " + Si);
810            //System.out.println("Ti =  " + Ti + "\n");
811
812            // prepare for next iteration
813            Qi = Q.getIntegerModul().multiply(Q.getIntegerModul());
814            Mq = Qi;
815            //lmfac = mfac;
816            // Q = new ModIntegerRing(Qi.getVal());
817            if (ModLongRing.MAX_LONG.compareTo(Qi.getVal()) > 0) {
818                Q = (ModularRingFactory) new ModLongRing(Qi.getVal());
819            } else {
820                Q = (ModularRingFactory) new ModIntegerRing(Qi.getVal());
821            }
822            qfac = new GenPolynomialRing<MOD>(Q, pfac);
823            BigInteger Qmmi = Qmm.getIntegerModul().multiply(Qmm.getIntegerModul());
824            //Qmm = new ModIntegerRing(Qmmi.getVal());
825            if (ModLongRing.MAX_LONG.compareTo(Qmmi.getVal()) > 0) {
826                Qmm = (ModularRingFactory) new ModLongRing(Qmmi.getVal());
827            } else {
828                Qmm = (ModularRingFactory) new ModIntegerRing(Qmmi.getVal());
829            }
830            mfac = new GenPolynomialRing<MOD>(Qmm, qfac);
831            Qm = Qmm.fromInteger(Qi.getVal());
832
833            Cm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, C);
834            Am = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Ai);
835            Bm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Bi);
836            Sm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Si);
837            Tm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Ti);
838
839            assert (isHenselLift(C, Mi, PP, Ai, Bi));
840            Mi = Mi.fromInteger(Qmm.getIntegerModul().getVal());
841
842            Aq = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Ai);
843            Bq = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Bi);
844            Sp = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Si);
845            Tp = PolyUtil.<MOD> fromIntegerCoefficients(qfac, Ti);
846
847            //System.out.println("Am =  " + Am);
848            //System.out.println("Bm =  " + Bm);
849            //System.out.println("Sm =  " + Sm);
850            //System.out.println("Tm =  " + Tm);
851            //System.out.println("mfac =  " + mfac);
852            //System.out.println("Qmm = " + Qmm + ", M2   =  " + M2 + ", Mq   =  " + Mq + "\n");
853        }
854        //System.out.println("*Ai =  " + Ai);
855        //System.out.println("*Bi =  " + Bi);
856
857        Em = Cm.subtract(Am.multiply(Bm));
858        if (!Em.isZERO()) {
859            System.out.println("Em =  " + Em);
860            //throw new NoLiftingException("no exact lifting possible");
861        }
862        // remove normalization not possible when not exact factorization
863        GreatestCommonDivisorAbstract<BigInteger> ufd = new GreatestCommonDivisorPrimitive<BigInteger>();
864        // remove normalization if possible
865        BigInteger ai = ufd.baseContent(Ai);
866        Ai = Ai.divide(ai); // Ai=pp(Ai)
867        BigInteger[] qr = c.quotientRemainder(ai);
868        BigInteger bi = null;
869        boolean exact = true;
870        if (qr[1].isZERO()) {
871            bi = qr[0];
872            try {
873                Bi = Bi.divide(bi); // divide( c/a )
874            } catch (RuntimeException e) {
875                System.out.println("*catch: no exact factorization: " + bi + ", e = " + e);
876                exact = false;
877            }
878        } else {
879            System.out.println("*remainder: no exact factorization: q = " + qr[0] + ", r = " + qr[1]);
880            exact = false;
881        }
882        if (!exact) {
883            System.out.println("*Ai =  " + Ai);
884            System.out.println("*ai =  " + ai);
885            System.out.println("*Bi =  " + Bi);
886            System.out.println("*bi =  " + bi);
887            System.out.println("*c  =  " + c);
888            throw new NoLiftingException("no exact lifting possible");
889        }
890        return new HenselApprox<MOD>(Ai, Bi, Aq, Bq);
891    }
892
893
894    /**
895     * Modular Hensel lifting test. Let p be a prime number and assume C ==
896     * prod_{0,...,n-1} g_i mod p with gcd(g_i,g_j) == 1 mod p for i != j.
897     * @param C GenPolynomial
898     * @param G = [g_0,...,g_{n-1}] list of GenPolynomial
899     * @param M bound on the coefficients of g_i as factors of C.
900     * @param p prime number.
901     * @return true if C = prod_{0,...,n-1} g_i mod p^e, else false.
902     */
903    public static//<MOD extends GcdRingElem<MOD> & Modular> 
904    boolean isHenselLift(GenPolynomial<BigInteger> C, BigInteger M, BigInteger p,
905                    List<GenPolynomial<BigInteger>> G) {
906        if (C == null || C.isZERO()) {
907            return false;
908        }
909        GenPolynomialRing<BigInteger> pfac = C.ring;
910        ModIntegerRing pm = new ModIntegerRing(p.getVal(), true);
911        GenPolynomialRing<ModInteger> mfac = new GenPolynomialRing<ModInteger>(pm, pfac);
912
913        // check mod p
914        GenPolynomial<ModInteger> cl = mfac.getONE();
915        GenPolynomial<ModInteger> hlp;
916        for (GenPolynomial<BigInteger> hl : G) {
917            //System.out.println("hl       = " + hl);
918            hlp = PolyUtil.<ModInteger> fromIntegerCoefficients(mfac, hl);
919            //System.out.println("hl mod p = " + hlp);
920            cl = cl.multiply(hlp);
921        }
922        GenPolynomial<ModInteger> cp = PolyUtil.<ModInteger> fromIntegerCoefficients(mfac, C);
923        if (!cp.equals(cl)) {
924            System.out.println("Hensel precondition wrong!");
925            if (debug) {
926                System.out.println("cl      = " + cl);
927                System.out.println("cp      = " + cp);
928                System.out.println("mon(cl) = " + cl.monic());
929                System.out.println("mon(cp) = " + cp.monic());
930                System.out.println("cp-cl   = " + cp.subtract(cl));
931                System.out.println("M       = " + M + ", p = " + p);
932            }
933            return false;
934        }
935
936        // check mod p^e 
937        BigInteger mip = p;
938        while (mip.compareTo(M) < 0) {
939            mip = mip.multiply(mip); // p
940        }
941        // mip = mip.multiply(p);
942        pm = new ModIntegerRing(mip.getVal(), false);
943        mfac = new GenPolynomialRing<ModInteger>(pm, pfac);
944        cl = mfac.getONE();
945        for (GenPolynomial<BigInteger> hl : G) {
946            //System.out.println("hl         = " + hl);
947            hlp = PolyUtil.<ModInteger> fromIntegerCoefficients(mfac, hl);
948            //System.out.println("hl mod p^e = " + hlp);
949            cl = cl.multiply(hlp);
950        }
951        cp = PolyUtil.<ModInteger> fromIntegerCoefficients(mfac, C);
952        if (!cp.equals(cl)) {
953            System.out.println("Hensel post condition wrong!");
954            System.out.println("cl    = " + cl);
955            System.out.println("cp    = " + cp);
956            System.out.println("cp-cl = " + cp.subtract(cl));
957            System.out.println("M = " + M + ", p = " + p + ", p^e = " + mip);
958            return false;
959        }
960        return true;
961    }
962
963
964    /**
965     * Modular Hensel lifting test. Let p be a prime number and assume C == A *
966     * B mod p with gcd(A,B) == 1 mod p.
967     * @param C GenPolynomial
968     * @param A GenPolynomial
969     * @param B GenPolynomial
970     * @param M bound on the coefficients of A and B as factors of C.
971     * @param p prime number.
972     * @return true if C = A * B mod p**e, else false.
973     */
974    public static//<MOD extends GcdRingElem<MOD> & Modular>
975    boolean isHenselLift(GenPolynomial<BigInteger> C, BigInteger M, BigInteger p, GenPolynomial<BigInteger> A,
976                    GenPolynomial<BigInteger> B) {
977        List<GenPolynomial<BigInteger>> G = new ArrayList<GenPolynomial<BigInteger>>(2);
978        G.add(A);
979        G.add(B);
980        return isHenselLift(C, M, p, G);
981    }
982
983
984    /**
985     * Modular Hensel lifting test. Let p be a prime number and assume C == A *
986     * B mod p with gcd(A,B) == 1 mod p.
987     * @param C GenPolynomial
988     * @param Ha Hensel approximation.
989     * @param M bound on the coefficients of A and B as factors of C.
990     * @param p prime number.
991     * @return true if C = A * B mod p^e, else false.
992     */
993    public static <MOD extends GcdRingElem<MOD> & Modular> boolean isHenselLift(GenPolynomial<BigInteger> C,
994                    BigInteger M, BigInteger p, HenselApprox<MOD> Ha) {
995        List<GenPolynomial<BigInteger>> G = new ArrayList<GenPolynomial<BigInteger>>(2);
996        G.add(Ha.A);
997        G.add(Ha.B);
998        return isHenselLift(C, M, p, G);
999    }
1000
1001
1002    /**
1003     * Constructing and lifting algorithm for extended Euclidean relation. Let p
1004     * = A.ring.coFac.modul() and assume gcd(A,B) == 1 mod p.
1005     * @param A modular GenPolynomial
1006     * @param B modular GenPolynomial
1007     * @param k desired approximation exponent p^k.
1008     * @return [s,t] with s A + t B = 1 mod p^k.
1009     */
1010    @SuppressWarnings("unchecked")
1011    public static <MOD extends GcdRingElem<MOD> & Modular> GenPolynomial<MOD>[] liftExtendedEuclidean(
1012                    GenPolynomial<MOD> A, GenPolynomial<MOD> B, long k) throws NoLiftingException {
1013        if (A == null || A.isZERO() || B == null || B.isZERO()) {
1014            throw new IllegalArgumentException("A and B must be nonzero, A = " + A + ", B = " + B);
1015        }
1016        GenPolynomialRing<MOD> fac = A.ring;
1017        if (fac.nvar != 1) { // assert ?
1018            throw new IllegalArgumentException("polynomial ring not univariate");
1019        }
1020        // start with extended Euclidean relation mod p
1021        GenPolynomial<MOD>[] gst = null;
1022        try {
1023            gst = A.egcd(B);
1024            if (!gst[0].isONE()) {
1025                throw new NoLiftingException(
1026                                "A and B not coprime, gcd = " + gst[0] + ", A = " + A + ", B = " + B);
1027            }
1028        } catch (ArithmeticException e) {
1029            throw new NoLiftingException("coefficient error " + e);
1030        }
1031        GenPolynomial<MOD> S = gst[1];
1032        GenPolynomial<MOD> T = gst[2];
1033        //System.out.println("eeS = " + S + ": " + S.ring.coFac);
1034        //System.out.println("eeT = " + T + ": " + T.ring.coFac);
1035
1036        // setup integer polynomial ring
1037        GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac);
1038        GenPolynomial<BigInteger> one = ifac.getONE();
1039        GenPolynomial<BigInteger> Ai = PolyUtil.integerFromModularCoefficients(ifac, A);
1040        GenPolynomial<BigInteger> Bi = PolyUtil.integerFromModularCoefficients(ifac, B);
1041        GenPolynomial<BigInteger> Si = PolyUtil.integerFromModularCoefficients(ifac, S);
1042        GenPolynomial<BigInteger> Ti = PolyUtil.integerFromModularCoefficients(ifac, T);
1043        //System.out.println("Ai = " + Ai);
1044        //System.out.println("Bi = " + Bi);
1045        //System.out.println("Si = " + Si);
1046        //System.out.println("Ti = " + Ti);
1047
1048        // approximate mod p^i
1049        ModularRingFactory<MOD> mcfac = (ModularRingFactory<MOD>) fac.coFac;
1050        BigInteger p = mcfac.getIntegerModul();
1051        BigInteger modul = p;
1052        GenPolynomialRing<MOD> mfac; // = new GenPolynomialRing<MOD>(mcfac, fac);
1053        for (int i = 1; i < k; i++) {
1054            // e = 1 - s a - t b in Z[x]
1055            GenPolynomial<BigInteger> e = one.subtract(Si.multiply(Ai)).subtract(Ti.multiply(Bi));
1056            //System.out.println("\ne = " + e);
1057            if (e.isZERO()) {
1058                logger.info("leaving on zero e in liftExtendedEuclidean");
1059                break;
1060            }
1061            e = e.divide(modul);
1062            // move to Z_p[x] and compute next approximation 
1063            GenPolynomial<MOD> c = PolyUtil.<MOD> fromIntegerCoefficients(fac, e);
1064            //System.out.println("c = " + c + ": " + c.ring.coFac);
1065            GenPolynomial<MOD> s = S.multiply(c);
1066            GenPolynomial<MOD> t = T.multiply(c);
1067            //System.out.println("s = " + s + ": " + s.ring.coFac);
1068            //System.out.println("t = " + t + ": " + t.ring.coFac);
1069
1070            GenPolynomial<MOD>[] QR = s.quotientRemainder(B); // watch for ordering 
1071            GenPolynomial<MOD> q = QR[0];
1072            s = QR[1];
1073            t = t.sum(q.multiply(A));
1074            //System.out.println("s = " + s + ": " + s.ring.coFac);
1075            //System.out.println("t = " + t + ": " + t.ring.coFac);
1076
1077            GenPolynomial<BigInteger> si = PolyUtil.integerFromModularCoefficients(ifac, s);
1078            GenPolynomial<BigInteger> ti = PolyUtil.integerFromModularCoefficients(ifac, t);
1079            //System.out.println("si = " + si);
1080            //System.out.println("ti = " + si);
1081            // add approximation to solution
1082            Si = Si.sum(si.multiply(modul));
1083            Ti = Ti.sum(ti.multiply(modul));
1084            //System.out.println("Si = " + Si);
1085            //System.out.println("Ti = " + Ti);
1086            modul = modul.multiply(p);
1087            //System.out.println("modul = " + modul + ", " + p + "^" + k + ", p^k = " + p.power(k));
1088        }
1089        //System.out.println("Si = " + Si + ", Ti = " + Ti);
1090        // setup ring mod p^i
1091        if (ModLongRing.MAX_LONG.compareTo(modul.getVal()) > 0) {
1092            mcfac = (ModularRingFactory) new ModLongRing(modul.getVal());
1093        } else {
1094            mcfac = (ModularRingFactory) new ModIntegerRing(modul.getVal());
1095        }
1096        //System.out.println("mcfac = " + mcfac);
1097        mfac = new GenPolynomialRing<MOD>(mcfac, fac);
1098        S = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Si);
1099        T = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Ti);
1100        //System.out.println("S = " + S + ": " + S.ring.coFac);
1101        //System.out.println("T = " + T + ": " + T.ring.coFac);
1102        if (debug) {
1103            List<GenPolynomial<MOD>> AP = new ArrayList<GenPolynomial<MOD>>();
1104            AP.add(B);
1105            AP.add(A);
1106            List<GenPolynomial<MOD>> SP = new ArrayList<GenPolynomial<MOD>>();
1107            SP.add(S);
1108            SP.add(T);
1109            if (!HenselUtil.<MOD> isExtendedEuclideanLift(AP, SP)) {
1110                System.out.println("isExtendedEuclideanLift: false");
1111            }
1112        }
1113        @SuppressWarnings("cast")
1114        GenPolynomial<MOD>[] rel = (GenPolynomial<MOD>[]) new GenPolynomial[2];
1115        rel[0] = S;
1116        rel[1] = T;
1117        return rel;
1118    }
1119
1120
1121    /**
1122     * Constructing and lifting algorithm for extended Euclidean relation. Let p
1123     * = A_i.ring.coFac.modul() and assume gcd(A_i,A_j) == 1 mod p, i != j.
1124     * @param A list of modular GenPolynomials
1125     * @param k desired approximation exponent p^k.
1126     * @return [s_0,...,s_n-1] with sum_i s_i * B_i = 1 mod p^k, with B_i =
1127     *         prod_{i!=j} A_j.
1128     */
1129    public static <MOD extends GcdRingElem<MOD> & Modular> List<GenPolynomial<MOD>> liftExtendedEuclidean(
1130                    List<GenPolynomial<MOD>> A, long k) throws NoLiftingException {
1131        if (A == null || A.size() <= 1) {
1132            throw new IllegalArgumentException("A must be non null and non empty");
1133        }
1134        GenPolynomialRing<MOD> fac = A.get(0).ring;
1135        if (fac.nvar != 1) { // assert ?
1136            throw new IllegalArgumentException("polynomial ring not univariate");
1137        }
1138        GenPolynomial<MOD> zero = fac.getZERO();
1139        int r = A.size();
1140        List<GenPolynomial<MOD>> Q = new ArrayList<GenPolynomial<MOD>>(r);
1141        for (int i = 0; i < r; i++) {
1142            Q.add(zero);
1143        }
1144        //System.out.println("A = " + A);
1145        Q.set(r - 2, A.get(r - 1));
1146        for (int j = r - 3; j >= 0; j--) {
1147            GenPolynomial<MOD> q = A.get(j + 1).multiply(Q.get(j + 1));
1148            Q.set(j, q);
1149        }
1150        //System.out.println("Q = " + Q);
1151        List<GenPolynomial<MOD>> B = new ArrayList<GenPolynomial<MOD>>(r + 1);
1152        List<GenPolynomial<MOD>> lift = new ArrayList<GenPolynomial<MOD>>(r);
1153        for (int i = 0; i < r; i++) {
1154            B.add(zero);
1155            lift.add(zero);
1156        }
1157        GenPolynomial<MOD> one = fac.getONE();
1158        GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac);
1159        B.add(0, one);
1160        //System.out.println("B(0) = " + B.get(0));
1161        GenPolynomial<MOD> b = one;
1162        for (int j = 0; j < r - 1; j++) {
1163            //System.out.println("Q("+(j)+") = " + Q.get(j));
1164            //System.out.println("A("+(j)+") = " + A.get(j));
1165            //System.out.println("B("+(j)+") = " + B.get(j));
1166            List<GenPolynomial<MOD>> S = liftDiophant(Q.get(j), A.get(j), B.get(j), k);
1167            //System.out.println("\nSb = " + S);
1168            b = S.get(0);
1169            GenPolynomial<MOD> bb = PolyUtil.<MOD> fromIntegerCoefficients(fac,
1170                            PolyUtil.integerFromModularCoefficients(ifac, b));
1171            B.set(j + 1, bb);
1172            lift.set(j, S.get(1));
1173            //System.out.println("B("+(j+1)+") = " + B.get(j+1));
1174            if (debug) {
1175                logger.info("lift(" + j + ") = " + lift.get(j));
1176            }
1177        }
1178        //System.out.println("liftb = " + lift);
1179        lift.set(r - 1, b);
1180        if (debug) {
1181            logger.info("lift(" + (r - 1) + ") = " + b);
1182        }
1183        //System.out.println("B("+(r-1)+") = " + B.get(r-1) + " : " +  B.get(r-1).ring.coFac + ", b = " +  b + " : " +  b.ring.coFac);
1184        //System.out.println("B = " + B);
1185        //System.out.println("liftb = " + lift);
1186        return lift;
1187    }
1188
1189
1190    /**
1191     * Modular diophantine equation solution and lifting algorithm. Let p =
1192     * A_i.ring.coFac.modul() and assume gcd(A,B) == 1 mod p.
1193     * @param A modular GenPolynomial, mod p^k
1194     * @param B modular GenPolynomial, mod p^k
1195     * @param C modular GenPolynomial, mod p^k
1196     * @param k desired approximation exponent p^k.
1197     * @return [s, t] with s A' + t B' = C mod p^k, with A' = B, B' = A.
1198     */
1199    public static <MOD extends GcdRingElem<MOD> & Modular> List<GenPolynomial<MOD>> liftDiophant(
1200                    GenPolynomial<MOD> A, GenPolynomial<MOD> B, GenPolynomial<MOD> C, long k)
1201                    throws NoLiftingException {
1202        if (A == null || A.isZERO() || B == null || B.isZERO()) {
1203            throw new IllegalArgumentException(
1204                            "A and B must be nonzero, A = " + A + ", B = " + B + ", C = " + C);
1205        }
1206        List<GenPolynomial<MOD>> sol = new ArrayList<GenPolynomial<MOD>>();
1207        GenPolynomialRing<MOD> fac = C.ring;
1208        if (fac.nvar != 1) { // assert ?
1209            throw new IllegalArgumentException("polynomial ring not univariate");
1210        }
1211        //System.out.println("C = " + C);
1212        GenPolynomial<MOD> zero = fac.getZERO();
1213        for (int i = 0; i < 2; i++) {
1214            sol.add(zero);
1215        }
1216        GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac);
1217        for (Monomial<MOD> m : C) {
1218            //System.out.println("monomial = " + m);
1219            long e = m.e.getVal(0);
1220            List<GenPolynomial<MOD>> S = liftDiophant(A, B, e, k);
1221            //System.out.println("Se = " + S);
1222            MOD a = m.c;
1223            //System.out.println("C.fac = " + fac.toScript());
1224            a = fac.coFac.fromInteger(a.getSymmetricInteger().getVal());
1225            int i = 0;
1226            for (GenPolynomial<MOD> d : S) {
1227                //System.out.println("d = " + d);
1228                d = PolyUtil.<MOD> fromIntegerCoefficients(fac,
1229                                PolyUtil.integerFromModularCoefficients(ifac, d));
1230                d = d.multiply(a);
1231                d = sol.get(i).sum(d);
1232                //System.out.println("d = " + d);
1233                sol.set(i++, d);
1234            }
1235            //System.out.println("sol = " + sol + ", for " + m);
1236        }
1237        if (debug) {
1238            //GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac);
1239            A = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, A));
1240            B = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, B));
1241            C = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, C));
1242            GenPolynomial<MOD> y = B.multiply(sol.get(0)).sum(A.multiply(sol.get(1)));
1243            if (!y.equals(C)) {
1244                System.out.println("A = " + A + ", B = " + B);
1245                System.out.println("s1 = " + sol.get(0) + ", s2 = " + sol.get(1));
1246                System.out.println("Error: A*r1 + B*r2 = " + y + " : " + fac.coFac);
1247            }
1248        }
1249        return sol;
1250    }
1251
1252
1253    /**
1254     * Modular diophantine equation solution and lifting algorithm. Let p =
1255     * A_i.ring.coFac.modul() and assume gcd(a,b) == 1 mod p, for a, b in A.
1256     * @param A list of modular GenPolynomials, mod p^k
1257     * @param C modular GenPolynomial, mod p^k
1258     * @param k desired approximation exponent p^k.
1259     * @return [s_1,..., s_n] with sum_i s_i A_i' = C mod p^k, with Ai' =
1260     *         prod_{j!=i} A_j.
1261     */
1262    public static <MOD extends GcdRingElem<MOD> & Modular> List<GenPolynomial<MOD>> liftDiophant(
1263                    List<GenPolynomial<MOD>> A, GenPolynomial<MOD> C, long k) throws NoLiftingException {
1264        if (false && A.size() <= 2) {
1265            return HenselUtil.<MOD> liftDiophant(A.get(0), A.get(1), C, k);
1266        }
1267        List<GenPolynomial<MOD>> sol = new ArrayList<GenPolynomial<MOD>>();
1268        GenPolynomialRing<MOD> fac = C.ring;
1269        if (fac.nvar != 1) { // assert ?
1270            throw new IllegalArgumentException("polynomial ring not univariate");
1271        }
1272        //System.out.println("C = " + C);
1273        GenPolynomial<MOD> zero = fac.getZERO();
1274        for (int i = 0; i < A.size(); i++) {
1275            sol.add(zero);
1276        }
1277        GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac);
1278        for (Monomial<MOD> m : C) {
1279            //System.out.println("monomial = " + m);
1280            long e = m.e.getVal(0);
1281            List<GenPolynomial<MOD>> S = liftDiophant(A, e, k);
1282            //System.out.println("Se = " + S);
1283            MOD a = m.c;
1284            //System.out.println("C.fac = " + fac.toScript());
1285            a = fac.coFac.fromInteger(a.getSymmetricInteger().getVal());
1286            int i = 0;
1287            for (GenPolynomial<MOD> d : S) {
1288                //System.out.println("d = " + d);
1289                d = PolyUtil.<MOD> fromIntegerCoefficients(fac,
1290                                PolyUtil.integerFromModularCoefficients(ifac, d));
1291                d = d.multiply(a);
1292                d = sol.get(i).sum(d);
1293                //System.out.println("d = " + d);
1294                sol.set(i++, d);
1295            }
1296            //System.out.println("sol = " + sol + ", for " + m);
1297        }
1298        /*
1299        if (true || debug) {
1300            //GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac);
1301            A = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, A));
1302            B = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, B));
1303            C = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, C));
1304            GenPolynomial<MOD> y = B.multiply(sol.get(0)).sum(A.multiply(sol.get(1)));
1305            if (!y.equals(C)) {
1306                System.out.println("A = " + A + ", B = " + B);
1307                System.out.println("s1 = " + sol.get(0) + ", s2 = " + sol.get(1));
1308                System.out.println("Error: A*r1 + B*r2 = " + y + " : " + fac.coFac);
1309            }
1310        }
1311        */
1312        return sol;
1313    }
1314
1315
1316    /**
1317     * Modular diophantine equation solution and lifting algorithm. Let p =
1318     * A_i.ring.coFac.modul() and assume gcd(A,B) == 1 mod p.
1319     * @param A modular GenPolynomial
1320     * @param B modular GenPolynomial
1321     * @param e exponent for x^e
1322     * @param k desired approximation exponent p^k.
1323     * @return [s, t] with s A' + t B' = x^e mod p^k, with A' = B, B' = A.
1324     */
1325    public static <MOD extends GcdRingElem<MOD> & Modular> List<GenPolynomial<MOD>> liftDiophant(
1326                    GenPolynomial<MOD> A, GenPolynomial<MOD> B, long e, long k) throws NoLiftingException {
1327        if (A == null || A.isZERO() || B == null || B.isZERO()) {
1328            throw new IllegalArgumentException("A and B must be nonzero, A = " + A + ", B = " + B);
1329        }
1330        List<GenPolynomial<MOD>> sol = new ArrayList<GenPolynomial<MOD>>();
1331        GenPolynomialRing<MOD> fac = A.ring;
1332        if (fac.nvar != 1) { // assert ?
1333            throw new IllegalArgumentException("polynomial ring not univariate");
1334        }
1335        // lift EE relation to p^k
1336        GenPolynomial<MOD>[] lee = liftExtendedEuclidean(B, A, k);
1337        GenPolynomial<MOD> s1 = lee[0];
1338        GenPolynomial<MOD> s2 = lee[1];
1339        if (e == 0L) {
1340            sol.add(s1);
1341            sol.add(s2);
1342            //System.out.println("sol@0 = " + sol); 
1343            return sol;
1344        }
1345        fac = s1.ring;
1346        GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac);
1347        A = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, A));
1348        B = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, B));
1349
1350        //      this is the wrong sequence:
1351        //         GenPolynomial<MOD> xe = fac.univariate(0,e);
1352        //         GenPolynomial<MOD> q = s1.multiply(xe);
1353        //         GenPolynomial<MOD>[] QR = q.quotientRemainder(B);
1354        //         q = QR[0];
1355        //         GenPolynomial<MOD> r1 = QR[1];
1356        //         GenPolynomial<MOD> r2 = s2.multiply(xe).sum( q.multiply(A) );
1357
1358        GenPolynomial<MOD> xe = fac.univariate(0, e);
1359        GenPolynomial<MOD> q = s1.multiply(xe);
1360        GenPolynomial<MOD>[] QR = q.quotientRemainder(A);
1361        q = QR[0];
1362        //System.out.println("ee coeff qr = " + Arrays.toString(QR));
1363        GenPolynomial<MOD> r1 = QR[1];
1364        GenPolynomial<MOD> r2 = s2.multiply(xe).sum(q.multiply(B));
1365        //System.out.println("r1 = " + r1 + ", r2 = " + r2);
1366        sol.add(r1);
1367        sol.add(r2);
1368        //System.out.println("sol@"+ e + " = " + sol); 
1369        if (debug) {
1370            GenPolynomial<MOD> y = B.multiply(r1).sum(A.multiply(r2));
1371            if (!y.equals(xe)) {
1372                System.out.println("A = " + A + ", B = " + B);
1373                System.out.println("r1 = " + r1 + ", r2 = " + r2);
1374                System.out.println("Error: A*r1 + B*r2 = " + y);
1375            }
1376        }
1377        return sol;
1378    }
1379
1380
1381    /**
1382     * Modular diophantine equation solution and lifting algorithm. Let p =
1383     * A_i.ring.coFac.modul() and assume gcd(a,b) == 1 mod p, for a, b in A.
1384     * @param A list of modular GenPolynomials
1385     * @param e exponent for x^e
1386     * @param k desired approximation exponent p^k.
1387     * @return [s_1,..., s_n] with sum_i s_i A_i' = x^e mod p^k, with Ai' =
1388     *         prod_{j!=i} A_j.
1389     */
1390    public static <MOD extends GcdRingElem<MOD> & Modular> List<GenPolynomial<MOD>> liftDiophant(
1391                    List<GenPolynomial<MOD>> A, long e, long k) throws NoLiftingException {
1392        if (false && A.size() <= 2) {
1393            return HenselUtil.<MOD> liftDiophant(A.get(0), A.get(1), e, k);
1394        }
1395        List<GenPolynomial<MOD>> sol = new ArrayList<GenPolynomial<MOD>>();
1396        GenPolynomialRing<MOD> fac = A.get(0).ring;
1397        if (fac.nvar != 1) { // assert ?
1398            throw new IllegalArgumentException("polynomial ring not univariate");
1399        }
1400        // lift EE relation to p^k
1401        List<GenPolynomial<MOD>> lee = liftExtendedEuclidean(A, k);
1402        if (e == 0L) {
1403            //System.out.println("sol@0 = " + sol); 
1404            return lee;
1405        }
1406        fac = lee.get(0).ring;
1407        GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac);
1408        List<GenPolynomial<MOD>> S = new ArrayList<GenPolynomial<MOD>>(lee.size());
1409        for (GenPolynomial<MOD> a : lee) {
1410            a = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, a));
1411            S.add(a);
1412        }
1413        GenPolynomial<MOD> xe = fac.univariate(0, e);
1414        //List<GenPolynomial<MOD>> Sr = new ArrayList<GenPolynomial<MOD>>(lee.size());
1415        int i = 0;
1416        for (GenPolynomial<MOD> s : S) {
1417            GenPolynomial<MOD> q = s.multiply(xe);
1418            GenPolynomial<MOD> r = q.remainder(A.get(i++));
1419            //System.out.println("r = " + r);
1420            sol.add(r);
1421        }
1422        //System.out.println("sol@"+ e + " = " + sol); 
1423        /*
1424        if (true || debug) {
1425            GenPolynomial<MOD> y = B.multiply(r1).sum(A.multiply(r2));
1426            if (!y.equals(xe)) {
1427                System.out.println("A = " + A + ", B = " + B);
1428                System.out.println("r1 = " + r1 + ", r2 = " + r2);
1429                System.out.println("Error: A*r1 + B*r2 = " + y);
1430            }
1431        }
1432        */
1433        return sol;
1434    }
1435
1436
1437    /**
1438     * Modular Diophant relation lifting test.
1439     * @param A modular GenPolynomial
1440     * @param B modular GenPolynomial
1441     * @param C modular GenPolynomial
1442     * @param S1 modular GenPolynomial
1443     * @param S2 modular GenPolynomial
1444     * @return true if A*S1 + B*S2 = C, else false.
1445     */
1446    public static <MOD extends GcdRingElem<MOD> & Modular> boolean isDiophantLift(GenPolynomial<MOD> A,
1447                    GenPolynomial<MOD> B, GenPolynomial<MOD> S1, GenPolynomial<MOD> S2,
1448                    GenPolynomial<MOD> C) {
1449        GenPolynomialRing<MOD> fac = C.ring;
1450        GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac);
1451        GenPolynomial<MOD> a = PolyUtil.<MOD> fromIntegerCoefficients(fac,
1452                        PolyUtil.integerFromModularCoefficients(ifac, A));
1453        GenPolynomial<MOD> b = PolyUtil.<MOD> fromIntegerCoefficients(fac,
1454                        PolyUtil.integerFromModularCoefficients(ifac, B));
1455        GenPolynomial<MOD> s1 = PolyUtil.<MOD> fromIntegerCoefficients(fac,
1456                        PolyUtil.integerFromModularCoefficients(ifac, S1));
1457        GenPolynomial<MOD> s2 = PolyUtil.<MOD> fromIntegerCoefficients(fac,
1458                        PolyUtil.integerFromModularCoefficients(ifac, S2));
1459        GenPolynomial<MOD> t = a.multiply(s1).sum(b.multiply(s2));
1460        if (t.equals(C)) {
1461            return true;
1462        }
1463        if (debug) {
1464            System.out.println("a  = " + a);
1465            System.out.println("b  = " + b);
1466            System.out.println("s1 = " + s1);
1467            System.out.println("s2 = " + s2);
1468            System.out.println("t  = " + t);
1469            System.out.println("C  = " + C);
1470        }
1471        return false;
1472    }
1473
1474
1475    /**
1476     * Modular extended Euclidean relation lifting test.
1477     * @param A list of GenPolynomials
1478     * @param S = [s_0,...,s_{n-1}] list of GenPolynomial
1479     * @return true if prod_{0,...,n-1} s_i * B_i = 1 mod p^e, with B_i =
1480     *         prod_{i!=j} A_j, else false.
1481     */
1482    public static <MOD extends GcdRingElem<MOD> & Modular> boolean isExtendedEuclideanLift(
1483                    List<GenPolynomial<MOD>> A, List<GenPolynomial<MOD>> S) {
1484        GenPolynomialRing<MOD> fac = A.get(0).ring;
1485        GenPolynomial<MOD> C = fac.getONE();
1486        return isDiophantLift(A, S, C);
1487    }
1488
1489
1490    /**
1491     * Modular Diophant relation lifting test.
1492     * @param A list of GenPolynomials
1493     * @param S = [s_0,...,s_{n-1}] list of GenPolynomials
1494     * @param C = GenPolynomial
1495     * @return true if prod_{0,...,n-1} s_i * B_i = C mod p^k, with B_i =
1496     *         prod_{i!=j} A_j, else false.
1497     */
1498    public static <MOD extends GcdRingElem<MOD> & Modular> boolean isDiophantLift(List<GenPolynomial<MOD>> A,
1499                    List<GenPolynomial<MOD>> S, GenPolynomial<MOD> C) {
1500        GenPolynomialRing<MOD> fac = A.get(0).ring;
1501        GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac);
1502        List<GenPolynomial<MOD>> B = new ArrayList<GenPolynomial<MOD>>(A.size());
1503        int i = 0;
1504        for (GenPolynomial<MOD> ai : A) {
1505            GenPolynomial<MOD> b = fac.getONE();
1506            int j = 0;
1507            for (GenPolynomial<MOD> aj : A) {
1508                if (i != j /*!ai.equals(aj)*/) {
1509                    b = b.multiply(aj);
1510                }
1511                j++;
1512            }
1513            //System.out.println("b = " + b);
1514            b = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, b));
1515            B.add(b);
1516            i++;
1517        }
1518        //System.out.println("B = " + B);
1519        // check mod p^e 
1520        GenPolynomial<MOD> t = fac.getZERO();
1521        i = 0;
1522        for (GenPolynomial<MOD> a : B) {
1523            GenPolynomial<MOD> b = S.get(i++);
1524            b = PolyUtil.<MOD> fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, b));
1525            GenPolynomial<MOD> s = a.multiply(b);
1526            t = t.sum(s);
1527        }
1528        if (!t.equals(C)) {
1529            if (debug) {
1530                System.out.println("no diophant lift!");
1531                System.out.println("A = " + A);
1532                System.out.println("B = " + B);
1533                System.out.println("S = " + S);
1534                System.out.println("C = " + C);
1535                System.out.println("t = " + t);
1536            }
1537            return false;
1538        }
1539        return true;
1540    }
1541
1542
1543    /**
1544     * Modular Hensel lifting algorithm on coefficients. Let p =
1545     * f_i.ring.coFac.modul() and assume C == prod_{0,...,n-1} f_i mod p with
1546     * gcd(f_i,f_j) == 1 mod p for i != j
1547     * @param C monic integer polynomial
1548     * @param F = [f_0,...,f_{n-1}] list of monic modular polynomials.
1549     * @param k approximation exponent.
1550     * @return [g_0,...,g_{n-1}] with C = prod_{0,...,n-1} g_i mod p^k.
1551     */
1552    @SuppressWarnings("unchecked")
1553    public static <MOD extends GcdRingElem<MOD> & Modular> List<GenPolynomial<MOD>> liftHenselMonic(
1554                    GenPolynomial<BigInteger> C, List<GenPolynomial<MOD>> F, long k)
1555                    throws NoLiftingException {
1556        if (C == null || C.isZERO() || F == null || F.size() == 0) {
1557            throw new IllegalArgumentException("C must be nonzero and F must be nonempty");
1558        }
1559        GenPolynomialRing<BigInteger> fac = C.ring;
1560        if (fac.nvar != 1) { // assert ?
1561            throw new IllegalArgumentException("polynomial ring not univariate");
1562        }
1563        List<GenPolynomial<MOD>> lift = new ArrayList<GenPolynomial<MOD>>(F.size());
1564        GenPolynomialRing<MOD> pfac = F.get(0).ring;
1565        RingFactory<MOD> pcfac = pfac.coFac;
1566        ModularRingFactory<MOD> PF = (ModularRingFactory<MOD>) pcfac;
1567        BigInteger P = PF.getIntegerModul();
1568        int n = F.size();
1569        if (n == 1) { // lift F_0, this case will probably never be used
1570            GenPolynomial<MOD> f = F.get(0);
1571            ModularRingFactory<MOD> mcfac;
1572            if (ModLongRing.MAX_LONG.compareTo(P.getVal()) > 0) {
1573                mcfac = (ModularRingFactory) new ModLongRing(P.getVal());
1574            } else {
1575                mcfac = (ModularRingFactory) new ModIntegerRing(P.getVal());
1576            }
1577            GenPolynomialRing<MOD> mfac = new GenPolynomialRing<MOD>(mcfac, fac);
1578            f = PolyUtil.fromIntegerCoefficients(mfac, PolyUtil.integerFromModularCoefficients(fac, f));
1579            lift.add(f);
1580            return lift;
1581        }
1582        //         if (n == 2) { // only one step
1583        //             HenselApprox<MOD> ab = HenselUtil.<MOD> liftHenselQuadratic(C, M, F.get(0), F.get(1));
1584        //             lift.add(ab.Am);
1585        //             lift.add(ab.Bm);
1586        //             return lift;
1587        //         }
1588
1589        // setup integer polynomial ring
1590        GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac);
1591        List<GenPolynomial<BigInteger>> Fi = PolyUtil.integerFromModularCoefficients(ifac, F);
1592        //System.out.println("Fi = " + Fi);
1593
1594        List<GenPolynomial<MOD>> S = liftExtendedEuclidean(F, k + 1); // lift works for any k, use this
1595        //System.out.println("Sext = " + S);
1596        if (debug) {
1597            logger.info("EE lift = " + S);
1598            // adjust coefficients
1599            List<GenPolynomial<MOD>> Sx = PolyUtil.fromIntegerCoefficients(pfac,
1600                            PolyUtil.integerFromModularCoefficients(ifac, S));
1601            try {
1602                boolean il = HenselUtil.<MOD> isExtendedEuclideanLift(F, Sx);
1603                //System.out.println("islift = " + il);
1604            } catch (RuntimeException e) {
1605                e.printStackTrace();
1606            }
1607        }
1608        List<GenPolynomial<BigInteger>> Si = PolyUtil.integerFromModularCoefficients(ifac, S);
1609        //System.out.println("Si = " + Si);
1610        //System.out.println("C = " + C);
1611
1612        // approximate mod p^i
1613        ModularRingFactory<MOD> mcfac = PF;
1614        BigInteger p = mcfac.getIntegerModul();
1615        BigInteger modul = p;
1616        GenPolynomialRing<MOD> mfac = new GenPolynomialRing<MOD>(mcfac, fac);
1617        List<GenPolynomial<MOD>> Sp = PolyUtil.fromIntegerCoefficients(mfac, Si);
1618        //System.out.println("Sp = " + Sp);
1619        for (int i = 1; i < k; i++) {
1620            //System.out.println("i = " + i);
1621            GenPolynomial<BigInteger> e = fac.getONE();
1622            for (GenPolynomial<BigInteger> fi : Fi) {
1623                e = e.multiply(fi);
1624            }
1625            e = C.subtract(e);
1626            //System.out.println("\ne = " + e);
1627            if (e.isZERO()) {
1628                logger.info("leaving on zero e");
1629                break;
1630            }
1631            try {
1632                e = e.divide(modul);
1633            } catch (RuntimeException ex) {
1634                ex.printStackTrace();
1635                throw ex;
1636            }
1637            //System.out.println("e = " + e);
1638            // move to in Z_p[x]
1639            GenPolynomial<MOD> c = PolyUtil.<MOD> fromIntegerCoefficients(mfac, e);
1640            //System.out.println("c = " + c + ": " + c.ring.coFac);
1641
1642            List<GenPolynomial<MOD>> s = new ArrayList<GenPolynomial<MOD>>(S.size());
1643            int j = 0;
1644            for (GenPolynomial<MOD> f : Sp) {
1645                f = f.multiply(c);
1646                //System.out.println("f = " + f + " : " + f.ring.coFac);
1647                //System.out.println("F,i = " + F.get(j) + " : " + F.get(j).ring.coFac);
1648                f = f.remainder(F.get(j++));
1649                //System.out.println("f = " + f + " : " + f.ring.coFac);
1650                s.add(f);
1651            }
1652            //System.out.println("s = " + s);
1653            List<GenPolynomial<BigInteger>> si = PolyUtil.integerFromModularCoefficients(ifac, s);
1654            //System.out.println("si = " + si);
1655
1656            List<GenPolynomial<BigInteger>> Fii = new ArrayList<GenPolynomial<BigInteger>>(F.size());
1657            j = 0;
1658            for (GenPolynomial<BigInteger> f : Fi) {
1659                f = f.sum(si.get(j++).multiply(modul));
1660                Fii.add(f);
1661            }
1662            //System.out.println("Fii = " + Fii);
1663            Fi = Fii;
1664            modul = modul.multiply(p);
1665            if (i >= k - 1) {
1666                logger.info("e != 0 for k = " + k);
1667            }
1668        }
1669        // setup ring mod p^k
1670        modul = p.power(k);
1671        if (ModLongRing.MAX_LONG.compareTo(modul.getVal()) > 0) {
1672            mcfac = (ModularRingFactory) new ModLongRing(modul.getVal());
1673        } else {
1674            mcfac = (ModularRingFactory) new ModIntegerRing(modul.getVal());
1675        }
1676        //System.out.println("mcfac = " + mcfac);
1677        mfac = new GenPolynomialRing<MOD>(mcfac, fac);
1678        lift = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Fi);
1679        //System.out.println("lift = " + lift + ": " + lift.get(0).ring.coFac);
1680        return lift;
1681    }
1682
1683
1684    /**
1685     * Modular Hensel lifting algorithm on coefficients. Let p =
1686     * f_i.ring.coFac.modul() and assume C == prod_{0,...,n-1} f_i mod p with
1687     * gcd(f_i,f_j) == 1 mod p for i != j
1688     * @param C integer polynomial
1689     * @param F = [f_0,...,f_{n-1}] list of monic modular polynomials.
1690     * @param k approximation exponent.
1691     * @param g leading coefficient.
1692     * @return [g_0,...,g_{n-1}] with C = prod_{0,...,n-1} g_i mod p^k.
1693     */
1694    @SuppressWarnings("unchecked")
1695    public static <MOD extends GcdRingElem<MOD> & Modular> List<GenPolynomial<MOD>> liftHensel(
1696                    GenPolynomial<BigInteger> C, List<GenPolynomial<MOD>> F, long k, BigInteger g)
1697                    throws NoLiftingException {
1698        if (C == null || C.isZERO() || F == null || F.size() == 0) {
1699            throw new IllegalArgumentException("C must be nonzero and F must be nonempty");
1700        }
1701        GenPolynomialRing<BigInteger> fac = C.ring;
1702        if (fac.nvar != 1) { // assert ?
1703            throw new IllegalArgumentException("polynomial ring not univariate");
1704        }
1705        List<GenPolynomial<MOD>> lift = new ArrayList<GenPolynomial<MOD>>(F.size());
1706        GenPolynomialRing<MOD> pfac = F.get(0).ring;
1707        RingFactory<MOD> pcfac = pfac.coFac;
1708        ModularRingFactory<MOD> PF = (ModularRingFactory<MOD>) pcfac;
1709        BigInteger P = PF.getIntegerModul();
1710        int n = F.size();
1711        if (n == 1) { // lift F_0, this case will probably never be used
1712            GenPolynomial<MOD> f = F.get(0);
1713            ModularRingFactory<MOD> mcfac;
1714            if (ModLongRing.MAX_LONG.compareTo(P.getVal()) > 0) {
1715                mcfac = (ModularRingFactory) new ModLongRing(P.getVal());
1716            } else {
1717                mcfac = (ModularRingFactory) new ModIntegerRing(P.getVal());
1718            }
1719            GenPolynomialRing<MOD> mfac = new GenPolynomialRing<MOD>(mcfac, fac);
1720            f = PolyUtil.fromIntegerCoefficients(mfac, PolyUtil.integerFromModularCoefficients(fac, f));
1721            lift.add(f);
1722            return lift;
1723        }
1724        // if (n == 2) { // only one step
1725        //     HenselApprox<MOD> ab = HenselUtil.<MOD> liftHenselQuadratic(C, M, F.get(0), F.get(1));
1726        //     lift.add(ab.Am);
1727        //     lift.add(ab.Bm);
1728        //     return lift;
1729        // }
1730
1731        // normalize C and F_i factors
1732        BigInteger cc = g; //C.leadingBaseCoefficient(); // == g ??
1733        for (int i = 1; i < F.size(); i++) { // #F-1
1734            C = C.multiply(cc); // sic
1735        }
1736        MOD cm = PF.fromInteger(cc.getVal());
1737        List<GenPolynomial<MOD>> Fp = new ArrayList<GenPolynomial<MOD>>(F.size());
1738        for (GenPolynomial<MOD> fm : F) {
1739            GenPolynomial<MOD> am = fm.monic();
1740            am = am.multiply(cm);
1741            Fp.add(am);
1742        }
1743        F = Fp;
1744
1745        // setup integer polynomial ring
1746        GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), fac);
1747        List<GenPolynomial<BigInteger>> Fi = PolyUtil.integerFromModularCoefficients(ifac, F);
1748        //System.out.println("Fi = " + Fi);
1749
1750        // inplace modify polynomials, replace leading coefficient
1751        for (GenPolynomial<BigInteger> ai : Fi) {
1752            if (ai.isZERO()) {
1753                continue;
1754            }
1755            ExpVector ea = ai.leadingExpVector();
1756            ai.doPutToMap(ea, cc);
1757        }
1758        //System.out.println("Fi = " + Fi);
1759
1760        List<GenPolynomial<MOD>> S = liftExtendedEuclidean(F, k + 1); // lift works for any k, use this
1761        //System.out.println("Sext = " + S);
1762        if (debug) {
1763            logger.info("EE lift = " + S);
1764            // adjust coefficients
1765            List<GenPolynomial<MOD>> Sx = PolyUtil.fromIntegerCoefficients(pfac,
1766                            PolyUtil.integerFromModularCoefficients(ifac, S));
1767            try {
1768                boolean il = HenselUtil.<MOD> isExtendedEuclideanLift(F, Sx);
1769                //System.out.println("islift = " + il);
1770            } catch (RuntimeException e) {
1771                e.printStackTrace();
1772            }
1773        }
1774        List<GenPolynomial<BigInteger>> Si = PolyUtil.integerFromModularCoefficients(ifac, S);
1775        //System.out.println("Si = " + Si);
1776        //System.out.println("C = " + C);
1777
1778        // approximate mod p^i
1779        ModularRingFactory<MOD> mcfac = PF;
1780        BigInteger p = mcfac.getIntegerModul();
1781        BigInteger modul = p;
1782        GenPolynomialRing<MOD> mfac = new GenPolynomialRing<MOD>(mcfac, fac);
1783        List<GenPolynomial<MOD>> Sp = PolyUtil.fromIntegerCoefficients(mfac, Si);
1784        //System.out.println("Sp = " + Sp);
1785        for (int i = 1; i < k; i++) {
1786            //System.out.println("i = " + i);
1787            GenPolynomial<BigInteger> e = fac.getONE();
1788            for (GenPolynomial<BigInteger> fi : Fi) {
1789                e = e.multiply(fi);
1790            }
1791            e = C.subtract(e);
1792            //System.out.println("\ne = " + e);
1793            if (e.isZERO()) {
1794                logger.info("leaving on zero e");
1795                break;
1796            }
1797            try {
1798                e = e.divide(modul);
1799            } catch (RuntimeException ex) {
1800                ex.printStackTrace();
1801                throw ex;
1802            }
1803            //System.out.println("e = " + e);
1804            // move to in Z_p[x]
1805            GenPolynomial<MOD> c = PolyUtil.<MOD> fromIntegerCoefficients(mfac, e);
1806            //System.out.println("c = " + c + ": " + c.ring.coFac);
1807
1808            List<GenPolynomial<MOD>> s = new ArrayList<GenPolynomial<MOD>>(S.size());
1809            int j = 0;
1810            for (GenPolynomial<MOD> f : Sp) {
1811                f = f.multiply(c);
1812                //System.out.println("f = " + f + " : " + f.ring.coFac);
1813                //System.out.println("F,i = " + F.get(j) + " : " + F.get(j).ring.coFac);
1814                f = f.remainder(F.get(j++));
1815                //System.out.println("f = " + f + " : " + f.ring.coFac);
1816                s.add(f);
1817            }
1818            //System.out.println("s = " + s);
1819            List<GenPolynomial<BigInteger>> si = PolyUtil.integerFromModularCoefficients(ifac, s);
1820            //System.out.println("si = " + si);
1821
1822            List<GenPolynomial<BigInteger>> Fii = new ArrayList<GenPolynomial<BigInteger>>(F.size());
1823            j = 0;
1824            for (GenPolynomial<BigInteger> f : Fi) {
1825                f = f.sum(si.get(j++).multiply(modul));
1826                Fii.add(f);
1827            }
1828            //System.out.println("Fii = " + Fii);
1829            Fi = Fii;
1830            modul = modul.multiply(p);
1831            if (i >= k - 1) {
1832                logger.info("e != 0 for k = " + k);
1833            }
1834        }
1835        //System.out.println("Fi = " + Fi);
1836        // remove normalization
1837        GreatestCommonDivisorAbstract<BigInteger> ufd = GCDFactory.getImplementation(cc);
1838        //BigInteger ai = ufd.baseContent(Fi.get(0));
1839        //System.out.println("ai = " + ai + ", cc = " + cc);
1840        List<GenPolynomial<BigInteger>> Fii = new ArrayList<GenPolynomial<BigInteger>>(F.size());
1841        //int j = 0;
1842        for (GenPolynomial<BigInteger> bi : Fi) {
1843            GenPolynomial<BigInteger> ci = null;
1844            //if ( j++ == 0 ) {
1845            //    ci = bi.divide(ai);
1846            //} else {
1847            //    BigInteger i = cc.divide(ai);
1848            //    ci = bi.divide(i);
1849            //}
1850            ci = ufd.basePrimitivePart(bi); // ??
1851            //System.out.println("bi = " + bi + ", ci = " + ci);
1852            Fii.add(ci);
1853        }
1854        Fi = Fii;
1855
1856        // setup ring mod p^k
1857        modul = p.power(k);
1858        if (ModLongRing.MAX_LONG.compareTo(modul.getVal()) > 0) {
1859            mcfac = (ModularRingFactory) new ModLongRing(modul.getVal());
1860        } else {
1861            mcfac = (ModularRingFactory) new ModIntegerRing(modul.getVal());
1862        }
1863        //System.out.println("mcfac = " + mcfac);
1864        mfac = new GenPolynomialRing<MOD>(mcfac, fac);
1865        lift = PolyUtil.<MOD> fromIntegerCoefficients(mfac, Fi);
1866        //System.out.println("lift = " + lift + ": " + lift.get(0).ring.coFac);
1867        return lift;
1868    }
1869
1870}