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