001/*
002 * $Id$
003 */
004
005package edu.jas.ufd;
006
007
008import java.util.Map;
009import java.util.SortedMap;
010import java.util.TreeMap;
011
012import org.apache.logging.log4j.LogManager;
013import org.apache.logging.log4j.Logger;
014
015import edu.jas.poly.ExpVector;
016import edu.jas.poly.GenPolynomial;
017import edu.jas.poly.GenPolynomialRing;
018import edu.jas.poly.PolyUtil;
019import edu.jas.structure.GcdRingElem;
020import edu.jas.structure.RingFactory;
021
022
023/**
024 * Squarefree decomposition for coefficient fields of characteristic 0.
025 * @author Heinz Kredel
026 */
027
028public class SquarefreeFieldChar0<C extends GcdRingElem<C>> extends SquarefreeAbstract<C> {
029
030
031    private static final Logger logger = LogManager.getLogger(SquarefreeFieldChar0.class);
032
033
034    //private static final boolean debug = logger.isDebugEnabled();
035
036
037    /**
038     * Factory for field of characteristic 0 coefficients.
039     */
040    protected final RingFactory<C> coFac;
041
042
043    /**
044     * Constructor.
045     */
046    public SquarefreeFieldChar0(RingFactory<C> fac) {
047        super(GCDFactory.<C> getProxy(fac));
048        if (!fac.isField()) {
049            throw new IllegalArgumentException("fac must be a field");
050        }
051        if (fac.characteristic().signum() != 0) {
052            throw new IllegalArgumentException("characterisic(fac) must be zero");
053        }
054        coFac = fac;
055    }
056
057
058    /**
059     * Get the String representation.
060     * @see java.lang.Object#toString()
061     */
062    @Override
063    public String toString() {
064        return getClass().getName() + " with " + engine + " over " + coFac;
065    }
066
067
068    /**
069     * GenPolynomial polynomial greatest squarefree divisor.
070     * @param P GenPolynomial.
071     * @return squarefree(pp(P)).
072     */
073    @Override
074    public GenPolynomial<C> baseSquarefreePart(GenPolynomial<C> P) {
075        if (P == null || P.isZERO()) {
076            return P;
077        }
078        GenPolynomialRing<C> pfac = P.ring;
079        if (pfac.nvar > 1) {
080            throw new IllegalArgumentException(
081                            this.getClass().getName() + " only for univariate polynomials");
082        }
083        GenPolynomial<C> pp = P.monic();
084        if (pp.isConstant()) {
085            return pp;
086        }
087        GenPolynomial<C> d = PolyUtil.<C> baseDeriviative(pp);
088        d = d.monic();
089        //System.out.println("d = " + d);
090        GenPolynomial<C> g = engine.baseGcd(pp, d);
091        g = g.monic();
092        GenPolynomial<C> q = PolyUtil.<C> basePseudoDivide(pp, g);
093        q = q.monic();
094        return q;
095    }
096
097
098    /**
099     * GenPolynomial test if is squarefree.
100     * @param P GenPolynomial.
101     * @return true if P is squarefree, else false.
102     */
103    public boolean isBaseSquarefree(GenPolynomial<C> P) {
104        if (P == null || P.isZERO()) {
105            return true;
106        }
107        GenPolynomialRing<C> pfac = P.ring;
108        if (pfac.nvar > 1) {
109            throw new IllegalArgumentException(
110                            this.getClass().getName() + " only for univariate polynomials");
111        }
112        GenPolynomial<C> pp = P.monic();
113        if (pp.isConstant()) {
114            return true;
115        }
116        GenPolynomial<C> d = PolyUtil.<C> baseDeriviative(pp);
117        d = d.monic();
118        //System.out.println("d = " + d);
119        GenPolynomial<C> g = engine.baseGcd(pp, d);
120        //g = g.monic();
121        //return g.isONE();
122        return g.degree(0) == 0;
123    }
124
125
126    /**
127     * GenPolynomial polynomial squarefree factorization.
128     * @param A GenPolynomial.
129     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k}
130     *         p_i^{e_i} and p_i squarefree.
131     */
132    @Override
133    public SortedMap<GenPolynomial<C>, Long> baseSquarefreeFactors(GenPolynomial<C> A) {
134        SortedMap<GenPolynomial<C>, Long> sfactors = new TreeMap<GenPolynomial<C>, Long>();
135        if (A == null || A.isZERO()) {
136            return sfactors;
137        }
138        if (A.isConstant()) {
139            sfactors.put(A, 1L);
140            return sfactors;
141        }
142        GenPolynomialRing<C> pfac = A.ring;
143        if (pfac.nvar > 1) {
144            throw new IllegalArgumentException(
145                            this.getClass().getName() + " only for univariate polynomials");
146        }
147        C ldbcf = A.leadingBaseCoefficient();
148        if (!ldbcf.isONE()) {
149            A = A.divide(ldbcf);
150            GenPolynomial<C> f1 = pfac.getONE().multiply(ldbcf);
151            //System.out.println("gcda sqf f1 = " + f1);
152            sfactors.put(f1, 1L);
153            ldbcf = pfac.coFac.getONE();
154        }
155        // divide by trailing term
156        ExpVector et = A.trailingExpVector();
157        if (!et.isZERO()) {
158            GenPolynomial<C> tr = pfac.valueOf(et);
159            if (logger.isInfoEnabled()) {
160                logger.info("trailing term = " + tr);
161            }
162            A = PolyUtil.<C> basePseudoDivide(A, tr);
163            long ep = et.getVal(0); // univariate
164            et = et.subst(0, 1);
165            tr = pfac.valueOf(et);
166            if (logger.isInfoEnabled()) {
167                logger.info("tr, ep = " + tr + ", " + ep);
168            }
169            sfactors.put(tr, ep);
170            if (A.length() == 1) {
171                return sfactors;
172            }
173        }
174        GenPolynomial<C> T0 = A;
175        GenPolynomial<C> Tp;
176        GenPolynomial<C> T = null;
177        GenPolynomial<C> V = null;
178        long k = 0L;
179        boolean init = true;
180        while (true) {
181            if (init) {
182                if (T0.isConstant() || T0.isZERO()) {
183                    break;
184                }
185                Tp = PolyUtil.<C> baseDeriviative(T0);
186                T = engine.baseGcd(T0, Tp);
187                T = T.monic();
188                V = PolyUtil.<C> basePseudoDivide(T0, T);
189                //System.out.println("iT0 = " + T0);
190                //System.out.println("iTp = " + Tp);
191                //System.out.println("iT  = " + T);
192                //System.out.println("iV  = " + V);
193                k = 0L;
194                init = false;
195            }
196            if (V.isConstant()) {
197                break;
198            }
199            k++;
200            GenPolynomial<C> W = engine.baseGcd(T, V);
201            W = W.monic();
202            GenPolynomial<C> z = PolyUtil.<C> basePseudoDivide(V, W);
203            //System.out.println("W = " + W);
204            //System.out.println("z = " + z);
205            V = W;
206            T = PolyUtil.<C> basePseudoDivide(T, V);
207            //System.out.println("V = " + V);
208            //System.out.println("T = " + T);
209            if (z.degree(0) > 0) {
210                if (ldbcf.isONE() && !z.leadingBaseCoefficient().isONE()) {
211                    z = z.monic();
212                    //logger.info("z,monic = " + z);
213                }
214                logger.info("z, k = " + z + ", " + k);
215                sfactors.put(z, k);
216            }
217        }
218        return normalizeFactorization(sfactors);
219    }
220
221
222    /**
223     * GenPolynomial recursive univariate polynomial greatest squarefree
224     * divisor.
225     * @param P recursive univariate GenPolynomial.
226     * @return squarefree(pp(P)).
227     */
228    @Override
229    public GenPolynomial<GenPolynomial<C>> recursiveUnivariateSquarefreePart(
230                    GenPolynomial<GenPolynomial<C>> P) {
231        if (P == null || P.isZERO()) {
232            return P;
233        }
234        GenPolynomialRing<GenPolynomial<C>> pfac = P.ring;
235        if (pfac.nvar > 1) {
236            throw new IllegalArgumentException(
237                            this.getClass().getName() + " only for univariate recursive polynomials");
238        }
239        // squarefree content
240        GenPolynomial<GenPolynomial<C>> pp = P;
241        GenPolynomial<C> Pc = engine.recursiveContent(P);
242        //?? Pc = Pc.monic();
243        if (!Pc.isONE()) {
244            pp = PolyUtil.<C> coefficientPseudoDivide(pp, Pc);
245            //System.out.println("pp,sqp = " + pp);
246            //GenPolynomial<C> Pr = squarefreePart(Pc);
247            //Pr = Pr.monic();
248            //System.out.println("Pr,sqp = " + Pr);
249        }
250        if (pp.leadingExpVector().getVal(0) < 1) {
251            //System.out.println("pp = " + pp);
252            //System.out.println("Pc = " + Pc);
253            return pp.multiply(Pc);
254        }
255        GenPolynomial<GenPolynomial<C>> d = PolyUtil.<C> recursiveDeriviative(pp);
256        //System.out.println("d = " + d);
257        GenPolynomial<GenPolynomial<C>> g = engine.recursiveUnivariateGcd(pp, d);
258        //System.out.println("g,rec = " + g);
259        //??g = PolyUtil.<C> monic(g);
260        GenPolynomial<GenPolynomial<C>> q = PolyUtil.<C> recursivePseudoDivide(pp, g);
261        //?? q = PolyUtil.<C> monic(q);
262        return q.multiply(Pc);
263    }
264
265
266    /**
267     * GenPolynomial test if is squarefree.
268     * @param P GenPolynomial.
269     * @return true if P is squarefree, else false.
270     */
271    public boolean isRecursiveUnivariateSquarefree(GenPolynomial<GenPolynomial<C>> P) {
272        if (P == null || P.isZERO()) {
273            return true;
274        }
275        GenPolynomialRing<GenPolynomial<C>> pfac = P.ring;
276        if (pfac.nvar > 1) {
277            throw new IllegalArgumentException(
278                            this.getClass().getName() + " only for univariate recursive polynomials");
279        }
280        GenPolynomial<GenPolynomial<C>> pp = P;
281        GenPolynomial<GenPolynomial<C>> d = PolyUtil.<C> recursiveDeriviative(pp);
282        //System.out.println("d = " + d);
283        GenPolynomial<GenPolynomial<C>> g = engine.recursiveUnivariateGcd(pp, d);
284        if (logger.isInfoEnabled()) {
285            logger.info("gcd = " + g);
286        }
287        //System.out.println("g,rec = " + g);
288        //g = PolyUtil.<C> monic(g);
289        //return g.isONE();
290        return g.degree(0) == 0;
291    }
292
293
294    /**
295     * GenPolynomial recursive univariate polynomial squarefree factorization.
296     * @param P recursive univariate GenPolynomial.
297     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k}
298     *         p_i^{e_i} and p_i squarefree.
299     */
300    @Override
301    public SortedMap<GenPolynomial<GenPolynomial<C>>, Long> recursiveUnivariateSquarefreeFactors(
302                    GenPolynomial<GenPolynomial<C>> P) {
303        SortedMap<GenPolynomial<GenPolynomial<C>>, Long> sfactors = new TreeMap<GenPolynomial<GenPolynomial<C>>, Long>();
304        if (P == null || P.isZERO()) {
305            return sfactors;
306        }
307        GenPolynomialRing<GenPolynomial<C>> pfac = P.ring;
308        if (pfac.nvar > 1) {
309            // recursiveContent not possible by return type
310            throw new IllegalArgumentException(
311                            this.getClass().getName() + " only for univariate polynomials");
312        }
313        // if base coefficient ring is a field, make monic
314        GenPolynomialRing<C> cfac = (GenPolynomialRing<C>) pfac.coFac;
315        C ldbcf = P.leadingBaseCoefficient().leadingBaseCoefficient();
316        if (!ldbcf.isONE()) {
317            GenPolynomial<C> lc = cfac.getONE().multiply(ldbcf);
318            GenPolynomial<GenPolynomial<C>> pl = pfac.getONE().multiply(lc);
319            sfactors.put(pl, 1L);
320            C li = ldbcf.inverse();
321            //System.out.println("li = " + li);
322            P = P.multiply(cfac.getONE().multiply(li));
323            //System.out.println("P,monic = " + P);
324            ldbcf = P.leadingBaseCoefficient().leadingBaseCoefficient();
325        }
326        // factors of content
327        GenPolynomial<C> Pc = engine.recursiveContent(P);
328        if (logger.isInfoEnabled()) {
329            logger.info("recursiveContent = " + Pc);
330        }
331        Pc = Pc.monic();
332        if (!Pc.isONE()) {
333            P = PolyUtil.<C> coefficientPseudoDivide(P, Pc);
334        }
335        SortedMap<GenPolynomial<C>, Long> rsf = squarefreeFactors(Pc);
336        if (logger.isInfoEnabled()) {
337            logger.info("squarefreeFactors = " + rsf);
338        }
339        // add factors of content
340        for (Map.Entry<GenPolynomial<C>, Long> me : rsf.entrySet()) {
341            GenPolynomial<C> c = me.getKey();
342            if (!c.isONE()) {
343                GenPolynomial<GenPolynomial<C>> cr = pfac.getONE().multiply(c);
344                Long rk = me.getValue(); // rsf.get(c);
345                sfactors.put(cr, rk);
346            }
347        }
348        // divide by trailing term
349        ExpVector et = P.trailingExpVector();
350        if (!et.isZERO()) {
351            GenPolynomial<GenPolynomial<C>> tr = pfac.valueOf(et);
352            if (logger.isInfoEnabled()) {
353                logger.info("trailing term = " + tr);
354            }
355            P = PolyUtil.<C> recursivePseudoDivide(P, tr);
356            long ep = et.getVal(0); // univariate
357            et = et.subst(0, 1);
358            tr = pfac.valueOf(et);
359            sfactors.put(tr, ep);
360        }
361
362        // factors of recursive polynomial
363        GenPolynomial<GenPolynomial<C>> T0 = P;
364        GenPolynomial<GenPolynomial<C>> Tp;
365        GenPolynomial<GenPolynomial<C>> T = null;
366        GenPolynomial<GenPolynomial<C>> V = null;
367        long k = 0L;
368        boolean init = true;
369        while (true) {
370            if (init) {
371                if (T0.isConstant() || T0.isZERO()) {
372                    break;
373                }
374                Tp = PolyUtil.<C> recursiveDeriviative(T0);
375                T = engine.recursiveUnivariateGcd(T0, Tp);
376                T = PolyUtil.<C> monic(T);
377                V = PolyUtil.<C> recursivePseudoDivide(T0, T);
378                //System.out.println("iT0 = " + T0);
379                //System.out.println("iTp = " + Tp);
380                //System.out.println("iT = " + T);
381                //System.out.println("iV = " + V);
382                k = 0L;
383                init = false;
384            }
385            if (V.isConstant()) {
386                break;
387            }
388            k++;
389            GenPolynomial<GenPolynomial<C>> W = engine.recursiveUnivariateGcd(T, V);
390            W = PolyUtil.<C> monic(W);
391            GenPolynomial<GenPolynomial<C>> z = PolyUtil.<C> recursivePseudoDivide(V, W);
392            //System.out.println("W = " + W);
393            //System.out.println("z = " + z);
394            V = W;
395            T = PolyUtil.<C> recursivePseudoDivide(T, V);
396            //System.out.println("V = " + V);
397            //System.out.println("T = " + T);
398            //was: if ( z.degree(0) > 0 ) {
399            if (!z.isONE() && !z.isZERO()) {
400                if (ldbcf.isONE()) {
401                    z = PolyUtil.<C> monic(z);
402                    logger.info("z,monic = " + z);
403                }
404                sfactors.put(z, k);
405            }
406        }
407        return sfactors;
408    }
409
410
411    /**
412     * GenPolynomial greatest squarefree divisor.
413     * @param P GenPolynomial.
414     * @return squarefree(pp(P)).
415     */
416    @Override
417    public GenPolynomial<C> squarefreePart(GenPolynomial<C> P) {
418        if (P == null) {
419            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
420        }
421        if (P.isZERO()) {
422            return P;
423        }
424        GenPolynomialRing<C> pfac = P.ring;
425        if (pfac.nvar <= 1) {
426            return baseSquarefreePart(P);
427        }
428        GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1);
429        GenPolynomial<GenPolynomial<C>> Pr = PolyUtil.<C> recursive(rfac, P);
430        GenPolynomial<C> Pc = engine.recursiveContent(Pr);
431        Pr = PolyUtil.<C> coefficientPseudoDivide(Pr, Pc);
432        GenPolynomial<C> Ps = squarefreePart(Pc);
433        if (logger.isInfoEnabled()) {
434            logger.info("content = " + Pc + ", squarefreePart = " + Ps);
435        }
436        GenPolynomial<GenPolynomial<C>> PP = recursiveUnivariateSquarefreePart(Pr);
437        GenPolynomial<GenPolynomial<C>> PS = PP.multiply(Ps);
438        GenPolynomial<C> D = PolyUtil.<C> distribute(pfac, PS);
439        if (logger.isInfoEnabled()) {
440            logger.info("univRec = " + Pr + ", squarefreePart = " + PP);
441        }
442        return D;
443    }
444
445
446    /**
447     * GenPolynomial test if is squarefree.
448     * @param P GenPolynomial.
449     * @return true if P is squarefree, else false.
450     */
451    @Override
452    public boolean isSquarefree(GenPolynomial<C> P) {
453        if (P == null) {
454            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
455        }
456        if (P.isZERO()) {
457            return true;
458        }
459        GenPolynomialRing<C> pfac = P.ring;
460        if (pfac.nvar <= 1) {
461            return isBaseSquarefree(P);
462        }
463        GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1);
464        GenPolynomial<GenPolynomial<C>> Pr = PolyUtil.<C> recursive(rfac, P);
465        return isRecursiveUnivariateSquarefree(Pr);
466    }
467
468
469    /**
470     * GenPolynomial squarefree factorization.
471     * @param P GenPolynomial.
472     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k}
473     *         p_i^{e_i} and p_i squarefree.
474     */
475    @Override
476    public SortedMap<GenPolynomial<C>, Long> squarefreeFactors(GenPolynomial<C> P) {
477        if (P == null) {
478            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
479        }
480        GenPolynomialRing<C> pfac = P.ring;
481        if (pfac.nvar <= 1) {
482            return normalizeFactorization(baseSquarefreeFactors(P));
483        }
484        SortedMap<GenPolynomial<C>, Long> sfactors = new TreeMap<GenPolynomial<C>, Long>();
485        if (P.isZERO()) {
486            return normalizeFactorization(sfactors);
487        }
488        if (P.isONE()) {
489            sfactors.put(P, 1L);
490            return normalizeFactorization(sfactors);
491        }
492        GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1);
493        GenPolynomial<GenPolynomial<C>> Pr = PolyUtil.<C> recursive(rfac, P);
494        SortedMap<GenPolynomial<GenPolynomial<C>>, Long> PP = recursiveUnivariateSquarefreeFactors(Pr);
495
496        for (Map.Entry<GenPolynomial<GenPolynomial<C>>, Long> m : PP.entrySet()) {
497            Long i = m.getValue();
498            GenPolynomial<GenPolynomial<C>> Dr = m.getKey();
499            GenPolynomial<C> D = PolyUtil.<C> distribute(pfac, Dr);
500            sfactors.put(D, i);
501        }
502        if (logger.isInfoEnabled()) {
503            logger.info("squarefreeFactors(" + P + ") = " + sfactors);
504        }
505        return normalizeFactorization(sfactors);
506    }
507
508
509    /**
510     * Coefficients squarefree factorization.
511     * @param P coefficient.
512     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k}
513     *         p_i^{e_i} and p_i squarefree.
514     */
515    @Override
516    public SortedMap<C, Long> squarefreeFactors(C P) {
517        throw new UnsupportedOperationException("method not implemented");
518    }
519
520}