001    /*
002     * $Id: FactorInteger.java 3753 2011-08-27 20:34:30Z kredel $
003     */
004    
005    package edu.jas.ufd;
006    
007    
008    import java.util.ArrayList;
009    import java.util.BitSet;
010    import java.util.Iterator;
011    import java.util.List;
012    import java.util.SortedMap;
013    
014    import org.apache.log4j.Logger;
015    
016    import edu.jas.arith.BigInteger;
017    import edu.jas.arith.ModIntegerRing;
018    import edu.jas.arith.ModLongRing;
019    import edu.jas.arith.Modular;
020    import edu.jas.arith.ModularRingFactory;
021    import edu.jas.arith.PrimeList;
022    import edu.jas.poly.ExpVector;
023    import edu.jas.poly.GenPolynomial;
024    import edu.jas.poly.GenPolynomialRing;
025    import edu.jas.poly.PolyUtil;
026    import edu.jas.structure.GcdRingElem;
027    import edu.jas.structure.Power;
028    import edu.jas.structure.RingElem;
029    import edu.jas.structure.RingFactory;
030    import edu.jas.util.KsubSet;
031    
032    
033    /**
034     * Integer coefficients factorization algorithms. This class implements
035     * factorization methods for polynomials over integers.
036     * @author Heinz Kredel
037     */
038    
039    /**
040     * @author kredel
041     * 
042     * @param <MOD>
043     */
044    public class FactorInteger<MOD extends GcdRingElem<MOD> & Modular> extends FactorAbstract<BigInteger> {
045    
046    
047        private static final Logger logger = Logger.getLogger(FactorInteger.class);
048    
049    
050        private final boolean debug = true || logger.isDebugEnabled();
051    
052    
053        /**
054         * Factorization engine for modular base coefficients.
055         */
056        protected final FactorAbstract<MOD> mfactor;
057    
058    
059        /**
060         * Gcd engine for modular base coefficients.
061         */
062        protected final GreatestCommonDivisorAbstract<MOD> mengine;
063    
064    
065        /**
066         * No argument constructor.
067         */
068        public FactorInteger() {
069            this(BigInteger.ONE);
070        }
071    
072    
073        /**
074         * Constructor.
075         * @param cfac coefficient ring factory.
076         */
077        public FactorInteger(RingFactory<BigInteger> cfac) {
078            super(cfac);
079            ModularRingFactory<MOD> mcofac = (ModularRingFactory<MOD>) (Object) new ModLongRing(13, true); // hack
080            mfactor = FactorFactory.getImplementation(mcofac); //new FactorModular(mcofac);
081            mengine = GCDFactory.getImplementation(mcofac);
082            //mengine = GCDFactory.getProxy(mcofac);
083        }
084    
085    
086        /**
087         * GenPolynomial base factorization of a squarefree polynomial.
088         * @param P squarefree and primitive! GenPolynomial.
089         * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i.
090         */
091        @SuppressWarnings("unchecked")
092        @Override
093        public List<GenPolynomial<BigInteger>> baseFactorsSquarefree(GenPolynomial<BigInteger> P) {
094            if (P == null) {
095                throw new IllegalArgumentException(this.getClass().getName() + " P == null");
096            }
097            List<GenPolynomial<BigInteger>> factors = new ArrayList<GenPolynomial<BigInteger>>();
098            if (P.isZERO()) {
099                return factors;
100            }
101            if (P.isONE()) {
102                factors.add(P);
103                return factors;
104            }
105            GenPolynomialRing<BigInteger> pfac = P.ring;
106            if (pfac.nvar > 1) {
107                throw new IllegalArgumentException(this.getClass().getName() + " only for univariate polynomials");
108            }
109            if (!engine.baseContent(P).isONE()) {
110                throw new IllegalArgumentException(this.getClass().getName() + " P not primitive");
111            }
112            if (P.degree(0) <= 1L) { // linear is irreducible
113                factors.add(P);
114                return factors;
115            }
116            // compute norm
117            BigInteger an = P.maxNorm();
118            BigInteger ac = P.leadingBaseCoefficient();
119            //compute factor coefficient bounds
120            ExpVector degv = P.degreeVector();
121            int degi = (int) P.degree(0);
122            BigInteger M = an.multiply(PolyUtil.factorBound(degv));
123            M = M.multiply(ac.abs().multiply(ac.fromInteger(8)));
124            //System.out.println("M = " + M);
125            //M = M.multiply(M); // test
126    
127            //initialize prime list and degree vector
128            PrimeList primes = new PrimeList(PrimeList.Range.small);
129            int pn = 30; //primes.size();
130            ModularRingFactory<MOD> cofac = null;
131            GenPolynomial<MOD> am = null;
132            GenPolynomialRing<MOD> mfac = null;
133            final int TT = 5; // 7
134            List<GenPolynomial<MOD>>[] modfac = new List[TT];
135            List<GenPolynomial<BigInteger>>[] intfac = new List[TT];
136            BigInteger[] plist = new BigInteger[TT];
137            List<GenPolynomial<MOD>> mlist = null;
138            List<GenPolynomial<BigInteger>> ilist = null;
139            int i = 0;
140            if (debug) {
141                logger.debug("an  = " + an);
142                logger.debug("ac  = " + ac);
143                logger.debug("M   = " + M);
144                logger.info("degv = " + degv);
145            }
146            Iterator<java.math.BigInteger> pit = primes.iterator();
147            pit.next(); // skip p = 2
148            pit.next(); // skip p = 3
149            MOD nf = null;
150            for (int k = 0; k < TT; k++) {
151                if (k == TT - 1) { // -2
152                    primes = new PrimeList(PrimeList.Range.medium);
153                    pit = primes.iterator();
154                }
155                if (k == TT + 1) { // -1
156                    primes = new PrimeList(PrimeList.Range.large);
157                    pit = primes.iterator();
158                }
159                while (pit.hasNext()) {
160                    java.math.BigInteger p = pit.next();
161                    //System.out.println("next run ++++++++++++++++++++++++++++++++++");
162                    if (++i >= pn) {
163                        logger.error("prime list exhausted, pn = " + pn);
164                        throw new ArithmeticException("prime list exhausted");
165                    }
166                    if (ModLongRing.MAX_LONG.compareTo(p) > 0) {
167                        cofac = (ModularRingFactory) new ModLongRing(p, true);
168                    } else {
169                        cofac = (ModularRingFactory) new ModIntegerRing(p, true);
170                    }
171                    logger.info("prime = " + cofac);
172                    nf = cofac.fromInteger(ac.getVal());
173                    if (nf.isZERO()) {
174                        logger.info("unlucky prime (nf) = " + p);
175                        //System.out.println("unlucky prime (nf) = " + p);
176                        continue;
177                    }
178                    // initialize polynomial factory and map polynomial
179                    mfac = new GenPolynomialRing<MOD>(cofac, pfac);
180                    am = PolyUtil.<MOD> fromIntegerCoefficients(mfac, P);
181                    if (!am.degreeVector().equals(degv)) { // allways true
182                        logger.info("unlucky prime (deg) = " + p);
183                        //System.out.println("unlucky prime (deg) = " + p);
184                        continue;
185                    }
186                    GenPolynomial<MOD> ap = PolyUtil.<MOD> baseDeriviative(am);
187                    if (ap.isZERO()) {
188                        logger.info("unlucky prime (a')= " + p);
189                        //System.out.println("unlucky prime (a')= " + p);
190                        continue;
191                    }
192                    GenPolynomial<MOD> g = mengine.baseGcd(am, ap);
193                    if (g.isONE()) {
194                        logger.info("**lucky prime = " + p);
195                        //System.out.println("**lucky prime = " + p);
196                        break;
197                    }
198                }
199                // now am is squarefree mod p, make monic and factor mod p
200                if (!nf.isONE()) {
201                    //System.out.println("nf = " + nf);
202                    am = am.divide(nf); // make monic
203                }
204                mlist = mfactor.baseFactorsSquarefree(am);
205                if (logger.isInfoEnabled()) {
206                    logger.info("modlist  = " + mlist);
207                }
208                if (mlist.size() <= 1) {
209                    factors.add(P);
210                    return factors;
211                }
212                if (!nf.isONE()) {
213                    GenPolynomial<MOD> mp = mfac.getONE(); //mlist.get(0);
214                    //System.out.println("mp = " + mp);
215                    mp = mp.multiply(nf);
216                    //System.out.println("mp = " + mp);
217                    mlist.add(0, mp); // set(0,mp);
218                }
219                modfac[k] = mlist;
220                plist[k] = cofac.getIntegerModul(); // p
221            }
222    
223            // search shortest factor list
224            int min = Integer.MAX_VALUE;
225            BitSet AD = null;
226            for (int k = 0; k < TT; k++) {
227                List<ExpVector> ev = PolyUtil.<MOD> leadingExpVector(modfac[k]);
228                BitSet D = factorDegrees(ev, degi);
229                if (AD == null) {
230                    AD = D;
231                } else {
232                    AD.and(D);
233                }
234                int s = modfac[k].size();
235                logger.info("mod(" + plist[k] + ") #s = " + s + ", D = " + D /*+ ", lt = " + ev*/);
236                //System.out.println("mod s = " + s);
237                if (s < min) {
238                    min = s;
239                    mlist = modfac[k];
240                }
241            }
242            logger.info("min = " + min + ", AD = " + AD);
243            if (mlist.size() <= 1) {
244                logger.info("mlist.size() = 1");
245                factors.add(P);
246                return factors;
247            }
248            if (AD.cardinality() <= 2) { // only one possible factor
249                logger.info("degree set cardinality = " + AD.cardinality());
250                factors.add(P);
251                return factors;
252            }
253    
254            boolean allLists = false; //true; //false;
255            if (allLists) {
256                // try each factor list
257                for (int k = 0; k < TT; k++) {
258                    mlist = modfac[k];
259                    if (debug) {
260                        logger.info("lifting from " + mlist);
261                    }
262                    if (false && P.leadingBaseCoefficient().isONE()) {
263                        factors = searchFactorsMonic(P, M, mlist, AD); // does now work in all cases
264                        if (factors.size() == 1) {
265                            factors = searchFactorsNonMonic(P, M, mlist, AD);
266                        }
267                    } else {
268                        factors = searchFactorsNonMonic(P, M, mlist, AD);
269                    }
270                    intfac[k] = factors;
271                }
272            } else {
273                // try only shortest factor list
274                if (debug) {
275                    logger.info("lifting shortest from " + mlist);
276                }
277                if (true && P.leadingBaseCoefficient().isONE()) {
278                    long t = System.currentTimeMillis();
279                    try {
280                        mlist = PolyUtil.<MOD> monic(mlist);
281                        factors = searchFactorsMonic(P, M, mlist, AD); // does now work in all cases
282                        t = System.currentTimeMillis() - t;
283                        //System.out.println("monic time = " + t);
284                        if (false && debug) {
285                            t = System.currentTimeMillis();
286                            List<GenPolynomial<BigInteger>> fnm = searchFactorsNonMonic(P, M, mlist, AD);
287                            t = System.currentTimeMillis() - t;
288                            System.out.println("non monic time = " + t);
289                            if (debug) {
290                                if (!factors.equals(fnm)) {
291                                    System.out.println("monic factors     = " + factors);
292                                    System.out.println("non monic factors = " + fnm);
293                                }
294                            }
295                        }
296                    } catch (RuntimeException e) {
297                        t = System.currentTimeMillis();
298                        factors = searchFactorsNonMonic(P, M, mlist, AD);
299                        t = System.currentTimeMillis() - t;
300                        //System.out.println("only non monic time = " + t);
301                    }
302                } else {
303                    long t = System.currentTimeMillis();
304                    factors = searchFactorsNonMonic(P, M, mlist, AD);
305                    t = System.currentTimeMillis() - t;
306                    //System.out.println("non monic time = " + t);
307                }
308                return factors;
309            }
310    
311            // search longest factor list
312            int max = 0;
313            for (int k = 0; k < TT; k++) {
314                int s = intfac[k].size();
315                logger.info("int s = " + s);
316                //System.out.println("int s = " + s);
317                if (s > max) {
318                    max = s;
319                    ilist = intfac[k];
320                }
321            }
322            factors = ilist;
323            return factors;
324        }
325    
326    
327        /**
328         * BitSet for factor degree list.
329         * @param E exponent vector list.
330         * @return b_0,...,b_k} a BitSet of possible factor degrees.
331         */
332        public BitSet factorDegrees(List<ExpVector> E, int deg) {
333            BitSet D = new BitSet(deg + 1);
334            D.set(0); // constant factor
335            for (ExpVector e : E) {
336                int i = (int) e.getVal(0);
337                BitSet s = new BitSet(deg + 1);
338                for (int k = 0; k < deg + 1 - i; k++) { // shift by i places
339                    s.set(i + k, D.get(k));
340                }
341                //System.out.println("s = " + s);
342                D.or(s);
343                //System.out.println("D = " + D);
344            }
345            return D;
346        }
347    
348    
349        /**
350         * Sum of all degrees.
351         * @param L univariate polynomial list.
352         * @return sum deg(p) for p in L.
353         */
354        public static <C extends RingElem<C>> long degreeSum(List<GenPolynomial<C>> L) {
355            long s = 0L;
356            for (GenPolynomial<C> p : L) {
357                ExpVector e = p.leadingExpVector();
358                long d = e.getVal(0);
359                s += d;
360            }
361            return s;
362        }
363    
364    
365        /**
366         * Factor search with modular Hensel lifting algorithm. Let p =
367         * f_i.ring.coFac.modul() i = 0, ..., n-1 and assume C == prod_{0,...,n-1}
368         * f_i mod p with ggt(f_i,f_j) == 1 mod p for i != j
369         * @param C GenPolynomial.
370         * @param M bound on the coefficients of g_i as factors of C.
371         * @param F = [f_0,...,f_{n-1}] List&lt;GenPolynomial&gt;.
372         * @param D bit set of possible factor degrees.
373         * @return [g_0,...,g_{n-1}] = lift(C,F), with C = prod_{0,...,n-1} g_i mod
374         *         p**e. <b>Note:</b> does not work in all cases.
375         */
376        List<GenPolynomial<BigInteger>> searchFactorsMonic(GenPolynomial<BigInteger> C, BigInteger M,
377                        List<GenPolynomial<MOD>> F, BitSet D) {
378            //System.out.println("*** monic factor combination ***");
379            if (C == null || C.isZERO() || F == null || F.size() == 0) {
380                throw new IllegalArgumentException("C must be nonzero and F must be nonempty");
381            }
382            GenPolynomialRing<BigInteger> pfac = C.ring;
383            if (pfac.nvar != 1) { // todo assert
384                throw new IllegalArgumentException("polynomial ring not univariate");
385            }
386            List<GenPolynomial<BigInteger>> factors = new ArrayList<GenPolynomial<BigInteger>>(F.size());
387            List<GenPolynomial<MOD>> mlist = F;
388            List<GenPolynomial<MOD>> lift;
389    
390            //MOD nf = null;
391            GenPolynomial<MOD> ct = mlist.get(0);
392            if (ct.isConstant()) {
393                //nf = ct.leadingBaseCoefficient();
394                mlist.remove(ct);
395                //System.out.println("=== nf = " + nf);
396                if (mlist.size() <= 1) {
397                    factors.add(C);
398                    return factors;
399                }
400            } else {
401                //nf = ct.ring.coFac.getONE();
402            }
403            //System.out.println("modlist  = " + mlist); // includes not ldcf
404            ModularRingFactory<MOD> mcfac = (ModularRingFactory<MOD>) ct.ring.coFac;
405            BigInteger m = mcfac.getIntegerModul();
406            long k = 1;
407            BigInteger pi = m;
408            while (pi.compareTo(M) < 0) {
409                k++;
410                pi = pi.multiply(m);
411            }
412            logger.info("p^k = " + m + "^" + k);
413            GenPolynomial<BigInteger> PP = C, P = C;
414            // lift via Hensel
415            try {
416                lift = HenselUtil.<MOD> liftHenselMonic(PP, mlist, k);
417                //System.out.println("lift = " + lift);
418            } catch (NoLiftingException e) {
419                throw new RuntimeException(e);
420            }
421            if (logger.isInfoEnabled()) {
422                logger.info("lifted modlist = " + lift);
423            }
424            GenPolynomialRing<MOD> mpfac = lift.get(0).ring;
425    
426            // combine trial factors
427            int dl = (lift.size() + 1) / 2;
428            //System.out.println("dl = " + dl); 
429            GenPolynomial<BigInteger> u = PP;
430            long deg = (u.degree(0) + 1L) / 2L;
431            //System.out.println("deg = " + deg); 
432            //BigInteger ldcf = u.leadingBaseCoefficient();
433            //System.out.println("ldcf = " + ldcf); 
434            for (int j = 1; j <= dl; j++) {
435                //System.out.println("j = " + j + ", dl = " + dl + ", lift = " + lift); 
436                KsubSet<GenPolynomial<MOD>> ps = new KsubSet<GenPolynomial<MOD>>(lift, j);
437                for (List<GenPolynomial<MOD>> flist : ps) {
438                    //System.out.println("degreeSum = " + degreeSum(flist));
439                    if (!D.get((int) FactorInteger.<MOD> degreeSum(flist))) {
440                        logger.info("skipped by degree set " + D + ", deg = " + degreeSum(flist));
441                        continue;
442                    }
443                    GenPolynomial<MOD> mtrial = Power.<GenPolynomial<MOD>> multiply(mpfac, flist);
444                    //GenPolynomial<MOD> mtrial = mpfac.getONE();
445                    //for (int kk = 0; kk < flist.size(); kk++) {
446                    //    GenPolynomial<MOD> fk = flist.get(kk);
447                    //    mtrial = mtrial.multiply(fk);
448                    //}
449                    //System.out.println("+flist = " + flist + ", mtrial = " + mtrial);
450                    if (mtrial.degree(0) > deg) { // this test is sometimes wrong
451                        logger.info("degree " + mtrial.degree(0) + " > deg " + deg);
452                        //continue;
453                    }
454                    //System.out.println("+flist    = " + flist);
455                    GenPolynomial<BigInteger> trial = PolyUtil.integerFromModularCoefficients(pfac, mtrial);
456                    //System.out.println("+trial = " + trial);
457                    //trial = engine.basePrimitivePart( trial.multiply(ldcf) );
458                    trial = engine.basePrimitivePart(trial);
459                    //System.out.println("pp(trial)= " + trial);
460                    if (PolyUtil.<BigInteger> basePseudoRemainder(u, trial).isZERO()) {
461                        logger.info("successful trial = " + trial);
462                        //System.out.println("trial    = " + trial);
463                        //System.out.println("flist    = " + flist);
464                        //trial = engine.basePrimitivePart(trial);
465                        //System.out.println("pp(trial)= " + trial);
466                        factors.add(trial);
467                        u = PolyUtil.<BigInteger> basePseudoDivide(u, trial); //u.divide( trial );
468                        //System.out.println("u        = " + u);
469                        //if (lift.removeAll(flist)) {
470                        lift = removeOnce(lift, flist);
471                        logger.info("new lift= " + lift);
472                        dl = (lift.size() + 1) / 2;
473                        //System.out.println("dl = " + dl); 
474                        j = 0; // since j++
475                        break;
476                        //} logger.error("error removing flist from lift = " + lift);
477                    }
478                }
479            }
480            if (!u.isONE() && !u.equals(P)) {
481                logger.info("rest u = " + u);
482                //System.out.println("rest u = " + u);
483                factors.add(u);
484            }
485            if (factors.size() == 0) {
486                logger.info("irred u = " + u);
487                //System.out.println("irred u = " + u);
488                factors.add(PP);
489            }
490            return factors;
491        }
492    
493    
494        /**
495         * Factor search with modular Hensel lifting algorithm. Let p =
496         * f_i.ring.coFac.modul() i = 0, ..., n-1 and assume C == prod_{0,...,n-1}
497         * f_i mod p with ggt(f_i,f_j) == 1 mod p for i != j
498         * @param C GenPolynomial.
499         * @param M bound on the coefficients of g_i as factors of C.
500         * @param F = [f_0,...,f_{n-1}] List&lt;GenPolynomial&gt;.
501         * @param D bit set of possible factor degrees.
502         * @return [g_0,...,g_{n-1}] = lift(C,F), with C = prod_{0,...,n-1} g_i mod
503         *         p**e.
504         */
505        List<GenPolynomial<BigInteger>> searchFactorsNonMonic(GenPolynomial<BigInteger> C, BigInteger M,
506                        List<GenPolynomial<MOD>> F, BitSet D) {
507            //System.out.println("*** non monic factor combination ***");
508            if (C == null || C.isZERO() || F == null || F.size() == 0) {
509                throw new IllegalArgumentException("C must be nonzero and F must be nonempty");
510            }
511            GenPolynomialRing<BigInteger> pfac = C.ring;
512            if (pfac.nvar != 1) { // todo assert
513                throw new IllegalArgumentException("polynomial ring not univariate");
514            }
515            List<GenPolynomial<BigInteger>> factors = new ArrayList<GenPolynomial<BigInteger>>(F.size());
516            List<GenPolynomial<MOD>> mlist = F;
517    
518            MOD nf = null;
519            GenPolynomial<MOD> ct = mlist.get(0);
520            if (ct.isConstant()) {
521                nf = ct.leadingBaseCoefficient();
522                mlist.remove(ct);
523                //System.out.println("=== nf   = " + nf);
524                //System.out.println("=== ldcf = " + C.leadingBaseCoefficient());
525                if (mlist.size() <= 1) {
526                    factors.add(C);
527                    return factors;
528                }
529            } else {
530                nf = ct.ring.coFac.getONE();
531            }
532            //System.out.println("modlist  = " + mlist); // includes not ldcf
533            GenPolynomialRing<MOD> mfac = ct.ring;
534            GenPolynomial<MOD> Pm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, C);
535            GenPolynomial<BigInteger> PP = C, P = C;
536    
537            // combine trial factors
538            int dl = (mlist.size() + 1) / 2;
539            GenPolynomial<BigInteger> u = PP;
540            long deg = (u.degree(0) + 1L) / 2L;
541            GenPolynomial<MOD> um = Pm;
542            //BigInteger ldcf = u.leadingBaseCoefficient();
543            //System.out.println("ldcf = " + ldcf); 
544            HenselApprox<MOD> ilist = null;
545            for (int j = 1; j <= dl; j++) {
546                //System.out.println("j = " + j + ", dl = " + dl + ", ilist = " + ilist); 
547                KsubSet<GenPolynomial<MOD>> ps = new KsubSet<GenPolynomial<MOD>>(mlist, j);
548                for (List<GenPolynomial<MOD>> flist : ps) {
549                    //System.out.println("degreeSum = " + degreeSum(flist));
550                    if (!D.get((int) FactorInteger.<MOD> degreeSum(flist))) {
551                        logger.info("skipped by degree set " + D + ", deg = " + degreeSum(flist));
552                        continue;
553                    }
554                    GenPolynomial<MOD> trial = mfac.getONE().multiply(nf);
555                    for (int kk = 0; kk < flist.size(); kk++) {
556                        GenPolynomial<MOD> fk = flist.get(kk);
557                        trial = trial.multiply(fk);
558                    }
559                    if (trial.degree(0) > deg) { // this test is sometimes wrong
560                        logger.info("degree > deg " + deg + ", degree = " + trial.degree(0));
561                        //continue;
562                    }
563                    GenPolynomial<MOD> cofactor = um.divide(trial);
564                    //System.out.println("trial    = " + trial);
565                    //System.out.println("cofactor = " + cofactor);
566    
567                    // lift via Hensel
568                    try {
569                        // ilist = HenselUtil.liftHenselQuadraticFac(PP, M, trial, cofactor);
570                        ilist = HenselUtil.<MOD> liftHenselQuadratic(PP, M, trial, cofactor);
571                        //ilist = HenselUtil.<MOD> liftHensel(PP, M, trial, cofactor);
572                    } catch (NoLiftingException e) {
573                        // no liftable factors
574                        if ( /*debug*/logger.isDebugEnabled()) {
575                            logger.info("no liftable factors " + e);
576                            //e.printStackTrace();
577                        }
578                        continue;
579                    }
580                    GenPolynomial<BigInteger> itrial = ilist.A;
581                    GenPolynomial<BigInteger> icofactor = ilist.B;
582                    if (logger.isDebugEnabled()) {
583                        logger.info("       modlist = " + trial + ", cofactor " + cofactor);
584                        logger.info("lifted intlist = " + itrial + ", cofactor " + icofactor);
585                    }
586                    //System.out.println("lifted intlist = " + itrial + ", cofactor " + icofactor); 
587    
588                    itrial = engine.basePrimitivePart(itrial);
589                    //System.out.println("pp(trial)= " + itrial);
590                    if (PolyUtil.<BigInteger> basePseudoRemainder(u, itrial).isZERO()) {
591                        logger.info("successful trial = " + itrial);
592                        //System.out.println("trial    = " + itrial);
593                        //System.out.println("cofactor = " + icofactor);
594                        //System.out.println("flist    = " + flist);
595                        //itrial = engine.basePrimitivePart(itrial);
596                        //System.out.println("pp(itrial)= " + itrial);
597                        factors.add(itrial);
598                        //u = PolyUtil.<BigInteger> basePseudoDivide(u, itrial); //u.divide( trial );
599                        u = icofactor;
600                        PP = u; // fixed finally on 2009-05-03
601                        um = cofactor;
602                        //System.out.println("u        = " + u);
603                        //System.out.println("um       = " + um);
604                        //if (mlist.removeAll(flist)) {
605                        mlist = removeOnce(mlist, flist);
606                        logger.info("new mlist= " + mlist);
607                        dl = (mlist.size() + 1) / 2;
608                        j = 0; // since j++
609                        break;
610                        //} logger.error("error removing flist from ilist = " + mlist);
611                    }
612                }
613            }
614            if (!u.isONE() && !u.equals(P)) {
615                logger.info("rest u = " + u);
616                //System.out.println("rest u = " + u);
617                factors.add(u);
618            }
619            if (factors.size() == 0) {
620                logger.info("irred u = " + u);
621                //System.out.println("irred u = " + u);
622                factors.add(PP);
623            }
624            return factors;
625        }
626    
627    
628        /**
629         * GenPolynomial factorization of a multivariate squarefree polynomial,
630         * using Hensel lifting if possible.
631         * @param P squarefree and primitive! (respectively monic) multivariate
632         *            GenPolynomial over the integers.
633         * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i.
634         */
635        @Override
636        public List<GenPolynomial<BigInteger>> factorsSquarefree(GenPolynomial<BigInteger> P) {
637            ExpVector degv = P.degreeVector();
638            int[] donv = degv.dependencyOnVariables();
639            List<GenPolynomial<BigInteger>> facs = null;
640            if (degv.length() == donv.length) { // all variables appear, hack for Hensel, TODO check
641                try {
642                    logger.info("try factorsSquarefreeHensel: " + P);
643                    facs = factorsSquarefreeHensel(P);
644                } catch (Exception e) {
645                    logger.warn("exception " + e);
646                    //e.printStackTrace();
647                }
648            } else { // not all variables appear, remove unused variables, hack for Hensel, TODO check
649                GenPolynomial<BigInteger> pu = PolyUtil.<BigInteger> removeUnusedUpperVariables(P);
650                GenPolynomial<BigInteger> pl = PolyUtil.<BigInteger> removeUnusedLowerVariables(pu);
651                try {
652                    logger.info("try factorsSquarefreeHensel: " + pl);
653                    facs = factorsSquarefreeHensel(pu);
654                    List<GenPolynomial<BigInteger>> fs = new ArrayList<GenPolynomial<BigInteger>>(facs.size());
655                    GenPolynomialRing<BigInteger> pf = P.ring;
656                    GenPolynomialRing<BigInteger> pfu = pu.ring;
657                    for (GenPolynomial<BigInteger> p : facs) {
658                        GenPolynomial<BigInteger> pel = p.extendLower(pfu, 0, 0L);
659                        GenPolynomial<BigInteger> pe = pel.extend(pf, 0, 0L);
660                        fs.add(pe);
661                    }
662                    //System.out.println("fs = " + fs);
663                    facs = fs;
664                } catch (Exception e) {
665                    logger.warn("exception " + e);
666                    //e.printStackTrace();
667                }
668            }
669            if (facs == null) {
670                logger.info("factorsSquarefreeHensel not applicable or failed, reverting to Kronecker for: " + P);
671                facs = super.factorsSquarefree(P);
672            }
673            return facs;
674        }
675    
676    
677        /**
678         * GenPolynomial factorization of a multivariate squarefree polynomial,
679         * using Hensel lifting.
680         * @param P squarefree and primitive! (respectively monic) multivariate
681         *            GenPolynomial over the integers.
682         * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i.
683         */
684        public List<GenPolynomial<BigInteger>> factorsSquarefreeHensel(GenPolynomial<BigInteger> P) {
685            if (P == null) {
686                throw new IllegalArgumentException(this.getClass().getName() + " P != null");
687            }
688            GenPolynomialRing<BigInteger> pfac = P.ring;
689            if (pfac.nvar == 1) {
690                return baseFactorsSquarefree(P);
691            }
692            List<GenPolynomial<BigInteger>> factors = new ArrayList<GenPolynomial<BigInteger>>();
693            if (P.isZERO()) {
694                return factors;
695            }
696            if (P.degreeVector().totalDeg() <= 1L) {
697                factors.add(P);
698                return factors;
699            }
700            GenPolynomial<BigInteger> pd = P;
701            //System.out.println("pd   = " + pd);
702            // ldcf(pd)
703            BigInteger ac = pd.leadingBaseCoefficient();
704    
705            // factor leading coefficient as polynomial in the lowest! variable
706            GenPolynomialRing<GenPolynomial<BigInteger>> rnfac = pfac.recursive(pfac.nvar - 1);
707            GenPolynomial<GenPolynomial<BigInteger>> pr = PolyUtil.<BigInteger> recursive(rnfac, pd);
708            GenPolynomial<GenPolynomial<BigInteger>> prr = PolyUtil.<BigInteger> switchVariables(pr);
709    
710            GenPolynomial<BigInteger> prrc = engine.recursiveContent(prr); // can have content wrt this variable
711            List<GenPolynomial<BigInteger>> cfactors = null;
712            if (!prrc.isONE()) {
713                prr = PolyUtil.<BigInteger> recursiveDivide(prr, prrc);
714                GenPolynomial<BigInteger> prrcu = prrc.extendLower(pfac, 0, 0L); // since switched vars
715                pd = PolyUtil.<BigInteger> basePseudoDivide(pd, prrcu);
716                logger.info("recursive content = " + prrc + ", new P = " + pd);
717                cfactors = factorsSquarefree(prrc);
718                List<GenPolynomial<BigInteger>> cff = new ArrayList<GenPolynomial<BigInteger>>(cfactors.size());
719                for (GenPolynomial<BigInteger> fs : cfactors) {
720                    GenPolynomial<BigInteger> fsp = fs.extendLower(pfac, 0, 0L); // since switched vars
721                    cff.add(fsp);
722                }
723                cfactors = cff;
724                logger.info("cfactors = " + cfactors);
725            }
726            GenPolynomial<BigInteger> lprr = prr.leadingBaseCoefficient();
727            //System.out.println("prr  = " + prr);
728            logger.info("leading coeffcient = " + lprr);
729            boolean isMonic = false; // multivariate monic
730            if (lprr.isConstant()) { // isONE ?
731                isMonic = true;
732            }
733            SortedMap<GenPolynomial<BigInteger>, Long> lfactors = factors(lprr);
734            //System.out.println("lfactors = " + lfactors);
735            List<GenPolynomial<BigInteger>> lfacs = new ArrayList<GenPolynomial<BigInteger>>(lfactors.keySet());
736            logger.info("leading coefficient factors = " + lfacs);
737    
738            // search evaluation point and evaluate
739            GenPolynomialRing<BigInteger> cpfac = pfac;
740            GenPolynomial<BigInteger> pe = pd;
741            GenPolynomial<BigInteger> pep;
742            GenPolynomialRing<BigInteger> ccpfac = lprr.ring;
743            List<GenPolynomial<BigInteger>> ce = lfacs;
744            List<GenPolynomial<BigInteger>> cep = null;
745            List<BigInteger> cei = null;
746            List<BigInteger> dei = new ArrayList<BigInteger>();
747            BigInteger pec = null;
748            BigInteger pecw = null;
749            BigInteger ped = null;
750    
751            List<GenPolynomial<BigInteger>> ufactors = null;
752            List<TrialParts> tParts = new ArrayList<TrialParts>();
753            List<GenPolynomial<BigInteger>> lf = null;
754            GenPolynomial<BigInteger> lpx = null;
755            List<GenPolynomial<BigInteger>> ln = null;
756            List<GenPolynomial<BigInteger>> un = null;
757            GenPolynomial<BigInteger> pes = null;
758    
759            List<BigInteger> V = null;
760            long evStart = 0L; //3L * 5L;
761            List<Long> Evs = new ArrayList<Long>(pfac.nvar + 1); // Evs(0), Evs(1) unused
762            for (int j = 0; j <= pfac.nvar; j++) {
763                Evs.add(evStart);
764            }
765            final int trials = 4;
766            int countSeparate = 0;
767            final int COUNT_MAX = 50;
768            double ran = 1.001; // higher values not good
769            boolean isPrimitive = true;
770            boolean notLucky = true;
771            while (notLucky) { // for Wang's test
772                if (Math.abs(evStart) > 400L) {
773                    System.out.println("P = " + P + ", lprr = " + lprr + ", lfacs = " + lfacs);
774                    throw new RuntimeException("no lucky evaluation point found after " + evStart + " iterations");
775                }
776                if (Math.abs(evStart) % 100L <= 3L) {
777                    ran = ran * (Math.PI - 2.14);
778                }
779                //System.out.println("-------------------------------------------- Evs = " + Evs);
780                notLucky = false;
781                V = new ArrayList<BigInteger>();
782                cpfac = pfac;
783                pe = pd;
784                ccpfac = lprr.ring;
785                ce = lfacs;
786                cep = null;
787                cei = null;
788                pec = null;
789                ped = null;
790                long vi = 0L;
791                for (int j = pfac.nvar; j > 1; j--) {
792                    // evaluation up to univariate case
793                    long degp = pe.degree(cpfac.nvar - 2);
794                    cpfac = cpfac.contract(1);
795                    ccpfac = ccpfac.contract(1);
796                    //vi = evStart; // + j;//0L; //(long)(pfac.nvar-j); // 1L; 0 not so good for small p
797                    vi = Evs.get(j); //evStart + j;//0L; //(long)(pfac.nvar-j); // 1L; 0 not so good for small p
798                    BigInteger Vi;
799    
800                    // search evaluation point
801                    boolean doIt = true;
802                    Vi = null;
803                    pep = null;
804                    while (doIt) {
805                        logger.info("vi(" + j + ") = " + vi);
806                        Vi = new BigInteger(vi);
807                        pep = PolyUtil.<BigInteger> evaluateMain(cpfac, pe, Vi);
808                        //System.out.println("pep = " + pep);
809                        // check lucky evaluation point 
810                        if (degp == pep.degree(cpfac.nvar - 1)) {
811                            logger.info("pep = " + pep);
812                            //System.out.println("deg(pe) = " + degp + ", deg(pep) = " + pep.degree(cpfac.nvar-1));
813                            // check squarefree
814                            if (sengine.isSquarefree(pep)) { // cpfac.nvar == 1 && ?? no, must test on each variable
815                                //if ( isNearlySquarefree(pep) ) {
816                                //System.out.println("squarefeee(pep)"); // + pep);
817                                doIt = false; //break;
818                            }
819                        }
820                        if (vi > 0L) {
821                            vi = -vi;
822                        } else {
823                            vi = 1L - vi;
824                        }
825                    }
826                    //if ( !isMonic ) {
827                    if (ccpfac.nvar >= 1) {
828                        cep = PolyUtil.<BigInteger> evaluateMain(ccpfac, ce, Vi);
829                    } else {
830                        cei = PolyUtil.<BigInteger> evaluateMain(ccpfac.coFac, ce, Vi);
831                    }
832                    //}
833                    int jj = (int) Math.round(ran + 0.52 * Math.random()); // j, random increment
834                    //jj = 1; // ...4 test   
835                    //System.out.println("minimal jj = " + jj + ", vi " + vi);
836                    if (vi > 0L) {
837                        Evs.set(j, vi + jj); // record last tested value plus increment
838                        evStart = vi + jj;
839                    } else {
840                        Evs.set(j, vi - jj); // record last tested value minus increment
841                        evStart = vi - jj;
842                    }
843                    //evStart = vi+1L;
844                    V.add(Vi);
845                    pe = pep;
846                    ce = cep;
847                }
848                //System.out.println("ce = " + ce + ", pe = " + pe);
849                pecw = engine.baseContent(pe); // original Wang
850                isPrimitive = pecw.isONE();
851                ped = ccpfac.coFac.getONE();
852                pec = pe.ring.coFac.getONE();
853                //System.out.println("cei = " + cei + ", pecw = " + pecw);
854                if (!isMonic) {
855                    if (countSeparate > COUNT_MAX) {
856                        pec = pe.ring.coFac.getONE(); // hack is sometimes better
857                    } else {
858                        pec = pecw;
859                    }
860                    //pec = pecw;
861                    //System.out.println("cei = " + cei + ", pec = " + pec + ", pe = " + pe);
862                    if (lfacs.get(0).isConstant()) {
863                        ped = cei.remove(0);
864                        //lfacs.remove(0); // later
865                    }
866                    //System.out.println("lfacs = " + lfacs + ", cei = " + cei + ", ped = " + ped + ", pecw = " + pecw);
867                    // test Wang's condition
868                    dei = new ArrayList<BigInteger>();
869                    dei.add(pec.multiply(ped).abs()); // .abs()
870                    int i = 1;
871                    for (BigInteger ci : cei) {
872                        if (ci.isZERO()) {
873                            logger.info("condition (0) not met for cei = " + cei); // + ", dei = " + dei);
874                            notLucky = true;
875                            break;
876                        }
877                        BigInteger q = ci.abs();
878                        //System.out.println("q = " + q);
879                        for (int ii = i - 1; ii >= 0; ii--) {
880                            BigInteger r = dei.get(ii);
881                            //System.out.println("r = " + r);
882                            while (!r.isONE()) {
883                                r = r.gcd(q);
884                                q = q.divide(r);
885                                //System.out.println("r = " + r + ", q = " + q);
886                            }
887                        }
888                        dei.add(q);
889                        if (q.isONE()) {
890                            logger.info("condition (1) not met for dei = " + dei + ", cei = " + cei);
891                            if (!testSeparate(cei, pecw)) {
892                                countSeparate++;
893                                if (countSeparate > COUNT_MAX) {
894                                    logger.info("too many inseparable evaluation points: " + countSeparate
895                                                    + ", removing " + pecw);
896                                }
897                            }
898                            notLucky = true;
899                            break;
900                        }
901                        i++;
902                    }
903                    //System.out.println("dei = " + dei);
904                }
905                if (notLucky) {
906                    continue;
907                }
908                logger.info("evaluation points  = " + V + ", dei = " + dei);
909                //System.out.println("Evs = " + Evs);
910                logger.info("univariate polynomial = " + pe + ", pecw = " + pecw);
911                //pe = pe.abs();
912                //ufactors = baseFactorsRadical(pe); //baseFactorsSquarefree(pe); wrong since not primitive
913                ufactors = baseFactorsSquarefree(pe.divide(pecw)); //wrong if not primitive
914                if (!pecw.isONE()) {
915                    ufactors.add(0, cpfac.getONE().multiply(pecw));
916                }
917                if (ufactors.size() <= 1) {
918                    logger.info("irreducible univariate polynomial");
919                    factors.add(pd); // P
920                    if (cfactors != null) {
921                        cfactors.addAll(factors);
922                        factors = cfactors;
923                    }
924                    return factors;
925                }
926                logger.info("univariate factors = " + ufactors); // + ", of " + pe);
927                //System.out.println("lfacs    = " + lfacs);
928                //System.out.println("cei      = " + cei);
929                //System.out.println("pecw     = " + pecw);
930    
931                // determine leading coefficient polynomials for factors
932                lf = new ArrayList<GenPolynomial<BigInteger>>();
933                lpx = lprr.ring.getONE();
934                for (GenPolynomial<BigInteger> pp : ufactors) {
935                    lf.add(lprr.ring.getONE());
936                }
937                //System.out.println("lf = " + lf);             
938                if (!isMonic || !pecw.isONE()) {
939                    if (lfacs.size() > 0 && lfacs.get(0).isConstant()) {
940                        GenPolynomial<BigInteger> xx = lfacs.remove(0);
941                        //BigInteger xxi = xx.leadingBaseCoefficient();
942                        //System.out.println("xx = " + xx + " == ped = " +ped);
943                    }
944                    for (int i = ufactors.size() - 1; i >= 0; i--) {
945                        GenPolynomial<BigInteger> pp = ufactors.get(i);
946                        BigInteger ppl = pp.leadingBaseCoefficient();
947                        //System.out.println("ppl = " + ppl + ", pp = " + pp);
948                        ppl = ppl.multiply(pec); // content
949                        GenPolynomial<BigInteger> lfp = lf.get(i);
950                        int ii = 0;
951                        for (BigInteger ci : cei) {
952                            //System.out.println("ci = " + ci + ", lfp = " + lfp + ", lfacs.get(ii) = " + lfacs.get(ii));
953                            if (ci.abs().isONE()) {
954                                System.out.println("ppl = " + ppl + ", ci = " + ci + ", lfp = " + lfp
955                                                + ", lfacs.get(ii) = " + lfacs.get(ii));
956                                throw new RuntimeException("something is wrong, ci is a unit");
957                                //notLucky = true;
958                            }
959                            while (ppl.remainder(ci).isZERO() && lfacs.size() > ii) {
960                                ppl = ppl.divide(ci);
961                                lfp = lfp.multiply(lfacs.get(ii));
962                            }
963                            ii++;
964                        }
965                        //System.out.println("ppl = " + ppl + ", lfp = " + lfp);
966                        lfp = lfp.multiply(ppl);
967                        lf.set(i, lfp);
968                    }
969                    // adjust if pec != 1
970                    pec = pecw;
971                    lpx = Power.<GenPolynomial<BigInteger>> multiply(lprr.ring, lf); // test only, not used
972                    //System.out.println("lpx = " + lpx);
973                    if (!lprr.degreeVector().equals(lpx.degreeVector())) {
974                        logger.info("deg(lprr) != deg(lpx): lprr = " + lprr + ", lpx = " + lpx);
975                        notLucky = true;
976                        continue;
977                    }
978                    if (!pec.isONE()) { // content, was always false by hack
979                        // evaluate factors of ldcf
980                        List<GenPolynomial<BigInteger>> lfe = lf;
981                        List<BigInteger> lfei = null;
982                        ccpfac = lprr.ring;
983                        for (int j = lprr.ring.nvar; j > 0; j--) {
984                            ccpfac = ccpfac.contract(1);
985                            BigInteger Vi = V.get(lprr.ring.nvar - j);
986                            if (ccpfac.nvar >= 1) {
987                                lfe = PolyUtil.<BigInteger> evaluateMain(ccpfac, lfe, Vi);
988                            } else {
989                                lfei = PolyUtil.<BigInteger> evaluateMain(ccpfac.coFac, lfe, Vi);
990                            }
991                        }
992                        //System.out.println("lfe = " + lfe + ", lfei = " + lfei + ", V = " + V);
993    
994                        ln = new ArrayList<GenPolynomial<BigInteger>>(lf.size());
995                        un = new ArrayList<GenPolynomial<BigInteger>>(lf.size());
996                        for (int jj = 0; jj < lf.size(); jj++) {
997                            GenPolynomial<BigInteger> up = ufactors.get(jj);
998                            BigInteger ui = up.leadingBaseCoefficient();
999                            BigInteger li = lfei.get(jj);
1000                            BigInteger di = ui.gcd(li).abs();
1001                            BigInteger udi = ui.divide(di);
1002                            BigInteger ldi = li.divide(di);
1003                            GenPolynomial<BigInteger> lp = lf.get(jj);
1004                            GenPolynomial<BigInteger> lpd = lp.multiply(udi);
1005                            GenPolynomial<BigInteger> upd = up.multiply(ldi);
1006                            if (pec.isONE()) {
1007                                ln.add(lp);
1008                                un.add(up);
1009                            } else {
1010                                ln.add(lpd);
1011                                un.add(upd);
1012                                BigInteger pec1 = pec.divide(ldi);
1013                                //System.out.println("pec = " + pec + ", pec1 = " + pec1);
1014                                pec = pec1;
1015                            }
1016                        }
1017                        if (!lf.equals(ln) || !un.equals(ufactors)) {
1018                            //System.out.println("pe  = " + pe);
1019                            //System.out.println("#ln  = " + ln + ", #lf = " + lf);
1020                            //System.out.println("#un  = " + un + ", #ufactors = " + ufactors);
1021                            //lf = ln;
1022                            //ufactors = un;
1023                            // adjust pe
1024                        }
1025                        if (!pec.isONE()) { // still not 1
1026                            ln = new ArrayList<GenPolynomial<BigInteger>>(lf.size());
1027                            un = new ArrayList<GenPolynomial<BigInteger>>(lf.size());
1028                            pes = pe;
1029                            for (int jj = 0; jj < lf.size(); jj++) {
1030                                GenPolynomial<BigInteger> up = ufactors.get(jj);
1031                                GenPolynomial<BigInteger> lp = lf.get(jj);
1032                                //System.out.println("up  = " + up + ", lp  = " + lp);
1033                                if (!up.isConstant()) {
1034                                    up = up.multiply(pec);
1035                                }
1036                                lp = lp.multiply(pec);
1037                                if (jj != 0) {
1038                                    pes = pes.multiply(pec);
1039                                }
1040                                un.add(up);
1041                                ln.add(lp);
1042                            }
1043                            if (pes.equals(Power.<GenPolynomial<BigInteger>> multiply(pe.ring, un))) {
1044                                //System.out.println("*pe  = " + pes + ", pec = " + pec);
1045                                //ystem.out.println("*ln  = " + ln + ", *lf = " + lf);
1046                                //System.out.println("*un  = " + un + ", *ufactors = " + ufactors);
1047                                //System.out.println("*pe == prod(un) ");
1048                                isPrimitive = false;
1049                                //pe = pes;
1050                                //lf = ln;
1051                                //ufactors = un;
1052                            } else {
1053                                //System.out.println("*pe != prod(un): " + Power.<GenPolynomial<BigInteger>> multiply(pe.ring,un));
1054                            }
1055                        }
1056                    }
1057                    if (notLucky) {
1058                        continue;
1059                    }
1060                    logger.info("distributed factors of leading coefficient = " + lf);
1061                    lpx = Power.<GenPolynomial<BigInteger>> multiply(lprr.ring, lf);
1062                    if (!lprr.abs().equals(lpx.abs())) { // not correctly distributed
1063                        if (!lprr.degreeVector().equals(lpx.degreeVector())) {
1064                            logger.info("lprr != lpx: lprr = " + lprr + ", lpx = " + lpx);
1065                            notLucky = true;
1066                        }
1067                    }
1068                } // end determine leading coefficients for factors
1069    
1070                if (!notLucky) {
1071                    TrialParts tp = null;
1072                    if (isPrimitive) {
1073                        tp = new TrialParts(V, pe, ufactors, cei, lf);
1074                    } else {
1075                        tp = new TrialParts(V, pes, un, cei, ln);
1076                    }
1077                    //System.out.println("trialParts = " + tp);
1078                    tParts.add(tp);
1079                    if (tParts.size() < trials) {
1080                        notLucky = true;
1081                    }
1082                }
1083            } // end notLucky loop
1084    
1085            // search TrialParts with shortest factorization of univariate polynomial
1086            int min = Integer.MAX_VALUE;
1087            TrialParts tpmin = null;
1088            for (TrialParts tp : tParts) {
1089                logger.info("tp.univFactors.size() = " + tp.univFactors.size());
1090                if (tp.univFactors.size() < min) {
1091                    min = tp.univFactors.size();
1092                    tpmin = tp;
1093                }
1094            }
1095            for (TrialParts tp : tParts) {
1096                //logger.info("tp.univFactors.get(0) = " + tp.univFactors.get(0));
1097                if (tp.univFactors.size() == min) {
1098                    if (!tp.univFactors.get(0).isConstant()) {
1099                        tpmin = tp;
1100                        break;
1101                    }
1102                }
1103            }
1104            // set to (first) shortest 
1105            V = tpmin.evalPoints;
1106            pe = tpmin.univPoly;
1107            ufactors = tpmin.univFactors;
1108            cei = tpmin.ldcfEval; // unused
1109            lf = tpmin.ldcfFactors;
1110            logger.info("minimal trial = " + tpmin);
1111    
1112            GenPolynomialRing<BigInteger> ufac = pe.ring;
1113    
1114            //initialize prime list
1115            PrimeList primes = new PrimeList(PrimeList.Range.medium); // PrimeList.Range.medium);
1116            Iterator<java.math.BigInteger> primeIter = primes.iterator();
1117            int pn = 50; //primes.size();
1118            BigInteger ae = pe.leadingBaseCoefficient();
1119            GenPolynomial<MOD> Pm = null;
1120            ModularRingFactory<MOD> cofac = null;
1121            GenPolynomialRing<MOD> mufac = null;
1122    
1123            // search lucky prime
1124            for (int i = 0; i < 11; i++) { // prime meta loop
1125                //for ( int i = 0; i < 1; i++ ) { // meta loop
1126                java.math.BigInteger p = null; //new java.math.BigInteger("19"); //primes.next();
1127                // 2 small, 5 medium and 4 large size primes
1128                if (i == 0) { // medium size
1129                    primes = new PrimeList(PrimeList.Range.medium);
1130                    primeIter = primes.iterator();
1131                }
1132                if (i == 5) { // small size
1133                    primes = new PrimeList(PrimeList.Range.small);
1134                    primeIter = primes.iterator();
1135                    p = primeIter.next(); // 2
1136                    p = primeIter.next(); // 3
1137                    p = primeIter.next(); // 5
1138                    p = primeIter.next(); // 7
1139                }
1140                if (i == 7) { // large size
1141                    primes = new PrimeList(PrimeList.Range.large);
1142                    primeIter = primes.iterator();
1143                }
1144                int pi = 0;
1145                while (pi < pn && primeIter.hasNext()) {
1146                    p = primeIter.next();
1147                    logger.info("prime = " + p);
1148                    // initialize coefficient factory and map normalization factor and polynomials
1149                    ModularRingFactory<MOD> cf = null;
1150                    if (ModLongRing.MAX_LONG.compareTo(p) > 0) {
1151                        cf = (ModularRingFactory) new ModLongRing(p, true);
1152                    } else {
1153                        cf = (ModularRingFactory) new ModIntegerRing(p, true);
1154                    }
1155                    MOD nf = cf.fromInteger(ae.getVal());
1156                    if (nf.isZERO()) {
1157                        continue;
1158                    }
1159                    mufac = new GenPolynomialRing<MOD>(cf, ufac);
1160                    //System.out.println("mufac = " + mufac.toScript());
1161                    Pm = PolyUtil.<MOD> fromIntegerCoefficients(mufac, pe);
1162                    //System.out.println("Pm = " + Pm);
1163                    if (!mfactor.isSquarefree(Pm)) {
1164                        continue;
1165                    }
1166                    cofac = cf;
1167                    break;
1168                }
1169                if (cofac != null) {
1170                    break;
1171                }
1172            } // end prime meta loop
1173            if (cofac == null) { // no lucky prime found
1174                throw new RuntimeException("giving up on Hensel preparation, no lucky prime found");
1175            }
1176            logger.info("lucky prime = " + cofac.getIntegerModul());
1177            if (logger.isDebugEnabled()) {
1178                logger.debug("univariate modulo p: = " + Pm);
1179            }
1180    
1181            // coefficient bound
1182            BigInteger an = pd.maxNorm();
1183            BigInteger mn = an.multiply(ac.abs()).multiply(new BigInteger(2L));
1184            long k = Power.logarithm(cofac.getIntegerModul(), mn) + 1L;
1185            //System.out.println("mn = " + mn + ", k = " +k);
1186    
1187            BigInteger q = Power.positivePower(cofac.getIntegerModul(), k);
1188            ModularRingFactory<MOD> muqfac;
1189            if (ModLongRing.MAX_LONG.compareTo(q.getVal()) > 0) {
1190                muqfac = (ModularRingFactory) new ModLongRing(q.getVal());
1191            } else {
1192                muqfac = (ModularRingFactory) new ModIntegerRing(q.getVal());
1193            }
1194            //System.out.println("muqfac = " + muqfac);
1195            GenPolynomialRing<MOD> mucpfac = new GenPolynomialRing<MOD>(muqfac, ufac);
1196    
1197            List<GenPolynomial<MOD>> muqfactors = PolyUtil.<MOD> fromIntegerCoefficients(mucpfac, ufactors);
1198            GenPolynomial<MOD> peqq = PolyUtil.<MOD> fromIntegerCoefficients(mucpfac, pe);
1199            if (debug) {
1200                if (!mfactor.isFactorization(peqq, muqfactors)) { // should not happen
1201                    System.out.println("muqfactors = " + muqfactors);
1202                    System.out.println("peqq       = " + peqq);
1203                    throw new RuntimeException("something is wrong, no modular p^k factorization");
1204                }
1205            }
1206            logger.info("univariate modulo p^k: " + peqq + " = " + muqfactors);
1207    
1208            // convert C from Z[...] to Z_q[...]
1209            GenPolynomialRing<MOD> qcfac = new GenPolynomialRing<MOD>(muqfac, pd.ring);
1210            GenPolynomial<MOD> pq = PolyUtil.<MOD> fromIntegerCoefficients(qcfac, pd);
1211            //System.out.println("pd = " + pd);
1212            logger.info("multivariate modulo p^k: " + pq);
1213    
1214            List<MOD> Vm = new ArrayList<MOD>(V.size());
1215            for (BigInteger v : V) {
1216                MOD vm = muqfac.fromInteger(v.getVal());
1217                Vm.add(vm);
1218            }
1219            //System.out.println("Vm = " + Vm);
1220    
1221            // Hensel lifting of factors
1222            List<GenPolynomial<MOD>> mlift;
1223            try {
1224                mlift = HenselMultUtil.<MOD> liftHensel(pd, pq, muqfactors, Vm, k, lf);
1225                logger.info("mlift = " + mlift);
1226            } catch (NoLiftingException nle) {
1227                //System.out.println("exception : " + nle);
1228                //nle.printStackTrace();
1229                mlift = new ArrayList<GenPolynomial<MOD>>();
1230                throw new RuntimeException(nle);
1231            } catch (ArithmeticException aex) {
1232                //System.out.println("exception : " + aex);
1233                //aex.printStackTrace();
1234                mlift = new ArrayList<GenPolynomial<MOD>>();
1235                throw aex;
1236            }
1237            if (mlift.size() <= 1) { // irreducible mod I, p^k, can this happen?
1238                logger.info("modular lift size == 1: " + mlift);
1239                factors.add(pd); // P
1240                if (cfactors != null) {
1241                    cfactors.addAll(factors);
1242                    factors = cfactors;
1243                }
1244                return factors;
1245            }
1246    
1247            // combine trial factors
1248            GenPolynomialRing<MOD> mfac = mlift.get(0).ring;
1249            int dl = (mlift.size() + 1) / 2;
1250            GenPolynomial<BigInteger> u = P;
1251            long deg = (u.degree() + 1L) / 2L;
1252    
1253            GenPolynomial<BigInteger> ui = pd;
1254            for (int j = 1; j <= dl; j++) {
1255                //System.out.println("j = " + j + ", dl = " + dl + ", mlift = " + mlift); 
1256                KsubSet<GenPolynomial<MOD>> subs = new KsubSet<GenPolynomial<MOD>>(mlift, j);
1257                for (List<GenPolynomial<MOD>> flist : subs) {
1258                    //System.out.println("degreeSum = " + degreeSum(flist));
1259                    GenPolynomial<MOD> mtrial = Power.<GenPolynomial<MOD>> multiply(mfac, flist);
1260                    if (mtrial.degree() > deg) { // this test is sometimes wrong
1261                        logger.info("degree > deg " + deg + ", degree = " + mtrial.degree());
1262                        //continue;
1263                    }
1264                    GenPolynomial<BigInteger> trial = PolyUtil.integerFromModularCoefficients(pfac, mtrial);
1265                    trial = engine.basePrimitivePart(trial);
1266                    //if ( ! isPrimitive ) {
1267                    //}
1268                    if (debug) {
1269                        logger.info("trial    = " + trial); // + ", mtrial = " + mtrial);
1270                    }
1271                    if (PolyUtil.<BigInteger> basePseudoRemainder(ui, trial).isZERO()) {
1272                        logger.info("successful trial = " + trial);
1273                        factors.add(trial);
1274                        ui = PolyUtil.<BigInteger> basePseudoDivide(ui, trial);
1275                        //System.out.println("ui        = " + ui);
1276                        mlift = removeOnce(mlift, flist);
1277                        logger.info("new mlift= " + mlift);
1278                        //System.out.println("dl = " + dl); 
1279                        if (mlift.size() > 1) {
1280                            dl = (mlift.size() + 1) / 2;
1281                            j = 0; // since j++
1282                            break;
1283                        }
1284                        logger.info("last factor = " + ui);
1285                        factors.add(ui);
1286                        if (cfactors != null) {
1287                            cfactors.addAll(factors);
1288                            factors = cfactors;
1289                        }
1290                        return factors;
1291                    }
1292                }
1293            }
1294            if (!ui.isONE() && !ui.equals(pd)) {
1295                logger.info("rest factor = " + ui);
1296                // pp(ui) ?? no ??
1297                factors.add(ui);
1298            }
1299            if (factors.size() == 0) {
1300                logger.info("irreducible P = " + P);
1301                factors.add(pd); // P
1302            }
1303            if (cfactors != null) {
1304                cfactors.addAll(factors);
1305                factors = cfactors;
1306            }
1307            return factors;
1308        }
1309    
1310    
1311        /**
1312         * Test if b has a prime factor different to the elements of A.
1313         * @param A list of integer with at least one different prime factor.
1314         * @param b integer to test with A.
1315         * @return true, if b hase a prime factor different to elements of A
1316         */
1317        boolean testSeparate(List<BigInteger> A, BigInteger b) {
1318            int i = 0;
1319            List<BigInteger> gei = new ArrayList<BigInteger>(A.size());
1320            for (BigInteger c : A) {
1321                BigInteger g = c.gcd(b).abs();
1322                gei.add(g);
1323                if (!g.isONE()) {
1324                    i++;
1325                }
1326            }
1327            //if ( i >= 1 ) {
1328            //System.out.println("gei = " + gei + ", cei = " + cei + ", pec(w) = " + pec);
1329            //}
1330            return (i <= 1);
1331        }
1332    
1333    
1334        // not useable
1335        boolean isNearlySquarefree(GenPolynomial<BigInteger> P) { // unused
1336            // in main variable
1337            GenPolynomialRing<BigInteger> pfac = P.ring;
1338            if (true || pfac.nvar <= 4) {
1339                return sengine.isSquarefree(P);
1340            }
1341            GenPolynomialRing<GenPolynomial<BigInteger>> rfac = pfac.recursive(1);
1342            GenPolynomial<GenPolynomial<BigInteger>> Pr = PolyUtil.<BigInteger> recursive(rfac, P);
1343            GenPolynomial<GenPolynomial<BigInteger>> Ps = PolyUtil.<BigInteger> recursiveDeriviative(Pr);
1344            System.out.println("Pr = " + Pr);
1345            System.out.println("Ps = " + Ps);
1346            GenPolynomial<GenPolynomial<BigInteger>> g = engine.recursiveUnivariateGcd(Pr, Ps);
1347            System.out.println("g_m = " + g);
1348            if (!g.isONE()) {
1349                return false;
1350            }
1351            // in lowest variable
1352            rfac = pfac.recursive(pfac.nvar - 1);
1353            Pr = PolyUtil.<BigInteger> recursive(rfac, P);
1354            Pr = PolyUtil.<BigInteger> switchVariables(Pr);
1355            Ps = PolyUtil.<BigInteger> recursiveDeriviative(Pr);
1356            System.out.println("Pr = " + Pr);
1357            System.out.println("Ps = " + Ps);
1358            g = engine.recursiveUnivariateGcd(Pr, Ps);
1359            System.out.println("g_1 = " + g);
1360            if (!g.isONE()) {
1361                return false;
1362            }
1363            return true;
1364        }
1365    
1366    }
1367    
1368    
1369    /**
1370     * Container for factorization trial lifting parameters.
1371     */
1372    class TrialParts {
1373    
1374    
1375        /**
1376         * evaluation points
1377         */
1378        public final List<BigInteger> evalPoints;
1379    
1380    
1381        /**
1382         * univariate polynomial
1383         */
1384        public final GenPolynomial<BigInteger> univPoly;
1385    
1386    
1387        /**
1388         * irreducible factors of univariate polynomial
1389         */
1390        public final List<GenPolynomial<BigInteger>> univFactors;
1391    
1392    
1393        /**
1394         * irreducible factors of leading coefficient
1395         */
1396        public final List<GenPolynomial<BigInteger>> ldcfFactors;
1397    
1398    
1399        /**
1400         * evaluated factors of leading coefficient factors by evaluation points
1401         */
1402        public final List<BigInteger> ldcfEval;
1403    
1404    
1405        /**
1406         * Constructor.
1407         * @param ev evaluation points.
1408         * @param up univariate polynomial.
1409         * @param uf irreducible factors of up.
1410         * @param le irreducible factors of leading coefficient.
1411         * @param lf evaluated le by evaluation points.
1412         */
1413        public TrialParts(List<BigInteger> ev, GenPolynomial<BigInteger> up, List<GenPolynomial<BigInteger>> uf,
1414                        List<BigInteger> le, List<GenPolynomial<BigInteger>> lf) {
1415            evalPoints = ev;
1416            univPoly = up;
1417            univFactors = uf;
1418            //ldcfPoly = lp;
1419            ldcfFactors = lf;
1420            ldcfEval = le;
1421        }
1422    
1423    
1424        /**
1425         * @see java.lang.Object#toString()
1426         */
1427        @Override
1428        public String toString() {
1429            StringBuffer sb = new StringBuffer();
1430            sb.append("TrialParts[");
1431            sb.append("evalPoints = " + evalPoints);
1432            sb.append(", univPoly = " + univPoly);
1433            sb.append(", univFactors = " + univFactors);
1434            sb.append(", ldcfEval = " + ldcfEval);
1435            sb.append(", ldcfFactors = " + ldcfFactors);
1436            sb.append("]");
1437            return sb.toString();
1438        }
1439    
1440    }