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