001    /*
002     * $Id: GreatestCommonDivisorHensel.java 3718 2011-08-03 19:58:03Z kredel $
003     */
004    
005    package edu.jas.ufd;
006    
007    import java.util.ArrayList;
008    import java.util.List;
009    import java.util.Iterator;
010    
011    import org.apache.log4j.Logger;
012    
013    import edu.jas.arith.BigInteger;
014    import edu.jas.arith.ModIntegerRing;
015    import edu.jas.arith.ModLongRing;
016    import edu.jas.arith.Modular;
017    import edu.jas.arith.ModularRingFactory;
018    import edu.jas.arith.PrimeList;
019    import edu.jas.poly.ExpVector;
020    import edu.jas.poly.GenPolynomial;
021    import edu.jas.poly.GenPolynomialRing;
022    import edu.jas.poly.PolyUtil;
023    import edu.jas.structure.Power;
024    import edu.jas.structure.GcdRingElem;
025    import edu.jas.structure.RingFactory;
026    
027    
028    /** 
029     * Greatest common divisor algorithms with subresultant polynomial remainder
030     * sequence and univariate Hensel lifting.
031     * @author Heinz Kredel
032     */
033    
034    public class GreatestCommonDivisorHensel<MOD extends GcdRingElem<MOD> & Modular> extends
035                                                 GreatestCommonDivisorAbstract<BigInteger> {
036    
037    
038        private static final Logger logger = Logger.getLogger(GreatestCommonDivisorHensel.class);
039    
040    
041        private final boolean debug = /*true ||*/logger.isDebugEnabled();
042    
043    
044        /**
045         * Flag for linear or quadratic Hensel lift.
046         */
047        public final boolean quadratic;
048    
049    
050        /**
051         * Fall back gcd algorithm.
052         */
053        public final GreatestCommonDivisorAbstract<BigInteger> iufd;
054    
055    
056        /**
057         * Constructor.
058         */
059        public GreatestCommonDivisorHensel() {
060            this(true);
061        }
062    
063    
064        /**
065         * Constructor.
066         * @param quadratic use quadratic Hensel lift.
067         */
068        public GreatestCommonDivisorHensel(boolean quadratic) {
069            this.quadratic = quadratic;
070            iufd = new GreatestCommonDivisorSubres<BigInteger>();
071        }
072    
073    
074        /**
075         * Univariate GenPolynomial greatest comon divisor. Uses univariate Hensel
076         * lifting.
077         * @param P univariate GenPolynomial.
078         * @param S univariate GenPolynomial.
079         * @return gcd(P,S).
080         */
081        @Override
082        public GenPolynomial<BigInteger> baseGcd(GenPolynomial<BigInteger> P, GenPolynomial<BigInteger> S) {
083            if (S == null || S.isZERO()) {
084                return P;
085            }
086            if (P == null || P.isZERO()) {
087                return S;
088            }
089            if (P.ring.nvar > 1) {
090                throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial");
091            }
092            GenPolynomialRing<BigInteger> fac = P.ring;
093            long e = P.degree(0);
094            long f = S.degree(0);
095            GenPolynomial<BigInteger> q;
096            GenPolynomial<BigInteger> r;
097            if (f > e) {
098                r = P;
099                q = S;
100                long g = f;
101                f = e;
102                e = g;
103            } else {
104                q = P;
105                r = S;
106            }
107            r = r.abs();
108            q = q.abs();
109            // compute contents and primitive parts
110            BigInteger a = baseContent(r);
111            BigInteger b = baseContent(q);
112            // gcd of coefficient contents
113            BigInteger c = gcd(a, b); // indirection
114            r = divide(r, a); // indirection
115            q = divide(q, b); // indirection
116            if (r.isONE()) {
117                return r.multiply(c);
118            }
119            if (q.isONE()) {
120                return q.multiply(c);
121            }
122            // compute normalization factor
123            BigInteger ac = r.leadingBaseCoefficient();
124            BigInteger bc = q.leadingBaseCoefficient();
125            BigInteger cc = gcd(ac, bc); // indirection
126            // compute degree vectors, only univeriate
127            ExpVector rdegv = r.degreeVector();
128            ExpVector qdegv = q.degreeVector();
129            //initialize prime list and degree vector
130            PrimeList primes = new PrimeList(PrimeList.Range.medium);
131            int pn = 50; //primes.size();
132    
133            ModularRingFactory<MOD> cofac;
134            GenPolynomial<MOD> qm;
135            GenPolynomial<MOD> qmf;
136            GenPolynomial<MOD> rm;
137            GenPolynomial<MOD> rmf;
138            GenPolynomial<MOD> cmf;
139            GenPolynomialRing<MOD> mfac;
140            GenPolynomial<MOD> cm = null;
141            GenPolynomial<MOD>[] ecm = null;
142            GenPolynomial<MOD> sm = null;
143            GenPolynomial<MOD> tm = null;
144            HenselApprox<MOD> lift = null;
145            if (debug) {
146                logger.debug("c = " + c);
147                logger.debug("cc = " + cc);
148                logger.debug("primes = " + primes);
149            }
150    
151            int i = 0;
152            for (java.math.BigInteger p : primes) {
153                //System.out.println("next run ++++++++++++++++++++++++++++++++++");
154                if (++i >= pn) {
155                    logger.error("prime list exhausted, pn = " + pn);
156                    logger.info("primes = " + primes);
157                    return iufd.baseGcd(P, S);
158                    //throw new ArithmeticException("prime list exhausted");
159                }
160                // initialize coefficient factory and map normalization factor
161                //cofac = new ModIntegerRing(p, true);
162                if (ModLongRing.MAX_LONG.compareTo(p) > 0) {
163                    cofac = (ModularRingFactory) new ModLongRing(p, true);
164                } else {
165                    cofac = (ModularRingFactory) new ModIntegerRing(p, true);
166                }
167                MOD nf = cofac.fromInteger(cc.getVal());
168                if (nf.isZERO()) {
169                    continue;
170                }
171                nf = cofac.fromInteger(q.leadingBaseCoefficient().getVal());
172                if (nf.isZERO()) {
173                    continue;
174                }
175                nf = cofac.fromInteger(r.leadingBaseCoefficient().getVal());
176                if (nf.isZERO()) {
177                    continue;
178                }
179                // initialize polynomial factory and map polynomials
180                mfac = new GenPolynomialRing<MOD>(cofac, fac.nvar, fac.tord, fac.getVars());
181                qm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, q);
182                if (!qm.degreeVector().equals(qdegv)) {
183                    continue;
184                }
185                rm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, r);
186                if (!rm.degreeVector().equals(rdegv)) {
187                    continue;
188                }
189                if (debug) {
190                    logger.info("cofac = " + cofac.getIntegerModul());
191                }
192    
193                // compute univariate modular gcd
194                cm = qm.gcd(rm);
195    
196                // test for constant g.c.d
197                if (cm.isConstant()) {
198                    logger.debug("cm, constant = " + cm);
199                    return fac.getONE().multiply(c);
200                }
201    
202                // compute factors and gcd with factor
203                GenPolynomial<BigInteger> crq;
204                rmf = rm.divide(cm); // rm = cm * rmf
205                ecm = cm.egcd(rmf);
206                if (ecm[0].isONE()) {
207                    //logger.debug("gcd() first factor " + rmf);
208                    crq = r;
209                    cmf = rmf;
210                    sm = ecm[1];
211                    tm = ecm[2];
212                } else {
213                    qmf = qm.divide(cm); // qm = cm * qmf
214                    ecm = cm.egcd(qmf);
215                    if (ecm[0].isONE()) {
216                        //logger.debug("gcd() second factor " + qmf);
217                        crq = q;
218                        cmf = qmf;
219                        sm = ecm[1];
220                        tm = ecm[2];
221                    } else {
222                        logger.info("giving up on Hensel gcd reverting to Subres gcd");
223                        return iufd.baseGcd(P, S);
224                    }
225                }
226                BigInteger cn = crq.maxNorm();
227                cn = cn.multiply(crq.leadingBaseCoefficient().abs());
228                cn = cn.multiply(cn.fromInteger(2));
229                if (debug) {
230                    System.out.println("crq = " + crq);
231                    System.out.println("cm  = " + cm);
232                    System.out.println("cmf = " + cmf);
233                    System.out.println("sm  = " + sm);
234                    System.out.println("tm  = " + tm);
235                    System.out.println("cn  = " + cn);
236                }
237                try {
238                    if (quadratic) {
239                        lift = HenselUtil.liftHenselQuadratic(crq, cn, cm, cmf, sm, tm);
240                    } else {
241                        lift = HenselUtil.liftHensel(crq, cn, cm, cmf, sm, tm);
242                    }
243                } catch (NoLiftingException nle) {
244                    logger.info("giving up on Hensel gcd reverting to Subres gcd " + nle);
245                    return iufd.baseGcd(P, S);
246                }
247                q = lift.A;
248                if (debug) {
249                    System.out.println("q   = " + q);
250                    System.out.println("qf  = " + lift.B);
251                }
252                q = basePrimitivePart(q);
253                q = q.multiply(c).abs();
254                if (PolyUtil.<BigInteger> basePseudoRemainder(P, q).isZERO()
255                    && PolyUtil.<BigInteger> basePseudoRemainder(S, q).isZERO()) {
256                    break;
257                } else { // else should not happen at this point
258                    logger.info("final devision not successfull");
259                    //System.out.println("P rem q = " + PolyUtil.<BigInteger>basePseudoRemainder(P,q));
260                    //System.out.println("S rem q = " + PolyUtil.<BigInteger>basePseudoRemainder(S,q));
261                    //break;
262                }
263            }
264            return q;
265        }
266    
267    
268        /**
269         * Univariate GenPolynomial recursive greatest comon divisor. Uses
270         * multivariate Hensel list.
271         * @param P univariate recursive GenPolynomial.
272         * @param S univariate recursive GenPolynomial.
273         * @return gcd(P,S).
274         */
275        @Override
276        public GenPolynomial<GenPolynomial<BigInteger>> recursiveUnivariateGcd(
277                  GenPolynomial<GenPolynomial<BigInteger>> P,
278                  GenPolynomial<GenPolynomial<BigInteger>> S) {
279            if (S == null || S.isZERO()) {
280                return P;
281            }
282            if (P == null || P.isZERO()) {
283                return S;
284            }
285            if (P.ring.nvar > 1) {
286                throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial");
287            }
288            long e = P.degree(0);
289            long f = S.degree(0);
290            GenPolynomial<GenPolynomial<BigInteger>> q;
291            GenPolynomial<GenPolynomial<BigInteger>> r;
292            if (f > e) {
293                r = P;
294                q = S;
295                long g = f;
296                f = e;
297                e = g;
298            } else {
299                q = P;
300                r = S;
301            }
302            r = r.abs();
303            q = q.abs();
304            GenPolynomial<BigInteger> a = recursiveContent(r);
305            GenPolynomial<BigInteger> b = recursiveContent(q);
306    
307            GenPolynomial<BigInteger> c = gcd(a, b); // go to recursion
308            //System.out.println("rgcd c = " + c);
309            r = PolyUtil.<BigInteger> recursiveDivide(r, a);
310            q = PolyUtil.<BigInteger> recursiveDivide(q, b);
311            a = PolyUtil.<BigInteger> basePseudoDivide(a, c);
312            b = PolyUtil.<BigInteger> basePseudoDivide(b, c);
313            if (r.isONE()) {
314                return r.multiply(c);
315            }
316            if (q.isONE()) {
317                return q.multiply(c);
318            }
319            // convert from Z[y1,...,yr][x] to Z[x][y1,...,yr] to Z[x,y1,...,yr]
320            GenPolynomial<GenPolynomial<BigInteger>> qs = PolyUtil.<BigInteger> switchVariables(q);
321            GenPolynomial<GenPolynomial<BigInteger>> rs = PolyUtil.<BigInteger> switchVariables(r);
322    
323            GenPolynomialRing<GenPolynomial<BigInteger>> rfac = qs.ring;
324            RingFactory<GenPolynomial<BigInteger>> rrfac = rfac.coFac;
325            GenPolynomialRing<BigInteger> cfac = (GenPolynomialRing<BigInteger>) rrfac;
326            GenPolynomialRing<BigInteger> dfac = cfac.extend(rfac.getVars());
327            //System.out.println("pfac = " + P.ring.toScript());
328            //System.out.println("rfac = " + rfac.toScript());
329            //System.out.println("dfac = " + dfac.toScript());
330    
331            GenPolynomial<BigInteger> qd = PolyUtil.<BigInteger> distribute(dfac, qs);
332            GenPolynomial<BigInteger> rd = PolyUtil.<BigInteger> distribute(dfac, rs);
333            //System.out.println("qd = " + qd);
334            //System.out.println("rd = " + rd);
335            //System.out.println("a  = " + a);
336            //System.out.println("b  = " + b);
337            //System.out.println("c  = " + c);
338    
339            // compute normalization factor
340            BigInteger ac = rd.leadingBaseCoefficient();
341            BigInteger bc = qd.leadingBaseCoefficient();
342            BigInteger cc = gcd(ac, bc); // indirection
343    
344            //initialize prime list
345            PrimeList primes = new PrimeList(PrimeList.Range.medium); // PrimeList.Range.medium);
346            Iterator<java.math.BigInteger> primeIter = primes.iterator();
347            int pn = 50; //primes.size();
348    
349            // double check variables
350            // need qe,re,qd,rd,a,b
351            GenPolynomial<MOD> qe0;
352            GenPolynomial<MOD> re0;
353            GenPolynomial<MOD> ce0 = null;
354    
355            for ( int i = 0; i < 11; i++ ) { // meta loop
356                //System.out.println("======================================================= run " 
357                //                   + dfac.nvar + ", " + i);
358                java.math.BigInteger p = null; //new java.math.BigInteger("19"); //primes.next();
359                // 5 small, 5 medium and 1 large size primes
360                if ( i == 0 ) { // medium size
361                    primes = new PrimeList(PrimeList.Range.medium);
362                    primeIter = primes.iterator();
363                }
364                if ( i == 5 ) { // smal size
365                    primes = new PrimeList(PrimeList.Range.small);
366                    primeIter = primes.iterator();
367                    p = primeIter.next(); // 2
368                    p = primeIter.next(); // 3
369                    p = primeIter.next(); // 5
370                    p = primeIter.next(); // 7
371                }
372                if ( i == 10 ) { // large size
373                    primes = new PrimeList(PrimeList.Range.large);
374                    primeIter = primes.iterator();
375                }
376                ModularRingFactory<MOD> cofac = null;
377                int pi = 0;
378                while ( pi < pn && primeIter.hasNext() ) {
379                    p = primeIter.next();
380                    //p = new java.math.BigInteger("19");
381                    logger.info("prime = " + p);
382                    // initialize coefficient factory and map normalization factor and polynomials
383                    ModularRingFactory<MOD> cf = null;
384                    if (ModLongRing.MAX_LONG.compareTo(p) > 0) {
385                        cf = (ModularRingFactory) new ModLongRing(p, true);
386                    } else {
387                        cf = (ModularRingFactory) new ModIntegerRing(p, true);
388                    }
389                    MOD nf = cf.fromInteger(cc.getVal());
390                    if (nf.isZERO()) {
391                        continue;
392                    }
393                    nf = cf.fromInteger(q.leadingBaseCoefficient().leadingBaseCoefficient().getVal());
394                    if (nf.isZERO()) {
395                        continue;
396                    }
397                    nf = cf.fromInteger(r.leadingBaseCoefficient().leadingBaseCoefficient().getVal());
398                    if (nf.isZERO()) {
399                        continue;
400                    }
401                    cofac = cf;
402                    break;
403                }
404                if ( cofac == null ) { // no lucky prime found
405                    System.out.println("giving up on Hensel gcd reverting to Subres gcd");
406                    GenPolynomial<GenPolynomial<BigInteger>> T = iufd.recursiveUnivariateGcd(P, S);
407                    return T.abs().multiply(c); //.abs();
408                }
409                //System.out.println("cofac = " + cofac);
410    
411                List<MOD> V = new ArrayList<MOD>(P.ring.nvar);
412                GenPolynomialRing<MOD> mfac = new GenPolynomialRing<MOD>(cofac, dfac);
413                //System.out.println("mfac = " + mfac.toScript());
414                GenPolynomial<MOD> qm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, qd);
415                GenPolynomial<MOD> rm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, rd);
416                //System.out.println("qm = " + qm);
417                //System.out.println("rm = " + rm);
418    
419                // search evaluation point and evaluate
420                GenPolynomialRing<MOD> ckfac = mfac;
421                GenPolynomial<MOD> qe = qm;
422                GenPolynomial<MOD> re = rm;
423                GenPolynomial<MOD> qep;
424                GenPolynomial<MOD> rep;
425                for ( int j = dfac.nvar; j > 1; j-- ) {
426                    // evaluation to univariate case
427                    long degq = qe.degree(ckfac.nvar-2);
428                    long degr = re.degree(ckfac.nvar-2);
429                    ckfac = ckfac.contract(1);
430                    long vi = 1L; //(long)(dfac.nvar-j); // 1L; 0 not so good for small p
431                    if ( p.longValue() > 1000L ) {
432                        //vi = (long)j+1L;
433                        vi = 0L;
434                    }
435                    // search small evaluation point
436                    while( true ) { 
437                        MOD vp = cofac.fromInteger(vi++);
438                        //System.out.println("vp = " + vp);
439                        if ( vp.isZERO() && vi != 1L ) { // all elements of Z_p exhausted
440                            qe = null;
441                            re = null;
442                            break;
443                            //GenPolynomial<GenPolynomial<BigInteger>> T = iufd.recursiveUnivariateGcd(P, S);
444                            //return T.abs().multiply(c); //.abs();
445                        }
446                        qep = PolyUtil.<MOD> evaluateMain(ckfac,qe,vp);
447                        rep = PolyUtil.<MOD> evaluateMain(ckfac,re,vp);
448                        //System.out.println("qep = " + qep);
449                        //System.out.println("rep = " + rep);
450    
451                        // check lucky evaluation point 
452                        MOD ql = qep.leadingBaseCoefficient();
453                        MOD rl = rep.leadingBaseCoefficient();
454                        if (ql.isZERO()||rl.isZERO()) { // nearly non sense
455                            continue;
456                        }
457                        if (degq != qep.degree(ckfac.nvar-1)) {
458                            //System.out.println("degv(qe) = " + qe.degreeVector());
459                            //System.out.println("deg(qe) = " + degq + ", deg(qe) = " + qep.degree(ckfac.nvar-1));
460                            continue;
461                        }
462                        if (degr != rep.degree(ckfac.nvar-1)) {
463                            //System.out.println("degv(re) = " + re.degreeVector());
464                            //System.out.println("deg(re) = " + degr + ", deg(re) = " + rep.degree(ckfac.nvar-1));
465                            continue;
466                        }
467                        V.add(vp);
468                        qe = qep;
469                        re = rep;
470                        break;
471                    }
472                    if ( qe == null && re == null ) {
473                        break;
474                    }
475                }
476                if ( qe == null && re == null ) {
477                    continue;
478                }
479                logger.info("evaluation points  = " + V);
480                //System.out.println("qe = " + qe);
481                //System.out.println("re = " + re);
482    
483                // recursion base:
484                GreatestCommonDivisorAbstract<MOD> mufd = GCDFactory.getImplementation(cofac);
485                GenPolynomial<MOD> ce = mufd.baseGcd(qe,re);
486                if ( ce.isConstant() ) {
487                    return P.ring.getONE().multiply(c);
488                }
489                //System.out.println("ce = " + ce);
490                logger.info("base gcd = " + ce);
491                //System.out.println("c = " + c);
492    
493                // double check 
494                // need qe,re,qd,rd,a,b
495                if ( i == 0 ) {
496                    qe0 = qe;
497                    re0 = re; 
498                    ce0 = ce;
499                    continue;
500                } else {
501                    long d0 = ce0.degree(0);
502                    long d1 = ce.degree(0);
503                    //System.out.println("d0, d1 = " + d0 + ", " + d1);
504                    if ( d1 < d0 ) {
505                        qe0 = qe;
506                        re0 = re;
507                        ce0 = ce;
508                        continue;
509                    } else if ( d1 > d0 ) {
510                        continue;
511                    } 
512                    // d0 == d1 is ok
513                    long dx = r.degree(0);
514                    //System.out.println("d0, dx = " + d0 + ", " + dx);
515                    if ( d0 == dx ) { // gcd == r ??
516                        if (PolyUtil.<BigInteger> recursivePseudoRemainder(q,r).isZERO() ) {
517                            r = r.abs().multiply(c); //.abs();
518                            logger.info("exit with r | q : " + r);
519                            return r;
520                        }
521                        continue;
522                    }
523                }
524    
525                // norm
526                BigInteger mn = null; 
527                //mn = mn.multiply(cc).multiply(mn.fromInteger(2));
528    
529                // prepare lifting
530                GenPolynomial<MOD> re1 = PolyUtil.<MOD> basePseudoDivide(re,ce);
531                GenPolynomial<MOD> qe1 = PolyUtil.<MOD> basePseudoDivide(qe,ce);
532                GenPolynomial<BigInteger> ui;
533                GenPolynomial<MOD> he;
534                GenPolynomial<BigInteger> g;
535                if ( mufd.baseGcd(re1,ce).isONE() ) {
536                    ui = rd; 
537                    he = re1;
538                    BigInteger an = rd.maxNorm();
539                    mn = an.multiply(cc).multiply(new BigInteger(2L));
540                    g = a;
541                } else if ( mufd.baseGcd(qe1,ce).isONE() ) {
542                    ui = qd; 
543                    he = qe1;
544                    BigInteger bn = qd.maxNorm();
545                    mn = bn.multiply(cc).multiply(new BigInteger(2L));
546                    g = b;
547                } else {
548                    break;
549                    //System.out.println("giving up on Hensel gcd reverting to Subres gcd");
550                }
551                //System.out.println("ui = " + ui);
552    
553                long k = Power.logarithm(new BigInteger(p),mn);
554                //System.out.println("mn = " + mn);
555                //System.out.println("k = " + k);
556            
557                List<GenPolynomial<MOD>> F = new ArrayList<GenPolynomial<MOD>>(2);
558                F.add(ce);
559                F.add(he);
560                List<GenPolynomial<BigInteger>> G = new ArrayList<GenPolynomial<BigInteger>>(2);
561                G.add(g.ring.getONE()); // TODO
562                G.add(g.ring.getONE());
563                List<GenPolynomial<MOD>> lift;
564                try {
565                    lift = HenselMultUtil.<MOD> liftHenselFull(ui,F,V,k,G);
566                    logger.info("lift = " + lift);
567                } catch ( NoLiftingException nle ) {
568                    //System.out.println("exception : " + nle);
569                    continue;  
570                } catch ( ArithmeticException ae ) {
571                    //System.out.println("exception : " + ae);
572                    continue;  
573                }
574    
575                // convert Ci from Z_{p^k}[x,y1,...,yr] to Z[x,y1,...,yr] to Z[x][y1,...,yr] to Z[y1,...,yr][x]
576                GenPolynomial<BigInteger> ci = PolyUtil.integerFromModularCoefficients( dfac, lift.get(0) );
577                GenPolynomial<GenPolynomial<BigInteger>> Cr = PolyUtil.<BigInteger> recursive(rfac,ci);
578                GenPolynomial<GenPolynomial<BigInteger>> Cs = PolyUtil.<BigInteger> switchVariables(Cr);
579                if ( ! Cs.ring.equals(P.ring) ) {
580                    System.out.println("Cs.ring = " + Cs.ring + ", P.ring = " + P.ring);
581                }
582                q = recursivePrimitivePart(Cs);
583                q = q.abs().multiply(c); //.abs();
584                if ( PolyUtil.<BigInteger> recursivePseudoRemainder(P,q).isZERO() 
585                     && PolyUtil.<BigInteger> recursivePseudoRemainder(S,q).isZERO() ) {
586                    return q;
587                } else {
588                    //System.out.println("bad q = " + q);
589                    //System.out.println("bad P/q = " + PolyUtil.<BigInteger> recursivePseudoRemainder(P,q));
590                    //System.out.println("bad S/q = " + PolyUtil.<BigInteger> recursivePseudoRemainder(S,q));
591                }
592            } // end for meta loop
593            // Hensel gcd failed
594            GenPolynomial<GenPolynomial<BigInteger>> T = iufd.recursiveUnivariateGcd(P, S);
595            T = T.abs().multiply(c); //.abs();
596            logger.info("giving up on Hensel gcd reverting to Subres gcd " + T);
597            //System.out.println("giving up on Hensel gcd reverted to Subres gcd: " + T);
598            return T;
599        }
600    
601    }