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