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