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