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