001/*
002 * $Id: FactorAbsolute.java 5813 2018-04-25 21:29:28Z 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.TreeMap;
013
014import org.apache.log4j.Logger;
015
016import edu.jas.poly.AlgebraicNumber;
017import edu.jas.poly.AlgebraicNumberRing;
018import edu.jas.poly.GenPolynomial;
019import edu.jas.poly.GenPolynomialRing;
020import edu.jas.poly.PolyUtil;
021import edu.jas.structure.GcdRingElem;
022import edu.jas.structure.RingFactory;
023
024
025/**
026 * Absolute factorization algorithms class. This class contains implementations
027 * of methods for factorization over algebraically closed fields. The required
028 * field extension is computed along with the factors. The methods have been
029 * tested for prime fields of characteristic zero, that is for
030 * <code>BigRational</code>. It might eventually also be used for prime fields
031 * of non-zero characteristic, that is with <code>ModInteger</code>. The field
032 * extension may yet not be minimal.
033 * @author Heinz Kredel
034 * @param <C> coefficient type
035 */
036
037public abstract class FactorAbsolute<C extends GcdRingElem<C>> extends FactorAbstract<C> {
038
039
040    private static final Logger logger = Logger.getLogger(FactorAbsolute.class);
041
042
043    private static final boolean debug = logger.isDebugEnabled();
044
045
046    /*     
047     * Factorization engine for algebraic number coefficients.
048     */
049    //not possible here because of recursion AN -> Int|Mod -> AN -> ...
050    //public final FactorAbstract<AlgebraicNumber<C>> aengine;
051
052    /**
053     * No argument constructor. <b>Note:</b> can't use this constructor.
054     */
055    protected FactorAbsolute() {
056        throw new IllegalArgumentException("don't use this constructor");
057    }
058
059
060    /**
061     * Constructor.
062     * @param cfac coefficient ring factory.
063     */
064    public FactorAbsolute(RingFactory<C> cfac) {
065        super(cfac);
066        //GenPolynomialRing<C> fac = new GenPolynomialRing<C>(cfac,1);
067        //GenPolynomial<C> p = fac.univariate(0);
068        //AlgebraicNumberRing<C> afac = new AlgebraicNumberRing<C>(p);
069        //aengine = null; //FactorFactory.<C>getImplementation(afac); // hack
070    }
071
072
073    /**
074     * Get the String representation.
075     * @see java.lang.Object#toString()
076     */
077    @Override
078    public String toString() {
079        return getClass().getName();
080    }
081
082
083    /**
084     * GenPolynomial test if is absolute irreducible.
085     * @param P GenPolynomial.
086     * @return true if P is absolute irreducible, else false.
087     */
088    public boolean isAbsoluteIrreducible(GenPolynomial<C> P) {
089        if (!isIrreducible(P)) {
090            return false;
091        }
092        Factors<C> F = factorsAbsoluteIrreducible(P);
093        if (F.afac == null) {
094            return true;
095        } else if (F.afactors.size() > 2) {
096            return false;
097        } else { //F.size() == 2
098            boolean cnst = false;
099            for (GenPolynomial<AlgebraicNumber<C>> p : F.afactors) {
100                if (p.isConstant()) {
101                    cnst = true;
102                }
103            }
104            return cnst;
105        }
106    }
107
108
109    /**
110     * GenPolynomial absolute base factorization of a polynomial.
111     * @param P univariate GenPolynomial.
112     * @return factors map container: [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P
113     *         = prod_{i=1,...,k} p_i**e_i. <b>Note:</b> K(alpha) not yet
114     *         minimal.
115     */
116    // @Override
117    public FactorsMap<C> baseFactorsAbsolute(GenPolynomial<C> P) {
118        if (P == null) {
119            throw new IllegalArgumentException(this.getClass().getName() + " P == null");
120        }
121        SortedMap<GenPolynomial<C>, Long> factors = new TreeMap<GenPolynomial<C>, Long>();
122        if (P.isZERO()) {
123            return new FactorsMap<C>(P, factors);
124        }
125        //System.out.println("\nP_base = " + P);
126        GenPolynomialRing<C> pfac = P.ring; // K[x]
127        if (pfac.nvar > 1) {
128            //System.out.println("\nfacs_base: univ");
129            throw new IllegalArgumentException("only for univariate polynomials");
130        }
131        if (!pfac.coFac.isField()) {
132            //System.out.println("\nfacs_base: field");
133            throw new IllegalArgumentException("only for field coefficients");
134        }
135        if (P.degree(0) <= 1) {
136            factors.put(P, 1L);
137            return new FactorsMap<C>(P, factors);
138        }
139        // factor over K (=C)
140        SortedMap<GenPolynomial<C>, Long> facs = baseFactors(P);
141        if (debug && !isFactorization(P, facs)) {
142            System.out.println("facs   = " + facs);
143            throw new ArithmeticException("isFactorization = false");
144        }
145        if (logger.isInfoEnabled()) {
146            logger.info("all K factors = " + facs); // Q[X]
147            //System.out.println("\nall K factors = " + facs); // Q[X]
148        }
149        // factor over some K(alpha)
150        SortedMap<Factors<C>, Long> afactors = new TreeMap<Factors<C>, Long>();
151        for (Map.Entry<GenPolynomial<C>, Long> me : facs.entrySet()) {
152            GenPolynomial<C> p = me.getKey();
153            Long e = me.getValue(); //facs.get(p);
154            if (p.degree(0) <= 1) {
155                factors.put(p, e);
156            } else {
157                Factors<C> afacs = baseFactorsAbsoluteIrreducible(p);
158                //System.out.println("afacs   = " + afacs);
159                afactors.put(afacs, e);
160            }
161        }
162        //System.out.println("K(alpha) factors = " + factors);
163        return new FactorsMap<C>(P, factors, afactors);
164    }
165
166
167    /**
168     * GenPolynomial absolute base factorization of a squarefree polynomial.
169     * @param P squarefree and primitive univariate GenPolynomial.
170     * @return factors list container: [p_1,...,p_k] with P = prod_{i=1, ..., k}
171     *         p_i. <b>Note:</b> K(alpha) not yet minimal.
172     */
173    // @Override
174    public FactorsList<C> baseFactorsAbsoluteSquarefree(GenPolynomial<C> P) {
175        if (P == null) {
176            throw new IllegalArgumentException(this.getClass().getName() + " P == null");
177        }
178        List<GenPolynomial<C>> factors = new ArrayList<GenPolynomial<C>>();
179        if (P.isZERO()) {
180            return new FactorsList<C>(P, factors);
181        }
182        //System.out.println("\nP_base_sqf = " + P);
183        GenPolynomialRing<C> pfac = P.ring; // K[x]
184        if (pfac.nvar > 1) {
185            //System.out.println("facs_base_sqf: univ");
186            throw new IllegalArgumentException("only for univariate polynomials");
187        }
188        if (!pfac.coFac.isField()) {
189            //System.out.println("facs_base_sqf: field");
190            throw new IllegalArgumentException("only for field coefficients");
191        }
192        if (P.degree(0) <= 1) {
193            factors.add(P);
194            return new FactorsList<C>(P, factors);
195        }
196        // factor over K (=C)
197        List<GenPolynomial<C>> facs = baseFactorsSquarefree(P);
198        //System.out.println("facs_base_irred = " + facs);
199        if (debug && !isFactorization(P, facs)) {
200            throw new ArithmeticException("isFactorization = false");
201        }
202        if (logger.isInfoEnabled()) {
203            logger.info("all K factors = " + facs); // Q[X]
204            //System.out.println("\nall K factors = " + facs); // Q[X]
205        }
206        // factor over K(alpha)
207        List<Factors<C>> afactors = new ArrayList<Factors<C>>();
208        for (GenPolynomial<C> p : facs) {
209            //System.out.println("facs_base_sqf_p = " + p);
210            if (p.degree(0) <= 1) {
211                factors.add(p);
212            } else {
213                Factors<C> afacs = baseFactorsAbsoluteIrreducible(p);
214                //System.out.println("afacs_base_sqf = " + afacs);
215                if (logger.isInfoEnabled()) {
216                    logger.info("K(alpha) factors = " + afacs); // K(alpha)[X]
217                }
218                afactors.add(afacs);
219            }
220        }
221        //System.out.println("K(alpha) factors = " + factors);
222        return new FactorsList<C>(P, factors, afactors);
223    }
224
225
226    /**
227     * GenPolynomial base absolute factorization of a irreducible polynomial.
228     * @param P irreducible! univariate GenPolynomial.
229     * @return factors container: [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i
230     *         in K(alpha)[x] for suitable alpha and p_i irreducible over L[x],
231     *         where K \subset K(alpha) \subset L is an algebraically closed
232     *         field over K. <b>Note:</b> K(alpha) not yet minimal.
233     */
234    public Factors<C> baseFactorsAbsoluteIrreducible(GenPolynomial<C> P) {
235        if (P == null) {
236            throw new IllegalArgumentException(this.getClass().getName() + " P == null");
237        }
238        if (P.isZERO()) {
239            return new Factors<C>(P);
240        }
241        //System.out.println("\nP_base_irred = " + P);
242        GenPolynomialRing<C> pfac = P.ring; // K[x]
243        if (pfac.nvar > 1) {
244            //System.out.println("facs_base_irred: univ");
245            throw new IllegalArgumentException("only for univariate polynomials");
246        }
247        if (!pfac.coFac.isField()) {
248            //System.out.println("facs_base_irred: field");
249            throw new IllegalArgumentException("only for field coefficients");
250        }
251        if (P.degree(0) <= 1) {
252            return new Factors<C>(P);
253        }
254        // setup field extension K(alpha) where alpha = z_xx
255        //String[] vars = new String[] { "z_" + Math.abs(P.hashCode() % 1000) };
256        String[] vars = pfac.newVars("z_");
257        pfac = pfac.copy();
258        vars = pfac.setVars(vars);
259        GenPolynomial<C> aP = pfac.copy(P); // hack to exchange the variables
260        AlgebraicNumberRing<C> afac = new AlgebraicNumberRing<C>(aP, true); // since irreducible
261        if (logger.isInfoEnabled()) {
262            logger.info("K(alpha) = " + afac);
263            logger.info("K(alpha) = " + afac.toScript());
264            //System.out.println("K(alpha) = " + afac);
265        }
266        GenPolynomialRing<AlgebraicNumber<C>> pafac = new GenPolynomialRing<AlgebraicNumber<C>>(afac,
267                        aP.ring.nvar, aP.ring.tord, /*old*/vars);
268        // convert to K(alpha)
269        GenPolynomial<AlgebraicNumber<C>> Pa = PolyUtil.<C> convertToAlgebraicCoefficients(pafac, P);
270        if (logger.isInfoEnabled()) {
271            logger.info("P over K(alpha) = " + Pa);
272            //logger.info("P over K(alpha) = " + Pa.toScript()); 
273            //System.out.println("P in K(alpha) = " + Pa);
274        }
275        // factor over K(alpha)
276        FactorAbstract<AlgebraicNumber<C>> engine = FactorFactory.<C> getImplementation(afac);
277        //System.out.println("K(alpha) engine = " + engine);
278        List<GenPolynomial<AlgebraicNumber<C>>> factors = engine.baseFactorsSquarefree(Pa);
279        //System.out.println("factors = " + factors);
280        if (logger.isInfoEnabled()) {
281            logger.info("factors over K(alpha) = " + factors);
282            //System.out.println("factors over K(alpha) = " + factors);
283        }
284        List<GenPolynomial<AlgebraicNumber<C>>> faca = new ArrayList<GenPolynomial<AlgebraicNumber<C>>>(
285                        factors.size());
286        List<Factors<AlgebraicNumber<C>>> facar = new ArrayList<Factors<AlgebraicNumber<C>>>();
287        for (GenPolynomial<AlgebraicNumber<C>> fi : factors) {
288            if (fi.degree(0) <= 1) {
289                faca.add(fi);
290            } else {
291                //System.out.println("fi.deg > 1 = " + fi);
292                FactorAbsolute<AlgebraicNumber<C>> aengine = (FactorAbsolute<AlgebraicNumber<C>>) FactorFactory
293                                .<C> getImplementation(afac);
294                Factors<AlgebraicNumber<C>> fif = aengine.baseFactorsAbsoluteIrreducible(fi);
295                //System.out.println("fif = " + fif);
296                facar.add(fif);
297            }
298        }
299        if (facar.size() == 0) {
300            facar = null;
301        }
302        // find minimal field extension K(beta) \subset K(alpha)
303        return new Factors<C>(P, afac, Pa, faca, facar);
304    }
305
306
307    /**
308     * Univariate GenPolynomial algebraic partial fraction decomposition,
309     * Absolute factorization for elementary integration algorithm to linear factors.
310     * @param A univariate GenPolynomial, deg(A) < deg(P).
311     * @param P univariate squarefree GenPolynomial, gcd(A,P) == 1.
312     * @return partial fraction container.
313     */
314    public PartialFraction<C> baseAlgebraicPartialFraction(GenPolynomial<C> A, GenPolynomial<C> P) {
315        if (P == null || P.isZERO()) {
316            throw new IllegalArgumentException(" P == null or P == 0");
317        }
318        if (A == null || A.isZERO()) {
319            throw new IllegalArgumentException(" A == null or A == 0");
320            // PartialFraction(A,P,al,pl,empty,empty)
321        }
322        //System.out.println("\nP_base_algeb_part = " + P);
323        GenPolynomialRing<C> pfac = P.ring; // K[x]
324        if (pfac.nvar > 1) {
325            //System.out.println("facs_base_irred: univ");
326            throw new IllegalArgumentException("only for univariate polynomials");
327        }
328        if (!pfac.coFac.isField()) {
329            //System.out.println("facs_base_irred: field");
330            throw new IllegalArgumentException("only for field coefficients");
331        }
332        List<C> cfactors = new ArrayList<C>();
333        List<GenPolynomial<C>> cdenom = new ArrayList<GenPolynomial<C>>();
334        List<AlgebraicNumber<C>> afactors = new ArrayList<AlgebraicNumber<C>>();
335        List<GenPolynomial<AlgebraicNumber<C>>> adenom = new ArrayList<GenPolynomial<AlgebraicNumber<C>>>();
336
337        // P linear
338        if (P.degree(0) <= 1) {
339            cfactors.add(A.leadingBaseCoefficient());
340            cdenom.add(P);
341            return new PartialFraction<C>(A, P, cfactors, cdenom, afactors, adenom);
342        }
343        List<GenPolynomial<C>> Pfac = baseFactorsSquarefree(P);
344        //System.out.println("\nPfac = " + Pfac);
345
346        List<GenPolynomial<C>> Afac = engine.basePartialFraction(A, Pfac);
347
348        GenPolynomial<C> A0 = Afac.remove(0);
349        if (!A0.isZERO()) {
350            throw new ArithmeticException(" A0 != 0: deg(A)>= deg(P)");
351        }
352
353        // algebraic and linear factors
354        int i = 0;
355        for (GenPolynomial<C> pi : Pfac) {
356            GenPolynomial<C> ai = Afac.get(i++);
357            if (pi.degree(0) <= 1) {
358                cfactors.add(ai.leadingBaseCoefficient());
359                cdenom.add(pi);
360                continue;
361            }
362            PartialFraction<C> pf = baseAlgebraicPartialFractionIrreducibleAbsolute(ai, pi);
363            //PartialFraction<C> pf = baseAlgebraicPartialFractionIrreducible(ai,pi);
364            cfactors.addAll(pf.cfactors);
365            cdenom.addAll(pf.cdenom);
366            afactors.addAll(pf.afactors);
367            adenom.addAll(pf.adenom);
368        }
369        return new PartialFraction<C>(A, P, cfactors, cdenom, afactors, adenom);
370    }
371
372
373    /**
374     * Univariate GenPolynomial algebraic partial fraction decomposition, via
375     * absolute factorization to linear factors.
376     * @param A univariate GenPolynomial, deg(A) < deg(P).
377     * @param P univariate irreducible GenPolynomial, gcd(A,P) == 1.
378     * @return partial fraction container.
379     */
380    @SuppressWarnings("cast")
381    public PartialFraction<C> baseAlgebraicPartialFractionIrreducibleAbsolute(GenPolynomial<C> A,
382                    GenPolynomial<C> P) {
383        if (P == null || P.isZERO()) {
384            throw new IllegalArgumentException(" P == null or P == 0");
385        }
386        //System.out.println("\nP_base_algeb_part = " + P);
387        GenPolynomialRing<C> pfac = P.ring; // K[x]
388        if (pfac.nvar > 1) {
389            //System.out.println("facs_base_irred: univ");
390            throw new IllegalArgumentException("only for univariate polynomials");
391        }
392        if (!pfac.coFac.isField()) {
393            //System.out.println("facs_base_irred: field");
394            throw new IllegalArgumentException("only for field coefficients");
395        }
396        List<C> cfactors = new ArrayList<C>();
397        List<GenPolynomial<C>> cdenom = new ArrayList<GenPolynomial<C>>();
398        List<AlgebraicNumber<C>> afactors = new ArrayList<AlgebraicNumber<C>>();
399        List<GenPolynomial<AlgebraicNumber<C>>> adenom = new ArrayList<GenPolynomial<AlgebraicNumber<C>>>();
400
401        // P linear
402        if (P.degree(0) <= 1) {
403            cfactors.add(A.leadingBaseCoefficient());
404            cdenom.add(P);
405            return new PartialFraction<C>(A, P, cfactors, cdenom, afactors, adenom);
406        }
407
408        // non linear case
409        Factors<C> afacs = factorsAbsoluteIrreducible(P);
410        //System.out.println("linear algebraic factors = " + afacs);
411        //System.out.println("afactors      = " + afacs.afactors);
412        //System.out.println("arfactors     = " + afacs.arfactors);
413        //System.out.println("arfactors pol = " + afacs.arfactors.get(0).poly);
414        //System.out.println("arfactors2    = " + afacs.arfactors.get(0).afactors);
415
416        List<GenPolynomial<AlgebraicNumber<C>>> fact = afacs.getFactors();
417        //System.out.println("factors       = " + fact);
418        GenPolynomial<AlgebraicNumber<C>> Pa = afacs.apoly;
419        GenPolynomial<AlgebraicNumber<C>> Aa = PolyUtil.<C> convertToRecAlgebraicCoefficients(1, Pa.ring, A);
420
421        GreatestCommonDivisorAbstract<AlgebraicNumber<C>> aengine = GCDFactory.getProxy(afacs.afac);
422        //System.out.println("denom         = " + Pa);
423        //System.out.println("numer         = " + Aa);
424        List<GenPolynomial<AlgebraicNumber<C>>> numers = aengine.basePartialFraction(Aa, fact);
425        //System.out.println("part frac     = " + numers);
426        GenPolynomial<AlgebraicNumber<C>> A0 = numers.remove(0);
427        if (!A0.isZERO()) {
428            throw new ArithmeticException(" A0 != 0: deg(A)>= deg(P)");
429        }
430        int i = 0;
431        for (GenPolynomial<AlgebraicNumber<C>> fa : fact) {
432            GenPolynomial<AlgebraicNumber<C>> an = numers.get(i++);
433            if (fa.degree(0) <= 1) {
434                afactors.add(an.leadingBaseCoefficient());
435                adenom.add(fa);
436                continue;
437            }
438            System.out.println("fa = " + fa);
439            Factors<AlgebraicNumber<C>> faf = afacs.getFactor(fa);
440            System.out.println("faf = " + faf);
441            List<GenPolynomial<AlgebraicNumber<AlgebraicNumber<C>>>> fafact = faf.getFactors();
442            GenPolynomial<AlgebraicNumber<AlgebraicNumber<C>>> Aaa = PolyUtil
443                            .<AlgebraicNumber<C>> convertToRecAlgebraicCoefficients(1, faf.apoly.ring, an);
444
445            GreatestCommonDivisorAbstract<AlgebraicNumber<AlgebraicNumber<C>>> aaengine = GCDFactory
446                            .getImplementation(faf.afac);
447
448            List<GenPolynomial<AlgebraicNumber<AlgebraicNumber<C>>>> anumers = aaengine
449                            .basePartialFraction(Aaa, fafact);
450            System.out.println("algeb part frac = " + anumers);
451            GenPolynomial<AlgebraicNumber<AlgebraicNumber<C>>> A0a = anumers.remove(0);
452            if (!A0a.isZERO()) {
453                throw new ArithmeticException(" A0 != 0: deg(A)>= deg(P)");
454            }
455            int k = 0;
456            for (GenPolynomial<AlgebraicNumber<AlgebraicNumber<C>>> faa : fafact) {
457                GenPolynomial<AlgebraicNumber<AlgebraicNumber<C>>> ana = anumers.get(k++);
458                System.out.println("faa = " + faa);
459                System.out.println("ana = " + ana);
460                if (faa.degree(0) > 1) {
461                    throw new ArithmeticException(" faa not linear");
462                }
463                GenPolynomial<AlgebraicNumber<C>> ana1 = (GenPolynomial<AlgebraicNumber<C>>) (GenPolynomial) ana;
464                GenPolynomial<AlgebraicNumber<C>> faa1 = (GenPolynomial<AlgebraicNumber<C>>) (GenPolynomial) faa;
465
466                afactors.add(ana1.leadingBaseCoefficient());
467                adenom.add(faa1);
468            }
469        }
470        return new PartialFraction<C>(A, P, cfactors, cdenom, afactors, adenom);
471    }
472
473
474    /**
475     * GenPolynomial absolute factorization of a polynomial.
476     * @param P GenPolynomial.
477     * @return factors map container: [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P
478     *         = prod_{i=1,...,k} p_i**e_i. <b>Note:</b> K(alpha) not yet
479     *         minimal.
480     */
481    public FactorsMap<C> factorsAbsolute(GenPolynomial<C> P) {
482        if (P == null) {
483            throw new IllegalArgumentException(this.getClass().getName() + " P == null");
484        }
485        SortedMap<GenPolynomial<C>, Long> factors = new TreeMap<GenPolynomial<C>, Long>();
486        if (P.isZERO()) {
487            return new FactorsMap<C>(P, factors);
488        }
489        //System.out.println("\nP_mult = " + P);
490        GenPolynomialRing<C> pfac = P.ring; // K[x]
491        if (pfac.nvar <= 1) {
492            return baseFactorsAbsolute(P);
493        }
494        if (!pfac.coFac.isField()) {
495            throw new IllegalArgumentException("only for field coefficients");
496        }
497        if (P.degree() <= 1) {
498            factors.put(P, 1L);
499            return new FactorsMap<C>(P, factors);
500        }
501        // factor over K (=C)
502        SortedMap<GenPolynomial<C>, Long> facs = factors(P);
503        if (debug && !isFactorization(P, facs)) {
504            throw new ArithmeticException("isFactorization = false");
505        }
506        if (logger.isInfoEnabled()) {
507            logger.info("all K factors = " + facs); // Q[X]
508            //System.out.println("\nall K factors = " + facs); // Q[X]
509        }
510        SortedMap<Factors<C>, Long> afactors = new TreeMap<Factors<C>, Long>();
511        // factor over K(alpha)
512        for (Map.Entry<GenPolynomial<C>, Long> me : facs.entrySet()) {
513            GenPolynomial<C> p = me.getKey();
514            Long e = me.getValue(); //facs.get(p);
515            if (p.degree() <= 1) {
516                factors.put(p, e);
517            } else {
518                Factors<C> afacs = factorsAbsoluteIrreducible(p);
519                if (afacs.afac == null) { // absolute irreducible
520                    factors.put(p, e);
521                } else {
522                    afactors.put(afacs, e);
523                }
524            }
525        }
526        //System.out.println("K(alpha) factors multi = " + factors);
527        return new FactorsMap<C>(P, factors, afactors);
528    }
529
530
531    /**
532     * GenPolynomial absolute factorization of a squarefree polynomial.
533     * @param P squarefree and primitive GenPolynomial.
534     * @return factors list container: [p_1,...,p_k] with P = prod_{i=1, ..., k}
535     *         p_i. <b>Note:</b> K(alpha) not yet minimal.
536     */
537    // @Override
538    public FactorsList<C> factorsAbsoluteSquarefree(GenPolynomial<C> P) {
539        if (P == null) {
540            throw new IllegalArgumentException(this.getClass().getName() + " P == null");
541        }
542        List<GenPolynomial<C>> factors = new ArrayList<GenPolynomial<C>>();
543        if (P.isZERO()) {
544            return new FactorsList<C>(P, factors);
545        }
546        //System.out.println("\nP = " + P);
547        GenPolynomialRing<C> pfac = P.ring; // K[x]
548        if (pfac.nvar <= 1) {
549            return baseFactorsAbsoluteSquarefree(P);
550        }
551        if (!pfac.coFac.isField()) {
552            throw new IllegalArgumentException("only for field coefficients");
553        }
554        if (P.degree() <= 1) {
555            factors.add(P);
556            return new FactorsList<C>(P, factors);
557        }
558        // factor over K (=C)
559        List<GenPolynomial<C>> facs = factorsSquarefree(P);
560        if (debug && !isFactorization(P, facs)) {
561            throw new ArithmeticException("isFactorization = false");
562        }
563        if (logger.isInfoEnabled()) {
564            logger.info("all K factors = " + facs); // Q[X]
565            //System.out.println("\nall K factors = " + facs); // Q[X]
566        }
567        List<Factors<C>> afactors = new ArrayList<Factors<C>>();
568        // factor over K(alpha)
569        for (GenPolynomial<C> p : facs) {
570            if (p.degree() <= 1) {
571                factors.add(p);
572            } else {
573                Factors<C> afacs = factorsAbsoluteIrreducible(p);
574                if (debug) {
575                    logger.info("K(alpha) factors = " + afacs); // K(alpha)[X]
576                }
577                if (afacs.afac == null) { // absolute irreducible
578                    factors.add(p);
579                } else {
580                    afactors.add(afacs);
581                }
582            }
583        }
584        //System.out.println("K(alpha) factors = " + factors);
585        return new FactorsList<C>(P, factors, afactors);
586    }
587
588
589    /**
590     * GenPolynomial absolute factorization of a irreducible polynomial.
591     * @param P irreducible! GenPolynomial.
592     * @return factors container: [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i
593     *         in K(alpha)[x] for suitable alpha and p_i irreducible over L[x],
594     *         where K \subset K(alpha) \subset L is an algebraically closed
595     *         field over K. <b>Note:</b> K(alpha) not yet minimal.
596     */
597    public Factors<C> factorsAbsoluteIrreducible(GenPolynomial<C> P) {
598        if (P == null) {
599            throw new IllegalArgumentException(this.getClass().getName() + " P == null");
600        }
601        if (P.isZERO()) {
602            return new Factors<C>(P);
603        }
604        GenPolynomialRing<C> pfac = P.ring; // K[x]
605        if (pfac.nvar <= 1) {
606            return baseFactorsAbsoluteIrreducible(P);
607        }
608        if (!pfac.coFac.isField()) {
609            throw new IllegalArgumentException("only for field coefficients");
610        }
611        //List<GenPolynomial<C>> factors = new ArrayList<GenPolynomial<C>>();
612        if (P.degree() <= 1) {
613            return new Factors<C>(P);
614        }
615        // find field extension K(alpha)
616        GenPolynomial<C> up = P;
617        RingFactory<C> cf = pfac.coFac;
618        long cr = cf.characteristic().longValue(); // char might be larger
619        if (cr == 0L) {
620            cr = Long.MAX_VALUE;
621        }
622        long rp = 0L;
623        for (int i = 0; i < (pfac.nvar - 1); i++) {
624            rp = 0L;
625            GenPolynomialRing<C> nfac = pfac.contract(1);
626            String[] vn = new String[] { pfac.getVars()[pfac.nvar - 1] };
627            GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(nfac, 1,
628                            pfac.tord, vn);
629            GenPolynomial<GenPolynomial<C>> upr = PolyUtil.<C> recursive(rfac, up);
630            //System.out.println("upr = " + upr);
631            GenPolynomial<C> ep;
632            do {
633                if (rp >= cr) {
634                    throw new ArithmeticException("elements of prime field exhausted: " + cr);
635                }
636                C r = cf.fromInteger(rp); //cf.random(rp);
637                //System.out.println("r   = " + r);
638                ep = PolyUtil.<C> evaluateMainRecursive(nfac, upr, r);
639                //System.out.println("ep  = " + ep);
640                rp++;
641            } while (!isSquarefree(ep) /*todo: || ep.degree() <= 1*/); // max deg
642            up = ep;
643            pfac = nfac;
644        }
645        up = up.monic();
646        if (debug) {
647            logger.info("P(" + rp + ") = " + up);
648            //System.out.println("up  = " + up);
649        }
650        if (debug && !isSquarefree(up)) {
651            throw new ArithmeticException("not irreducible up = " + up);
652        }
653        if (up.degree(0) <= 1) {
654            return new Factors<C>(P);
655        }
656        // find irreducible factor of up
657        List<GenPolynomial<C>> UF = baseFactorsSquarefree(up);
658        //System.out.println("UF  = " + UF);
659        FactorsList<C> aUF = baseFactorsAbsoluteSquarefree(up);
660        //System.out.println("aUF  = " + aUF);
661        AlgebraicNumberRing<C> arfac = aUF.findExtensionField();
662        //System.out.println("arfac  = " + arfac);
663
664        long e = up.degree(0);
665        // search factor polynomial with smallest degree 
666        for (int i = 0; i < UF.size(); i++) {
667            GenPolynomial<C> upi = UF.get(i);
668            long d = upi.degree(0);
669            if (1 <= d && d <= e) {
670                up = upi;
671                e = up.degree(0);
672            }
673        }
674        if (up.degree(0) <= 1) {
675            return new Factors<C>(P);
676        }
677        if (debug) {
678            logger.info("field extension by " + up);
679        }
680
681        List<GenPolynomial<AlgebraicNumber<C>>> afactors = new ArrayList<GenPolynomial<AlgebraicNumber<C>>>();
682
683        // setup field extension K(alpha)
684        //String[] vars = new String[] { "z_" + Math.abs(up.hashCode() % 1000) };
685        String[] vars = pfac.newVars("z_");
686        pfac = pfac.copy();
687        //String[] ovars = 
688        pfac.setVars(vars); // side effects! 
689        //GenPolynomial<C> aup = pfac.copy(up); // hack to exchange the variables
690        //AlgebraicNumberRing<C> afac = new AlgebraicNumberRing<C>(aup,true); // since irreducible
691        AlgebraicNumberRing<C> afac = arfac;
692        int depth = afac.depth();
693        //System.out.println("afac = " + afac);
694        GenPolynomialRing<AlgebraicNumber<C>> pafac = new GenPolynomialRing<AlgebraicNumber<C>>(afac,
695                        P.ring.nvar, P.ring.tord, P.ring.getVars());
696        //System.out.println("pafac = " + pafac);
697        // convert to K(alpha)
698        GenPolynomial<AlgebraicNumber<C>> Pa = PolyUtil.<C> convertToRecAlgebraicCoefficients(depth, pafac,
699                        P);
700        //System.out.println("Pa = " + Pa);
701        // factor over K(alpha)
702        FactorAbstract<AlgebraicNumber<C>> engine = FactorFactory.<C> getImplementation(afac);
703        afactors = engine.factorsSquarefree(Pa);
704        if (debug) {
705            logger.info("K(alpha) factors multi = " + afactors);
706            //System.out.println("K(alpha) factors = " + afactors);
707        }
708        if (afactors.size() <= 1) {
709            return new Factors<C>(P);
710        }
711        // normalize first factor to monic
712        GenPolynomial<AlgebraicNumber<C>> p1 = afactors.get(0);
713        AlgebraicNumber<C> p1c = p1.leadingBaseCoefficient();
714        if (!p1c.isONE()) {
715            GenPolynomial<AlgebraicNumber<C>> p2 = afactors.get(1);
716            afactors.remove(p1);
717            afactors.remove(p2);
718            p1 = p1.divide(p1c);
719            p2 = p2.multiply(p1c);
720            afactors.add(p1);
721            afactors.add(p2);
722        }
723        // recursion for splitting field
724        // find minimal field extension K(beta) \subset K(alpha)
725        return new Factors<C>(P, afac, Pa, afactors);
726    }
727
728
729    /**
730     * GenPolynomial is absolute factorization.
731     * @param facs factors container.
732     * @return true if P = prod_{i=1,...,r} p_i, else false.
733     */
734    public boolean isAbsoluteFactorization(Factors<C> facs) {
735        if (facs == null) {
736            throw new IllegalArgumentException("facs may not be null");
737        }
738        if (facs.afac == null) {
739            return true;
740        }
741        GenPolynomial<AlgebraicNumber<C>> fa = facs.apoly;
742        GenPolynomialRing<AlgebraicNumber<C>> pafac = fa.ring;
743        GenPolynomial<AlgebraicNumber<C>> t = pafac.getONE();
744        for (GenPolynomial<AlgebraicNumber<C>> f : facs.afactors) {
745            t = t.multiply(f);
746        }
747        //return fa.equals(t) || fa.equals(t.negate());
748        boolean b = fa.equals(t) || fa.equals(t.negate());
749        if (b) {
750            return b;
751        }
752        if (facs.arfactors == null) {
753            return false;
754        }
755        for (Factors<AlgebraicNumber<C>> arp : facs.arfactors) {
756            t = t.multiply(arp.poly);
757        }
758        b = fa.equals(t) || fa.equals(t.negate());
759        if (!b) {
760            System.out.println("\nFactors: " + facs);
761            System.out.println("fa = " + fa);
762            System.out.println("t = " + t);
763        }
764        return b;
765    }
766
767
768    /**
769     * GenPolynomial is absolute factorization.
770     * @param facs factors list container.
771     * @return true if P = prod_{i=1,...,r} p_i, else false.
772     */
773    public boolean isAbsoluteFactorization(FactorsList<C> facs) {
774        if (facs == null) {
775            throw new IllegalArgumentException("facs may not be null");
776        }
777        GenPolynomial<C> P = facs.poly;
778        GenPolynomial<C> t = P.ring.getONE();
779        for (GenPolynomial<C> f : facs.factors) {
780            t = t.multiply(f);
781        }
782        if (P.equals(t) || P.equals(t.negate())) {
783            return true;
784        }
785        if (facs.afactors == null) {
786            return false;
787        }
788        for (Factors<C> fs : facs.afactors) {
789            if (!isAbsoluteFactorization(fs)) {
790                return false;
791            }
792            t = t.multiply(facs.poly);
793        }
794        //return P.equals(t) || P.equals(t.negate());
795        boolean b = P.equals(t) || P.equals(t.negate());
796        if (!b) {
797            System.out.println("\nFactorsList: " + facs);
798            System.out.println("P = " + P);
799            System.out.println("t = " + t);
800        }
801        return b;
802    }
803
804
805    /**
806     * GenPolynomial is absolute factorization.
807     * @param facs factors map container.
808     * @return true if P = prod_{i=1,...,k} p_i**e_i , else false.
809     */
810    public boolean isAbsoluteFactorization(FactorsMap<C> facs) {
811        if (facs == null) {
812            throw new IllegalArgumentException("facs may not be null");
813        }
814        GenPolynomial<C> P = facs.poly;
815        GenPolynomial<C> t = P.ring.getONE();
816        for (Map.Entry<GenPolynomial<C>, Long> me : facs.factors.entrySet()) {
817            GenPolynomial<C> f = me.getKey();
818            long e = me.getValue();
819            GenPolynomial<C> g = f.power(e);
820            t = t.multiply(g);
821        }
822        if (P.equals(t) || P.equals(t.negate())) {
823            return true;
824        }
825        if (facs.afactors == null) {
826            return false;
827        }
828        for (Map.Entry<Factors<C>, Long> me : facs.afactors.entrySet()) {
829            Factors<C> fs = me.getKey();
830            if (!isAbsoluteFactorization(fs)) {
831                return false;
832            }
833            long e = me.getValue();
834            GenPolynomial<C> g = fs.poly.power(e);
835            t = t.multiply(g);
836        }
837        boolean b = P.equals(t) || P.equals(t.negate());
838        if (!b) {
839            System.out.println("\nFactorsMap: " + facs);
840            System.out.println("P = " + P);
841            System.out.println("t = " + t);
842        }
843        return b;
844    }
845
846}