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