001/*
002 * $Id$
003 */
004
005package edu.jas.ufd;
006
007
008import java.util.ArrayList;
009import java.util.Iterator;
010import java.util.List;
011
012import org.apache.logging.log4j.LogManager;
013import org.apache.logging.log4j.Logger;
014
015import edu.jas.arith.BigInteger;
016import edu.jas.arith.ModIntegerRing;
017import edu.jas.arith.ModLongRing;
018import edu.jas.arith.Modular;
019import edu.jas.arith.ModularRingFactory;
020import edu.jas.arith.PrimeList;
021import edu.jas.poly.ExpVector;
022import edu.jas.poly.GenPolynomial;
023import edu.jas.poly.GenPolynomialRing;
024import edu.jas.poly.PolyUtil;
025import edu.jas.structure.GcdRingElem;
026import edu.jas.structure.NotInvertibleException;
027import edu.jas.structure.Power;
028import edu.jas.structure.RingFactory;
029
030
031/**
032 * Greatest common divisor algorithms with subresultant polynomial remainder
033 * sequence and univariate Hensel lifting.
034 * @author Heinz Kredel
035 */
036
037public class GreatestCommonDivisorHensel<MOD extends GcdRingElem<MOD> & Modular>
038                extends GreatestCommonDivisorAbstract<BigInteger> {
039
040
041    private static final Logger logger = LogManager.getLogger(GreatestCommonDivisorHensel.class);
042
043
044    private static final boolean debug = logger.isDebugEnabled();
045
046
047    /**
048     * Flag for linear or quadratic Hensel lift.
049     */
050    public final boolean quadratic;
051
052
053    /**
054     * Fall back gcd algorithm.
055     */
056    public final GreatestCommonDivisorAbstract<BigInteger> iufd;
057
058
059    /*
060     * Internal dispatcher.
061     */
062    private final GreatestCommonDivisorAbstract<BigInteger> ufd;
063
064
065    /**
066     * Constructor.
067     */
068    public GreatestCommonDivisorHensel() {
069        this(true);
070    }
071
072
073    /**
074     * Constructor.
075     * @param quadratic use quadratic Hensel lift.
076     */
077    public GreatestCommonDivisorHensel(boolean quadratic) {
078        this.quadratic = quadratic;
079        iufd = new GreatestCommonDivisorSubres<BigInteger>();
080        ufd = this; //iufd;
081    }
082
083
084    /**
085     * Univariate GenPolynomial greatest comon divisor. Uses univariate Hensel
086     * lifting.
087     * @param P univariate GenPolynomial.
088     * @param S univariate GenPolynomial.
089     * @return gcd(P,S).
090     */
091    @Override
092    @SuppressWarnings("unchecked")
093    public GenPolynomial<BigInteger> baseGcd(GenPolynomial<BigInteger> P, GenPolynomial<BigInteger> S) {
094        if (S == null || S.isZERO()) {
095            return P;
096        }
097        if (P == null || P.isZERO()) {
098            return S;
099        }
100        if (P.ring.nvar > 1) {
101            throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial");
102        }
103        GenPolynomialRing<BigInteger> fac = P.ring;
104        long e = P.degree(0);
105        long f = S.degree(0);
106        GenPolynomial<BigInteger> q;
107        GenPolynomial<BigInteger> r;
108        if (f > e) {
109            r = P;
110            q = S;
111            long g = f;
112            f = e;
113            e = g;
114        } else {
115            q = P;
116            r = S;
117        }
118        if (debug) {
119            logger.debug("degrees: e = " + e + ", f = " + f);
120        }
121        r = r.abs();
122        q = q.abs();
123        // compute contents and primitive parts
124        BigInteger a = baseContent(r);
125        BigInteger b = baseContent(q);
126        // gcd of coefficient contents
127        BigInteger c = gcd(a, b); // indirection
128        r = divide(r, a); // indirection
129        q = divide(q, b); // indirection
130        if (r.isONE()) {
131            return r.multiply(c);
132        }
133        if (q.isONE()) {
134            return q.multiply(c);
135        }
136        // compute normalization factor
137        BigInteger ac = r.leadingBaseCoefficient();
138        BigInteger bc = q.leadingBaseCoefficient();
139        BigInteger cc = gcd(ac, bc); // indirection
140        // compute degree vectors, only univeriate
141        ExpVector rdegv = r.degreeVector();
142        ExpVector qdegv = q.degreeVector();
143        //initialize prime list and degree vector
144        PrimeList primes = new PrimeList(PrimeList.Range.medium);
145        int pn = 50; //primes.size();
146
147        ModularRingFactory<MOD> cofac;
148        GenPolynomial<MOD> qm;
149        GenPolynomial<MOD> qmf;
150        GenPolynomial<MOD> rm;
151        GenPolynomial<MOD> rmf;
152        GenPolynomial<MOD> cmf;
153        GenPolynomialRing<MOD> mfac;
154        GenPolynomial<MOD> cm = null;
155        GenPolynomial<MOD>[] ecm = null;
156        GenPolynomial<MOD> sm = null;
157        GenPolynomial<MOD> tm = null;
158        HenselApprox<MOD> lift = null;
159        if (debug) {
160            logger.debug("c = " + c);
161            logger.debug("cc = " + cc);
162            logger.debug("primes = " + primes);
163        }
164
165        int i = 0;
166        for (java.math.BigInteger p : primes) {
167            //System.out.println("next run ++++++++++++++++++++++++++++++++++");
168            if (++i >= pn) {
169                logger.error("prime list exhausted, pn = " + pn);
170                //logger.info("primes = " + primes);
171                return iufd.baseGcd(P, S);
172                //throw new ArithmeticException("prime list exhausted");
173            }
174            // initialize coefficient factory and map normalization factor
175            //cofac = new ModIntegerRing(p, true);
176            if (ModLongRing.MAX_LONG.compareTo(p) > 0) {
177                cofac = (ModularRingFactory) new ModLongRing(p, true);
178            } else {
179                cofac = (ModularRingFactory) new ModIntegerRing(p, true);
180            }
181            MOD nf = cofac.fromInteger(cc.getVal());
182            if (nf.isZERO()) {
183                continue;
184            }
185            nf = cofac.fromInteger(q.leadingBaseCoefficient().getVal());
186            if (nf.isZERO()) {
187                continue;
188            }
189            nf = cofac.fromInteger(r.leadingBaseCoefficient().getVal());
190            if (nf.isZERO()) {
191                continue;
192            }
193            // initialize polynomial factory and map polynomials
194            mfac = new GenPolynomialRing<MOD>(cofac, fac.nvar, fac.tord, fac.getVars());
195            qm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, q);
196            if (!qm.degreeVector().equals(qdegv)) {
197                continue;
198            }
199            rm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, r);
200            if (!rm.degreeVector().equals(rdegv)) {
201                continue;
202            }
203            if (debug) {
204                logger.info("cofac = " + cofac.getIntegerModul());
205            }
206
207            // compute univariate modular gcd
208            cm = qm.gcd(rm);
209
210            // test for constant g.c.d
211            if (cm.isConstant()) {
212                logger.debug("cm, constant = " + cm);
213                return fac.getONE().multiply(c);
214            }
215
216            // compute factors and gcd with factor
217            GenPolynomial<BigInteger> crq;
218            rmf = rm.divide(cm); // rm = cm * rmf
219            ecm = cm.egcd(rmf);
220            if (ecm[0].isONE()) {
221                //logger.debug("gcd() first factor " + rmf);
222                crq = r;
223                cmf = rmf;
224                sm = ecm[1];
225                tm = ecm[2];
226            } else {
227                qmf = qm.divide(cm); // qm = cm * qmf
228                ecm = cm.egcd(qmf);
229                if (ecm[0].isONE()) {
230                    //logger.debug("gcd() second factor " + qmf);
231                    crq = q;
232                    cmf = qmf;
233                    sm = ecm[1];
234                    tm = ecm[2];
235                } else {
236                    logger.info("both gcd != 1: Hensel not applicable");
237                    return iufd.baseGcd(P, S);
238                }
239            }
240            BigInteger cn = crq.maxNorm();
241            cn = cn.multiply(crq.leadingBaseCoefficient().abs());
242            cn = cn.multiply(cn.fromInteger(2));
243            if (debug) {
244                System.out.println("crq = " + crq);
245                System.out.println("cm  = " + cm);
246                System.out.println("cmf = " + cmf);
247                System.out.println("sm  = " + sm);
248                System.out.println("tm  = " + tm);
249                System.out.println("cn  = " + cn);
250            }
251            try {
252                if (quadratic) {
253                    lift = HenselUtil.liftHenselQuadratic(crq, cn, cm, cmf, sm, tm);
254                } else {
255                    lift = HenselUtil.liftHensel(crq, cn, cm, cmf, sm, tm);
256                }
257            } catch (NoLiftingException nle) {
258                logger.info("giving up on Hensel gcd reverting to Subres gcd " + nle);
259                return iufd.baseGcd(P, S);
260            }
261            q = lift.A;
262            if (debug) {
263                System.out.println("q   = " + q);
264                System.out.println("qf  = " + lift.B);
265            }
266            q = basePrimitivePart(q);
267            q = q.multiply(c).abs();
268            if (PolyUtil.<BigInteger> baseSparsePseudoRemainder(P, q).isZERO()
269                            && PolyUtil.<BigInteger> baseSparsePseudoRemainder(S, q).isZERO()) {
270                break;
271            }
272            logger.info("final devision not successfull");
273            //System.out.println("P rem q = " + PolyUtil.<BigInteger>baseSparsePseudoRemainder(P,q));
274            //System.out.println("S rem q = " + PolyUtil.<BigInteger>baseSparsePseudoRemainder(S,q));
275            //break;
276        }
277        return q;
278    }
279
280
281    /**
282     * Univariate GenPolynomial recursive greatest comon divisor. Uses
283     * multivariate Hensel list.
284     * @param P univariate recursive GenPolynomial.
285     * @param S univariate recursive GenPolynomial.
286     * @return gcd(P,S).
287     */
288    @Override
289    @SuppressWarnings("unchecked")
290    public GenPolynomial<GenPolynomial<BigInteger>> recursiveUnivariateGcd(
291                    GenPolynomial<GenPolynomial<BigInteger>> P, GenPolynomial<GenPolynomial<BigInteger>> S) {
292        if (S == null || S.isZERO()) {
293            return P;
294        }
295        if (P == null || P.isZERO()) {
296            return S;
297        }
298        if (P.ring.nvar > 1) {
299            throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial");
300        }
301        long e = P.degree(0);
302        long f = S.degree(0);
303        GenPolynomial<GenPolynomial<BigInteger>> q, r; //, s;
304        if (f > e) {
305            r = P;
306            q = S;
307            long g = f;
308            f = e;
309            e = g;
310        } else {
311            q = P;
312            r = S;
313        }
314        if (debug) {
315            logger.debug("degrees: e = " + e + ", f = " + f);
316        }
317        r = r.abs();
318        q = q.abs();
319        //logger.info("r: " + r + ", q: " + q);
320
321        GenPolynomial<BigInteger> a = ufd.recursiveContent(r);
322        GenPolynomial<BigInteger> b = ufd.recursiveContent(q);
323
324        GenPolynomial<BigInteger> c = ufd.gcd(a, b); // go to recursion
325        //System.out.println("rgcd c = " + c);
326        r = PolyUtil.<BigInteger> recursiveDivide(r, a);
327        q = PolyUtil.<BigInteger> recursiveDivide(q, b);
328        //a = PolyUtil.<BigInteger> basePseudoDivide(a, c); // unused ?
329        //b = PolyUtil.<BigInteger> basePseudoDivide(b, c); // unused ?
330        if (r.isONE()) {
331            return r.multiply(c);
332        }
333        if (q.isONE()) {
334            return q.multiply(c);
335        }
336        // check constant ldcf, TODO general case
337        GenPolynomial<BigInteger> la, lb, lc, lh;
338        la = r.leadingBaseCoefficient();
339        lb = q.leadingBaseCoefficient();
340        lc = ufd.gcd(la, lb);
341        //logger.info("la = " + la + ", lb = " + lb + ", lc = " + lc);
342        if (!lc.isConstant()) {
343            //continue; // easy way out
344            GenPolynomial<GenPolynomial<BigInteger>> T = iufd.recursiveUnivariateGcd(r, q);
345            T = T.abs().multiply(c);
346            logger.info("non monic ldcf (" + lc + ") not implemented: " + T + "= gcd(" + r + "," + q + ") * "
347                            + c);
348            return T;
349        }
350
351        // convert from Z[y1,...,yr][x] to Z[x][y1,...,yr] to Z[x,y1,...,yr]
352        GenPolynomial<GenPolynomial<BigInteger>> qs = PolyUtil.<BigInteger> switchVariables(q);
353        GenPolynomial<GenPolynomial<BigInteger>> rs = PolyUtil.<BigInteger> switchVariables(r);
354
355        GenPolynomialRing<GenPolynomial<BigInteger>> rfac = qs.ring;
356        RingFactory<GenPolynomial<BigInteger>> rrfac = rfac.coFac;
357        GenPolynomialRing<BigInteger> cfac = (GenPolynomialRing<BigInteger>) rrfac;
358        GenPolynomialRing<BigInteger> dfac = cfac.extend(rfac.getVars());
359        //System.out.println("pfac = " + P.ring.toScript());
360        //System.out.println("rfac = " + rfac.toScript());
361        //System.out.println("dfac = " + dfac.toScript());
362        GenPolynomial<BigInteger> qd = PolyUtil.<BigInteger> distribute(dfac, qs);
363        GenPolynomial<BigInteger> rd = PolyUtil.<BigInteger> distribute(dfac, rs);
364
365        // compute normalization factor
366        BigInteger ac = rd.leadingBaseCoefficient();
367        BigInteger bc = qd.leadingBaseCoefficient();
368        BigInteger cc = gcd(ac, bc); // indirection
369
370        //initialize prime list
371        PrimeList primes = new PrimeList(PrimeList.Range.medium);
372        Iterator<java.math.BigInteger> primeIter = primes.iterator();
373        int pn = 50; //primes.size();
374
375        // double check variables
376        // need qe,re,qd,rd,a,b
377        GenPolynomial<BigInteger> ce0 = null; // qe0, re0,
378
379        for (int i = 0; i < 11; i++) { // meta loop
380            //System.out.println("======== run " + dfac.nvar + ", " + i);
381            java.math.BigInteger p = null; //new java.math.BigInteger("19"); //primes.next();
382            // 5 small, 4 medium and 2 large size primes
383            if (i == 0) { // medium size
384                primes = new PrimeList(PrimeList.Range.medium);
385                primeIter = primes.iterator();
386            }
387            if (i == 4) { // small size
388                primes = new PrimeList(PrimeList.Range.small);
389                primeIter = primes.iterator();
390                p = primeIter.next(); // 2
391                p = primeIter.next(); // 3
392                p = primeIter.next(); // 5
393                p = primeIter.next(); // 7
394            }
395            if (i == 9) { // large size
396                primes = new PrimeList(PrimeList.Range.large);
397                primeIter = primes.iterator();
398            }
399            ModularRingFactory<MOD> cofac = null;
400            int pi = 0;
401            while (pi++ < pn && primeIter.hasNext()) {
402                p = primeIter.next();
403                //p = new java.math.BigInteger("19");
404                logger.info("prime = " + p);
405                // initialize coefficient factory and map normalization factor and polynomials
406                ModularRingFactory<MOD> cf = null;
407                if (ModLongRing.MAX_LONG.compareTo(p) > 0) {
408                    cf = (ModularRingFactory) new ModLongRing(p, true);
409                } else {
410                    cf = (ModularRingFactory) new ModIntegerRing(p, true);
411                }
412                MOD nf = cf.fromInteger(cc.getVal());
413                if (nf.isZERO()) {
414                    continue;
415                }
416                nf = cf.fromInteger(q.leadingBaseCoefficient().leadingBaseCoefficient().getVal());
417                if (nf.isZERO()) {
418                    continue;
419                }
420                nf = cf.fromInteger(r.leadingBaseCoefficient().leadingBaseCoefficient().getVal());
421                if (nf.isZERO()) {
422                    continue;
423                }
424                cofac = cf;
425                break;
426            }
427            if (cofac == null) { // no lucky prime found
428                GenPolynomial<GenPolynomial<BigInteger>> T = iufd.recursiveUnivariateGcd(q, r);
429                logger.info("no lucky prime, gave up on Hensel: " + T + "= gcd(" + r + "," + q + ")");
430                return T.abs().multiply(c); //.abs();
431            }
432            //System.out.println("cofac = " + cofac);
433
434            // search evaluation points and evaluate
435            List<BigInteger> V = new ArrayList<BigInteger>(P.ring.nvar);
436            GenPolynomialRing<BigInteger> ckfac = dfac;
437            GenPolynomial<BigInteger> qe = qd;
438            GenPolynomial<BigInteger> re = rd;
439            GenPolynomial<BigInteger> qei;
440            GenPolynomial<BigInteger> rei;
441            for (int j = dfac.nvar; j > 1; j--) {
442                // evaluation to univariate case
443                long degq = qe.degree(ckfac.nvar - 2);
444                long degr = re.degree(ckfac.nvar - 2);
445                ckfac = ckfac.contract(1);
446                long vi = 1L; //(long)(dfac.nvar-j); // 1L; 0 not so good for small p
447                if (p.longValueExact() > 1000L) {
448                    //vi = (long)j+1L;
449                    vi = 0L;
450                }
451                // search small evaluation point
452                while (true) {
453                    MOD vp = cofac.fromInteger(vi++);
454                    //System.out.println("vp = " + vp);
455                    if (vp.isZERO() && vi != 1L) { // all elements of Z_p exhausted
456                        qe = null;
457                        re = null;
458                        break;
459                    }
460                    BigInteger vii = new BigInteger(vi - 1);
461                    qei = PolyUtil.<BigInteger> evaluateMain(ckfac, qe, vii);
462                    rei = PolyUtil.<BigInteger> evaluateMain(ckfac, re, vii);
463                    //System.out.println("qei = " + qei);
464                    //System.out.println("rei = " + rei);
465
466                    // check lucky evaluation point 
467                    if (degq != qei.degree(ckfac.nvar - 1)) {
468                        //System.out.println("degv(qe) = " + qe.degreeVector());
469                        //System.out.println("deg(qe) = " + degq + ", deg(qe) = " + qei.degree(ckfac.nvar-1));
470                        continue;
471                    }
472                    if (degr != rei.degree(ckfac.nvar - 1)) {
473                        //System.out.println("degv(re) = " + re.degreeVector());
474                        //System.out.println("deg(re) = " + degr + ", deg(re) = " + rei.degree(ckfac.nvar-1));
475                        continue;
476                    }
477                    V.add(vii);
478                    qe = qei;
479                    re = rei;
480                    break;
481                }
482                if (qe == null && re == null) {
483                    break;
484                }
485            }
486            if (qe == null && re == null) {
487                continue;
488            }
489            logger.info("evaluation points  = " + V);
490
491            // recursion base:
492            GenPolynomial<BigInteger> ce = ufd.baseGcd(qe, re);
493            if (ce.isConstant()) {
494                return P.ring.getONE().multiply(c);
495            }
496            logger.info("base gcd = " + ce);
497
498            // double check 
499            // need qe,re,qd,rd,a,b
500            if (i == 0) {
501                //qe0 = qe;
502                //re0 = re;
503                ce0 = ce;
504                continue;
505            }
506            long d0 = ce0.degree(0);
507            long d1 = ce.degree(0);
508            //System.out.println("d0, d1 = " + d0 + ", " + d1);
509            if (d1 < d0) {
510                //qe0 = qe;
511                //re0 = re;
512                ce0 = ce;
513                continue;
514            } else if (d1 > d0) {
515                continue;
516            }
517            // d0 == d1 is ok
518            long dx = r.degree(0);
519            //System.out.println("d0, dx = " + d0 + ", " + dx);
520            if (d0 == dx) { // gcd == r ?
521                if (PolyUtil.<BigInteger> recursiveSparsePseudoRemainder(q, r).isZERO()) {
522                    r = r.abs().multiply(c); //.abs();
523                    logger.info("exit with r | q : " + r);
524                    return r;
525                }
526                continue;
527            }
528            // norm
529            BigInteger mn = null; //mn = mn.multiply(cc).multiply(mn.fromInteger(2));
530            // prepare lifting, chose factor polynomials
531            GenPolynomial<BigInteger> re1 = PolyUtil.<BigInteger> basePseudoDivide(re, ce);
532            GenPolynomial<BigInteger> qe1 = PolyUtil.<BigInteger> basePseudoDivide(qe, ce);
533            GenPolynomial<BigInteger> ui, he; //, pe;
534            GenPolynomial<BigInteger> g, gi, lui;
535            GenPolynomial<BigInteger> gcr, gcq;
536            gcr = ufd.baseGcd(re1, ce);
537            gcq = ufd.baseGcd(qe1, ce);
538            if (gcr.isONE() && gcq.isONE()) { // both gcds == 1: chose smaller ldcf
539                if (la.totalDegree() > lb.totalDegree()) {
540                    ui = qd;
541                    //s = q;
542                    he = qe1;
543                    //pe = qe;
544                    BigInteger bn = qd.maxNorm();
545                    mn = bn.multiply(cc).multiply(new BigInteger(2L));
546                    g = lb;
547                    logger.debug("select deg: ui = qd, g = b"); //, qe1 = " + qe1); // + ", qe = " + qe);
548                } else {
549                    ui = rd;
550                    //s = r;
551                    he = re1;
552                    //pe = re;
553                    BigInteger an = rd.maxNorm();
554                    mn = an.multiply(cc).multiply(new BigInteger(2L));
555                    g = la;
556                    logger.debug("select deg: ui = rd, g = a"); //, re1 = " + re1); // + ", re = " + re);
557                }
558            } else if (gcr.isONE()) {
559                ui = rd;
560                //s = r;
561                he = re1;
562                //pe = re;
563                BigInteger an = rd.maxNorm();
564                mn = an.multiply(cc).multiply(new BigInteger(2L));
565                g = la;
566                logger.debug("select: ui = rd, g = a"); //, re1 = " + re1); // + ", re = " + re);
567            } else if (gcq.isONE()) {
568                ui = qd;
569                //s = q;
570                he = qe1;
571                //pe = qe;
572                BigInteger bn = qd.maxNorm();
573                mn = bn.multiply(cc).multiply(new BigInteger(2L));
574                g = lb;
575                logger.debug("select: ui = qd, g = b"); //, qe1 = " + qe1); // + ", qe = " + qe);
576            } else { // both gcds != 1: method not applicable
577                logger.info("both gcds != 1: method not applicable");
578                break;
579            }
580            lui = lc; //s.leadingBaseCoefficient();
581            lh = PolyUtil.<BigInteger> basePseudoDivide(g, lui);
582            BigInteger ge = PolyUtil.<BigInteger> evaluateAll(g.ring.coFac, lui, V);
583            if (ge.isZERO()) {
584                continue;
585            }
586            BigInteger geh = PolyUtil.<BigInteger> evaluateAll(g.ring.coFac, lh, V);
587            if (geh.isZERO()) {
588                continue;
589            }
590            BigInteger gg = PolyUtil.<BigInteger> evaluateAll(g.ring.coFac, g, V);
591            if (gg.isZERO()) {
592                continue;
593            }
594            //System.out.println("ge = " + ge + ", geh = " + geh + ", gg = " + gg + ", pe = " + pe); 
595            // 
596            //ce = ce.multiply(geh); //ge);
597            // 
598            he = he.multiply(ge); //gg); //ge); //geh);
599            //
600            gi = lui.extendLower(dfac, 0, 0L); //lui. // g.
601            //
602            ui = ui.multiply(gi); // gi !.multiply(gi) 
603            //System.out.println("ui = " + ui + ", deg(ui) = " + ui.degreeVector());
604            //System.out.println("ce = " + ce + ", he = " + he + ", ge = " + ge);
605            logger.info("gcd(ldcf): " + lui + ", ldcf cofactor: " + lh + ", base cofactor: " + he);
606
607            long k = Power.logarithm(new BigInteger(p), mn);
608            //System.out.println("mn = " + mn);
609            //System.out.println("k = " + k);
610
611            BigInteger qp = cofac.getIntegerModul().power(k);
612            ModularRingFactory<MOD> muqfac;
613            if (ModLongRing.MAX_LONG.compareTo(qp.getVal()) > 0) {
614                muqfac = (ModularRingFactory) new ModLongRing(qp.getVal(), true); // nearly a field
615            } else {
616                muqfac = (ModularRingFactory) new ModIntegerRing(qp.getVal(), true); // nearly a field
617            }
618            GenPolynomialRing<MOD> mucpfac = new GenPolynomialRing<MOD>(muqfac, ckfac);
619            //System.out.println("mucpfac = " + mucpfac.toScript());
620            if (muqfac.fromInteger(ge.getVal()).isZERO()) {
621                continue;
622            }
623            //GenPolynomial<BigInteger> xxx = invertPoly(muqfac,lui,V);
624            //System.out.println("inv(lui) = " + xxx + ", muqfac = " + muqfac + ", lui = " + lui);
625            //ce = ce.multiply(xxx); //.leadingBaseCoefficient()); 
626            //xxx = invertPoly(muqfac,lh,V);
627            //System.out.println("inv(lh) = " + xxx + ", muqfac = " + muqfac + ", lh = " + lh);
628            //he = he.multiply(xxx); //.leadingBaseCoefficient()); 
629
630            GenPolynomial<MOD> cm = PolyUtil.<MOD> fromIntegerCoefficients(mucpfac, ce);
631            GenPolynomial<MOD> hm = PolyUtil.<MOD> fromIntegerCoefficients(mucpfac, he);
632            if (cm.degree(0) != ce.degree(0) || hm.degree(0) != he.degree(0)) {
633                continue;
634            }
635            if (cm.isZERO() || hm.isZERO()) {
636                continue;
637            }
638            logger.info("univariate modulo p^k: " + cm + ", " + hm);
639
640            // convert C from Z[...] to Z_q[...]
641            GenPolynomialRing<MOD> qcfac = new GenPolynomialRing<MOD>(muqfac, dfac);
642            GenPolynomial<MOD> uq = PolyUtil.<MOD> fromIntegerCoefficients(qcfac, ui);
643            if (!ui.leadingExpVector().equals(uq.leadingExpVector())) {
644                logger.info("ev(ui) = " + ui.leadingExpVector() + ", ev(uq) = " + uq.leadingExpVector());
645                continue;
646            }
647            logger.info("multivariate modulo p^k: " + uq);
648
649            List<GenPolynomial<MOD>> F = new ArrayList<GenPolynomial<MOD>>(2);
650            F.add(cm);
651            F.add(hm);
652            List<GenPolynomial<BigInteger>> G = new ArrayList<GenPolynomial<BigInteger>>(2);
653            G.add(lui.ring.getONE()); //lui: lui.ring.getONE()); // TODO 
654            G.add(lui.ring.getONE()); //lh: lui);
655            List<GenPolynomial<MOD>> lift;
656            try {
657                //lift = HenselMultUtil.<MOD> liftHenselFull(ui, F, V, k, G);
658                lift = HenselMultUtil.<MOD> liftHensel(ui, uq, F, V, k, G);
659                logger.info("lift = " + lift);
660            } catch (NoLiftingException nle) {
661                logger.info("NoLiftingException");
662                //System.out.println("exception : " + nle);
663                continue;
664            } catch (ArithmeticException ae) {
665                logger.info("ArithmeticException");
666                //System.out.println("exception : " + ae);
667                continue;
668            } catch (NotInvertibleException ni) {
669                logger.info("NotInvertibleException");
670                //System.out.println("exception : " + ni);
671                continue;
672            }
673            //if (!HenselMultUtil.<MOD> isHenselLift(ui, uq, F, k, lift)) { // not meaningfull test
674            //    logger.info("isHenselLift: false");
675            //    //continue;
676            //}
677
678            // convert Ci from Z_{p^k}[x,y1,...,yr] to Z[x,y1,...,yr] to Z[x][y1,...,yr] to Z[y1,...,yr][x]
679            GenPolynomial<BigInteger> ci = PolyUtil.integerFromModularCoefficients(dfac, lift.get(0));
680            ci = basePrimitivePart(ci);
681            GenPolynomial<GenPolynomial<BigInteger>> Cr = PolyUtil.<BigInteger> recursive(rfac, ci);
682            GenPolynomial<GenPolynomial<BigInteger>> Cs = PolyUtil.<BigInteger> switchVariables(Cr);
683            if (!Cs.ring.equals(P.ring)) {
684                System.out.println("Cs.ring = " + Cs.ring + ", P.ring = " + P.ring);
685            }
686            GenPolynomial<GenPolynomial<BigInteger>> Q = ufd.recursivePrimitivePart(Cs);
687            Q = ufd.baseRecursivePrimitivePart(Q);
688            Q = Q.abs().multiply(c); //.abs();
689            GenPolynomial<GenPolynomial<BigInteger>> Pq, Sq;
690            Pq = PolyUtil.<BigInteger> recursiveSparsePseudoRemainder(P, Q);
691            Sq = PolyUtil.<BigInteger> recursiveSparsePseudoRemainder(S, Q);
692            if (Pq.isZERO() && Sq.isZERO()) {
693                logger.info("gcd normal exit: " + Q);
694                return Q;
695            }
696            logger.info("bad Q = " + Q); // + ", Pq = " + Pq + ", Sq = " + Sq);
697        } // end for meta loop
698          // Hensel gcd failed
699        GenPolynomial<GenPolynomial<BigInteger>> T = iufd.recursiveUnivariateGcd(r, q);
700        T = T.abs().multiply(c);
701        logger.info("no lucky prime or evaluation points, gave up on Hensel: " + T + "= gcd(" + r + "," + q
702                        + ")");
703        return T;
704    }
705
706
707    /* move to Ideal ?
708    GenPolynomial<BigInteger> invertPoly(ModularRingFactory<MOD> mfac, GenPolynomial<BigInteger> li,
709                    List<BigInteger> V) {
710        if (li == null || li.isZERO()) {
711            throw new RuntimeException("li not invertible: " + li);
712        }
713        if (li.isONE()) {
714            return li;
715        }
716        //System.out.println("mfac = " + mfac + ", V = " + V +", li = " + li);
717        GenPolynomialRing<BigInteger> pfac = li.ring;
718        GenPolynomialRing<MOD> mpfac = new GenPolynomialRing<MOD>(mfac, pfac);
719        GenPolynomial<MOD> lm = PolyUtil.<MOD> fromIntegerCoefficients(mpfac, li);
720        //System.out.println("pfac = " + pfac + ", lm = " + lm);
721        List<GenPolynomial<MOD>> lid = new ArrayList<GenPolynomial<MOD>>(V.size());
722        int i = 0;
723        for (BigInteger bi : V) {
724            MOD m = mfac.fromInteger(bi.getVal());
725            GenPolynomial<MOD> mp = mpfac.univariate(i);
726            mp = mp.subtract(m); // X_i - v_i
727            lid.add(mp);
728            i++;
729        }
730        //System.out.println("lid = " + lid);
731        //Ideal<MOD> id = new Ideal<MOD>(mpfac,lid,true); // is a GB
732        //System.out.println("id = " + id);
733        GenPolynomial<MOD> mi = lm; //id.inverse(lm);
734        //System.out.println("mi = " + mi);
735        GenPolynomial<BigInteger> inv = PolyUtil.integerFromModularCoefficients(pfac, mi);
736        return inv;
737    }
738    */
739
740}