001/*
002 * $Id: FactorInteger.java 6026 2020-12-11 09:41:51Z 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;
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        GenPolynomial<BigInteger> Pp = P;
702        GenPolynomialRing<BigInteger> pfac = Pp.ring;
703        if (pfac.nvar <= 1) {
704            return baseFactorsSquarefree(Pp);
705        }
706        boolean noINVLEX = true;
707        if (pfac.tord.equals(TermOrderByName.INVLEX)) {
708            noINVLEX = false;
709        } else {
710            pfac = new GenPolynomialRing<BigInteger>(pfac,TermOrderByName.INVLEX);
711            Pp = pfac.copy(Pp);
712            logger.warn("invlexed polynomial: " + Pp + ", from ring " + P.ring);
713        }
714        OptimizedPolynomialList<BigInteger> opt = null;
715        List<Integer> iperm = null;
716        final boolean USE_OPT = true;
717        if (USE_OPT) {
718            List<GenPolynomial<BigInteger>> topt = new ArrayList<GenPolynomial<BigInteger>>(1);
719            topt.add(Pp);
720            opt = TermOrderOptimization.<BigInteger> optimizeTermOrder(pfac, topt);
721            if (!TermOrderOptimization.isIdentityPermutation(opt.perm)) {
722                iperm = TermOrderOptimization.inversePermutation(opt.perm);
723                Pp = opt.list.get(0);
724                logger.info("optimized polynomial: " + Pp);
725                logger.warn("optimized ring: " + opt.ring + ", original ring: " + pfac);
726            }
727        }
728        ExpVector degv = Pp.degreeVector();
729        int[] donv = degv.dependencyOnVariables();
730        List<GenPolynomial<BigInteger>> facs = null;
731        if (degv.length() == donv.length) { // all variables appear, hack for Hensel, check
732            try {
733                logger.info("try factorsSquarefreeHensel: " + Pp);
734                facs = factorsSquarefreeHensel(Pp);
735            } catch (Exception e) {
736                logger.info("exception " + e);
737                //e.printStackTrace();
738            }
739        } else { // not all variables appear, remove unused variables, hack for Hensel, check
740            GenPolynomial<BigInteger> pu = PolyUtil.<BigInteger> removeUnusedUpperVariables(Pp);
741            //GenPolynomial<BigInteger> pl = PolyUtil.<BigInteger> removeUnusedLowerVariables(pu); // not useful
742            try {
743                logger.info("try factorsSquarefreeHensel: " + pu);
744                facs = factorsSquarefreeHensel(pu);
745                List<GenPolynomial<BigInteger>> fs = new ArrayList<GenPolynomial<BigInteger>>(facs.size());
746                GenPolynomialRing<BigInteger> pf = Pp.ring;
747                //GenPolynomialRing<BigInteger> pfu = pu.ring;
748                for (GenPolynomial<BigInteger> p : facs) {
749                    //GenPolynomial<BigInteger> pel = p.extendLower(pfu, 0, 0L);
750                    GenPolynomial<BigInteger> pe = p.extend(pf, 0, 0L);
751                    fs.add(pe);
752                }
753                //System.out.println("fs = " + fs);
754                facs = fs;
755            } catch (Exception e) {
756                logger.info("exception " + e);
757                //e.printStackTrace();
758            }
759        }
760        if (facs == null) {
761            logger.warn("factorsSquarefreeHensel not applicable or failed, reverting to Kronecker for: "
762                            + Pp);
763            facs = super.factorsSquarefree(Pp);
764        }
765        if (USE_OPT && iperm != null) {
766            facs = TermOrderOptimization.<BigInteger> permutation(iperm, pfac, facs);
767            logger.warn("de-optimized polynomials: " + facs);
768        }
769        if (noINVLEX) {
770            facs = P.ring.copy(facs);
771            logger.warn("de-invlexed polynomials: " + facs);
772        }
773        facs = normalizeFactorization(facs);
774        return facs;
775    }
776
777
778    /**
779     * GenPolynomial factorization of a multivariate squarefree polynomial,
780     * using Hensel lifting.
781     * @param P squarefree and primitive! (respectively monic) multivariate
782     *            GenPolynomial over the integers.
783     * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i.
784     */
785    @SuppressWarnings("unchecked")
786    public List<GenPolynomial<BigInteger>> factorsSquarefreeHensel(GenPolynomial<BigInteger> P) {
787        if (P == null) {
788            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
789        }
790        GenPolynomialRing<BigInteger> pfac = P.ring;
791        if (pfac.nvar == 1) {
792            return baseFactorsSquarefree(P);
793        }
794        List<GenPolynomial<BigInteger>> factors = new ArrayList<GenPolynomial<BigInteger>>();
795        if (P.isZERO()) {
796            return factors;
797        }
798        if (P.degreeVector().totalDeg() <= 1L) {
799            factors.add(P);
800            return factors;
801        }
802        GenPolynomial<BigInteger> pd = P;
803        //System.out.println("pd   = " + pd);
804        // ldcf(pd)
805        BigInteger ac = pd.leadingBaseCoefficient();
806
807        // factor leading coefficient as polynomial in the lowest! variable
808        GenPolynomialRing<GenPolynomial<BigInteger>> rnfac = pfac.recursive(pfac.nvar - 1);
809        GenPolynomial<GenPolynomial<BigInteger>> pr = PolyUtil.<BigInteger> recursive(rnfac, pd);
810        GenPolynomial<GenPolynomial<BigInteger>> prr = PolyUtil.<BigInteger> switchVariables(pr);
811
812        GenPolynomial<BigInteger> prrc = engine.recursiveContent(prr); // can have content wrt this variable
813        List<GenPolynomial<BigInteger>> cfactors = null;
814        if (!prrc.isONE()) {
815            prr = PolyUtil.<BigInteger> recursiveDivide(prr, prrc);
816            GenPolynomial<BigInteger> prrcu = prrc.extendLower(pfac, 0, 0L); // since switched vars
817            pd = PolyUtil.<BigInteger> basePseudoDivide(pd, prrcu);
818            logger.info("recursive content = " + prrc + ", new P = " + pd);
819            cfactors = factorsSquarefree(prrc);
820            List<GenPolynomial<BigInteger>> cff = new ArrayList<GenPolynomial<BigInteger>>(cfactors.size());
821            for (GenPolynomial<BigInteger> fs : cfactors) {
822                GenPolynomial<BigInteger> fsp = fs.extendLower(pfac, 0, 0L); // since switched vars
823                cff.add(fsp);
824            }
825            cfactors = cff;
826            logger.info("cfactors = " + cfactors);
827        }
828        GenPolynomial<BigInteger> lprr = prr.leadingBaseCoefficient();
829        //System.out.println("prr  = " + prr);
830        logger.info("leading coeffcient = " + lprr);
831        boolean isMonic = false; // multivariate monic
832        if (lprr.isConstant()) { // isONE ?
833            isMonic = true;
834        }
835        SortedMap<GenPolynomial<BigInteger>, Long> lfactors = factors(lprr);
836        //System.out.println("lfactors = " + lfactors);
837        List<GenPolynomial<BigInteger>> lfacs = new ArrayList<GenPolynomial<BigInteger>>(lfactors.keySet());
838        logger.info("leading coefficient factors = " + lfacs);
839
840        // search evaluation point and evaluate
841        GenPolynomialRing<BigInteger> cpfac = pfac;
842        GenPolynomial<BigInteger> pe = pd;
843        GenPolynomial<BigInteger> pep;
844        GenPolynomialRing<BigInteger> ccpfac = lprr.ring;
845        List<GenPolynomial<BigInteger>> ce = lfacs;
846        List<GenPolynomial<BigInteger>> cep = null;
847        List<BigInteger> cei = null;
848        List<BigInteger> dei = new ArrayList<BigInteger>();
849        BigInteger pec = null;
850        BigInteger pecw = null;
851        BigInteger ped = null;
852
853        List<GenPolynomial<BigInteger>> ufactors = null;
854        List<TrialParts> tParts = new ArrayList<TrialParts>();
855        List<GenPolynomial<BigInteger>> lf = null;
856        GenPolynomial<BigInteger> lpx = null;
857        List<GenPolynomial<BigInteger>> ln = null;
858        List<GenPolynomial<BigInteger>> un = null;
859        GenPolynomial<BigInteger> pes = null;
860
861        List<BigInteger> V = null;
862        long evStart = 0L; //3L * 5L;
863        List<Long> Evs = new ArrayList<Long>(pfac.nvar + 1); // Evs(0), Evs(1) unused
864        for (int j = 0; j <= pfac.nvar; j++) {
865            Evs.add(evStart++); // bug
866        }
867        //no: Collections.reverse(Evs);
868        evStart = Evs.get(0);
869        final int trials = 4;
870        int countSeparate = 0;
871        final int COUNT_MAX = 50;
872        double ran = 1.001; // higher values not good
873        boolean isPrimitive = true;
874        boolean notLucky = true;
875        while (notLucky) { // for Wang's test
876            if (Math.abs(evStart) > 371L) {
877                logger.warn("found         points   : V = " + V + ", dei = " + dei);
878                //if (tParts != null && tParts.size() > 0) { // at least one successful eval point 
879                //    logger.warn("some evaluation points found after " + Math.abs(evStart) + " iterations, tParts = " + tParts);
880                //    break;
881                //}
882                logger.warn("no evaluation point for: P = " + P + ", prr = " + prr + ", lprr = " + lprr + ", lfacs = " + lfacs);
883                throw new RuntimeException(
884                                "no evaluation point found after " + Math.abs(evStart) + " iterations");
885            }
886            if (Math.abs(evStart) % 100L <= 3L) {
887                ran = ran * (Math.PI - 2.14);
888            }
889            //System.out.println("-------------------------------------------- Evs = " + Evs);
890            notLucky = false;
891            V = new ArrayList<BigInteger>();
892            cpfac = pfac;
893            pe = pd;
894            ccpfac = lprr.ring;
895            ce = lfacs;
896            cep = null;
897            cei = null;
898            pec = null;
899            ped = null;
900            long vi = 0L;
901            for (int j = pfac.nvar; j > 1; j--) {
902                // evaluation up to univariate case
903                long degp = pe.degree(cpfac.nvar - 2);
904                cpfac = cpfac.contract(1);
905                ccpfac = ccpfac.contract(1);
906                //vi = evStart; // + j;//0L; //(long)(pfac.nvar-j); // 1L; 0 not so good for small p
907                vi = Evs.get(j); //evStart + j;//0L; //(long)(pfac.nvar-j); // 1L; 0 not so good for small p
908                BigInteger Vi;
909
910                // search evaluation point
911                boolean doIt = true;
912                Vi = null;
913                pep = null;
914                while (doIt) {
915                    logger.info("vi(" + j + ") = " + vi);
916                    Vi = new BigInteger(vi);
917                    pep = PolyUtil.<BigInteger> evaluateMain(cpfac, pe, Vi);
918                    //System.out.println("pep = " + pep);
919                    // check lucky evaluation point 
920                    if (degp == pep.degree(cpfac.nvar - 1)) {
921                        logger.info("pep = " + pep);
922                        //System.out.println("deg(pe) = " + degp + ", deg(pep) = " + pep.degree(cpfac.nvar-1));
923                        // check squarefree
924                        if (sengine.isSquarefree(pep)) { // cpfac.nvar == 1 && ?? no, must test on each variable
925                            //if ( isNearlySquarefree(pep) ) {
926                            //System.out.println("squarefeee(pep)"); // + pep);
927                            doIt = false; //break;
928                        } else {
929                            logger.info("pep not squarefree ");
930                        }
931                    }
932                    if (vi > 0L) {
933                        vi = -vi;
934                    } else {
935                        vi = 1L - vi;
936                    }
937                }
938                //if ( !isMonic ) {
939                if (ccpfac.nvar >= 1) {
940                    cep = PolyUtil.<BigInteger> evaluateMain(ccpfac, ce, Vi);
941                } else {
942                    cei = PolyUtil.<BigInteger> evaluateMain(ccpfac.coFac, ce, Vi);
943                }
944                //}
945                int jj = (int) Math.round(ran + 0.52 * Math.random()); // j, random increment
946                //jj = 0; // ...4 test   
947                //System.out.print("minimal jj = " + jj + ", vi_a " + vi);
948                if (vi > 0L) {
949                    Evs.set(j, vi + jj); // record last tested value plus increment
950                    evStart = vi + jj;
951                } else {
952                    Evs.set(j, vi - jj); // record last tested value minus increment
953                    evStart = vi - jj;
954                }
955                // ensure different evaluation points
956                Set<Long> Evset = new HashSet<Long>(Evs);
957                while (Evset.size() != Evs.size()) {
958                    //logger.warn("same eval points: " + Evs + " != " + Evset);
959                    long vgi = Evs.get(j);
960                    if (vgi > 0L) {
961                        vgi += 1L;
962                    } else {
963                        vgi -= 1L;
964                    }
965                    Evs.set(j, vgi);
966                    Evset.clear(); Evset.addAll(Evs); //= new HashSet<Long>(Evs);
967                    evStart = vgi;
968                    //logger.warn("same eval points: " + Evs + ", j = " + j);
969                }
970                //System.out.println(", j = " + j + ", vi_b " + Vi);
971                //evStart = vi+1L;
972                V.add(Vi);
973                pe = pep;
974                ce = cep;
975            }
976            //System.out.println("ce = " + ce + ", pe = " + pe);
977            pecw = engine.baseContent(pe); // original Wang
978            isPrimitive = pecw.isONE();
979            ped = ccpfac.coFac.getONE();
980            pec = pe.ring.coFac.getONE();
981            //System.out.println("cei = " + cei + ", pecw = " + pecw);
982            if (!isMonic) {
983                if (countSeparate > COUNT_MAX) {
984                    pec = pe.ring.coFac.getONE(); // hack is sometimes better
985                } else {
986                    pec = pecw;
987                }
988                //pec = pecw;
989                //System.out.println("cei = " + cei + ", pec = " + pec + ", pe = " + pe);
990                if (lfacs.get(0).isConstant()) {
991                    ped = cei.remove(0);
992                    //lfacs.remove(0); // later
993                }
994                //System.out.println("lfacs = " + lfacs + ", cei = " + cei + ", ped = " + ped + ", pecw = " + pecw);
995                // test Wang's condition
996                dei = new ArrayList<BigInteger>();
997                dei.add(pec.multiply(ped).abs()); // .abs()
998                int i = 1;
999                for (BigInteger ci : cei) {
1000                    if (ci.isZERO()) {
1001                        logger.info("condition (0) not met for cei = " + cei); // + ", dei = " + dei);
1002                        notLucky = true;
1003                        break;
1004                    }
1005                    BigInteger q = ci.abs();
1006                    //System.out.println("q = " + q);
1007                    for (int ii = i - 1; ii >= 0; ii--) {
1008                        BigInteger r = dei.get(ii);
1009                        //System.out.println("r = " + r);
1010                        while (!r.isONE()) {
1011                            r = r.gcd(q);
1012                            q = q.divide(r);
1013                            //System.out.println("r = " + r + ", q = " + q);
1014                        }
1015                    }
1016                    dei.add(q);
1017                    if (q.isONE()) {
1018                        logger.info("condition (1) not met for dei = " + dei + ", cei = " + cei);
1019                        if (!testSeparate(cei, pecw)) {
1020                            countSeparate++;
1021                            if (countSeparate > COUNT_MAX) {
1022                                logger.info("too many inseparable evaluation points: " + countSeparate
1023                                                + ", removing " + pecw);
1024                            }
1025                        }
1026                        notLucky = true;
1027                        break;
1028                    }
1029                    i++;
1030                }
1031                //System.out.println("dei = " + dei);
1032            }
1033            if (notLucky) {
1034                continue;
1035            }
1036            logger.info("evaluation points  = " + V + ", dei = " + dei);
1037            //System.out.println("Evs = " + Evs);
1038            logger.info("univariate polynomial = " + pe + ", pecw = " + pecw);
1039            //pe = pe.abs();
1040            //ufactors = baseFactorsRadical(pe); //baseFactorsSquarefree(pe); wrong since not primitive
1041            ufactors = baseFactorsSquarefree(pe.divide(pecw)); //wrong if not primitive
1042            if (!pecw.isONE()) {
1043                ufactors.add(0, cpfac.getONE().multiply(pecw));
1044            }
1045            if (ufactors.size() <= 1) {
1046                logger.info("irreducible univariate polynomial");
1047                factors.add(pd); // P
1048                if (cfactors != null) {
1049                    cfactors.addAll(factors);
1050                    factors = cfactors;
1051                }
1052                return factors;
1053            }
1054            logger.info("univariate factors = " + ufactors); // + ", of " + pe);
1055            //System.out.println("lfacs    = " + lfacs);
1056            //System.out.println("cei      = " + cei);
1057            //System.out.println("pecw     = " + pecw);
1058
1059            // determine leading coefficient polynomials for factors
1060            lf = new ArrayList<GenPolynomial<BigInteger>>();
1061            lpx = lprr.ring.getONE();
1062            for (int i = 0; i < ufactors.size(); i++) {
1063                lf.add(lprr.ring.getONE());
1064            }
1065            //System.out.println("lf = " + lf);             
1066            if (!isMonic || !pecw.isONE()) {
1067                if (lfacs.size() > 0 && lfacs.get(0).isConstant()) {
1068                    //GenPolynomial<BigInteger> unused = 
1069                    lfacs.remove(0);
1070                    //BigInteger xxi = xx.leadingBaseCoefficient();
1071                    //System.out.println("xx = " + xx + " == ped = " +ped);
1072                }
1073                for (int i = ufactors.size() - 1; i >= 0; i--) {
1074                    GenPolynomial<BigInteger> pp = ufactors.get(i);
1075                    BigInteger ppl = pp.leadingBaseCoefficient();
1076                    //System.out.println("ppl = " + ppl + ", pp = " + pp);
1077                    ppl = ppl.multiply(pec); // content
1078                    GenPolynomial<BigInteger> lfp = lf.get(i);
1079                    int ii = 0;
1080                    for (BigInteger ci : cei) {
1081                        //System.out.println("ci = " + ci + ", lfp = " + lfp + ", lfacs.get(ii) = " + lfacs.get(ii));
1082                        if (ci.abs().isONE()) {
1083                            System.out.println("ppl = " + ppl + ", ci = " + ci + ", lfp = " + lfp
1084                                            + ", lfacs.get(ii) = " + lfacs.get(ii));
1085                            notLucky = true;
1086                            throw new RuntimeException("something is wrong, ci is a unit");
1087                        }
1088                        while (ppl.remainder(ci).isZERO() && lfacs.size() > ii) {
1089                            ppl = ppl.divide(ci);
1090                            lfp = lfp.multiply(lfacs.get(ii));
1091                        }
1092                        ii++;
1093                    }
1094                    //System.out.println("ppl = " + ppl + ", lfp = " + lfp);
1095                    lfp = lfp.multiply(ppl);
1096                    lf.set(i, lfp);
1097                }
1098                // adjust if pec != 1
1099                pec = pecw;
1100                lpx = Power.<GenPolynomial<BigInteger>> multiply(lprr.ring, lf); // test only, not used
1101                //System.out.println("lpx = " + lpx);
1102                if (!lprr.degreeVector().equals(lpx.degreeVector())) {
1103                    logger.info("deg(lprr) != deg(lpx): lprr = " + lprr + ", lpx = " + lpx);
1104                    notLucky = true;
1105                    continue;
1106                }
1107                if (!pec.isONE()) { // content, was always false by hack
1108                    // evaluate factors of ldcf
1109                    List<GenPolynomial<BigInteger>> lfe = lf;
1110                    List<BigInteger> lfei = null;
1111                    ccpfac = lprr.ring;
1112                    for (int j = lprr.ring.nvar; j > 0; j--) {
1113                        ccpfac = ccpfac.contract(1);
1114                        BigInteger Vi = V.get(lprr.ring.nvar - j);
1115                        if (ccpfac.nvar >= 1) {
1116                            lfe = PolyUtil.<BigInteger> evaluateMain(ccpfac, lfe, Vi);
1117                        } else {
1118                            lfei = PolyUtil.<BigInteger> evaluateMain(ccpfac.coFac, lfe, Vi);
1119                        }
1120                    }
1121                    //System.out.println("lfe = " + lfe + ", lfei = " + lfei + ", V = " + V);
1122
1123                    ln = new ArrayList<GenPolynomial<BigInteger>>(lf.size());
1124                    un = new ArrayList<GenPolynomial<BigInteger>>(lf.size());
1125                    for (int jj = 0; jj < lf.size(); jj++) {
1126                        GenPolynomial<BigInteger> up = ufactors.get(jj);
1127                        BigInteger ui = up.leadingBaseCoefficient();
1128                        BigInteger li = lfei.get(jj);
1129                        BigInteger di = ui.gcd(li).abs();
1130                        BigInteger udi = ui.divide(di);
1131                        BigInteger ldi = li.divide(di);
1132                        GenPolynomial<BigInteger> lp = lf.get(jj);
1133                        GenPolynomial<BigInteger> lpd = lp.multiply(udi);
1134                        GenPolynomial<BigInteger> upd = up.multiply(ldi);
1135                        if (pec.isONE()) {
1136                            ln.add(lp);
1137                            un.add(up);
1138                        } else {
1139                            ln.add(lpd);
1140                            un.add(upd);
1141                            BigInteger pec1 = pec.divide(ldi);
1142                            //System.out.println("pec = " + pec + ", pec1 = " + pec1);
1143                            pec = pec1;
1144                        }
1145                    }
1146                    if (!lf.equals(ln) || !un.equals(ufactors)) {
1147                        logger.debug("!lf.equals(ln) || !un.equals(ufactors)");
1148                        //System.out.println("pe  = " + pe);
1149                        //System.out.println("#ln  = " + ln + ", #lf = " + lf);
1150                        //System.out.println("#un  = " + un + ", #ufactors = " + ufactors);
1151                        //lf = ln;
1152                        //ufactors = un;
1153                        // adjust pe
1154                    }
1155                    if (!pec.isONE()) { // still not 1
1156                        ln = new ArrayList<GenPolynomial<BigInteger>>(lf.size());
1157                        un = new ArrayList<GenPolynomial<BigInteger>>(lf.size());
1158                        pes = pe;
1159                        for (int jj = 0; jj < lf.size(); jj++) {
1160                            GenPolynomial<BigInteger> up = ufactors.get(jj);
1161                            GenPolynomial<BigInteger> lp = lf.get(jj);
1162                            //System.out.println("up  = " + up + ", lp  = " + lp);
1163                            if (!up.isConstant()) {
1164                                up = up.multiply(pec);
1165                            }
1166                            lp = lp.multiply(pec);
1167                            if (jj != 0) {
1168                                pes = pes.multiply(pec);
1169                            }
1170                            un.add(up);
1171                            ln.add(lp);
1172                        }
1173                        if (pes.equals(Power.<GenPolynomial<BigInteger>> multiply(pe.ring, un))) {
1174                            //System.out.println("*pe  = " + pes + ", pec = " + pec);
1175                            //ystem.out.println("*ln  = " + ln + ", *lf = " + lf);
1176                            //System.out.println("*un  = " + un + ", *ufactors = " + ufactors);
1177                            //System.out.println("*pe == prod(un) ");
1178                            isPrimitive = false;
1179                            //pe = pes;
1180                            //lf = ln;
1181                            //ufactors = un;
1182                        } else {
1183                            //System.out.println("*pe != prod(un): " + Power.<GenPolynomial<BigInteger>> multiply(pe.ring,un));
1184                        }
1185                    }
1186                }
1187                //if (notLucky) {
1188                //    continue;
1189                //}
1190                logger.info("distributed factors of leading coefficient = " + lf);
1191                lpx = Power.<GenPolynomial<BigInteger>> multiply(lprr.ring, lf);
1192                if (!lprr.abs().equals(lpx.abs())) { // not correctly distributed
1193                    if (!lprr.degreeVector().equals(lpx.degreeVector())) {
1194                        logger.info("lprr != lpx: lprr = " + lprr + ", lpx = " + lpx);
1195                        notLucky = true;
1196                    }
1197                }
1198                //logger.warn("V = " + V + ", pe = " + pe + ", cei = " + cei + ", lf = " + lf + ", ln = " + ln);
1199            } // end determine leading coefficients for factors
1200
1201            if (!notLucky) {
1202                TrialParts tp = null;
1203                if (isPrimitive) {
1204                    tp = new TrialParts(V, pe, ufactors, cei, lf);
1205                } else {
1206                    tp = new TrialParts(V, pes, un, cei, ln);
1207                }
1208                //System.out.println("trialParts = " + tp);
1209                if (tp.univPoly != null) {
1210                    if (tp.ldcfEval.size() != 0) {
1211                        tParts.add(tp);
1212                    }
1213                }
1214                if (tParts.size() < trials) {
1215                    notLucky = true;
1216                }
1217            }
1218        } // end notLucky loop
1219        logger.warn("end notLucky loop, trial parts = " + tParts.size());
1220
1221        // search TrialParts with shortest factorization of univariate polynomial
1222        int min = Integer.MAX_VALUE;
1223        TrialParts tpmin = null;
1224        for (TrialParts tp : tParts) {
1225            //logger.info("tp.univFactors.size() = " + tp.univFactors.size());
1226            if (tp.univFactors.size() < min) {
1227                min = tp.univFactors.size();
1228                tpmin = tp;
1229            }
1230        }
1231        for (TrialParts tp : tParts) {
1232            if (tp.univFactors.size() == min) {
1233                if (!tp.univFactors.get(0).isConstant()) {
1234                    logger.info("tp.univFactors = " + tp.univFactors);
1235                    tpmin = tp;
1236                    break;
1237                }
1238            }
1239        }
1240        // set to (first) shortest 
1241        V = tpmin.evalPoints;
1242        pe = tpmin.univPoly;
1243        ufactors = tpmin.univFactors;
1244        cei = tpmin.ldcfEval; // unused
1245        lf = tpmin.ldcfFactors;
1246        logger.info("iterations    = " + Math.abs(evStart));
1247        logger.info("minimal trial = " + tpmin);
1248
1249        GenPolynomialRing<BigInteger> ufac = pe.ring;
1250
1251        //initialize prime list
1252        PrimeList primes = new PrimeList(PrimeList.Range.medium); // PrimeList.Range.medium);
1253        Iterator<java.math.BigInteger> primeIter = primes.iterator();
1254        int pn = 50; //primes.size();
1255        BigInteger ae = pe.leadingBaseCoefficient();
1256        GenPolynomial<MOD> Pm = null;
1257        ModularRingFactory<MOD> cofac = null;
1258        GenPolynomialRing<MOD> mufac = null;
1259
1260        // search lucky prime
1261        for (int i = 0; i < 11; i++) { // prime meta loop
1262            //for ( int i = 0; i < 1; i++ ) { // meta loop
1263            java.math.BigInteger p = null; //new java.math.BigInteger("19"); //primes.next();
1264            // 2 small, 5 medium and 4 large size primes
1265            if (i == 0) { // medium size
1266                primes = new PrimeList(PrimeList.Range.medium);
1267                primeIter = primes.iterator();
1268            }
1269            if (i == 5) { // small size
1270                primes = new PrimeList(PrimeList.Range.small);
1271                primeIter = primes.iterator();
1272                p = primeIter.next(); // 2
1273                p = primeIter.next(); // 3
1274                p = primeIter.next(); // 5
1275                p = primeIter.next(); // 7
1276            }
1277            if (i == 7) { // large size
1278                primes = new PrimeList(PrimeList.Range.large);
1279                primeIter = primes.iterator();
1280            }
1281            int pi = 0;
1282            while (pi < pn && primeIter.hasNext()) {
1283                p = primeIter.next();
1284                logger.info("prime = " + p);
1285                // initialize coefficient factory and map normalization factor and polynomials
1286                ModularRingFactory<MOD> cf = null;
1287                if (ModLongRing.MAX_LONG.compareTo(p) > 0) {
1288                    cf = (ModularRingFactory) new ModLongRing(p, true);
1289                } else {
1290                    cf = (ModularRingFactory) new ModIntegerRing(p, true);
1291                }
1292                MOD nf = cf.fromInteger(ae.getVal());
1293                if (nf.isZERO()) {
1294                    continue;
1295                }
1296                mufac = new GenPolynomialRing<MOD>(cf, ufac);
1297                //System.out.println("mufac = " + mufac.toScript());
1298                Pm = PolyUtil.<MOD> fromIntegerCoefficients(mufac, pe);
1299                //System.out.println("Pm = " + Pm);
1300                if (!mfactor.isSquarefree(Pm)) {
1301                    continue;
1302                }
1303                cofac = cf;
1304                break;
1305            }
1306            if (cofac != null) {
1307                break;
1308            }
1309        } // end prime meta loop
1310        if (cofac == null) { // no lucky prime found
1311            throw new RuntimeException("giving up on Hensel preparation, no lucky prime found");
1312        }
1313        logger.info("lucky prime = " + cofac.getIntegerModul());
1314        if (logger.isDebugEnabled()) {
1315            logger.debug("univariate modulo p: = " + Pm);
1316        }
1317
1318        // coefficient bound
1319        BigInteger an = pd.maxNorm();
1320        BigInteger mn = an.multiply(ac.abs()).multiply(new BigInteger(2L));
1321        long k = Power.logarithm(cofac.getIntegerModul(), mn) + 1L;
1322        //System.out.println("mn = " + mn + ", k = " +k);
1323
1324        BigInteger q = cofac.getIntegerModul().power(k);
1325        ModularRingFactory<MOD> muqfac;
1326        if (ModLongRing.MAX_LONG.compareTo(q.getVal()) > 0) {
1327            muqfac = (ModularRingFactory) new ModLongRing(q.getVal());
1328        } else {
1329            muqfac = (ModularRingFactory) new ModIntegerRing(q.getVal());
1330        }
1331        //System.out.println("muqfac = " + muqfac);
1332        GenPolynomialRing<MOD> mucpfac = new GenPolynomialRing<MOD>(muqfac, ufac);
1333
1334        List<GenPolynomial<MOD>> muqfactors = PolyUtil.<MOD> fromIntegerCoefficients(mucpfac, ufactors);
1335        GenPolynomial<MOD> peqq = PolyUtil.<MOD> fromIntegerCoefficients(mucpfac, pe);
1336        if (debug) {
1337            if (!mfactor.isFactorization(peqq, muqfactors)) { // should not happen
1338                System.out.println("muqfactors = " + muqfactors);
1339                System.out.println("peqq       = " + peqq);
1340                throw new RuntimeException("something is wrong, no modular p^k factorization");
1341            }
1342        }
1343        logger.info("univariate modulo p^k: " + peqq + " = " + muqfactors);
1344
1345        // convert C from Z[...] to Z_q[...]
1346        GenPolynomialRing<MOD> qcfac = new GenPolynomialRing<MOD>(muqfac, pd.ring);
1347        GenPolynomial<MOD> pq = PolyUtil.<MOD> fromIntegerCoefficients(qcfac, pd);
1348        //System.out.println("pd = " + pd);
1349        logger.info("multivariate modulo p^k: " + pq);
1350
1351        //List<MOD> Vm = new ArrayList<MOD>(V.size());
1352        //for (BigInteger v : V) {
1353        //    MOD vm = muqfac.fromInteger(v.getVal());
1354        //    Vm.add(vm);
1355        //}
1356        //System.out.println("Vm = " + Vm);
1357
1358        // Hensel lifting of factors
1359        List<GenPolynomial<MOD>> mlift;
1360        try {
1361            mlift = HenselMultUtil.<MOD> liftHensel(pd, pq, muqfactors, V, k, lf);
1362            logger.info("mlift = " + mlift);
1363        } catch (NoLiftingException nle) {
1364            //System.out.println("exception : " + nle);
1365            //nle.printStackTrace();
1366            //mlift = new ArrayList<GenPolynomial<MOD>>();
1367            throw new RuntimeException(nle);
1368        } catch (ArithmeticException aex) {
1369            //System.out.println("exception : " + aex);
1370            //aex.printStackTrace();
1371            //mlift = new ArrayList<GenPolynomial<MOD>>();
1372            throw aex;
1373        }
1374        if (mlift.size() <= 1) { // irreducible mod I, p^k, can this happen?
1375            logger.info("modular lift size == 1: " + mlift);
1376            factors.add(pd); // P
1377            if (cfactors != null) {
1378                cfactors.addAll(factors);
1379                factors = cfactors;
1380            }
1381            return factors;
1382        }
1383
1384        // combine trial factors
1385        GenPolynomialRing<MOD> mfac = mlift.get(0).ring;
1386        int dl = (mlift.size() + 1) / 2;
1387        GenPolynomial<BigInteger> u = P;
1388        long deg = (u.degree() + 1L) / 2L;
1389
1390        GenPolynomial<BigInteger> ui = pd;
1391        for (int j = 1; j <= dl; j++) {
1392            //System.out.println("j = " + j + ", dl = " + dl + ", mlift = " + mlift); 
1393            KsubSet<GenPolynomial<MOD>> subs = new KsubSet<GenPolynomial<MOD>>(mlift, j);
1394            for (List<GenPolynomial<MOD>> flist : subs) {
1395                //System.out.println("degreeSum = " + degreeSum(flist));
1396                GenPolynomial<MOD> mtrial = Power.<GenPolynomial<MOD>> multiply(mfac, flist);
1397                if (mtrial.degree() > deg) { // this test is sometimes wrong
1398                    logger.info("degree > deg " + deg + ", degree = " + mtrial.degree());
1399                    //continue;
1400                }
1401                GenPolynomial<BigInteger> trial = PolyUtil.integerFromModularCoefficients(pfac, mtrial);
1402                trial = engine.basePrimitivePart(trial);
1403                //if ( ! isPrimitive ) {
1404                //}
1405                if (debug) {
1406                    logger.info("trial    = " + trial); // + ", mtrial = " + mtrial);
1407                }
1408                if (PolyUtil.<BigInteger> baseSparsePseudoRemainder(ui, trial).isZERO()) {
1409                    logger.info("successful trial = " + trial);
1410                    factors.add(trial);
1411                    ui = PolyUtil.<BigInteger> basePseudoDivide(ui, trial);
1412                    //System.out.println("ui        = " + ui);
1413                    mlift = removeOnce(mlift, flist);
1414                    logger.info("new mlift= " + mlift);
1415                    //System.out.println("dl = " + dl); 
1416                    if (mlift.size() > 1) {
1417                        dl = (mlift.size() + 1) / 2;
1418                        j = 0; // since j++
1419                        break;
1420                    }
1421                    logger.info("last factor = " + ui);
1422                    factors.add(ui);
1423                    if (cfactors != null) {
1424                        cfactors.addAll(factors);
1425                        factors = cfactors;
1426                    }
1427                    return normalizeFactorization(factors);
1428                }
1429            }
1430        }
1431        if (!ui.isONE() && !ui.equals(pd)) {
1432            logger.info("rest factor = " + ui);
1433            // pp(ui) ?? no ??
1434            factors.add(ui);
1435        }
1436        if (factors.size() == 0) {
1437            logger.info("irreducible P = " + P);
1438            factors.add(pd); // P
1439        }
1440        if (cfactors != null) {
1441            cfactors.addAll(factors);
1442            factors = cfactors;
1443        }
1444        return normalizeFactorization(factors);
1445    }
1446
1447
1448    /**
1449     * Test if b has a prime factor different to the elements of A.
1450     * @param A list of integer with at least one different prime factor.
1451     * @param b integer to test with A.
1452     * @return true, if b hase a prime factor different to elements of A
1453     */
1454    boolean testSeparate(List<BigInteger> A, BigInteger b) {
1455        int i = 0;
1456        //List<BigInteger> gei = new ArrayList<BigInteger>(A.size());
1457        for (BigInteger c : A) {
1458            BigInteger g = c.gcd(b).abs();
1459            //gei.add(g);
1460            if (!g.isONE()) {
1461                i++;
1462            }
1463        }
1464        //if ( i >= 1 ) {
1465        //System.out.println("gei = " + gei + ", cei = " + cei + ", pec(w) = " + pec);
1466        //}
1467        return (i <= 1);
1468    }
1469
1470
1471    // not useable
1472    boolean isNearlySquarefree(GenPolynomial<BigInteger> P) { // unused
1473        // in main variable
1474        GenPolynomialRing<BigInteger> pfac = P.ring;
1475        if (pfac.nvar >= 0) { // allways true
1476            return sengine.isSquarefree(P);
1477        }
1478        GenPolynomialRing<GenPolynomial<BigInteger>> rfac = pfac.recursive(1);
1479        GenPolynomial<GenPolynomial<BigInteger>> Pr = PolyUtil.<BigInteger> recursive(rfac, P);
1480        GenPolynomial<GenPolynomial<BigInteger>> Ps = PolyUtil.<BigInteger> recursiveDeriviative(Pr);
1481        System.out.println("Pr = " + Pr);
1482        System.out.println("Ps = " + Ps);
1483        GenPolynomial<GenPolynomial<BigInteger>> g = engine.recursiveUnivariateGcd(Pr, Ps);
1484        System.out.println("g_m = " + g);
1485        if (!g.isONE()) {
1486            return false;
1487        }
1488        // in lowest variable
1489        rfac = pfac.recursive(pfac.nvar - 1);
1490        Pr = PolyUtil.<BigInteger> recursive(rfac, P);
1491        Pr = PolyUtil.<BigInteger> switchVariables(Pr);
1492        Ps = PolyUtil.<BigInteger> recursiveDeriviative(Pr);
1493        System.out.println("Pr = " + Pr);
1494        System.out.println("Ps = " + Ps);
1495        g = engine.recursiveUnivariateGcd(Pr, Ps);
1496        System.out.println("g_1 = " + g);
1497        if (!g.isONE()) {
1498            return false;
1499        }
1500        return true;
1501    }
1502
1503}
1504
1505
1506/**
1507 * Container for factorization trial lifting parameters.
1508 */
1509class TrialParts {
1510
1511
1512    /**
1513     * evaluation points
1514     */
1515    public final List<BigInteger> evalPoints;
1516
1517
1518    /**
1519     * univariate polynomial
1520     */
1521    public final GenPolynomial<BigInteger> univPoly;
1522
1523
1524    /**
1525     * irreducible factors of univariate polynomial
1526     */
1527    public final List<GenPolynomial<BigInteger>> univFactors;
1528
1529
1530    /**
1531     * irreducible factors of leading coefficient
1532     */
1533    public final List<GenPolynomial<BigInteger>> ldcfFactors;
1534
1535
1536    /**
1537     * evaluated factors of leading coefficient factors by evaluation points
1538     */
1539    public final List<BigInteger> ldcfEval;
1540
1541
1542    /**
1543     * Constructor.
1544     * @param ev evaluation points.
1545     * @param up univariate polynomial.
1546     * @param uf irreducible factors of up.
1547     * @param le irreducible factors of leading coefficient.
1548     * @param lf evaluated le by evaluation points.
1549     */
1550    public TrialParts(List<BigInteger> ev, GenPolynomial<BigInteger> up, List<GenPolynomial<BigInteger>> uf,
1551                    List<BigInteger> le, List<GenPolynomial<BigInteger>> lf) {
1552        evalPoints = ev;
1553        univPoly = up;
1554        univFactors = uf;
1555        //ldcfPoly = lp;
1556        ldcfFactors = lf;
1557        ldcfEval = le;
1558    }
1559
1560
1561    /**
1562     * @see java.lang.Object#toString()
1563     */
1564    @Override
1565    public String toString() {
1566        StringBuffer sb = new StringBuffer();
1567        sb.append("TrialParts[");
1568        sb.append("evalPoints = " + evalPoints);
1569        sb.append(", univPoly = " + univPoly);
1570        sb.append(", univFactors = " + univFactors);
1571        sb.append(", ldcfEval = " + ldcfEval);
1572        sb.append(", ldcfFactors = " + ldcfFactors);
1573        sb.append("]");
1574        return sb.toString();
1575    }
1576
1577}