001/*
002 * $Id: FactorAbstract.java 5160 2015-03-26 21:52:03Z kredel $
003 */
004
005package edu.jas.ufd;
006
007
008import java.util.ArrayList;
009import java.util.List;
010import java.util.Map;
011import java.util.SortedMap;
012import java.util.SortedSet;
013import java.util.TreeMap;
014import java.util.TreeSet;
015
016import org.apache.log4j.Logger;
017
018import edu.jas.kern.TimeStatus;
019import edu.jas.kern.StringUtil;
020import edu.jas.poly.ExpVector;
021import edu.jas.poly.GenPolynomial;
022import edu.jas.poly.GenPolynomialRing;
023import edu.jas.poly.OptimizedPolynomialList;
024import edu.jas.poly.PolyUtil;
025import edu.jas.poly.TermOrderOptimization;
026import edu.jas.structure.GcdRingElem;
027import edu.jas.structure.RingFactory;
028import edu.jas.util.KsubSet;
029
030
031/**
032 * Abstract factorization algorithms class. This class contains implementations
033 * of all methods of the <code>Factorization</code> interface, except the method
034 * for factorization of a squarefree polynomial. The methods to obtain
035 * squarefree polynomials delegate the computation to the
036 * <code>GreatestCommonDivisor</code> classes and are included for convenience.
037 * @param <C> coefficient type
038 * @author Heinz Kredel
039 * @see edu.jas.ufd.FactorFactory
040 */
041
042public abstract class FactorAbstract<C extends GcdRingElem<C>> implements Factorization<C> {
043
044
045    private static final Logger logger = Logger.getLogger(FactorAbstract.class);
046
047
048    private final boolean debug = logger.isDebugEnabled();
049
050
051    /**
052     * Gcd engine for base coefficients.
053     */
054    protected final GreatestCommonDivisorAbstract<C> engine;
055
056
057    /**
058     * Squarefree decompositon engine for base coefficients.
059     */
060    protected final SquarefreeAbstract<C> sengine;
061
062
063    /**
064     * No argument constructor.
065     */
066    protected FactorAbstract() {
067        throw new IllegalArgumentException("don't use this constructor");
068    }
069
070
071    /**
072     * Constructor.
073     * @param cfac coefficient ring factory.
074     */
075    public FactorAbstract(RingFactory<C> cfac) {
076        engine = GCDFactory.<C> getProxy(cfac);
077        //engine = GCDFactory.<C> getImplementation(cfac);
078        sengine = SquarefreeFactory.<C> getImplementation(cfac);
079    }
080
081
082    /**
083     * Get the String representation.
084     * @see java.lang.Object#toString()
085     */
086    @Override
087    public String toString() {
088        return getClass().getName();
089    }
090
091
092    /**
093     * GenPolynomial test if is irreducible.
094     * @param P GenPolynomial.
095     * @return true if P is irreducible, else false.
096     */
097    public boolean isIrreducible(GenPolynomial<C> P) {
098        if (!isSquarefree(P)) {
099            return false;
100        }
101        List<GenPolynomial<C>> F = factorsSquarefree(P);
102        if (F.size() == 1) {
103            return true;
104        } else if (F.size() > 2) {
105            return false;
106        } else { //F.size() == 2
107            boolean cnst = false;
108            for (GenPolynomial<C> p : F) {
109                if (p.isConstant()) {
110                    cnst = true;
111                }
112            }
113            return cnst;
114        }
115    }
116
117
118    /**
119     * GenPolynomial test if a non trivial factorization exsists.
120     * @param P GenPolynomial.
121     * @return true if P is reducible, else false.
122     */
123    public boolean isReducible(GenPolynomial<C> P) {
124        return !isIrreducible(P);
125    }
126
127
128    /**
129     * GenPolynomial test if is squarefree.
130     * @param P GenPolynomial.
131     * @return true if P is squarefree, else false.
132     */
133    public boolean isSquarefree(GenPolynomial<C> P) {
134        return sengine.isSquarefree(P);
135    }
136
137
138    /**
139     * GenPolynomial factorization of a multivariate squarefree polynomial,
140     * using Kronecker substitution and variable order optimization.
141     * @param P squarefree and primitive! (respectively monic) multivariate
142     *            GenPolynomial over the ring C.
143     * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i.
144     */
145    public List<GenPolynomial<C>> factorsSquarefreeOptimize(GenPolynomial<C> P) {
146        GenPolynomialRing<C> pfac = P.ring;
147        if (pfac.nvar <= 1) {
148            return baseFactorsSquarefree(P);
149        }
150        List<GenPolynomial<C>> topt = new ArrayList<GenPolynomial<C>>(1);
151        topt.add(P);
152        OptimizedPolynomialList<C> opt = TermOrderOptimization.<C> optimizeTermOrder(pfac, topt);
153        P = opt.list.get(0);
154        logger.info("optimized polynomial: " + P);
155        List<Integer> iperm = TermOrderOptimization.inversePermutation(opt.perm);
156        logger.info("optimize perm: " + opt.perm + ", de-optimize perm: " + iperm);
157
158        ExpVector degv = P.degreeVector();
159        int[] donv = degv.dependencyOnVariables();
160        List<GenPolynomial<C>> facs = null;
161        if (degv.length() == donv.length) { // all variables appear
162            logger.info("do.full factorsSquarefreeKronecker: " + P);
163            facs = factorsSquarefreeKronecker(P);
164        } else { // not all variables appear, remove unused variables
165            GenPolynomial<C> pu = PolyUtil.<C> removeUnusedUpperVariables(P);
166            //GenPolynomial<C> pl = PolyUtil.<C> removeUnusedLowerVariables(pu); // not useful after optimize
167            logger.info("do.sparse factorsSquarefreeKronecker: " + pu);
168            facs = factorsSquarefreeKronecker(pu); // pl
169            List<GenPolynomial<C>> fs = new ArrayList<GenPolynomial<C>>(facs.size());
170            GenPolynomialRing<C> pf = P.ring;
171            //GenPolynomialRing<C> pfu = pu.ring;
172            for (GenPolynomial<C> p : facs) {
173                //GenPolynomial<C> pel = p.extendLower(pfu, 0, 0L);
174                GenPolynomial<C> pe = p.extend(pf, 0, 0L); // pel
175                fs.add(pe);
176            }
177            //System.out.println("fs = " + fs);
178            facs = fs;
179        }
180        List<GenPolynomial<C>> iopt = TermOrderOptimization.<C> permutation(iperm, pfac, facs);
181        logger.info("de-optimized polynomials: " + iopt);
182        facs = normalizeFactorization(iopt);
183        return facs;
184    }
185
186
187    /**
188     * GenPolynomial factorization of a squarefree polynomial, using Kronecker
189     * substitution.
190     * @param P squarefree and primitive! (respectively monic) GenPolynomial.
191     * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i.
192     */
193    @Override
194    public List<GenPolynomial<C>> factorsSquarefree(GenPolynomial<C> P) {
195        if (logger.isInfoEnabled()) {
196            logger.info(StringUtil.selectStackTrace("edu\\.jas.*"));
197        }
198        return factorsSquarefreeKronecker(P);
199        //return factorsSquarefreeOptimize(P);
200    }
201
202
203    /**
204     * GenPolynomial factorization of a squarefree polynomial, using Kronecker
205     * substitution.
206     * @param P squarefree and primitive! (respectively monic) GenPolynomial.
207     * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i.
208     */
209    public List<GenPolynomial<C>> factorsSquarefreeKronecker(GenPolynomial<C> P) {
210        if (P == null) {
211            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
212        }
213        GenPolynomialRing<C> pfac = P.ring;
214        if (pfac.nvar == 1) {
215            return baseFactorsSquarefree(P);
216        }
217        List<GenPolynomial<C>> factors = new ArrayList<GenPolynomial<C>>();
218        if (P.isZERO()) {
219            return factors;
220        }
221        if (P.degreeVector().totalDeg() <= 1L) {
222            factors.add(P);
223            return factors;
224        }
225        long d = P.degree() + 1L;
226        GenPolynomial<C> kr = PolyUfdUtil.<C> substituteKronecker(P, d);
227        GenPolynomialRing<C> ufac = kr.ring;
228        ufac.setVars(ufac.newVars("zz")); // side effects 
229        logger.info("deg(subs(P,d=" + d + ")) = " + kr.degree(0) + ", original degrees: " + P.degreeVector());
230        if (debug) {
231            logger.info("subs(P,d=" + d + ") = " + kr);
232            //System.out.println("subs(P,d=" + d + ") = " + kr);
233        }
234        if (kr.degree(0) > 100) {
235            logger.warn("Kronecker substitution has to high degree");
236            TimeStatus.checkTime("degree > 100");
237        }
238
239        // factor Kronecker polynomial
240        List<GenPolynomial<C>> ulist = new ArrayList<GenPolynomial<C>>();
241        // kr might not be squarefree so complete factor univariate
242        SortedMap<GenPolynomial<C>, Long> slist = baseFactors(kr);
243        if (debug && !isFactorization(kr, slist)) {
244            System.out.println("kr    = " + kr);
245            System.out.println("slist = " + slist);
246            throw new ArithmeticException("no factorization");
247        }
248        for (Map.Entry<GenPolynomial<C>, Long> me : slist.entrySet()) {
249            GenPolynomial<C> g = me.getKey();
250            long e = me.getValue(); // slist.get(g);
251            for (int i = 0; i < e; i++) { // is this really required? yes!
252                ulist.add(g);
253            }
254        }
255        //System.out.println("ulist = " + ulist);
256        if (ulist.size() == 1 && ulist.get(0).degree() == P.degree()) {
257            factors.add(P);
258            return factors;
259        }
260        //wrong: List<GenPolynomial<C>> klist = PolyUfdUtil.<C> backSubstituteKronecker(pfac, ulist, d);
261        //System.out.println("back(klist) = " + PolyUfdUtil.<C> backSubstituteKronecker(pfac, ulist, d));
262        if (logger.isInfoEnabled()) {
263            logger.info("ulist = " + ulist);
264            //System.out.println("ulist = " + ulist);
265        }
266        // combine trial factors
267        int dl = ulist.size() - 1; //(ulist.size() + 1) / 2;
268        //System.out.println("dl = " + dl);
269        int ti = 0;
270        GenPolynomial<C> u = P;
271        long deg = (u.degree() + 1L) / 2L; // max deg
272        ExpVector evl = u.leadingExpVector();
273        ExpVector evt = u.trailingExpVector();
274        //System.out.println("deg = " + deg);
275        for (int j = 1; j <= dl; j++) {
276            KsubSet<GenPolynomial<C>> ps = new KsubSet<GenPolynomial<C>>(ulist, j);
277            for (List<GenPolynomial<C>> flist : ps) {
278                //System.out.println("flist = " + flist);
279                GenPolynomial<C> utrial = ufac.getONE();
280                for (int k = 0; k < flist.size(); k++) {
281                    utrial = utrial.multiply(flist.get(k));
282                }
283                GenPolynomial<C> trial = PolyUfdUtil.<C> backSubstituteKronecker(pfac, utrial, d);
284                ti++;
285                if (ti % 2000 == 0) {
286                    System.out.print("ti(" + ti + ") ");
287                    TimeStatus.checkTime(ti + " % 2000 == 0");
288                }
289                if (!evl.multipleOf(trial.leadingExpVector())) {
290                    continue;
291                }
292                if (!evt.multipleOf(trial.trailingExpVector())) {
293                    continue;
294                }
295                if (trial.degree() > deg || trial.isConstant()) {
296                    continue;
297                }
298                trial = trial.monic();
299                if (ti % 15000 == 0) {
300                    System.out.println("\ndl   = " + dl + ", deg(u) = " + deg);
301                    System.out.println("ulist = " + ulist);
302                    System.out.println("kr    = " + kr);
303                    System.out.println("u     = " + u);
304                    System.out.println("trial = " + trial);
305                }
306                GenPolynomial<C> rem = PolyUtil.<C> baseSparsePseudoRemainder(u, trial);
307                //System.out.println(" rem = " + rem);
308                if (rem.isZERO()) {
309                    logger.info("trial = " + trial);
310                    //System.out.println("trial = " + trial);
311                    factors.add(trial);
312                    u = PolyUtil.<C> basePseudoDivide(u, trial); //u = u.divide( trial );
313                    evl = u.leadingExpVector();
314                    evt = u.trailingExpVector();
315                    if (u.isConstant()) {
316                        j = dl + 1;
317                        break;
318                    }
319                    //if (ulist.removeAll(flist)) { // wrong
320                    ulist = removeOnce(ulist, flist);
321                    //System.out.println("new ulist = " + ulist);
322                    dl = (ulist.size() + 1) / 2;
323                    j = 0; // since j++
324                    break;
325                }
326            }
327        }
328        if (!u.isONE() && !u.equals(P)) {
329            logger.info("rest u = " + u);
330            factors.add(u);
331        }
332        if (factors.size() == 0) {
333            logger.info("irred P = " + P);
334            factors.add(P); // == u
335        }
336        return normalizeFactorization(factors);
337    }
338
339
340    /**
341     * Remove one occurrence of elements.
342     * @param a list of objects.
343     * @param b list of objects.
344     * @return remove every element of b from a, but only one occurrence.
345     *         <b>Note:</b> not available in java.util.
346     */
347    static <T> List<T> removeOnce(List<T> a, List<T> b) {
348        List<T> res = new ArrayList<T>();
349        res.addAll(a);
350        for (T e : b) {
351            @SuppressWarnings("unused")
352            boolean t = res.remove(e);
353        }
354        return res;
355    }
356
357
358    /**
359     * Univariate GenPolynomial factorization ignoring multiplicities.
360     * @param P GenPolynomial in one variable.
361     * @return [p_1, ..., p_k] with P = prod_{i=1,...,k} p_i**{e_i} for some
362     *         e_i.
363     */
364    public List<GenPolynomial<C>> baseFactorsRadical(GenPolynomial<C> P) {
365        return new ArrayList<GenPolynomial<C>>(baseFactors(P).keySet());
366    }
367
368
369    /**
370     * Univariate GenPolynomial factorization.
371     * @param P GenPolynomial in one variable.
372     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k}
373     *         p_i**e_i.
374     */
375    public SortedMap<GenPolynomial<C>, Long> baseFactors(GenPolynomial<C> P) {
376        if (P == null) {
377            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
378        }
379        GenPolynomialRing<C> pfac = P.ring;
380        SortedMap<GenPolynomial<C>, Long> factors = new TreeMap<GenPolynomial<C>, Long>(pfac.getComparator());
381        if (P.isZERO()) {
382            return factors;
383        }
384        if (pfac.nvar > 1) {
385            throw new IllegalArgumentException(this.getClass().getName() + " only for univariate polynomials");
386        }
387        if (P.isConstant()) {
388            factors.put(P, 1L);
389            return factors;
390        }
391        C c;
392        if (pfac.coFac.isField()) { //pfac.characteristic().signum() > 0
393            c = P.leadingBaseCoefficient();
394        } else {
395            c = engine.baseContent(P);
396            // move sign to the content
397            if (P.signum() < 0 && c.signum() > 0) {
398                c = c.negate();
399                //P = P.negate();
400            }
401        }
402        if (!c.isONE()) {
403            GenPolynomial<C> pc = pfac.getONE().multiply(c);
404            factors.put(pc, 1L);
405            P = P.divide(c); // make primitive or monic
406        }
407        if (logger.isInfoEnabled()) {
408            logger.info("base facs for P = " + P);
409            //System.out.println(StringUtil.selectStackTrace("edu\\.jas.*"));
410        }
411        SortedMap<GenPolynomial<C>, Long> facs = sengine.baseSquarefreeFactors(P);
412        if (facs == null || facs.size() == 0) {
413            facs = new TreeMap<GenPolynomial<C>, Long>();
414            facs.put(P, 1L);
415        }
416        if (logger.isInfoEnabled()
417                        && (facs.size() > 1 || (facs.size() == 1 && facs.get(facs.firstKey()) > 1))) {
418            logger.info("squarefree facs   = " + facs);
419            //System.out.println("sfacs   = " + facs);
420            //boolean tt = isFactorization(P,facs);
421            //System.out.println("sfacs tt   = " + tt);
422        }
423        for (Map.Entry<GenPolynomial<C>, Long> me : facs.entrySet()) {
424            GenPolynomial<C> g = me.getKey();
425            Long k = me.getValue(); //facs.get(g);
426            //System.out.println("g       = " + g);
427            if (pfac.coFac.isField() && !g.leadingBaseCoefficient().isONE()) {
428                g = g.monic(); // how can this happen?
429                logger.warn("squarefree facs mon = " + g);
430            }
431            if (g.degree(0) <= 1) {
432                if (!g.isONE()) {
433                    factors.put(g, k);
434                }
435            } else {
436                List<GenPolynomial<C>> sfacs = baseFactorsSquarefree(g);
437                if (debug) {
438                    logger.info("factors of squarefree = " + sfacs);
439                    //System.out.println("sfacs   = " + sfacs);
440                }
441                for (GenPolynomial<C> h : sfacs) {
442                    Long j = factors.get(h); // evtl. constants
443                    if (j != null) {
444                        k += j;
445                    }
446                    if (!h.isONE()) {
447                        factors.put(h, k);
448                    }
449                }
450            }
451        }
452        //System.out.println("factors = " + factors);
453        return factors;
454    }
455
456
457    /**
458     * Univariate GenPolynomial factorization of a squarefree polynomial.
459     * @param P squarefree and primitive! GenPolynomial in one variable.
460     * @return [p_1, ..., p_k] with P = prod_{i=1,...,k} p_i.
461     */
462    public abstract List<GenPolynomial<C>> baseFactorsSquarefree(GenPolynomial<C> P);
463
464
465    /**
466     * GenPolynomial factorization ignoring multiplicities.
467     * @param P GenPolynomial.
468     * @return [p_1, ..., p_k] with P = prod_{i=1,...,k} p_i**{e_i} for some
469     *         e_i.
470     */
471    public List<GenPolynomial<C>> factorsRadical(GenPolynomial<C> P) {
472        return new ArrayList<GenPolynomial<C>>(factors(P).keySet());
473    }
474
475
476    /**
477     * GenPolynomial list factorization ignoring multiplicities.
478     * @param L list of GenPolynomials.
479     * @return [p_1, ..., p_k] with p = prod_{i=1,...,k} p_i**{e_i} for some e_i
480     *         for all p in L.
481     */
482    public List<GenPolynomial<C>> factorsRadical(List<GenPolynomial<C>> L) {
483        SortedSet<GenPolynomial<C>> facs = new TreeSet<GenPolynomial<C>>();
484        for (GenPolynomial<C> p : L) {
485            List<GenPolynomial<C>> fs = factorsRadical(p);
486            facs.addAll(fs);
487        }
488        return new ArrayList<GenPolynomial<C>>(facs);
489    }
490
491
492    /**
493     * GenPolynomial factorization.
494     * @param P GenPolynomial.
495     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k}
496     *         p_i**e_i.
497     */
498    public SortedMap<GenPolynomial<C>, Long> factors(GenPolynomial<C> P) {
499        if (P == null) {
500            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
501        }
502        GenPolynomialRing<C> pfac = P.ring;
503        if (pfac.nvar == 1) {
504            return baseFactors(P);
505        }
506        SortedMap<GenPolynomial<C>, Long> factors = new TreeMap<GenPolynomial<C>, Long>(pfac.getComparator());
507        if (P.isZERO()) {
508            return factors;
509        }
510        if (P.isConstant()) {
511            factors.put(P, 1L);
512            return factors;
513        }
514        C c;
515        if (pfac.coFac.isField()) { // pfac.characteristic().signum() > 0
516            c = P.leadingBaseCoefficient();
517        } else {
518            c = engine.baseContent(P);
519            // move sign to the content
520            if (P.signum() < 0 && c.signum() > 0) {
521                c = c.negate();
522                //P = P.negate();
523            }
524        }
525        if (!c.isONE()) {
526            GenPolynomial<C> pc = pfac.getONE().multiply(c);
527            factors.put(pc, 1L);
528            P = P.divide(c); // make base primitive or base monic
529        }
530        if (logger.isInfoEnabled()) {
531            logger.info("squarefree mfacs P = " + P);
532        }
533        SortedMap<GenPolynomial<C>, Long> facs = sengine.squarefreeFactors(P);
534        if (facs == null || facs.size() == 0) {
535            facs = new TreeMap<GenPolynomial<C>, Long>();
536            facs.put(P, 1L);
537            throw new RuntimeException("this should not happen, facs is empty: " + facs);
538        }
539        if (logger.isInfoEnabled()) {
540            if (facs.size() > 1) {
541                logger.info("squarefree mfacs      = " + facs);
542            } else if (facs.size() == 1 && facs.get(facs.firstKey()) > 1L) {
543                logger.info("squarefree #mfacs 1-n = " + facs);
544            } else {
545                logger.info("squarefree #mfacs 1-1 = " + facs);
546            }
547        }
548        for (Map.Entry<GenPolynomial<C>, Long> me : facs.entrySet()) {
549            GenPolynomial<C> g = me.getKey();
550            if (g.isONE()) { // skip 1
551                continue;
552            }
553            Long d = me.getValue(); // facs.get(g);
554            List<GenPolynomial<C>> sfacs = factorsSquarefree(g);
555            if (logger.isInfoEnabled()) {
556                logger.info("factors of squarefree ^" + d + " = " + sfacs);
557                //System.out.println("sfacs   = " + sfacs);
558            }
559            for (GenPolynomial<C> h : sfacs) {
560                long dd = d;
561                Long j = factors.get(h); // evtl. constants
562                if (j != null) {
563                    dd += j;
564                }
565                factors.put(h, dd);
566            }
567        }
568        //System.out.println("factors = " + factors);
569        return factors;
570    }
571
572
573    /**
574     * GenPolynomial greatest squarefree divisor. Delegates computation to a
575     * GreatestCommonDivisor class.
576     * @param P GenPolynomial.
577     * @return squarefree(P).
578     */
579    public GenPolynomial<C> squarefreePart(GenPolynomial<C> P) {
580        return sengine.squarefreePart(P);
581    }
582
583
584    /**
585     * GenPolynomial primitive part. Delegates computation to a
586     * GreatestCommonDivisor class.
587     * @param P GenPolynomial.
588     * @return primitivePart(P).
589     */
590    public GenPolynomial<C> primitivePart(GenPolynomial<C> P) {
591        return engine.primitivePart(P);
592    }
593
594
595    /**
596     * GenPolynomial base primitive part. Delegates computation to a
597     * GreatestCommonDivisor class.
598     * @param P GenPolynomial.
599     * @return basePrimitivePart(P).
600     */
601    public GenPolynomial<C> basePrimitivePart(GenPolynomial<C> P) {
602        return engine.basePrimitivePart(P);
603    }
604
605
606    /**
607     * GenPolynomial squarefree factorization. Delegates computation to a
608     * GreatestCommonDivisor class.
609     * @param P GenPolynomial.
610     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k}
611     *         p_i**e_i.
612     */
613    public SortedMap<GenPolynomial<C>, Long> squarefreeFactors(GenPolynomial<C> P) {
614        return sengine.squarefreeFactors(P);
615    }
616
617
618    /**
619     * GenPolynomial is factorization.
620     * @param P GenPolynomial.
621     * @param F = [p_1,...,p_k].
622     * @return true if P = prod_{i=1,...,r} p_i, else false.
623     */
624    public boolean isFactorization(GenPolynomial<C> P, List<GenPolynomial<C>> F) {
625        return sengine.isFactorization(P, F);
626        // test irreducible
627    }
628
629
630    /**
631     * GenPolynomial is factorization.
632     * @param P GenPolynomial.
633     * @param F = [p_1 -&gt; e_1, ..., p_k -&gt; e_k].
634     * @return true if P = prod_{i=1,...,k} p_i**e_i , else false.
635     */
636    public boolean isFactorization(GenPolynomial<C> P, SortedMap<GenPolynomial<C>, Long> F) {
637        return sengine.isFactorization(P, F);
638        // test irreducible
639    }
640
641
642    /**
643     * Degree of a factorization.
644     * @param F a factors map [p_1 -&gt; e_1, ..., p_k -&gt; e_k].
645     * @return sum_{i=1,...,k} degree(p_i)*e_i.
646     */
647    public long factorsDegree(SortedMap<GenPolynomial<C>, Long> F) {
648        long d = 0;
649        for (Map.Entry<GenPolynomial<C>, Long> me : F.entrySet()) {
650            GenPolynomial<C> p = me.getKey();
651            long e = me.getValue(); //F.get(p);
652            d += p.degree() * e;
653        }
654        return d;
655    }
656
657
658    /**
659     * GenPolynomial is factorization.
660     * @param P GenPolynomial.
661     * @param F = [p_1 -&gt; e_1, ..., p_k -&gt; e_k].
662     * @return true if P = prod_{i=1,...,k} p_i**e_i , else false.
663     */
664    public boolean isRecursiveFactorization(GenPolynomial<GenPolynomial<C>> P,
665                    SortedMap<GenPolynomial<GenPolynomial<C>>, Long> F) {
666        return sengine.isRecursiveFactorization(P, F);
667        // test irreducible
668    }
669
670
671    /**
672     * Recursive GenPolynomial factorization of a squarefree polynomial.
673     * @param P squarefree recursive GenPolynomial.
674     * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i.
675     */
676    public List<GenPolynomial<GenPolynomial<C>>> recursiveFactorsSquarefree(GenPolynomial<GenPolynomial<C>> P) {
677        if (P == null) {
678            throw new IllegalArgumentException(this.getClass().getName() + " P == null");
679        }
680        List<GenPolynomial<GenPolynomial<C>>> factors = new ArrayList<GenPolynomial<GenPolynomial<C>>>();
681        if (P.isZERO()) {
682            return factors;
683        }
684        if (P.isONE()) {
685            factors.add(P);
686            return factors;
687        }
688        GenPolynomialRing<GenPolynomial<C>> pfac = P.ring;
689        GenPolynomialRing<C> qi = (GenPolynomialRing<C>) pfac.coFac;
690        GenPolynomialRing<C> ifac = qi.extend(pfac.getVars());
691        GenPolynomial<C> Pi = PolyUtil.<C> distribute(ifac, P);
692        //System.out.println("Pi = " + Pi);
693
694        C ldcf = Pi.leadingBaseCoefficient();
695        if (!ldcf.isONE() && ldcf.isUnit()) {
696            //System.out.println("ldcf = " + ldcf);
697            Pi = Pi.monic();
698        }
699
700        // factor in C[x_1,...,x_n,y_1,...,y_m]
701        List<GenPolynomial<C>> ifacts = factorsSquarefree(Pi);
702        if (logger.isInfoEnabled()) {
703            logger.info("ifacts = " + ifacts);
704        }
705        if (ifacts.size() <= 1) {
706            factors.add(P);
707            return factors;
708        }
709        if (!ldcf.isONE() && ldcf.isUnit()) {
710            GenPolynomial<C> r = ifacts.get(0);
711            ifacts.remove(r);
712            r = r.multiply(ldcf);
713            ifacts.add(0, r);
714        }
715        List<GenPolynomial<GenPolynomial<C>>> rfacts = PolyUtil.<C> recursive(pfac, ifacts);
716        //System.out.println("rfacts = " + rfacts);
717        if (logger.isDebugEnabled()) {
718            logger.info("recfacts = " + rfacts);
719        }
720        factors.addAll(rfacts);
721        return factors;
722    }
723
724
725    /**
726     * Recursive GenPolynomial factorization.
727     * @param P recursive GenPolynomial.
728     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k}
729     *         p_i**e_i.
730     */
731    public SortedMap<GenPolynomial<GenPolynomial<C>>, Long> recursiveFactors(GenPolynomial<GenPolynomial<C>> P) {
732        if (P == null) {
733            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
734        }
735        GenPolynomialRing<GenPolynomial<C>> pfac = P.ring;
736        SortedMap<GenPolynomial<GenPolynomial<C>>, Long> factors = new TreeMap<GenPolynomial<GenPolynomial<C>>, Long>(
737                        pfac.getComparator());
738        if (P.isZERO()) {
739            return factors;
740        }
741        if (P.isONE()) {
742            factors.put(P, 1L);
743            return factors;
744        }
745        GenPolynomialRing<C> qi = (GenPolynomialRing<C>) pfac.coFac;
746        GenPolynomialRing<C> ifac = qi.extend(pfac.getVars());
747        GenPolynomial<C> Pi = PolyUtil.<C> distribute(ifac, P);
748        //System.out.println("Pi = " + Pi);
749
750        C ldcf = Pi.leadingBaseCoefficient();
751        if (!ldcf.isONE() && ldcf.isUnit()) {
752            //System.out.println("ldcf = " + ldcf);
753            Pi = Pi.monic();
754        }
755
756        // factor in C[x_1,...,x_n,y_1,...,y_m]
757        SortedMap<GenPolynomial<C>, Long> dfacts = factors(Pi);
758        if (logger.isInfoEnabled()) {
759            logger.info("dfacts = " + dfacts);
760        }
761        if (!ldcf.isONE() && ldcf.isUnit()) {
762            GenPolynomial<C> r = dfacts.firstKey();
763            Long E = dfacts.remove(r);
764            r = r.multiply(ldcf);
765            dfacts.put(r, E);
766        }
767        for (Map.Entry<GenPolynomial<C>, Long> me : dfacts.entrySet()) {
768            GenPolynomial<C> f = me.getKey();
769            Long E = me.getValue(); //dfacts.get(f);
770            GenPolynomial<GenPolynomial<C>> rp = PolyUtil.<C> recursive(pfac, f);
771            factors.put(rp, E);
772        }
773        //System.out.println("rfacts = " + rfacts);
774        if (logger.isInfoEnabled()) {
775            logger.info("recursive factors = " + factors);
776        }
777        return factors;
778    }
779
780
781    /**
782     * Normalize factorization. p'_i &gt; 0 for i &gt; 1 and p'_1 != 1 if k &gt;
783     * 1.
784     * @param F = [p_1,...,p_k].
785     * @return F' = [p'_1,...,p'_k].
786     */
787    public List<GenPolynomial<C>> normalizeFactorization(List<GenPolynomial<C>> F) {
788        if (F == null || F.size() <= 1) {
789            return F;
790        }
791        List<GenPolynomial<C>> Fp = new ArrayList<GenPolynomial<C>>(F.size());
792        GenPolynomial<C> f0 = F.get(0);
793        for (int i = 1; i < F.size(); i++) {
794            GenPolynomial<C> fi = F.get(i);
795            if (fi.signum() < 0) {
796                fi = fi.negate();
797                f0 = f0.negate();
798            }
799            Fp.add(fi);
800        }
801        if (!f0.isONE()) {
802            Fp.add(0, f0);
803        }
804        return Fp;
805    }
806}