001/*
002 * $Id: FactorAbsolute.java 5047 2014-12-30 17:44:11Z 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.Power;
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 = Logger.getLogger(FactorAbsolute.class);
042
043
044    private 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 or Rothstein-Trager algorithm.
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,
376     * Rothstein-Trager algorithm.
377     * @param A univariate GenPolynomial, deg(A) < deg(P).
378     * @param P univariate squarefree GenPolynomial, gcd(A,P) == 1.
379     * @return partial fraction container.
380     */
381    @Deprecated
382    public PartialFraction<C> baseAlgebraicPartialFractionIrreducible(GenPolynomial<C> A, 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        // deriviative
409        GenPolynomial<C> Pp = PolyUtil.<C> baseDeriviative(P);
410        //no: Pp = Pp.monic();
411        //System.out.println("\nP  = " + P);
412        //System.out.println("Pp = " + Pp);
413
414        // Q[t]
415        String[] vars = new String[] { "t" };
416        GenPolynomialRing<C> cfac = new GenPolynomialRing<C>(pfac.coFac, 1, pfac.tord, vars);
417        GenPolynomial<C> t = cfac.univariate(0);
418        //System.out.println("t = " + t);
419
420        // Q[x][t]
421        GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(pfac, cfac); // sic
422        //System.out.println("rfac = " + rfac.toScript());
423
424        // transform polynomials to bi-variate polynomial
425        GenPolynomial<GenPolynomial<C>> Ac = PolyUfdUtil.<C> introduceLowerVariable(rfac, A);
426        //System.out.println("Ac = " + Ac);
427        GenPolynomial<GenPolynomial<C>> Pc = PolyUfdUtil.<C> introduceLowerVariable(rfac, P);
428        //System.out.println("Pc = " + Pc);
429        GenPolynomial<GenPolynomial<C>> Pcp = PolyUfdUtil.<C> introduceLowerVariable(rfac, Pp);
430        //System.out.println("Pcp = " + Pcp);
431
432        // Q[t][x]
433        GenPolynomialRing<GenPolynomial<C>> rfac1 = Pc.ring;
434        //System.out.println("rfac1 = " + rfac1.toScript());
435
436        // A - t P'
437        GenPolynomial<GenPolynomial<C>> tc = rfac1.getONE().multiply(t);
438        //System.out.println("tc = " + tc);
439        GenPolynomial<GenPolynomial<C>> At = Ac.subtract(tc.multiply(Pcp));
440        //System.out.println("At = " + At);
441
442        GreatestCommonDivisorSubres<C> engine = new GreatestCommonDivisorSubres<C>();
443        // = GCDFactory.<C>getImplementation( cfac.coFac );
444        GreatestCommonDivisorAbstract<AlgebraicNumber<C>> aengine = null;
445
446        GenPolynomial<GenPolynomial<C>> Rc = engine.recursiveUnivariateResultant(Pc, At);
447        //System.out.println("Rc = " + Rc);
448        GenPolynomial<C> res = Rc.leadingBaseCoefficient();
449        //no: res = res.monic();
450        //System.out.println("\nres = " + res);
451
452        SortedMap<GenPolynomial<C>, Long> resfac = baseFactors(res);
453        //System.out.println("resfac = " + resfac + "\n");
454
455        for (GenPolynomial<C> r : resfac.keySet()) {
456            //System.out.println("\nr(t) = " + r);
457            if (r.isConstant()) {
458                continue;
459            }
460            //             if ( r.degree(0) <= 1L ) {
461            //                 System.out.println("warning linear factor in resultant ignored");
462            //                 continue;
463            //                 //throw new ArithmeticException("input not irreducible");
464            //             }
465            //vars = new String[] { "z_" + Math.abs(r.hashCode() % 1000) };
466            vars = pfac.newVars("z_");
467            pfac = pfac.copy();
468            //String[] ovars = 
469            pfac.setVars(vars);
470            r = pfac.copy(r); // hack to exchange the variables
471            //System.out.println("r(z_) = " + r);
472            AlgebraicNumberRing<C> afac = new AlgebraicNumberRing<C>(r, true); // since irreducible
473            logger.debug("afac = " + afac.toScript());
474            AlgebraicNumber<C> a = afac.getGenerator();
475            //no: a = a.negate();
476            //System.out.println("a = " + a);
477
478            // K(alpha)[x]
479            GenPolynomialRing<AlgebraicNumber<C>> pafac = new GenPolynomialRing<AlgebraicNumber<C>>(afac,
480                            Pc.ring);
481            //System.out.println("pafac = " + pafac.toScript());
482
483            // convert to K(alpha)[x]
484            GenPolynomial<AlgebraicNumber<C>> Pa = PolyUtil.<C> convertToAlgebraicCoefficients(pafac, P);
485            //System.out.println("Pa = " + Pa);
486            GenPolynomial<AlgebraicNumber<C>> Pap = PolyUtil.<C> convertToAlgebraicCoefficients(pafac, Pp);
487            //System.out.println("Pap = " + Pap);
488            GenPolynomial<AlgebraicNumber<C>> Aa = PolyUtil.<C> convertToAlgebraicCoefficients(pafac, A);
489            //System.out.println("Aa = " + Aa);
490
491            // A - a P'
492            GenPolynomial<AlgebraicNumber<C>> Ap = Aa.subtract(Pap.multiply(a));
493            //System.out.println("Ap = " + Ap);
494
495            if (aengine == null) {
496                aengine = GCDFactory.<AlgebraicNumber<C>> getImplementation(afac);
497                //System.out.println("aengine = " + aengine);
498            }
499            GenPolynomial<AlgebraicNumber<C>> Ga = aengine.baseGcd(Pa, Ap);
500            //System.out.println("Ga = " + Ga);
501            if (Ga.isConstant()) {
502                //System.out.println("warning constant gcd ignored");
503                continue;
504            }
505            afactors.add(a);
506            adenom.add(Ga);
507            // quadratic case
508            if (P.degree(0) == 2 && Ga.degree(0) == 1) {
509                GenPolynomial<AlgebraicNumber<C>>[] qra = PolyUtil
510                                .<AlgebraicNumber<C>> basePseudoQuotientRemainder(Pa, Ga);
511                GenPolynomial<AlgebraicNumber<C>> Qa = qra[0];
512                if (!qra[1].isZERO()) {
513                    throw new ArithmeticException("remainder not zero");
514                }
515                //System.out.println("Qa = " + Qa);
516                afactors.add(a.negate());
517                adenom.add(Qa);
518            }
519            // if (P.degree(0) == 3 && Ga.degree(0) == 1) {
520            //     GenPolynomial<AlgebraicNumber<C>>[] qra = PolyUtil
521            //                   .<AlgebraicNumber<C>> basePseudoQuotientRemainder(Pa, Ga);
522            //     GenPolynomial<AlgebraicNumber<C>> Qa = qra[0];
523            //     if (!qra[1].isZERO()) {
524            //         throw new ArithmeticException("remainder not zero");
525            //     }
526            //     System.out.println("Qa3 = " + Qa);
527            //     //afactors.add( a.negate() );
528            //     //adenom.add( Qa );
529            // }
530        }
531        return new PartialFraction<C>(A, P, cfactors, cdenom, afactors, adenom);
532    }
533
534
535    /**
536     * Univariate GenPolynomial algebraic partial fraction decomposition, via
537     * absolute factorization to linear factors.
538     * @param A univariate GenPolynomial, deg(A) < deg(P).
539     * @param P univariate squarefree GenPolynomial, gcd(A,P) == 1.
540     * @return partial fraction container.
541     */
542    @SuppressWarnings("cast")
543    public PartialFraction<C> baseAlgebraicPartialFractionIrreducibleAbsolute(GenPolynomial<C> A,
544                    GenPolynomial<C> P) {
545        if (P == null || P.isZERO()) {
546            throw new IllegalArgumentException(" P == null or P == 0");
547        }
548        //System.out.println("\nP_base_algeb_part = " + P);
549        GenPolynomialRing<C> pfac = P.ring; // K[x]
550        if (pfac.nvar > 1) {
551            //System.out.println("facs_base_irred: univ");
552            throw new IllegalArgumentException("only for univariate polynomials");
553        }
554        if (!pfac.coFac.isField()) {
555            //System.out.println("facs_base_irred: field");
556            throw new IllegalArgumentException("only for field coefficients");
557        }
558        List<C> cfactors = new ArrayList<C>();
559        List<GenPolynomial<C>> cdenom = new ArrayList<GenPolynomial<C>>();
560        List<AlgebraicNumber<C>> afactors = new ArrayList<AlgebraicNumber<C>>();
561        List<GenPolynomial<AlgebraicNumber<C>>> adenom = new ArrayList<GenPolynomial<AlgebraicNumber<C>>>();
562
563        // P linear
564        if (P.degree(0) <= 1) {
565            cfactors.add(A.leadingBaseCoefficient());
566            cdenom.add(P);
567            return new PartialFraction<C>(A, P, cfactors, cdenom, afactors, adenom);
568        }
569
570        // non linear case
571        Factors<C> afacs = factorsAbsoluteIrreducible(P);
572        //System.out.println("linear algebraic factors = " + afacs);
573
574        //System.out.println("afactors      = " + afacs.afactors);
575        //System.out.println("arfactors     = " + afacs.arfactors);
576        //System.out.println("arfactors pol = " + afacs.arfactors.get(0).poly);
577        //System.out.println("arfactors2    = " + afacs.arfactors.get(0).afactors);
578
579        List<GenPolynomial<AlgebraicNumber<C>>> fact = afacs.getFactors();
580        //System.out.println("factors       = " + fact);
581        GenPolynomial<AlgebraicNumber<C>> Pa = afacs.apoly;
582
583        GenPolynomial<AlgebraicNumber<C>> Aa = PolyUtil.<C> convertToRecAlgebraicCoefficients(1, Pa.ring, A);
584
585
586        GreatestCommonDivisorAbstract<AlgebraicNumber<C>> aengine = GCDFactory.getProxy(afacs.afac);
587
588        //System.out.println("denom         = " + Pa);
589        //System.out.println("numer         = " + Aa);
590
591        List<GenPolynomial<AlgebraicNumber<C>>> numers = aengine.basePartialFraction(Aa, fact);
592        //System.out.println("part frac     = " + numers);
593        GenPolynomial<AlgebraicNumber<C>> A0 = numers.remove(0);
594        if (!A0.isZERO()) {
595            throw new ArithmeticException(" A0 != 0: deg(A)>= deg(P)");
596        }
597        int i = 0;
598        for (GenPolynomial<AlgebraicNumber<C>> fa : fact) {
599            GenPolynomial<AlgebraicNumber<C>> an = numers.get(i++);
600            if (fa.degree(0) <= 1) {
601                afactors.add(an.leadingBaseCoefficient());
602                adenom.add(fa);
603                continue;
604            }
605            System.out.println("fa = " + fa);
606            Factors<AlgebraicNumber<C>> faf = afacs.getFactor(fa);
607            System.out.println("faf = " + faf);
608            List<GenPolynomial<AlgebraicNumber<AlgebraicNumber<C>>>> fafact = faf.getFactors();
609            GenPolynomial<AlgebraicNumber<AlgebraicNumber<C>>> Aaa = PolyUtil
610                            .<AlgebraicNumber<C>> convertToRecAlgebraicCoefficients(1, faf.apoly.ring, an);
611
612            GreatestCommonDivisorAbstract<AlgebraicNumber<AlgebraicNumber<C>>> aaengine = GCDFactory
613                            .getImplementation(faf.afac);
614
615            List<GenPolynomial<AlgebraicNumber<AlgebraicNumber<C>>>> anumers = aaengine.basePartialFraction(
616                            Aaa, fafact);
617            System.out.println("algeb part frac = " + anumers);
618            GenPolynomial<AlgebraicNumber<AlgebraicNumber<C>>> A0a = anumers.remove(0);
619            if (!A0a.isZERO()) {
620                throw new ArithmeticException(" A0 != 0: deg(A)>= deg(P)");
621            }
622            int k = 0;
623            for (GenPolynomial<AlgebraicNumber<AlgebraicNumber<C>>> faa : fafact) {
624                GenPolynomial<AlgebraicNumber<AlgebraicNumber<C>>> ana = anumers.get(k++);
625                System.out.println("faa = " + faa);
626                System.out.println("ana = " + ana);
627                if (faa.degree(0) > 1) {
628                    throw new ArithmeticException(" faa not linear");
629                }
630                GenPolynomial<AlgebraicNumber<C>> ana1 = (GenPolynomial<AlgebraicNumber<C>>) (GenPolynomial) ana;
631                GenPolynomial<AlgebraicNumber<C>> faa1 = (GenPolynomial<AlgebraicNumber<C>>) (GenPolynomial) faa;
632
633
634                afactors.add(ana1.leadingBaseCoefficient());
635                adenom.add(faa1);
636            }
637        }
638        return new PartialFraction<C>(A, P, cfactors, cdenom, afactors, adenom);
639    }
640
641
642    /**
643     * GenPolynomial absolute factorization of a polynomial.
644     * @param P GenPolynomial.
645     * @return factors map container: [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P
646     *         = prod_{i=1,...,k} p_i**e_i. <b>Note:</b> K(alpha) not yet
647     *         minimal.
648     */
649    public FactorsMap<C> factorsAbsolute(GenPolynomial<C> P) {
650        if (P == null) {
651            throw new IllegalArgumentException(this.getClass().getName() + " P == null");
652        }
653        SortedMap<GenPolynomial<C>, Long> factors = new TreeMap<GenPolynomial<C>, Long>();
654        if (P.isZERO()) {
655            return new FactorsMap<C>(P, factors);
656        }
657        //System.out.println("\nP_mult = " + P);
658        GenPolynomialRing<C> pfac = P.ring; // K[x]
659        if (pfac.nvar <= 1) {
660            return baseFactorsAbsolute(P);
661        }
662        if (!pfac.coFac.isField()) {
663            throw new IllegalArgumentException("only for field coefficients");
664        }
665        if (P.degree() <= 1) {
666            factors.put(P, 1L);
667            return new FactorsMap<C>(P, factors);
668        }
669        // factor over K (=C)
670        SortedMap<GenPolynomial<C>, Long> facs = factors(P);
671        if (debug && !isFactorization(P, facs)) {
672            throw new ArithmeticException("isFactorization = false");
673        }
674        if (logger.isInfoEnabled()) {
675            logger.info("all K factors = " + facs); // Q[X]
676            //System.out.println("\nall K factors = " + facs); // Q[X]
677        }
678        SortedMap<Factors<C>, Long> afactors = new TreeMap<Factors<C>, Long>();
679        // factor over K(alpha)
680        for (Map.Entry<GenPolynomial<C>, Long> me : facs.entrySet()) {
681            GenPolynomial<C> p = me.getKey();
682            Long e = me.getValue(); //facs.get(p);
683            if (p.degree() <= 1) {
684                factors.put(p, e);
685            } else {
686                Factors<C> afacs = factorsAbsoluteIrreducible(p);
687                if (afacs.afac == null) { // absolute irreducible
688                    factors.put(p, e);
689                } else {
690                    afactors.put(afacs, e);
691                }
692            }
693        }
694        //System.out.println("K(alpha) factors multi = " + factors);
695        return new FactorsMap<C>(P, factors, afactors);
696    }
697
698
699    /**
700     * GenPolynomial absolute factorization of a squarefree polynomial.
701     * @param P squarefree and primitive GenPolynomial.
702     * @return factors list container: [p_1,...,p_k] with P = prod_{i=1, ..., k}
703     *         p_i. <b>Note:</b> K(alpha) not yet minimal.
704     */
705    // @Override
706    public FactorsList<C> factorsAbsoluteSquarefree(GenPolynomial<C> P) {
707        if (P == null) {
708            throw new IllegalArgumentException(this.getClass().getName() + " P == null");
709        }
710        List<GenPolynomial<C>> factors = new ArrayList<GenPolynomial<C>>();
711        if (P.isZERO()) {
712            return new FactorsList<C>(P, factors);
713        }
714        //System.out.println("\nP = " + P);
715        GenPolynomialRing<C> pfac = P.ring; // K[x]
716        if (pfac.nvar <= 1) {
717            return baseFactorsAbsoluteSquarefree(P);
718        }
719        if (!pfac.coFac.isField()) {
720            throw new IllegalArgumentException("only for field coefficients");
721        }
722        if (P.degree() <= 1) {
723            factors.add(P);
724            return new FactorsList<C>(P, factors);
725        }
726        // factor over K (=C)
727        List<GenPolynomial<C>> facs = factorsSquarefree(P);
728        if (debug && !isFactorization(P, facs)) {
729            throw new ArithmeticException("isFactorization = false");
730        }
731        if (logger.isInfoEnabled()) {
732            logger.info("all K factors = " + facs); // Q[X]
733            //System.out.println("\nall K factors = " + facs); // Q[X]
734        }
735        List<Factors<C>> afactors = new ArrayList<Factors<C>>();
736        // factor over K(alpha)
737        for (GenPolynomial<C> p : facs) {
738            if (p.degree() <= 1) {
739                factors.add(p);
740            } else {
741                Factors<C> afacs = factorsAbsoluteIrreducible(p);
742                if (debug) {
743                    logger.info("K(alpha) factors = " + afacs); // K(alpha)[X]
744                }
745                if (afacs.afac == null) { // absolute irreducible
746                    factors.add(p);
747                } else {
748                    afactors.add(afacs);
749                }
750            }
751        }
752        //System.out.println("K(alpha) factors = " + factors);
753        return new FactorsList<C>(P, factors, afactors);
754    }
755
756
757    /**
758     * GenPolynomial absolute factorization of a irreducible polynomial.
759     * @param P irreducible! GenPolynomial.
760     * @return factors container: [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i
761     *         in K(alpha)[x] for suitable alpha and p_i irreducible over L[x],
762     *         where K \subset K(alpha) \subset L is an algebraically closed
763     *         field over K. <b>Note:</b> K(alpha) not yet minimal.
764     */
765    public Factors<C> factorsAbsoluteIrreducible(GenPolynomial<C> P) {
766        if (P == null) {
767            throw new IllegalArgumentException(this.getClass().getName() + " P == null");
768        }
769        if (P.isZERO()) {
770            return new Factors<C>(P);
771        }
772        GenPolynomialRing<C> pfac = P.ring; // K[x]
773        if (pfac.nvar <= 1) {
774            return baseFactorsAbsoluteIrreducible(P);
775        }
776        if (!pfac.coFac.isField()) {
777            throw new IllegalArgumentException("only for field coefficients");
778        }
779        //List<GenPolynomial<C>> factors = new ArrayList<GenPolynomial<C>>();
780        if (P.degree() <= 1) {
781            return new Factors<C>(P);
782        }
783        // find field extension K(alpha)
784        GenPolynomial<C> up = P;
785        RingFactory<C> cf = pfac.coFac;
786        long cr = cf.characteristic().longValue(); // char might be larger
787        if (cr == 0L) {
788            cr = Long.MAX_VALUE;
789        }
790        long rp = 0L;
791        for (int i = 0; i < (pfac.nvar - 1); i++) {
792            rp = 0L;
793            GenPolynomialRing<C> nfac = pfac.contract(1);
794            String[] vn = new String[] { pfac.getVars()[pfac.nvar - 1] };
795            GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(nfac, 1,
796                            pfac.tord, vn);
797            GenPolynomial<GenPolynomial<C>> upr = PolyUtil.<C> recursive(rfac, up);
798            //System.out.println("upr = " + upr);
799            GenPolynomial<C> ep;
800            do {
801                if (rp >= cr) {
802                    throw new ArithmeticException("elements of prime field exhausted: " + cr);
803                }
804                C r = cf.fromInteger(rp); //cf.random(rp);
805                //System.out.println("r   = " + r);
806                ep = PolyUtil.<C> evaluateMainRecursive(nfac, upr, r);
807                //System.out.println("ep  = " + ep);
808                rp++;
809            } while (!isSquarefree(ep) /*todo: || ep.degree() <= 1*/); // max deg
810            up = ep;
811            pfac = nfac;
812        }
813        up = up.monic();
814        if (debug) {
815            logger.info("P(" + rp + ") = " + up);
816            //System.out.println("up  = " + up);
817        }
818        if (debug && !isSquarefree(up)) {
819            throw new ArithmeticException("not irreducible up = " + up);
820        }
821        if (up.degree(0) <= 1) {
822            return new Factors<C>(P);
823        }
824        // find irreducible factor of up
825        List<GenPolynomial<C>> UF = baseFactorsSquarefree(up);
826        //System.out.println("UF  = " + UF);
827        FactorsList<C> aUF = baseFactorsAbsoluteSquarefree(up);
828        //System.out.println("aUF  = " + aUF);
829        AlgebraicNumberRing<C> arfac = aUF.findExtensionField();
830        //System.out.println("arfac  = " + arfac);
831
832        long e = up.degree(0);
833        // search factor polynomial with smallest degree 
834        for (int i = 0; i < UF.size(); i++) {
835            GenPolynomial<C> upi = UF.get(i);
836            long d = upi.degree(0);
837            if (1 <= d && d <= e) {
838                up = upi;
839                e = up.degree(0);
840            }
841        }
842        if (up.degree(0) <= 1) {
843            return new Factors<C>(P);
844        }
845        if (debug) {
846            logger.info("field extension by " + up);
847        }
848
849        List<GenPolynomial<AlgebraicNumber<C>>> afactors = new ArrayList<GenPolynomial<AlgebraicNumber<C>>>();
850
851        // setup field extension K(alpha)
852        //String[] vars = new String[] { "z_" + Math.abs(up.hashCode() % 1000) };
853        String[] vars = pfac.newVars("z_");
854        pfac = pfac.copy();
855        //String[] ovars = 
856        pfac.setVars(vars); // side effects! 
857        //GenPolynomial<C> aup = pfac.copy(up); // hack to exchange the variables
858        //AlgebraicNumberRing<C> afac = new AlgebraicNumberRing<C>(aup,true); // since irreducible
859        AlgebraicNumberRing<C> afac = arfac;
860        int depth = afac.depth();
861        //System.out.println("afac = " + afac);
862        GenPolynomialRing<AlgebraicNumber<C>> pafac = new GenPolynomialRing<AlgebraicNumber<C>>(afac,
863                        P.ring.nvar, P.ring.tord, P.ring.getVars());
864        //System.out.println("pafac = " + pafac);
865        // convert to K(alpha)
866        GenPolynomial<AlgebraicNumber<C>> Pa = PolyUtil
867                        .<C> convertToRecAlgebraicCoefficients(depth, pafac, P);
868        //System.out.println("Pa = " + Pa);
869        // factor over K(alpha)
870        FactorAbstract<AlgebraicNumber<C>> engine = FactorFactory.<C> getImplementation(afac);
871        afactors = engine.factorsSquarefree(Pa);
872        if (debug) {
873            logger.info("K(alpha) factors multi = " + afactors);
874            //System.out.println("K(alpha) factors = " + afactors);
875        }
876        if (afactors.size() <= 1) {
877            return new Factors<C>(P);
878        }
879        // normalize first factor to monic
880        GenPolynomial<AlgebraicNumber<C>> p1 = afactors.get(0);
881        AlgebraicNumber<C> p1c = p1.leadingBaseCoefficient();
882        if (!p1c.isONE()) {
883            GenPolynomial<AlgebraicNumber<C>> p2 = afactors.get(1);
884            afactors.remove(p1);
885            afactors.remove(p2);
886            p1 = p1.divide(p1c);
887            p2 = p2.multiply(p1c);
888            afactors.add(p1);
889            afactors.add(p2);
890        }
891        // recursion for splitting field
892        // find minimal field extension K(beta) \subset K(alpha)
893        return new Factors<C>(P, afac, Pa, afactors);
894    }
895
896
897    /**
898     * GenPolynomial is absolute factorization.
899     * @param facs factors container.
900     * @return true if P = prod_{i=1,...,r} p_i, else false.
901     */
902    public boolean isAbsoluteFactorization(Factors<C> facs) {
903        if (facs == null) {
904            throw new IllegalArgumentException("facs may not be null");
905        }
906        if (facs.afac == null) {
907            return true;
908        }
909        GenPolynomial<AlgebraicNumber<C>> fa = facs.apoly;
910        GenPolynomialRing<AlgebraicNumber<C>> pafac = fa.ring;
911        GenPolynomial<AlgebraicNumber<C>> t = pafac.getONE();
912        for (GenPolynomial<AlgebraicNumber<C>> f : facs.afactors) {
913            t = t.multiply(f);
914        }
915        //return fa.equals(t) || fa.equals(t.negate());
916        boolean b = fa.equals(t) || fa.equals(t.negate());
917        if (b) {
918            return b;
919        }
920        if (facs.arfactors == null) {
921            return false;
922        }
923        for (Factors<AlgebraicNumber<C>> arp : facs.arfactors) {
924            t = t.multiply(arp.poly);
925        }
926        b = fa.equals(t) || fa.equals(t.negate());
927        if (!b) {
928            System.out.println("\nFactors: " + facs);
929            System.out.println("fa = " + fa);
930            System.out.println("t = " + t);
931        }
932        return b;
933    }
934
935
936    /**
937     * GenPolynomial is absolute factorization.
938     * @param facs factors list container.
939     * @return true if P = prod_{i=1,...,r} p_i, else false.
940     */
941    public boolean isAbsoluteFactorization(FactorsList<C> facs) {
942        if (facs == null) {
943            throw new IllegalArgumentException("facs may not be null");
944        }
945        GenPolynomial<C> P = facs.poly;
946        GenPolynomial<C> t = P.ring.getONE();
947        for (GenPolynomial<C> f : facs.factors) {
948            t = t.multiply(f);
949        }
950        if (P.equals(t) || P.equals(t.negate())) {
951            return true;
952        }
953        if (facs.afactors == null) {
954            return false;
955        }
956        for (Factors<C> fs : facs.afactors) {
957            if (!isAbsoluteFactorization(fs)) {
958                return false;
959            }
960            t = t.multiply(facs.poly);
961        }
962        //return P.equals(t) || P.equals(t.negate());
963        boolean b = P.equals(t) || P.equals(t.negate());
964        if (!b) {
965            System.out.println("\nFactorsList: " + facs);
966            System.out.println("P = " + P);
967            System.out.println("t = " + t);
968        }
969        return b;
970    }
971
972
973    /**
974     * GenPolynomial is absolute factorization.
975     * @param facs factors map container.
976     * @return true if P = prod_{i=1,...,k} p_i**e_i , else false.
977     */
978    public boolean isAbsoluteFactorization(FactorsMap<C> facs) {
979        if (facs == null) {
980            throw new IllegalArgumentException("facs may not be null");
981        }
982        GenPolynomial<C> P = facs.poly;
983        GenPolynomial<C> t = P.ring.getONE();
984        for (Map.Entry<GenPolynomial<C>, Long> me : facs.factors.entrySet()) {
985            GenPolynomial<C> f = me.getKey();
986            long e = me.getValue(); //facs.factors.get(f);
987            GenPolynomial<C> g = Power.<GenPolynomial<C>> positivePower(f, e);
988            t = t.multiply(g);
989        }
990        if (P.equals(t) || P.equals(t.negate())) {
991            return true;
992        }
993        if (facs.afactors == null) {
994            return false;
995        }
996        for (Map.Entry<Factors<C>, Long> me : facs.afactors.entrySet()) {
997            Factors<C> fs = me.getKey();
998            if (!isAbsoluteFactorization(fs)) {
999                return false;
1000            }
1001            long e = me.getValue(); // facs.afactors.get(fs);
1002            GenPolynomial<C> g = Power.<GenPolynomial<C>> positivePower(fs.poly, e);
1003            t = t.multiply(g);
1004        }
1005        boolean b = P.equals(t) || P.equals(t.negate());
1006        if (!b) {
1007            System.out.println("\nFactorsMap: " + facs);
1008            System.out.println("P = " + P);
1009            System.out.println("t = " + t);
1010        }
1011        return b;
1012    }
1013
1014}