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