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