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