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