001/*
002 * $Id$
003 */
004
005package edu.jas.ufd;
006
007
008import java.util.ArrayList;
009import java.util.List;
010import java.util.Map;
011import java.util.SortedMap;
012import java.util.TreeMap;
013
014import org.apache.logging.log4j.LogManager;
015import org.apache.logging.log4j.Logger;
016
017import edu.jas.poly.GenPolynomial;
018import edu.jas.poly.GenPolynomialRing;
019import edu.jas.poly.PolyUtil;
020import edu.jas.structure.GcdRingElem;
021import edu.jas.structure.RingFactory;
022
023
024/**
025 * Abstract squarefree decomposition class.
026 * @author Heinz Kredel
027 */
028
029public abstract class SquarefreeAbstract<C extends GcdRingElem<C>> implements Squarefree<C> {
030
031
032    private static final Logger logger = LogManager.getLogger(SquarefreeAbstract.class);
033
034
035    /**
036     * GCD engine for respective base coefficients.
037     */
038    protected final GreatestCommonDivisorAbstract<C> engine;
039
040
041    /**
042     * Constructor.
043     */
044    public SquarefreeAbstract(GreatestCommonDivisorAbstract<C> engine) {
045        this.engine = engine;
046    }
047
048
049    /**
050     * GenPolynomial polynomial greatest squarefree divisor.
051     * @param P GenPolynomial.
052     * @return squarefree(pp(P)).
053     */
054    public abstract GenPolynomial<C> baseSquarefreePart(GenPolynomial<C> P);
055
056
057    /**
058     * GenPolynomial polynomial squarefree factorization.
059     * @param A GenPolynomial.
060     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with A = prod_{i=1,...,k}
061     *         p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j.
062     */
063    public abstract SortedMap<GenPolynomial<C>, Long> baseSquarefreeFactors(GenPolynomial<C> A);
064
065
066    /**
067     * GenPolynomial recursive polynomial greatest squarefree divisor.
068     * @param P recursive univariate GenPolynomial.
069     * @return squarefree(pp(P)).
070     */
071    public abstract GenPolynomial<GenPolynomial<C>> recursiveUnivariateSquarefreePart(
072                    GenPolynomial<GenPolynomial<C>> P);
073
074
075    /**
076     * GenPolynomial recursive univariate polynomial squarefree factorization.
077     * @param P recursive univariate GenPolynomial.
078     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k}
079     *         p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j.
080     */
081    public abstract SortedMap<GenPolynomial<GenPolynomial<C>>, Long> recursiveUnivariateSquarefreeFactors(
082                    GenPolynomial<GenPolynomial<C>> P);
083
084
085    /**
086     * GenPolynomial greatest squarefree divisor.
087     * @param P GenPolynomial.
088     * @return squarefree(P) a primitive respectively monic polynomial.
089     */
090    public abstract GenPolynomial<C> squarefreePart(GenPolynomial<C> P);
091
092
093    /**
094     * GenPolynomial test if is squarefree.
095     * @param P GenPolynomial.
096     * @return true if P is squarefree, else false.
097     */
098    public boolean isSquarefree(GenPolynomial<C> P) {
099        GenPolynomial<C> S = squarefreePart(P);
100        GenPolynomial<C> Ps = P;
101        if (P.ring.coFac.isField()) {
102            Ps = Ps.monic();
103        } else {
104            Ps = engine.basePrimitivePart(Ps);
105        }
106        boolean f = Ps.equals(S);
107        return f;
108    }
109
110
111    /**
112     * GenPolynomial list test if squarefree.
113     * @param L list of GenPolynomial.
114     * @return true if each P in L is squarefree, else false.
115     */
116    public boolean isSquarefree(List<GenPolynomial<C>> L) {
117        if (L == null || L.isEmpty()) {
118            return true;
119        }
120        for (GenPolynomial<C> P : L) {
121            if (!isSquarefree(P)) {
122                return false;
123            }
124        }
125        return true;
126    }
127
128
129    /**
130     * Recursive GenPolynomial test if is squarefree.
131     * @param P recursive univariate GenPolynomial.
132     * @return true if P is squarefree, else false.
133     */
134    public boolean isRecursiveSquarefree(GenPolynomial<GenPolynomial<C>> P) {
135        GenPolynomial<GenPolynomial<C>> S = recursiveUnivariateSquarefreePart(P);
136        boolean f = P.equals(S);
137        if (!f) {
138            logger.info("not Squarefree, S != P: {} != {}", P, S);
139        }
140        return f;
141    }
142
143
144    /**
145     * GenPolynomial squarefree factorization.
146     * @param P GenPolynomial.
147     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k}
148     *         p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j.
149     */
150    public abstract SortedMap<GenPolynomial<C>, Long> squarefreeFactors(GenPolynomial<C> P);
151
152
153    /**
154     * GenPolynomial squarefree and co-prime list.
155     * @param A list of GenPolynomials.
156     * @return B with gcd(b,c) = 1 for all b != c in B and for all non-constant
157     *         a in A there exists b in B with b|a and each b in B is
158     *         squarefree. B does not contain zero or constant polynomials.
159     */
160    public List<GenPolynomial<C>> coPrimeSquarefree(List<GenPolynomial<C>> A) {
161        if (A == null || A.isEmpty()) {
162            return A;
163        }
164        List<GenPolynomial<C>> S = new ArrayList<GenPolynomial<C>>();
165        for (GenPolynomial<C> g : A) {
166            SortedMap<GenPolynomial<C>, Long> sm = squarefreeFactors(g);
167            S.addAll(sm.keySet());
168        }
169        List<GenPolynomial<C>> B = engine.coPrime(S);
170        return B;
171    }
172
173
174    /**
175     * GenPolynomial squarefree and co-prime list.
176     * @param a polynomial.
177     * @param P squarefree co-prime list of GenPolynomials.
178     * @return B with gcd(b,c) = 1 for all b != c in B and for non-constant a
179     *         there exists b in P with b|a. B does not contain zero or constant
180     *         polynomials.
181     */
182    public List<GenPolynomial<C>> coPrimeSquarefree(GenPolynomial<C> a, List<GenPolynomial<C>> P) {
183        if (a == null || a.isZERO() || a.isConstant()) {
184            return P;
185        }
186        SortedMap<GenPolynomial<C>, Long> sm = squarefreeFactors(a);
187        List<GenPolynomial<C>> B = P;
188        for (GenPolynomial<C> f : sm.keySet()) {
189            B = engine.coPrime(f, B);
190        }
191        return B;
192    }
193
194
195    /**
196     * Test if list of GenPolynomials is squarefree and co-prime.
197     * @param B list of GenPolynomials.
198     * @return true, if for all b != c in B gcd(b,c) = 1 and each b in B is
199     *         squarefree, else false.
200     */
201    public boolean isCoPrimeSquarefree(List<GenPolynomial<C>> B) {
202        if (B == null || B.isEmpty()) {
203            return true;
204        }
205        if (!engine.isCoPrime(B)) {
206            return false;
207        }
208        return isSquarefree(B);
209    }
210
211
212    /**
213     * Normalize factorization. p'_i &gt; 0 for i &gt; 1 and p'_1 != 1 if k &gt;
214     * 1.
215     * @param F = [p_1-&gt;e_1;, ..., p_k-&gt;e_k].
216     * @return F' = [p'_1-&gt;e_1, ..., p'_k-&gt;e_k].
217     */
218    public SortedMap<GenPolynomial<C>, Long> normalizeFactorization(SortedMap<GenPolynomial<C>, Long> F) {
219        if (F == null || F.size() <= 1) {
220            return F;
221        }
222        List<GenPolynomial<C>> Fp = new ArrayList<GenPolynomial<C>>(F.keySet());
223        GenPolynomial<C> f0 = Fp.get(0);
224        if (f0.ring.characteristic().signum() != 0) { // only ordered coefficients
225            return F;
226        }
227        long e0 = F.get(f0);
228        SortedMap<GenPolynomial<C>, Long> Sp = new TreeMap<GenPolynomial<C>, Long>();
229        for (int i = 1; i < Fp.size(); i++) {
230            GenPolynomial<C> fi = Fp.get(i);
231            long ei = F.get(fi);
232            if (fi.signum() < 0) {
233                //System.out.println("e0 = " + e0 + ", f0 = " + f0);
234                //System.out.println("ei = " + ei + ", fi = " + fi);
235                if (ei % 2 != 0 && e0 % 2 != 0) { // bug
236                    fi = fi.negate();
237                    f0 = f0.negate();
238                }
239            }
240            Sp.put(fi, ei);
241        }
242        if (!f0.isONE()) {
243            Sp.put(f0, e0);
244        }
245        return Sp;
246    }
247
248
249    /**
250     * GenPolynomial is (squarefree) factorization.
251     * @param P GenPolynomial.
252     * @param F = [p_1, ..., p_k].
253     * @return true if P = prod_{i=1,...,r} p_i, else false.
254     */
255    public boolean isFactorization(GenPolynomial<C> P, List<GenPolynomial<C>> F) {
256        if (P == null || F == null) {
257            throw new IllegalArgumentException("P and F may not be null");
258        }
259        if (P.isZERO() && F.size() == 0) {
260            return true;
261        }
262        GenPolynomial<C> t = P.ring.getONE();
263        for (GenPolynomial<C> f : F) {
264            t = t.multiply(f);
265        }
266        boolean f = P.equals(t) || P.equals(t.negate());
267        if (!f) {
268            logger.info("no factorization(list): F = {}, P = {}, t = {}", F, P, t);
269        }
270        return f;
271    }
272
273
274    /**
275     * Count number of factors in a (squarefree) factorization.
276     * @param F = [p_1 -&gt; e_1, ..., p_k -&gt; e_k].
277     * @return sum_{i=1,...,k} e_i.
278     */
279    public long factorCount(SortedMap<GenPolynomial<C>, Long> F) {
280        if (F == null || F.isEmpty()) {
281            return 0L;
282        }
283        long f = 0L;
284        for (Long e : F.values()) {
285            f += e;
286        }
287        return f;
288    }
289
290
291    /**
292     * GenPolynomial is (squarefree) factorization.
293     * @param P GenPolynomial.
294     * @param F = [p_1 -&gt; e_1, ..., p_k -&gt; e_k].
295     * @return true if P = prod_{i=1,...,k} p_i**e_i, else false.
296     */
297    public boolean isFactorization(GenPolynomial<C> P, SortedMap<GenPolynomial<C>, Long> F) {
298        if (P == null || F == null) {
299            throw new IllegalArgumentException("P and F may not be null");
300        }
301        if (P.isZERO() && F.size() == 0) {
302            return true;
303        }
304        GenPolynomial<C> t = P.ring.getONE();
305        for (Map.Entry<GenPolynomial<C>, Long> me : F.entrySet()) {
306            GenPolynomial<C> f = me.getKey();
307            Long E = me.getValue();
308            long e = E.longValue();
309            GenPolynomial<C> g = f.power(e);
310            t = t.multiply(g);
311        }
312        boolean f = P.equals(t) || P.equals(t.negate());
313        if (!f) {
314            P = P.monic();
315            t = t.monic();
316            f = P.equals(t) || P.equals(t.negate());
317            if (f) {
318                return f;
319            }
320            logger.info("no factorization(map): F = {}, P = {}, t = {}", F, P, t);
321            //RuntimeException e = new RuntimeException("fac-map");
322            //e.printStackTrace();
323            //throw e;
324        }
325        return f;
326    }
327
328
329    /**
330     * GenPolynomial is (squarefree) factorization.
331     * @param P GenPolynomial.
332     * @param F = [p_1 -&gt; e_1, ..., p_k -&gt; e_k].
333     * @return true if P = prod_{i=1,...,k} p_i**e_i, else false.
334     */
335    public boolean isRecursiveFactorization(GenPolynomial<GenPolynomial<C>> P,
336                    SortedMap<GenPolynomial<GenPolynomial<C>>, Long> F) {
337        if (P == null || F == null) {
338            throw new IllegalArgumentException("P and F may not be null");
339        }
340        if (P.isZERO() && F.size() == 0) {
341            return true;
342        }
343        GenPolynomial<GenPolynomial<C>> t = P.ring.getONE();
344        for (Map.Entry<GenPolynomial<GenPolynomial<C>>, Long> me : F.entrySet()) {
345            GenPolynomial<GenPolynomial<C>> f = me.getKey();
346            Long E = me.getValue(); // F.get(f);
347            long e = E.longValue();
348            GenPolynomial<GenPolynomial<C>> g = f.power(e);
349            t = t.multiply(g);
350        }
351        boolean f = P.equals(t) || P.equals(t.negate());
352        if (!f) {
353            GenPolynomialRing<C> cf = (GenPolynomialRing<C>) P.ring.coFac;
354            GreatestCommonDivisorAbstract<C> engine = GCDFactory.getProxy(cf.coFac);
355            GenPolynomial<GenPolynomial<C>> Pp = engine.recursivePrimitivePart(P);
356            Pp = PolyUtil.<C> monic(Pp);
357            GenPolynomial<GenPolynomial<C>> tp = engine.recursivePrimitivePart(t);
358            tp = PolyUtil.<C> monic(tp);
359            f = Pp.equals(tp) || Pp.equals(tp.negate());
360            if (f) {
361                return f;
362            }
363            logger.info("no factorization(map): F  = {}, P  = {}, t  = {}, Pp = {}, tp = {}", F, P, t, Pp, tp);
364            //RuntimeException e = new RuntimeException("fac-map");
365            //e.printStackTrace();
366            //throw e;
367        }
368        return f;
369    }
370
371
372    /**
373     * GenPolynomial recursive polynomial greatest squarefree divisor.
374     * @param P recursive GenPolynomial.
375     * @return squarefree(pp(P)).
376     */
377    public GenPolynomial<GenPolynomial<C>> recursiveSquarefreePart(GenPolynomial<GenPolynomial<C>> P) {
378        if (P == null || P.isZERO()) {
379            return P;
380        }
381        if (P.ring.nvar <= 1) {
382            return recursiveUnivariateSquarefreePart(P);
383        }
384        // distributed polynomials squarefree part
385        GenPolynomialRing<GenPolynomial<C>> rfac = P.ring;
386        RingFactory<GenPolynomial<C>> rrfac = rfac.coFac;
387        GenPolynomialRing<C> cfac = (GenPolynomialRing<C>) rrfac;
388        GenPolynomialRing<C> dfac = cfac.extend(rfac.nvar);
389        GenPolynomial<C> Pd = PolyUtil.<C> distribute(dfac, P);
390        GenPolynomial<C> Dd = squarefreePart(Pd);
391        // convert to recursive
392        GenPolynomial<GenPolynomial<C>> C = PolyUtil.<C> recursive(rfac, Dd);
393        return C;
394    }
395
396
397    /**
398     * GenPolynomial recursive polynomial squarefree factorization.
399     * @param P recursive GenPolynomial.
400     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k}
401     *         p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j.
402     */
403    public SortedMap<GenPolynomial<GenPolynomial<C>>, Long> recursiveSquarefreeFactors(
404                    GenPolynomial<GenPolynomial<C>> P) {
405        SortedMap<GenPolynomial<GenPolynomial<C>>, Long> factors;
406        factors = new TreeMap<GenPolynomial<GenPolynomial<C>>, Long>();
407        if (P == null || P.isZERO()) {
408            return factors;
409        }
410        if (P.ring.nvar <= 1) {
411            return recursiveUnivariateSquarefreeFactors(P);
412        }
413        // distributed polynomials squarefree part
414        GenPolynomialRing<GenPolynomial<C>> rfac = P.ring;
415        RingFactory<GenPolynomial<C>> rrfac = rfac.coFac;
416        GenPolynomialRing<C> cfac = (GenPolynomialRing<C>) rrfac;
417        GenPolynomialRing<C> dfac = cfac.extend(rfac.nvar);
418        GenPolynomial<C> Pd = PolyUtil.<C> distribute(dfac, P);
419        SortedMap<GenPolynomial<C>, Long> dfacs = squarefreeFactors(Pd);
420        // convert to recursive
421        for (Map.Entry<GenPolynomial<C>, Long> Dm : dfacs.entrySet()) {
422            GenPolynomial<C> Dd = Dm.getKey();
423            Long e = Dm.getValue();
424            GenPolynomial<GenPolynomial<C>> C = PolyUtil.<C> recursive(rfac, Dd);
425            factors.put(C, e);
426        }
427        return factors;
428    }
429
430
431    /**
432     * Univariate GenPolynomial partial fraction decomposition.
433     * @param A univariate GenPolynomial.
434     * @param D sorted map [d_1 -&gt; e_1, ..., d_k -&gt; e_k] with d_i
435     *            squarefree.
436     * @return [ [Ai0, Ai1,..., Aie_i], i=0,...,k ] with A/prod(D) = A0 + sum(
437     *         sum ( Aij/di^j ) ) with deg(Aij) &lt; deg(di).
438     */
439    public List<List<GenPolynomial<C>>> basePartialFraction(GenPolynomial<C> A,
440                    SortedMap<GenPolynomial<C>, Long> D) {
441        if (D == null || A == null) {
442            throw new IllegalArgumentException("null A or D not allowed");
443        }
444        List<List<GenPolynomial<C>>> pf = new ArrayList<List<GenPolynomial<C>>>(D.size() + 1);
445        if (D.size() == 0) {
446            return pf;
447        }
448        //List<GenPolynomial<C>> fi;
449        if (A.isZERO()) {
450            for (Map.Entry<GenPolynomial<C>, Long> me : D.entrySet()) {
451                long e = me.getValue();
452                int e1 = (int) e + 1;
453                List<GenPolynomial<C>> fi = new ArrayList<GenPolynomial<C>>(e1);
454                for (int i = 0; i < e1; i++) {
455                    fi.add(A);
456                }
457                pf.add(fi);
458            }
459            List<GenPolynomial<C>> fi = new ArrayList<GenPolynomial<C>>(1);
460            fi.add(A);
461            pf.add(0, fi);
462            return pf;
463        }
464        // A != 0, D != empty
465        List<GenPolynomial<C>> Dp = new ArrayList<GenPolynomial<C>>(D.size());
466        for (Map.Entry<GenPolynomial<C>, Long> me : D.entrySet()) {
467            GenPolynomial<C> d = me.getKey();
468            long e = me.getValue(); //D.get(d);
469            GenPolynomial<C> f = d.power(e);
470            Dp.add(f);
471        }
472        List<GenPolynomial<C>> F = engine.basePartialFraction(A, Dp);
473        //System.out.println("fraction list = " + F.size());
474        GenPolynomial<C> A0 = F.remove(0);
475        List<GenPolynomial<C>> fi = new ArrayList<GenPolynomial<C>>(1);
476        fi.add(A0);
477        pf.add(fi);
478        int i = 0;
479        for (Map.Entry<GenPolynomial<C>, Long> me : D.entrySet()) { // assume fixed sequence order
480            GenPolynomial<C> d = me.getKey();
481            long e = me.getValue();
482            int ei = (int) e;
483            GenPolynomial<C> gi = F.get(i); // assume fixed sequence order
484            List<GenPolynomial<C>> Fi = engine.basePartialFraction(gi, d, ei);
485            pf.add(Fi);
486            i++;
487        }
488        return pf;
489    }
490
491
492    /**
493     * Test for Univariate GenPolynomial partial fraction decomposition.
494     * @param A univariate GenPolynomial.
495     * @param D sorted map [d_1 -&gt; e_1, ..., d_k -&gt; e_k] with d_i
496     *            squarefree.
497     * @param F a list of lists [ [Ai0, Ai1,..., Aie_i], i=0,...,k ]
498     * @return true, if A/prod(D) = A0 + sum( sum ( Aij/di^j ) ), else false.
499     */
500    public boolean isBasePartialFraction(GenPolynomial<C> A, SortedMap<GenPolynomial<C>, Long> D,
501                    List<List<GenPolynomial<C>>> F) {
502        if (D == null || A == null || F == null) {
503            throw new IllegalArgumentException("null A, D or F not allowed");
504        }
505        if (D.isEmpty() && F.isEmpty()) {
506            return true;
507        }
508        if (D.isEmpty() || F.isEmpty()) {
509            return false;
510        }
511        List<GenPolynomial<C>> Dp = new ArrayList<GenPolynomial<C>>(D.size());
512        for (Map.Entry<GenPolynomial<C>, Long> me : D.entrySet()) {
513            GenPolynomial<C> d = me.getKey();
514            long e = me.getValue(); // D.get(d);
515            GenPolynomial<C> f = d.power(e);
516            Dp.add(f);
517        }
518        List<GenPolynomial<C>> fi = F.get(0);
519        if (fi.size() != 1) {
520            logger.info("size(fi) != 1 {}", fi);
521            return false;
522        }
523        boolean t;
524        GenPolynomial<C> A0 = fi.get(0);
525        //System.out.println("A0 = " + A0);
526        List<GenPolynomial<C>> Qp = new ArrayList<GenPolynomial<C>>(D.size() + 1);
527        Qp.add(A0);
528
529        //         List<GenPolynomial<C>> Fp = engine.basePartialFraction(A,Dp);
530        //         System.out.println("fraction list = " + F.size());
531        //         t = engine.isBasePartialFraction(A,Dp,Fp);
532        //         if ( ! t ) {
533        //             System.out.println("not recursion isPartFrac = " + Fp);
534        //             return false;
535        //         }
536        //         GenPolynomial<C> A0p = Fp.remove(0);
537        //         if ( ! A0.equals(A0p) ) {
538        //             System.out.println("A0 != A0p " + A0p);
539        //             return false;
540        //         }
541
542        int i = 0;
543        for (Map.Entry<GenPolynomial<C>, Long> me : D.entrySet()) { // assume fixed sequence order
544            GenPolynomial<C> d = me.getKey();
545            long e = me.getValue();
546            int ei = (int) e;
547            List<GenPolynomial<C>> Fi = F.get(i + 1); // assume fixed sequence order
548
549            //            GenPolynomial<C> pi = Fp.get(i);        // assume fixed sequence order
550            //             t = engine.isBasePartialFraction(pi,d,ei,Fi);
551            //             if ( ! t ) {
552            //                 System.out.println("not isPartFrac exp = " + pi + ", d = " + d + ", e = " + ei);
553            //                 System.out.println("not isPartFrac exp = " + Fi);
554            //                 return false;
555            //             }
556
557            GenPolynomial<C> qi = engine.basePartialFractionValue(d, ei, Fi);
558            Qp.add(qi);
559
560            //             t = qi.equals(pi);
561            //             if ( ! t ) {
562            //                 System.out.println("not isPartFrac exp = " + pi + ", d = " + d + ", e = " + ei + ", qi = " + qi);
563            //             }
564
565            i++;
566        }
567
568        t = engine.isBasePartialFraction(A, Dp, Qp);
569        if (!t) {
570            System.out.println("not final isPartFrac " + Qp);
571        }
572        return t;
573    }
574
575
576    /**
577     * Coefficients greatest squarefree divisor.
578     * @param P coefficient.
579     * @return squarefree part of P.
580     */
581    public C squarefreePart(C P) {
582        if (P == null) {
583            return null;
584        }
585        C s = null;
586        SortedMap<C, Long> factors = squarefreeFactors(P);
587        //if (logger.isWarnEnabled()) {
588        //    logger.warn("sqfPart, better use sqfFactors, factors = {}", factors);
589        //}
590        for (C sp : factors.keySet()) {
591            if (s == null) {
592                s = sp;
593            } else {
594                s = s.multiply(sp);
595            }
596        }
597        return s;
598    }
599
600
601    /**
602     * Coefficients squarefree factorization.
603     * @param P coefficient.
604     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k}
605     *         p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j.
606     */
607    public abstract SortedMap<C, Long> squarefreeFactors(C P);
608    /* not possible:
609    {
610        if (P == null) {
611            return null;
612        }
613        SortedMap<C, Long> factors = new TreeMap<C, Long>();
614        SquarefreeAbstract<C> reng = SquarefreeFactory.getImplementation((RingFactory<C>) P.factory());
615            System.out.println("fcp,reng = " + reng);
616            SortedMap<C, Long> rfactors = reng.squarefreeFactors(P);
617            for (C c : rfactors.keySet()) {
618                if (!c.isONE()) {
619                    C cr = (C) (Object) c;
620                    Long rk = rfactors.get(c);
621                    factors.put(cr, rk);
622                }
623            }
624    
625        return factors;
626    }
627    */
628
629}