001/*
002 * $Id: HenselMultUtil.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.ModIntegerRing;
015import edu.jas.arith.ModLongRing;
016import edu.jas.arith.Modular;
017import edu.jas.arith.ModularRingFactory;
018import edu.jas.poly.GenPolynomial;
019import edu.jas.poly.GenPolynomialRing;
020import edu.jas.poly.PolyUtil;
021import edu.jas.ps.PolynomialTaylorFunction;
022import edu.jas.ps.TaylorFunction;
023import edu.jas.ps.UnivPowerSeries;
024import edu.jas.ps.UnivPowerSeriesRing;
025import edu.jas.structure.GcdRingElem;
026import edu.jas.structure.RingFactory;
027
028
029/**
030 * Hensel multivariate lifting utilities.
031 * @author Heinz Kredel
032 */
033
034public class HenselMultUtil {
035
036
037    private static final Logger logger = Logger.getLogger(HenselMultUtil.class);
038
039
040    private static final boolean debug = logger.isInfoEnabled();
041
042
043    /**
044     * Modular diophantine equation solution and lifting algorithm. Let p =
045     * A_i.ring.coFac.modul() and assume ggt(A,B) == 1 mod p.
046     * @param A modular GenPolynomial, mod p^k
047     * @param B modular GenPolynomial, mod p^k
048     * @param C modular GenPolynomial, mod p^k
049     * @param V list of substitution values, mod p^k
050     * @param d desired approximation exponent (x_i-v_i)^d.
051     * @param k desired approximation exponent p^k.
052     * @return [s, t] with s A' + t B' = C mod p^k, with A' = B, B' = A.
053     */
054    public static <MOD extends GcdRingElem<MOD> & Modular> List<GenPolynomial<MOD>> liftDiophant(
055                    GenPolynomial<MOD> A, GenPolynomial<MOD> B, GenPolynomial<MOD> C, List<MOD> V, long d,
056                    long k) throws NoLiftingException {
057        GenPolynomialRing<MOD> pkfac = C.ring;
058        if (pkfac.nvar == 1) { // V, d ignored
059            return HenselUtil.<MOD> liftDiophant(A, B, C, k);
060        }
061        if (!pkfac.equals(A.ring)) {
062            throw new IllegalArgumentException("A.ring != pkfac: " + A.ring + " != " + pkfac);
063        }
064
065        // evaluate at v_n:
066        List<MOD> Vp = new ArrayList<MOD>(V);
067        MOD v = Vp.remove(Vp.size() - 1);
068        //GenPolynomial<MOD> zero = pkfac.getZERO();
069        // (x_n - v)
070        GenPolynomial<MOD> mon = pkfac.getONE();
071        GenPolynomial<MOD> xv = pkfac.univariate(0, 1);
072        xv = xv.subtract(pkfac.fromInteger(v.getSymmetricInteger().getVal()));
073        //System.out.println("xv = " + xv);
074        // A(v), B(v), C(v)
075        ModularRingFactory<MOD> cf = (ModularRingFactory<MOD>) pkfac.coFac;
076        MOD vp = cf.fromInteger(v.getSymmetricInteger().getVal());
077        //System.out.println("v = " + v + ", vp = " + vp);
078        GenPolynomialRing<MOD> ckfac = pkfac.contract(1);
079        GenPolynomial<MOD> Ap = PolyUtil.<MOD> evaluateMain(ckfac, A, vp);
080        GenPolynomial<MOD> Bp = PolyUtil.<MOD> evaluateMain(ckfac, B, vp);
081        GenPolynomial<MOD> Cp = PolyUtil.<MOD> evaluateMain(ckfac, C, vp);
082        //System.out.println("Ap = " + Ap);
083        //System.out.println("Bp = " + Bp);
084        //System.out.println("Cp = " + Cp);
085
086        // recursion:
087        List<GenPolynomial<MOD>> su = HenselMultUtil.<MOD> liftDiophant(Ap, Bp, Cp, Vp, d, k);
088        //System.out.println("su@p^" + k + " = " + su);
089        //System.out.println("coFac = " + su.get(0).ring.coFac.toScript());
090        if (pkfac.nvar == 2 && !HenselUtil.<MOD> isDiophantLift(Bp, Ap, su.get(0), su.get(1), Cp)) {
091            //System.out.println("isDiophantLift: false");
092            throw new NoLiftingException("isDiophantLift: false");
093        }
094        if (!ckfac.equals(su.get(0).ring)) {
095            throw new IllegalArgumentException("qfac != ckfac: " + su.get(0).ring + " != " + ckfac);
096        }
097        GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), pkfac);
098        //GenPolynomialRing<BigInteger> cifac = new GenPolynomialRing<BigInteger>(new BigInteger(), ckfac);
099        //System.out.println("ifac = " + ifac.toScript());
100        String[] mn = new String[] { pkfac.getVars()[pkfac.nvar - 1] };
101        GenPolynomialRing<GenPolynomial<MOD>> qrfac = new GenPolynomialRing<GenPolynomial<MOD>>(ckfac, 1, mn);
102        //System.out.println("qrfac = " + qrfac);
103
104        List<GenPolynomial<MOD>> sup = new ArrayList<GenPolynomial<MOD>>(su.size());
105        List<GenPolynomial<BigInteger>> supi = new ArrayList<GenPolynomial<BigInteger>>(su.size());
106        for (GenPolynomial<MOD> s : su) {
107            GenPolynomial<MOD> sp = s.extend(pkfac, 0, 0L);
108            sup.add(sp);
109            GenPolynomial<BigInteger> spi = PolyUtil.integerFromModularCoefficients(ifac, sp);
110            supi.add(spi);
111        }
112        //System.out.println("sup  = " + sup);
113        //System.out.println("supi = " + supi);
114        GenPolynomial<BigInteger> Ai = PolyUtil.integerFromModularCoefficients(ifac, A);
115        GenPolynomial<BigInteger> Bi = PolyUtil.integerFromModularCoefficients(ifac, B);
116        GenPolynomial<BigInteger> Ci = PolyUtil.integerFromModularCoefficients(ifac, C);
117        //System.out.println("Ai = " + Ai);
118        //System.out.println("Bi = " + Bi);
119        //System.out.println("Ci = " + Ci);
120        //GenPolynomial<MOD> aq = PolyUtil.<MOD> fromIntegerCoefficients(pkfac, Ai);
121        //GenPolynomial<MOD> bq = PolyUtil.<MOD> fromIntegerCoefficients(pkfac, Bi);
122        //System.out.println("aq = " + aq);
123        //System.out.println("bq = " + bq);
124
125        // compute error:
126        GenPolynomial<BigInteger> E = Ci; // - sum_i s_i b_i
127        E = E.subtract(Bi.multiply(supi.get(0)));
128        E = E.subtract(Ai.multiply(supi.get(1)));
129        //System.out.println("E     = " + E);
130        if (E.isZERO()) {
131            logger.info("liftDiophant leaving on zero E");
132            return sup;
133        }
134        GenPolynomial<MOD> Ep = PolyUtil.<MOD> fromIntegerCoefficients(pkfac, E);
135        //System.out.println("Ep(0," + pkfac.nvar + ") = " + Ep);
136        logger.info("Ep(0," + pkfac.nvar + ") = " + Ep);
137        if (Ep.isZERO()) {
138            logger.info("liftDiophant leaving on zero Ep mod p^k");
139            return sup;
140        }
141        for (int e = 1; e <= d; e++) {
142            //System.out.println("\ne = " + e + " -------------------------------------- " + pkfac.nvar);
143            GenPolynomial<GenPolynomial<MOD>> Epr = PolyUtil.<MOD> recursive(qrfac, Ep);
144            //System.out.println("Epr   = " + Epr);
145            UnivPowerSeriesRing<GenPolynomial<MOD>> psfac = new UnivPowerSeriesRing<GenPolynomial<MOD>>(
146                            qrfac);
147            //System.out.println("psfac = " + psfac);
148            TaylorFunction<GenPolynomial<MOD>> F = new PolynomialTaylorFunction<GenPolynomial<MOD>>(Epr);
149            //System.out.println("F     = " + F);
150            //List<GenPolynomial<MOD>> Vs = new ArrayList<GenPolynomial<MOD>>(1);
151            GenPolynomial<MOD> vq = ckfac.fromInteger(v.getSymmetricInteger().getVal());
152            //Vs.add(vq);
153            //System.out.println("Vs    = " + Vs);
154            UnivPowerSeries<GenPolynomial<MOD>> Epst = psfac.seriesOfTaylor(F, vq);
155            //System.out.println("Epst  = " + Epst);
156            GenPolynomial<MOD> cm = Epst.coefficient(e);
157            //System.out.println("cm   = " + cm + ", cm.ring   = " + cm.ring.toScript());
158
159            // recursion:
160            List<GenPolynomial<MOD>> S = HenselMultUtil.<MOD> liftDiophant(Ap, Bp, cm, Vp, d, k);
161            //System.out.println("S    = " + S);
162            if (!ckfac.coFac.equals(S.get(0).ring.coFac)) {
163                throw new IllegalArgumentException(
164                                "ckfac != pkfac: " + ckfac.coFac + " != " + S.get(0).ring.coFac);
165            }
166            if (pkfac.nvar == 2 && !HenselUtil.<MOD> isDiophantLift(Ap, Bp, S.get(1), S.get(0), cm)) {
167                //System.out.println("isDiophantLift: false");
168                throw new NoLiftingException("isDiophantLift: false");
169            }
170            mon = mon.multiply(xv); // Power.<GenPolynomial<MOD>> power(pkfac,xv,e);
171            //System.out.println("mon  = " + mon);
172            //List<GenPolynomial<MOD>> Sp = new ArrayList<GenPolynomial<MOD>>(S.size());
173            int i = 0;
174            supi = new ArrayList<GenPolynomial<BigInteger>>(su.size());
175            for (GenPolynomial<MOD> dd : S) {
176                //System.out.println("dd = " + dd);
177                GenPolynomial<MOD> de = dd.extend(pkfac, 0, 0L);
178                GenPolynomial<MOD> dm = de.multiply(mon);
179                //Sp.add(dm);
180                de = sup.get(i).sum(dm);
181                //System.out.println("dd = " + dd);
182                sup.set(i++, de);
183                GenPolynomial<BigInteger> spi = PolyUtil.integerFromModularCoefficients(ifac, dm);
184                supi.add(spi);
185            }
186            //System.out.println("Sp   = " + Sp);
187            //System.out.println("sup  = " + sup);
188            //System.out.println("supi = " + supi);
189            // compute new error
190            //E = E; // - sum_i s_i b_i
191            E = E.subtract(Bi.multiply(supi.get(0)));
192            E = E.subtract(Ai.multiply(supi.get(1)));
193            //System.out.println("E     = " + E);
194            if (E.isZERO()) {
195                logger.info("liftDiophant leaving on zero E");
196                return sup;
197            }
198            Ep = PolyUtil.<MOD> fromIntegerCoefficients(pkfac, E);
199            //System.out.println("Ep(" + e + "," + pkfac.nvar + ") = " + Ep); 
200            logger.info("Ep(" + e + "," + pkfac.nvar + ") = " + Ep);
201            if (Ep.isZERO()) {
202                logger.info("liftDiophant leaving on zero Ep mod p^k");
203                return sup;
204            }
205        }
206        //System.out.println("*** done: " + pkfac.nvar);
207        return sup;
208    }
209
210
211    /**
212     * Modular diophantine equation solution and lifting algorithm. Let p =
213     * A_i.ring.coFac.modul() and assume ggt(a,b) == 1 mod p, for a, b in A.
214     * @param A list of modular GenPolynomials, mod p^k
215     * @param C modular GenPolynomial, mod p^k
216     * @param V list of substitution values, mod p^k
217     * @param d desired approximation exponent (x_i-v_i)^d.
218     * @param k desired approximation exponent p^k.
219     * @return [s_1,..., s_n] with sum_i s_i A_i' = C mod p^k, with Ai' =
220     *         prod_{j!=i} A_j.
221     */
222    public static <MOD extends GcdRingElem<MOD> & Modular> List<GenPolynomial<MOD>> liftDiophant(
223                    List<GenPolynomial<MOD>> A, GenPolynomial<MOD> C, List<MOD> V, long d, long k)
224                    throws NoLiftingException {
225        GenPolynomialRing<MOD> pkfac = C.ring;
226        if (pkfac.nvar == 1) { // V, d ignored
227            return HenselUtil.<MOD> liftDiophant(A, C, k);
228        }
229        if (!pkfac.equals(A.get(0).ring)) {
230            throw new IllegalArgumentException("A.ring != pkfac: " + A.get(0).ring + " != " + pkfac);
231        }
232        // co-products
233        GenPolynomial<MOD> As = pkfac.getONE();
234        for (GenPolynomial<MOD> a : A) {
235            As = As.multiply(a);
236        }
237        List<GenPolynomial<MOD>> Bp = new ArrayList<GenPolynomial<MOD>>(A.size());
238        for (GenPolynomial<MOD> a : A) {
239            GenPolynomial<MOD> b = PolyUtil.<MOD> basePseudoDivide(As, a);
240            Bp.add(b);
241        }
242
243        // evaluate at v_n:
244        List<MOD> Vp = new ArrayList<MOD>(V);
245        MOD v = Vp.remove(Vp.size() - 1);
246        // (x_n - v)
247        GenPolynomial<MOD> mon = pkfac.getONE();
248        GenPolynomial<MOD> xv = pkfac.univariate(0, 1);
249        xv = xv.subtract(pkfac.fromInteger(v.getSymmetricInteger().getVal()));
250        //System.out.println("xv = " + xv);
251        // A(v), B(v), C(v)
252        ModularRingFactory<MOD> cf = (ModularRingFactory<MOD>) pkfac.coFac;
253        MOD vp = cf.fromInteger(v.getSymmetricInteger().getVal());
254        //System.out.println("v = " + v + ", vp = " + vp);
255        GenPolynomialRing<MOD> ckfac = pkfac.contract(1);
256        List<GenPolynomial<MOD>> Ap = new ArrayList<GenPolynomial<MOD>>(A.size());
257        for (GenPolynomial<MOD> a : A) {
258            GenPolynomial<MOD> ap = PolyUtil.<MOD> evaluateMain(ckfac, a, vp);
259            Ap.add(ap);
260        }
261        GenPolynomial<MOD> Cp = PolyUtil.<MOD> evaluateMain(ckfac, C, vp);
262        //System.out.println("Ap = " + Ap);
263        //System.out.println("Cp = " + Cp);
264
265        // recursion:
266        List<GenPolynomial<MOD>> su = HenselMultUtil.<MOD> liftDiophant(Ap, Cp, Vp, d, k);
267        //System.out.println("su@p^" + k + " = " + su);
268        //System.out.println("coFac = " + su.get(0).ring.coFac.toScript());
269        if (pkfac.nvar == 2 && !HenselUtil.<MOD> isDiophantLift(Ap, su, Cp)) {
270            //System.out.println("isDiophantLift: false");
271            throw new NoLiftingException("isDiophantLift: false");
272        }
273        if (!ckfac.equals(su.get(0).ring)) {
274            throw new IllegalArgumentException("qfac != ckfac: " + su.get(0).ring + " != " + ckfac);
275        }
276        GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), pkfac);
277        //GenPolynomialRing<BigInteger> cifac = new GenPolynomialRing<BigInteger>(new BigInteger(), ckfac);
278        //System.out.println("ifac = " + ifac.toScript());
279        String[] mn = new String[] { pkfac.getVars()[pkfac.nvar - 1] };
280        GenPolynomialRing<GenPolynomial<MOD>> qrfac = new GenPolynomialRing<GenPolynomial<MOD>>(ckfac, 1, mn);
281        //System.out.println("qrfac = " + qrfac);
282
283        List<GenPolynomial<MOD>> sup = new ArrayList<GenPolynomial<MOD>>(su.size());
284        List<GenPolynomial<BigInteger>> supi = new ArrayList<GenPolynomial<BigInteger>>(su.size());
285        for (GenPolynomial<MOD> s : su) {
286            GenPolynomial<MOD> sp = s.extend(pkfac, 0, 0L);
287            sup.add(sp);
288            GenPolynomial<BigInteger> spi = PolyUtil.integerFromModularCoefficients(ifac, sp);
289            supi.add(spi);
290        }
291        //System.out.println("sup  = " + sup);
292        //System.out.println("supi = " + supi);
293        //List<GenPolynomial<BigInteger>> Ai = new ArrayList<GenPolynomial<BigInteger>>(A.size());
294        //for (GenPolynomial<MOD> a : A) {
295        //    GenPolynomial<BigInteger> ai = PolyUtil.integerFromModularCoefficients(ifac, a);
296        //    Ai.add(ai);
297        //}
298        List<GenPolynomial<BigInteger>> Bi = new ArrayList<GenPolynomial<BigInteger>>(A.size());
299        for (GenPolynomial<MOD> b : Bp) {
300            GenPolynomial<BigInteger> bi = PolyUtil.integerFromModularCoefficients(ifac, b);
301            Bi.add(bi);
302        }
303        GenPolynomial<BigInteger> Ci = PolyUtil.integerFromModularCoefficients(ifac, C);
304        //System.out.println("Ai = " + Ai);
305        //System.out.println("Ci = " + Ci);
306
307        //List<GenPolynomial<MOD>> Aq = new ArrayList<GenPolynomial<MOD>>(A.size());
308        //for (GenPolynomial<BigInteger> ai : Ai) {
309        //    GenPolynomial<MOD> aq = PolyUtil.<MOD> fromIntegerCoefficients(pkfac, ai);
310        //    Aq.add(aq);
311        //}
312        //System.out.println("Aq = " + Aq);
313
314        // compute error:
315        GenPolynomial<BigInteger> E = Ci; // - sum_i s_i b_i
316        int i = 0;
317        for (GenPolynomial<BigInteger> bi : Bi) {
318            E = E.subtract(bi.multiply(supi.get(i++)));
319        }
320        //System.out.println("E     = " + E);
321        if (E.isZERO()) {
322            logger.info("liftDiophant leaving on zero E");
323            return sup;
324        }
325        GenPolynomial<MOD> Ep = PolyUtil.<MOD> fromIntegerCoefficients(pkfac, E);
326        //System.out.println("Ep(0," + pkfac.nvar + ") = " + Ep);
327        logger.info("Ep(0," + pkfac.nvar + ") = " + Ep);
328        if (Ep.isZERO()) {
329            logger.info("liftDiophant leaving on zero Ep mod p^k");
330            return sup;
331        }
332        for (int e = 1; e <= d; e++) {
333            //System.out.println("\ne = " + e + " -------------------------------------- " + pkfac.nvar);
334            GenPolynomial<GenPolynomial<MOD>> Epr = PolyUtil.<MOD> recursive(qrfac, Ep);
335            //System.out.println("Epr   = " + Epr);
336            UnivPowerSeriesRing<GenPolynomial<MOD>> psfac = new UnivPowerSeriesRing<GenPolynomial<MOD>>(
337                            qrfac);
338            //System.out.println("psfac = " + psfac);
339            TaylorFunction<GenPolynomial<MOD>> F = new PolynomialTaylorFunction<GenPolynomial<MOD>>(Epr);
340            //System.out.println("F     = " + F);
341            //List<GenPolynomial<MOD>> Vs = new ArrayList<GenPolynomial<MOD>>(1);
342            GenPolynomial<MOD> vq = ckfac.fromInteger(v.getSymmetricInteger().getVal());
343            //Vs.add(vq);
344            //System.out.println("Vs    = " + Vs);
345            UnivPowerSeries<GenPolynomial<MOD>> Epst = psfac.seriesOfTaylor(F, vq);
346            //System.out.println("Epst  = " + Epst);
347            GenPolynomial<MOD> cm = Epst.coefficient(e);
348            //System.out.println("cm   = " + cm + ", cm.ring   = " + cm.ring.toScript());
349            if (cm.isZERO()) {
350                continue;
351            }
352            // recursion:
353            List<GenPolynomial<MOD>> S = HenselMultUtil.<MOD> liftDiophant(Ap, cm, Vp, d, k);
354            //System.out.println("S    = " + S);
355            if (!ckfac.coFac.equals(S.get(0).ring.coFac)) {
356                throw new IllegalArgumentException(
357                                "ckfac != pkfac: " + ckfac.coFac + " != " + S.get(0).ring.coFac);
358            }
359            if (pkfac.nvar == 2 && !HenselUtil.<MOD> isDiophantLift(Ap, S, cm)) {
360                //System.out.println("isDiophantLift: false");
361                throw new NoLiftingException("isDiophantLift: false");
362            }
363            mon = mon.multiply(xv); // Power.<GenPolynomial<MOD>> power(pkfac,xv,e);
364            //System.out.println("mon  = " + mon);
365            //List<GenPolynomial<MOD>> Sp = new ArrayList<GenPolynomial<MOD>>(S.size());
366            i = 0;
367            supi = new ArrayList<GenPolynomial<BigInteger>>(su.size());
368            for (GenPolynomial<MOD> dd : S) {
369                //System.out.println("dd = " + dd);
370                GenPolynomial<MOD> de = dd.extend(pkfac, 0, 0L);
371                GenPolynomial<MOD> dm = de.multiply(mon);
372                //Sp.add(dm);
373                de = sup.get(i).sum(dm);
374                //System.out.println("dd = " + dd);
375                sup.set(i++, de);
376                GenPolynomial<BigInteger> spi = PolyUtil.integerFromModularCoefficients(ifac, dm);
377                supi.add(spi);
378            }
379            //System.out.println("Sp   = " + Sp);
380            //System.out.println("sup  = " + sup);
381            //System.out.println("supi = " + supi);
382            // compute new error
383            //E = E; // - sum_i s_i b_i
384            i = 0;
385            for (GenPolynomial<BigInteger> bi : Bi) {
386                E = E.subtract(bi.multiply(supi.get(i++)));
387            }
388            //System.out.println("E     = " + E);
389            if (E.isZERO()) {
390                logger.info("liftDiophant leaving on zero E");
391                return sup;
392            }
393            Ep = PolyUtil.<MOD> fromIntegerCoefficients(pkfac, E);
394            //System.out.println("Ep(" + e + "," + pkfac.nvar + ") = " + Ep); 
395            logger.info("Ep(" + e + "," + pkfac.nvar + ") = " + Ep);
396            if (Ep.isZERO()) {
397                logger.info("liftDiophant leaving on zero Ep mod p^k");
398                return sup;
399            }
400        }
401        //System.out.println("*** done: " + pkfac.nvar);
402        return sup;
403    }
404
405
406    /**
407     * Modular Hensel lifting algorithm on coefficients test. Let p =
408     * f_i.ring.coFac.modul() and assume C == prod_{0,...,n-1} f_i mod p with
409     * gcd(f_i,f_j) == 1 mod p for i != j
410     * @param C integer polynomial
411     * @param Cp GenPolynomial mod p^k
412     * @param F = [f_0,...,f_{n-1}] list of monic modular polynomials.
413     * @param L = [g_0,...,g_{n-1}] list of lifted modular polynomials.
414     * @return true if C = prod_{0,...,n-1} g_i mod p^k, else false.
415     */
416    @SuppressWarnings("unused")
417    public static <MOD extends GcdRingElem<MOD> & Modular> boolean isHenselLift(GenPolynomial<BigInteger> C,
418                    GenPolynomial<MOD> Cp, List<GenPolynomial<MOD>> F, List<GenPolynomial<MOD>> L) {
419        boolean t = true;
420        GenPolynomialRing<MOD> qfac = L.get(0).ring;
421        GenPolynomial<MOD> q = qfac.getONE();
422        for (GenPolynomial<MOD> fi : L) {
423            q = q.multiply(fi);
424        }
425        t = Cp.equals(q);
426        if (!t) {
427            System.out.println("Cp     = " + Cp);
428            System.out.println("q      = " + q);
429            System.out.println("Cp != q: " + Cp.subtract(q));
430            return t;
431        }
432        GenPolynomialRing<BigInteger> dfac = C.ring;
433        GenPolynomial<BigInteger> Ci = PolyUtil.integerFromModularCoefficients(dfac, q);
434        t = C.equals(Ci);
435        if (!t) {
436            System.out.println("C      = " + C);
437            System.out.println("Ci     = " + Ci);
438            System.out.println("C != Ci: " + C.subtract(Ci));
439            return t;
440        }
441        // test L mod id(V) == F
442        return t;
443    }
444
445
446    /**
447     * Modular Hensel lifting algorithm, monic case. Let p =
448     * A_i.ring.coFac.modul() and assume ggt(a,b) == 1 mod p, for a, b in A.
449     * @param C monic GenPolynomial with integer coefficients
450     * @param Cp GenPolynomial mod p^k
451     * @param F list of modular GenPolynomials, mod (I_v, p^k )
452     * @param V list of integer substitution values
453     * @param k desired approximation exponent p^k.
454     * @return [g'_1,..., g'_n] with prod_i g'_i = Cp mod p^k.
455     */
456    public static <MOD extends GcdRingElem<MOD> & Modular> List<GenPolynomial<MOD>> liftHenselMonic(
457                    GenPolynomial<BigInteger> C, GenPolynomial<MOD> Cp, List<GenPolynomial<MOD>> F,
458                    List<BigInteger> V, long k) throws NoLiftingException {
459        GenPolynomialRing<MOD> pkfac = Cp.ring;
460        //if (pkfac.nvar == 1) { // V ignored
461        //    return HenselUtil.<MOD> liftHenselMonic(C,F,k);
462        //}
463        long d = C.degree();
464        //System.out.println("d = " + d);
465        // prepare stack of polynomial rings and polynomials
466        List<GenPolynomialRing<MOD>> Pfac = new ArrayList<GenPolynomialRing<MOD>>();
467        List<GenPolynomial<MOD>> Ap = new ArrayList<GenPolynomial<MOD>>();
468        List<MOD> Vb = new ArrayList<MOD>();
469        MOD v = pkfac.coFac.fromInteger(V.get(0).getVal());
470        Pfac.add(pkfac);
471        Ap.add(Cp);
472        Vb.add(v);
473        GenPolynomialRing<MOD> pf = pkfac;
474        GenPolynomial<MOD> ap = Cp;
475        for (int j = pkfac.nvar; j > 2; j--) {
476            pf = pf.contract(1);
477            Pfac.add(0, pf);
478            //MOD vp = pkfac.coFac.fromInteger(V.get(j - 2).getSymmetricInteger().getVal());
479            MOD vp = pkfac.coFac.fromInteger(V.get(j - 2).getVal());
480            //System.out.println("vp     = " + vp);
481            Vb.add(1, vp);
482            ap = PolyUtil.<MOD> evaluateMain(pf, ap, vp);
483            Ap.add(0, ap);
484        }
485        //System.out.println("Pfac   = " + Pfac);
486        if (debug) {
487            logger.debug("Pfac   = " + Pfac);
488        }
489        //System.out.println("Ap     = " + Ap);
490        //System.out.println("V      = " + V);
491        //System.out.println("Vb     = " + Vb);
492        // setup bi-variate base case
493        GenPolynomialRing<MOD> pk1fac = F.get(0).ring;
494        if (!pkfac.coFac.equals(pk1fac.coFac)) {
495            throw new IllegalArgumentException("F.ring != pkfac: " + pk1fac + " != " + pkfac);
496        }
497        // TODO: adjust leading coefficients
498        pkfac = Pfac.get(0);
499        //Cp = Ap.get(0);
500        //System.out.println("pkfac  = " + pkfac.toScript());
501        //System.out.println("pk1fac = " + pk1fac.toScript());
502        GenPolynomialRing<BigInteger> i1fac = new GenPolynomialRing<BigInteger>(new BigInteger(), pk1fac);
503        //System.out.println("i1fac = " + i1fac.toScript());
504        List<GenPolynomial<BigInteger>> Bi = new ArrayList<GenPolynomial<BigInteger>>(F.size());
505        for (GenPolynomial<MOD> b : F) {
506            GenPolynomial<BigInteger> bi = PolyUtil.integerFromModularCoefficients(i1fac, b);
507            Bi.add(bi);
508        }
509        //System.out.println("Bi = " + Bi);
510        // evaluate Cp at v_n:
511        //ModularRingFactory<MOD> cf = (ModularRingFactory<MOD>) pkfac.coFac;
512        //MOD vp = cf.fromInteger(v.getSymmetricInteger().getVal());
513        //System.out.println("v = " + v + ", vp = " + vp);
514        GenPolynomialRing<MOD> ckfac; // = pkfac.contract(1);
515        //GenPolynomial<MOD> Cs = PolyUtil.<MOD> evaluateMain(ckfac, Cp, vp);
516        //System.out.println("Cp = " + Cp);
517        //System.out.println("Cs = " + Cs);
518
519        List<GenPolynomial<MOD>> U = new ArrayList<GenPolynomial<MOD>>(F.size());
520        for (GenPolynomial<MOD> b : F) {
521            GenPolynomial<MOD> bi = b.extend(pkfac, 0, 0L);
522            U.add(bi);
523        }
524        //System.out.println("U  = " + U);
525        List<GenPolynomial<MOD>> U1 = F;
526        //System.out.println("U1 = " + U1);
527
528        GenPolynomial<BigInteger> E = C.ring.getZERO();
529        List<MOD> Vh = new ArrayList<MOD>();
530
531        while (Pfac.size() > 0) { // loop through stack of polynomial rings
532            pkfac = Pfac.remove(0);
533            Cp = Ap.remove(0);
534            v = Vb.remove(0);
535            //Vh.add(0,v);
536            //System.out.println("\npkfac = " + pkfac.toScript() + " ================================== " + Vh);
537
538            // (x_n - v)
539            GenPolynomial<MOD> mon = pkfac.getONE();
540            GenPolynomial<MOD> xv = pkfac.univariate(0, 1);
541            xv = xv.subtract(pkfac.fromInteger(v.getSymmetricInteger().getVal()));
542            //System.out.println("xv = " + xv);
543
544            long deg = Cp.degree(pkfac.nvar - 1);
545            //System.out.println("deg = " + deg);
546
547            GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), pkfac);
548            //System.out.println("ifac = " + ifac.toScript());
549            List<GenPolynomial<BigInteger>> Bip = new ArrayList<GenPolynomial<BigInteger>>(F.size());
550            for (GenPolynomial<BigInteger> b : Bi) {
551                GenPolynomial<BigInteger> bi = b.extend(ifac, 0, 0L);
552                Bip.add(bi);
553            }
554            Bi = Bip;
555            //System.out.println("Bi = " + Bi);
556            GenPolynomial<BigInteger> Ci = PolyUtil.integerFromModularCoefficients(ifac, Cp);
557            //System.out.println("Ci = " + Ci);
558
559            // compute error:
560            E = ifac.getONE();
561            for (GenPolynomial<BigInteger> bi : Bi) {
562                E = E.multiply(bi);
563            }
564            E = Ci.subtract(E);
565            //System.out.println("E     = " + E);
566            GenPolynomial<MOD> Ep = PolyUtil.<MOD> fromIntegerCoefficients(pkfac, E);
567            //System.out.println("Ep(0," + pkfac.nvar + ") = " + Ep);
568            logger.info("Ep(0," + deg + "," + pkfac.nvar + ") = " + Ep);
569
570            String[] mn = new String[] { pkfac.getVars()[pkfac.nvar - 1] };
571            ckfac = pkfac.contract(1);
572            GenPolynomialRing<GenPolynomial<MOD>> pkrfac = new GenPolynomialRing<GenPolynomial<MOD>>(ckfac, 1,
573                            mn);
574            //System.out.println("pkrfac = " + pkrfac.toScript());
575
576            for (int e = 1; e <= deg && !Ep.isZERO(); e++) {
577                //System.out.println("\ne = " + e + " -------------------------------------- " + pkfac.nvar);
578                GenPolynomial<GenPolynomial<MOD>> Epr = PolyUtil.<MOD> recursive(pkrfac, Ep);
579                //System.out.println("Epr   = " + Epr);
580                UnivPowerSeriesRing<GenPolynomial<MOD>> psfac = new UnivPowerSeriesRing<GenPolynomial<MOD>>(
581                                pkrfac);
582                //System.out.println("psfac = " + psfac);
583                TaylorFunction<GenPolynomial<MOD>> T = new PolynomialTaylorFunction<GenPolynomial<MOD>>(Epr);
584                //System.out.println("T     = " + T);
585                //List<GenPolynomial<MOD>> Vs = new ArrayList<GenPolynomial<MOD>>(1);
586                GenPolynomial<MOD> vq = ckfac.fromInteger(v.getSymmetricInteger().getVal());
587                //Vs.add(vq);
588                //System.out.println("Vs    = " + Vs + ", Vh = " + Vh);
589                UnivPowerSeries<GenPolynomial<MOD>> Epst = psfac.seriesOfTaylor(T, vq);
590                //System.out.println("Epst  = " + Epst);
591                logger.info("Epst(" + e + "," + deg + ", " + pkfac.nvar + ") = " + Epst);
592                GenPolynomial<MOD> cm = Epst.coefficient(e);
593                //System.out.println("cm   = " + cm);
594                if (cm.isZERO()) {
595                    continue;
596                }
597                List<GenPolynomial<MOD>> Ud = HenselMultUtil.<MOD> liftDiophant(U1, cm, Vh, d, k);
598                //System.out.println("Ud = " + Ud);
599
600                mon = mon.multiply(xv);
601                //System.out.println("mon  = " + mon);
602                //List<GenPolynomial<MOD>> Sd = new ArrayList<GenPolynomial<MOD>>(Ud.size());
603                int i = 0;
604                List<GenPolynomial<BigInteger>> Si = new ArrayList<GenPolynomial<BigInteger>>(Ud.size());
605                for (GenPolynomial<MOD> dd : Ud) {
606                    //System.out.println("dd = " + dd);
607                    GenPolynomial<MOD> de = dd.extend(pkfac, 0, 0L);
608                    GenPolynomial<MOD> dm = de.multiply(mon);
609                    //Sd.add(dm);
610                    de = U.get(i).sum(dm);
611                    //System.out.println("de = " + de);
612                    U.set(i++, de);
613                    GenPolynomial<BigInteger> si = PolyUtil.integerFromModularCoefficients(ifac, de);
614                    Si.add(si);
615                }
616                //System.out.println("Sd   = " + Sd);
617                //System.out.println("U    = " + U);
618                //System.out.println("Si   = " + Si);
619
620                // compute new error:
621                E = ifac.getONE();
622                for (GenPolynomial<BigInteger> bi : Si) {
623                    E = E.multiply(bi);
624                }
625                E = Ci.subtract(E);
626                //System.out.println("E     = " + E);
627                Ep = PolyUtil.<MOD> fromIntegerCoefficients(pkfac, E);
628                //System.out.println("Ep(0," + pkfac.nvar + ") = " + Ep);
629                logger.info("Ep(" + e + "," + deg + "," + pkfac.nvar + ") = " + Ep);
630            }
631            Vh.add(v);
632            U1 = U;
633            if (Pfac.size() > 0) {
634                List<GenPolynomial<MOD>> U2 = new ArrayList<GenPolynomial<MOD>>(U.size());
635                pkfac = Pfac.get(0);
636                for (GenPolynomial<MOD> b : U) {
637                    GenPolynomial<MOD> bi = b.extend(pkfac, 0, 0L);
638                    U2.add(bi);
639                }
640                U = U2;
641                //System.out.println("U  = " + U);
642            }
643        }
644        if (E.isZERO()) {
645            logger.info("liftHensel leaving with zero E");
646        }
647        return U;
648    }
649
650
651    /**
652     * Modular Hensel lifting algorithm. Let p = A_i.ring.coFac.modul() and
653     * assume ggt(a,b) == 1 mod p, for a, b in A.
654     * @param C GenPolynomial with integer coefficients
655     * @param Cp GenPolynomial C mod p^k
656     * @param F list of modular GenPolynomials, mod (I_v, p^k )
657     * @param V list of integral substitution values
658     * @param k desired approximation exponent p^k.
659     * @param G list of leading coefficients of the factors of C.
660     * @return [g'_1,..., g'_n] with prod_i g'_i = Cp mod p^k.
661     */
662    public static <MOD extends GcdRingElem<MOD> & Modular> List<GenPolynomial<MOD>> liftHensel(
663                    GenPolynomial<BigInteger> C, GenPolynomial<MOD> Cp, List<GenPolynomial<MOD>> F,
664                    List<BigInteger> V, long k, List<GenPolynomial<BigInteger>> G) throws NoLiftingException {
665        GenPolynomialRing<MOD> pkfac = Cp.ring;
666        long d = C.degree();
667        //System.out.println("C = " + C);
668        //System.out.println("Cp = " + Cp);
669        //System.out.println("G = " + G);
670
671        //GenPolynomial<BigInteger> cd = G.get(0); // 1
672        //System.out.println("cd = " + cd + ", ring = " + C.ring);
673        //if ( cd.equals(C.ring.univariate(0)) ) {
674        //    System.out.println("cd == G[1]");
675        //}
676        // G mod p^k, in all variables
677        GenPolynomialRing<MOD> pkfac1 = new GenPolynomialRing<MOD>(pkfac.coFac, G.get(0).ring);
678        List<GenPolynomial<MOD>> Lp = new ArrayList<GenPolynomial<MOD>>(G.size());
679        for (GenPolynomial<BigInteger> cd1 : G) {
680            GenPolynomial<MOD> cdq = PolyUtil.<MOD> fromIntegerCoefficients(pkfac1, cd1);
681            cdq = cdq.extendLower(pkfac, 0, 0L); // reintroduce lower variable
682            Lp.add(cdq);
683        }
684        logger.info("G modulo p^k: " + Lp); // + ", ring = " + pkfac1);
685
686        // prepare stack of polynomial rings, polynomials and evaluated leading coefficients
687        List<GenPolynomialRing<MOD>> Pfac = new ArrayList<GenPolynomialRing<MOD>>();
688        List<GenPolynomial<MOD>> Ap = new ArrayList<GenPolynomial<MOD>>();
689        List<List<GenPolynomial<MOD>>> Gp = new ArrayList<List<GenPolynomial<MOD>>>();
690        List<MOD> Vb = new ArrayList<MOD>();
691        //MOD v = V.get(0); // fromInteger
692        Pfac.add(pkfac);
693        Ap.add(Cp);
694        Gp.add(Lp);
695        GenPolynomialRing<MOD> pf = pkfac;
696        //GenPolynomialRing<MOD> pf1 = pkfac1;
697        GenPolynomial<MOD> ap = Cp;
698        List<GenPolynomial<MOD>> Lpp = Lp;
699        for (int j = pkfac.nvar; j > 2; j--) {
700            pf = pf.contract(1);
701            Pfac.add(0, pf);
702            //MOD vp = pkfac.coFac.fromInteger(V.get(pkfac.nvar - j).getSymmetricInteger().getVal());
703            MOD vp = pkfac.coFac.fromInteger(V.get(pkfac.nvar - j).getVal());
704            //System.out.println("vp     = " + vp);
705            Vb.add(vp);
706            ap = PolyUtil.<MOD> evaluateMain(pf, ap, vp);
707            Ap.add(0, ap);
708            List<GenPolynomial<MOD>> Lps = new ArrayList<GenPolynomial<MOD>>(Lpp.size());
709            for (GenPolynomial<MOD> qp : Lpp) {
710                GenPolynomial<MOD> qpe = PolyUtil.<MOD> evaluateMain(pf, qp, vp);
711                Lps.add(qpe);
712            }
713            //System.out.println("Lps = " + Lps);
714            Lpp = Lps;
715            Gp.add(0, Lpp);
716        }
717        Vb.add(pkfac.coFac.fromInteger(V.get(pkfac.nvar - 2).getVal()));
718        //System.out.println("Pfac   = " + Pfac);
719        if (debug) {
720            logger.debug("Pfac   = " + Pfac);
721        }
722        //System.out.println("Ap     = " + Ap);
723        //System.out.println("Gp     = " + Gp);
724        //System.out.println("Gp[0]  = " + Gp.get(0) + ", Gp[0].ring = " + Gp.get(0).get(0).ring);
725        //System.out.println("V      = " + V);
726        //System.out.println("Vb     = " + Vb + ", V == Vb: " + V.equals(Vb));
727
728        // check bi-variate base case
729        GenPolynomialRing<MOD> pk1fac = F.get(0).ring;
730        if (!pkfac.coFac.equals(pk1fac.coFac)) {
731            throw new IllegalArgumentException("F.ring != pkfac: " + pk1fac + " != " + pkfac);
732        }
733
734        // init recursion
735        List<GenPolynomial<MOD>> U = F;
736        //logger.info("to lift U = " + U); // + ", U1.ring = " + U1.get(0).ring);
737        GenPolynomial<BigInteger> E = C.ring.getZERO();
738        List<MOD> Vh = new ArrayList<MOD>();
739        List<GenPolynomial<BigInteger>> Si; // = new ArrayList<GenPolynomial<BigInteger>>(F.size());
740        MOD v = null;
741
742        while (Pfac.size() > 0) { // loop through stack of polynomial rings
743            pkfac = Pfac.remove(0);
744            Cp = Ap.remove(0);
745            Lpp = Gp.remove(0);
746            v = Vb.remove(Vb.size() - 1); // last in stack
747            //System.out.println("\npkfac = " + pkfac.toScript() + " ================================== " + v);
748            logger.info("stack loop: pkfac = " + pkfac.toScript() + " v = " + v);
749
750            List<GenPolynomial<MOD>> U1 = U;
751            logger.info("to lift U1 = " + U1); // + ", U1.ring = " + U1.get(0).ring);
752            U = new ArrayList<GenPolynomial<MOD>>(U1.size());
753
754            // update U, replace leading coefficient if required
755            int j = 0;
756            for (GenPolynomial<MOD> b : U1) {
757                //System.out.println("b = " + b + ", b.ring = " + b.ring);
758                GenPolynomial<MOD> bi = b.extend(pkfac, 0, 0L);
759                GenPolynomial<MOD> li = Lpp.get(j);
760                if (!li.isONE()) {
761                    //System.out.println("li = " + li + ", li.ring = " + li.ring);
762                    //System.out.println("bi = " + bi);
763                    GenPolynomialRing<GenPolynomial<MOD>> pkrfac = pkfac.recursive(pkfac.nvar - 1);
764                    //System.out.println("pkrfac = " + pkrfac);
765                    GenPolynomial<GenPolynomial<MOD>> br = PolyUtil.<MOD> recursive(pkrfac, bi);
766                    //System.out.println("br = " + br);
767                    GenPolynomial<GenPolynomial<MOD>> bs = PolyUtil.<MOD> switchVariables(br);
768                    //System.out.println("bs = " + bs + ", bs.ring = " + bs.ring);
769
770                    GenPolynomial<GenPolynomial<MOD>> lr = PolyUtil.<MOD> recursive(pkrfac, li);
771                    //System.out.println("lr = " + lr);
772                    GenPolynomial<GenPolynomial<MOD>> ls = PolyUtil.<MOD> switchVariables(lr);
773                    //System.out.println("ls = " + ls + ", ls.ring = " + ls.ring);
774                    if (!ls.isConstant() && !ls.isZERO()) {
775                        throw new RuntimeException("ls not constant " + ls + ", li = " + li);
776                    }
777                    bs.doPutToMap(bs.leadingExpVector(), ls.leadingBaseCoefficient());
778                    //System.out.println("bs = " + bs + ", bs.ring = " + bs.ring);
779                    br = PolyUtil.<MOD> switchVariables(bs);
780                    //System.out.println("br = " + br);
781                    bi = PolyUtil.<MOD> distribute(pkfac, br);
782                    //System.out.println("bi = " + bi);
783                }
784                U.add(bi);
785                j++;
786            }
787            logger.info("U with leading coefficient replaced = " + U); // + ", U.ring = " + U.get(0).ring);
788
789            // (x_n - v)
790            GenPolynomial<MOD> mon = pkfac.getONE();
791            GenPolynomial<MOD> xv = pkfac.univariate(0, 1);
792            xv = xv.subtract(pkfac.fromInteger(v.getSymmetricInteger().getVal()));
793            //System.out.println("xv = " + xv);
794
795            long deg = Cp.degree(pkfac.nvar - 1);
796            //System.out.println("deg = " + deg + ", degv = " + Cp.degreeVector());
797
798            // convert to integer polynomials
799            GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), pkfac);
800            //System.out.println("ifac = " + ifac.toScript());
801            List<GenPolynomial<BigInteger>> Bi = PolyUtil.integerFromModularCoefficients(ifac, U);
802            //System.out.println("Bi = " + Bi);
803            GenPolynomial<BigInteger> Ci = PolyUtil.integerFromModularCoefficients(ifac, Cp);
804            //System.out.println("Ci = " + Ci);
805
806            // compute error:
807            E = ifac.getONE();
808            for (GenPolynomial<BigInteger> bi : Bi) {
809                E = E.multiply(bi);
810            }
811            //System.out.println("E  = " + E);
812            E = Ci.subtract(E);
813            //System.out.println("E  = " + E);
814            GenPolynomial<MOD> Ep = PolyUtil.<MOD> fromIntegerCoefficients(pkfac, E);
815            logger.info("Ep(0," + deg + "," + pkfac.nvar + ") = " + Ep);
816
817            GenPolynomialRing<GenPolynomial<MOD>> pkrfac = pkfac.recursive(1);
818            GenPolynomialRing<MOD> ckfac = (GenPolynomialRing<MOD>) pkrfac.coFac;
819            //System.out.println("pkrfac = " + pkrfac.toScript());
820
821            for (int e = 1; e <= deg && !Ep.isZERO(); e++) {
822                //System.out.println("\ne = " + e + " -------------------------------------- " + deg);
823                logger.info("approximation loop: e = " + e + " of deg = " + deg);
824                GenPolynomial<GenPolynomial<MOD>> Epr = PolyUtil.<MOD> recursive(pkrfac, Ep);
825                //System.out.println("Epr   = " + Epr);
826                UnivPowerSeriesRing<GenPolynomial<MOD>> psfac = new UnivPowerSeriesRing<GenPolynomial<MOD>>(
827                                pkrfac);
828                //System.out.println("psfac = " + psfac);
829                TaylorFunction<GenPolynomial<MOD>> T = new PolynomialTaylorFunction<GenPolynomial<MOD>>(Epr);
830                //System.out.println("T     = " + T);
831                GenPolynomial<MOD> vq = ckfac.fromInteger(v.getSymmetricInteger().getVal());
832                //System.out.println("vq    = " + vq + ", Vh = " + Vh);
833                UnivPowerSeries<GenPolynomial<MOD>> Epst = psfac.seriesOfTaylor(T, vq);
834                //System.out.println("Epst  = " + Epst);
835                logger.info("Epst(" + e + "," + deg + "," + pkfac.nvar + ") = " + Epst);
836                GenPolynomial<MOD> cm = Epst.coefficient(e);
837                if (cm.isZERO()) {
838                    //System.out.println("cm   = " + cm);
839                    continue;
840                }
841                List<GenPolynomial<MOD>> Ud = HenselMultUtil.<MOD> liftDiophant(U1, cm, Vh, d, k);
842                //System.out.println("Ud = " + Ud);
843
844                mon = mon.multiply(xv);
845                //System.out.println("mon  = " + mon);
846                //List<GenPolynomial<MOD>> Sd = new ArrayList<GenPolynomial<MOD>>(Ud.size());
847                int i = 0;
848                Si = new ArrayList<GenPolynomial<BigInteger>>(Ud.size());
849                for (GenPolynomial<MOD> dd : Ud) {
850                    //System.out.println("dd = " + dd);
851                    GenPolynomial<MOD> de = dd.extend(pkfac, 0, 0L);
852                    GenPolynomial<MOD> dm = de.multiply(mon);
853                    //Sd.add(dm);
854                    de = U.get(i).sum(dm);
855                    //System.out.println("de = " + de);
856                    U.set(i++, de);
857                    GenPolynomial<BigInteger> si = PolyUtil.integerFromModularCoefficients(ifac, de);
858                    Si.add(si);
859                }
860                //System.out.println("Sd   = " + Sd);
861                //System.out.println("U    = " + U + ", U.ring = " + U.get(0).ring);
862                //System.out.println("Si   = " + Si);
863
864                // compute new error:
865                E = ifac.getONE();
866                for (GenPolynomial<BigInteger> bi : Si) {
867                    E = E.multiply(bi);
868                }
869                E = Ci.subtract(E);
870                //System.out.println("E = " + E);
871                Ep = PolyUtil.<MOD> fromIntegerCoefficients(pkfac, E);
872                //System.out.println("Ep(0," + pkfac.nvar + ") = " + Ep);
873                logger.info("Ep(" + e + "," + deg + "," + pkfac.nvar + ") = " + Ep);
874            }
875            Vh.add(v);
876            GenPolynomial<MOD> Uf = U.get(0).ring.getONE();
877            for (GenPolynomial<MOD> Upp : U) {
878                Uf = Uf.multiply(Upp);
879            }
880            if (false && !Cp.leadingExpVector().equals(Uf.leadingExpVector())) { // not meanigfull test
881                System.out.println("\nU    = " + U);
882                System.out.println("Cp   = " + Cp);
883                System.out.println("Uf   = " + Uf);
884                //System.out.println("Cp.ring = " + Cp.ring.toScript() + ", Uf.ring = " + Uf.ring.toScript() + "\n");
885                System.out.println("");
886                //throw new NoLiftingException("no factorization, Cp != Uf");
887            }
888        }
889        if (E.isZERO()) {
890            logger.info("liftHensel leaving with zero E, Ep");
891        }
892        if (false && debug) {
893            // remove normalization required ??
894            GreatestCommonDivisorAbstract<BigInteger> ufd = GCDFactory.getImplementation(new BigInteger());
895            List<GenPolynomial<BigInteger>> Fii = new ArrayList<GenPolynomial<BigInteger>>(U.size());
896            for (GenPolynomial<BigInteger> bi : Si) {
897                GenPolynomial<BigInteger> ci = ufd.content(bi); //ufd.primitivePart(bi); // ??
898                if (!ci.isONE()) {
899                    System.out.println("bi = " + bi + ", cont(bi) = " + ci);
900                }
901                //Fii.add(ci);
902            }
903            //Si = Fii;
904            //System.out.println("Si  = " + Si);
905        }
906        logger.info("multivariate lift: U = " + U + ", of " + F);
907        return U;
908    }
909
910
911    /**
912     * Modular Hensel full lifting algorithm. Let p = A_i.ring.coFac.modul() and
913     * assume ggt(a,b) == 1 mod p, for a, b in A.
914     * @param C GenPolynomial with integer coefficients
915     * @param F list of modular GenPolynomials, mod (I_v, p )
916     * @param V list of integer substitution values
917     * @param k desired approximation exponent p^k.
918     * @param G = [g_1,...,g_n] list of factors of leading coefficients.
919     * @return [c_1,..., c_n] with prod_i c_i = C mod p^k.
920     */
921    @SuppressWarnings("unchecked")
922    public static <MOD extends GcdRingElem<MOD> & Modular> List<GenPolynomial<MOD>> liftHenselFull(
923                    GenPolynomial<BigInteger> C, List<GenPolynomial<MOD>> F, List<BigInteger> V, long k,
924                    List<GenPolynomial<BigInteger>> G) throws NoLiftingException {
925        if (F == null || F.size() == 0) {
926            return new ArrayList<GenPolynomial<MOD>>();
927        }
928        GenPolynomialRing<MOD> pkfac = F.get(0).ring;
929        //long d = C.degree();
930        // setup q = p^k
931        RingFactory<MOD> cfac = pkfac.coFac;
932        ModularRingFactory<MOD> pcfac = (ModularRingFactory<MOD>) cfac;
933        //System.out.println("pcfac = " + pcfac);
934        BigInteger p = pcfac.getIntegerModul();
935        BigInteger q = p.power(k);
936        ModularRingFactory<MOD> mcfac;
937        if (ModLongRing.MAX_LONG.compareTo(q.getVal()) > 0) {
938            mcfac = (ModularRingFactory) new ModLongRing(q.getVal());
939        } else {
940            mcfac = (ModularRingFactory) new ModIntegerRing(q.getVal());
941        }
942        //System.out.println("mcfac = " + mcfac);
943
944        // convert C from Z[...] to Z_q[...]
945        GenPolynomialRing<MOD> qcfac = new GenPolynomialRing<MOD>(mcfac, C.ring);
946        GenPolynomial<MOD> Cq = PolyUtil.<MOD> fromIntegerCoefficients(qcfac, C);
947        //System.out.println("C  = " + C);
948        //System.out.println("Cq = " + Cq);
949
950        // convert g_i from Z[...] to Z_q[...]
951        GenPolynomialRing<MOD> gcfac = new GenPolynomialRing<MOD>(mcfac, G.get(0).ring);
952        List<GenPolynomial<MOD>> GQ = new ArrayList<GenPolynomial<MOD>>();
953        boolean allOnes = true;
954        for (GenPolynomial<BigInteger> g : G) {
955            if (!g.isONE()) {
956                allOnes = false;
957            }
958            GenPolynomial<MOD> gq = PolyUtil.<MOD> fromIntegerCoefficients(gcfac, g);
959            GQ.add(gq);
960        }
961        //System.out.println("G  = " + G);
962        //System.out.println("GQ = " + GQ);
963
964        // evaluate C to Z_q[x]
965        GenPolynomialRing<MOD> pf = qcfac;
966        GenPolynomial<MOD> ap = Cq;
967        for (int j = C.ring.nvar; j > 1; j--) {
968            pf = pf.contract(1);
969            //MOD vp = mcfac.fromInteger(V.get(C.ring.nvar - j).getSymmetricInteger().getVal());
970            MOD vp = mcfac.fromInteger(V.get(C.ring.nvar - j).getVal());
971            //System.out.println("vp     = " + vp);
972            ap = PolyUtil.<MOD> evaluateMain(pf, ap, vp);
973            //System.out.println("ap     = " + ap);
974        }
975        GenPolynomial<MOD> Cq1 = ap;
976        //System.out.println("Cq1 = " + Cq1);
977        if (Cq1.isZERO()) {
978            throw new NoLiftingException("C mod (I, p^k) == 0: " + C);
979        }
980        GenPolynomialRing<BigInteger> ifac = new GenPolynomialRing<BigInteger>(new BigInteger(), pf);
981        GenPolynomial<BigInteger> Ci = PolyUtil.integerFromModularCoefficients(ifac, Cq1);
982        //System.out.println("Ci  = " + Ci);
983        GreatestCommonDivisorAbstract<BigInteger> ufd = GCDFactory.getImplementation(new BigInteger());
984        Ci = Ci.abs();
985        BigInteger cCi = ufd.baseContent(Ci);
986        Ci = Ci.divide(cCi);
987        //System.out.println("cCi = " + cCi);
988        //System.out.println("Ci  = " + Ci);
989        ////System.out.println("F.fac = " + F.get(0).ring);
990
991        // evaluate G to Z_q
992        //List<GenPolynomial<MOD>> GP = new ArrayList<GenPolynomial<MOD>>();
993        for (GenPolynomial<MOD> gq : GQ) {
994            GenPolynomialRing<MOD> gf = gcfac;
995            GenPolynomial<MOD> gp = gq;
996            for (int j = gcfac.nvar; j > 1; j--) {
997                gf = gf.contract(1);
998                //MOD vp = mcfac.fromInteger(V.get(gcfac.nvar - j).getSymmetricInteger().getVal());
999                MOD vp = mcfac.fromInteger(V.get(gcfac.nvar - j).getVal());
1000                //System.out.println("vp     = " + vp);
1001                gp = PolyUtil.<MOD> evaluateMain(gf, gp, vp);
1002                //System.out.println("gp     = " + gp);
1003            }
1004            //GP.add(gp);
1005        }
1006        //System.out.println("GP = " + GP); // + ", GP.ring = " + GP.get(0).ring);
1007
1008        // leading coefficient for recursion base, for Cq1 and list GP 
1009        BigInteger gi0 = Ci.leadingBaseCoefficient(); // gq0.getSymmetricInteger();
1010        //System.out.println("gi0 = " + gi0);
1011
1012        // lift F to Z_{p^k}[x]
1013        //System.out.println("Ci = " + Ci + ", F = " + F + ", k = " + k + ", p = " + F.get(0).ring + ", gi0 = " + gi0);
1014        List<GenPolynomial<MOD>> U1 = null;
1015        if (gi0.isONE()) {
1016            U1 = HenselUtil.<MOD> liftHenselMonic(Ci, F, k);
1017        } else {
1018            U1 = HenselUtil.<MOD> liftHensel(Ci, F, k, gi0); // gi0 TODO ??
1019        }
1020        logger.info("univariate lift: Ci = " + Ci + ", F = " + F + ", U1 = " + U1);
1021        //System.out.println("U1.fac = " + U1.get(0).ring);
1022
1023        // adjust leading coefficients of U1 with F
1024        List<GenPolynomial<BigInteger>> U1i = PolyUtil.<MOD> integerFromModularCoefficients(Ci.ring, U1);
1025        //System.out.println("U1i = " + U1i);
1026        boolean t = HenselUtil.isHenselLift(Ci, q, p, U1i);
1027        //System.out.println("isLift(U1) = " + t);
1028        if (!t) {
1029            //System.out.println("NoLiftingException, Ci = " + Ci + ", U1i = " + U1i);
1030            throw new NoLiftingException("Ci = " + Ci + ", U1i = " + U1i);
1031        }
1032        MOD cC = mcfac.fromInteger(cCi.getVal());
1033        List<GenPolynomial<MOD>> U1f = PolyUtil.<MOD> fromIntegerCoefficients(F.get(0).ring, U1i);
1034        //System.out.println("U1f = " + U1f);
1035        List<GenPolynomial<MOD>> U1s = new ArrayList<GenPolynomial<MOD>>(U1.size());
1036        int j = 0;
1037        int s = 0;
1038        for (GenPolynomial<MOD> u : U1) {
1039            GenPolynomial<MOD> uf = U1f.get(j);
1040            GenPolynomial<MOD> f = F.get(j);
1041            GenPolynomial<BigInteger> ui = U1i.get(j);
1042            GenPolynomial<BigInteger> gi = G.get(j);
1043            if (ui.signum() != gi.signum()) {
1044                //System.out.println("ui = " + ui + ", gi = " + gi);
1045                u = u.negate();
1046                uf = uf.negate();
1047                s++;
1048            }
1049            j++;
1050            if (uf.isConstant()) {
1051                //System.out.println("u   = " + u);
1052                u = u.monic();
1053                //System.out.println("u  = " + u);
1054                u = u.multiply(cC);
1055                cC = cC.divide(cC);
1056                //System.out.println("u   = " + u);
1057            } else {
1058                MOD x = f.leadingBaseCoefficient().divide(uf.leadingBaseCoefficient());
1059                //System.out.println("x   = " + x + ", xi = " + x.getSymmetricInteger());
1060                if (!x.isONE()) {
1061                    MOD xq = mcfac.fromInteger(x.getSymmetricInteger().getVal());
1062                    //System.out.println("xq  = " + xq);
1063                    u = u.multiply(xq);
1064                    cC = cC.divide(xq);
1065                    //System.out.println("cC  = " + cC);
1066                }
1067            }
1068            U1s.add(u);
1069        }
1070        //if ( s % 2 != 0 || !cC.isONE()) {
1071        if (!cC.isONE()) {
1072            throw new NoLiftingException("s = " + s + ", Ci = " + Ci + ", U1i = " + U1i + ", cC = " + cC);
1073        }
1074        U1 = U1s;
1075        U1i = PolyUtil.<MOD> integerFromModularCoefficients(Ci.ring, U1);
1076        //System.out.println("U1i = " + U1i);
1077        U1f = PolyUtil.<MOD> fromIntegerCoefficients(F.get(0).ring, U1i);
1078        if (!F.equals(U1f)) { // evtl loop until reached
1079            System.out.println("F   = " + F);
1080            System.out.println("U1f = " + U1f);
1081            throw new NoLiftingException("F = " + F + ", U1f = " + U1f);
1082        }
1083        logger.info("multivariate lift: U1 = " + U1);
1084
1085        // lift U to Z_{p^k}[x,...]
1086        //System.out.println("C = " + C + ", U1 = " + U1 + ", V = " + V + ", k = " + k + ", q = " + U1.get(0).ring + ", G = " + G);
1087        List<GenPolynomial<MOD>> U = null;
1088        if (allOnes) {
1089            U = HenselMultUtil.<MOD> liftHenselMonic(C, Cq, U1, V, k);
1090        } else {
1091            U = HenselMultUtil.<MOD> liftHensel(C, Cq, U1, V, k, G);
1092        }
1093        logger.info("multivariate lift: C = " + C + ", U1 = " + U1 + ", U = " + U);
1094        //System.out.println("U  = " + U);
1095        //System.out.println("U.fac = " + U.get(0).ring);
1096        return U;
1097    }
1098
1099}