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