001/*
002 * $Id: SquarefreeAbstract.java 5963 2018-11-11 12:42:14Z kredel $
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.Logger;
015import org.apache.logging.log4j.LogManager; 
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 P = prod_{i=1,...,k}
061     *         p_i^{e_i} and p_i squarefree.
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.
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.
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        GenPolynomial<C> t = P.ring.getONE();
260        for (GenPolynomial<C> f : F) {
261            t = t.multiply(f);
262        }
263        boolean f = P.equals(t) || P.equals(t.negate());
264        if (!f) {
265            logger.info("no factorization(list): F = " + F + ", P = " + P + ", t = " + t);
266        }
267        return f;
268    }
269
270
271    /**
272     * Count number of factors in a (squarefree) factorization.
273     * @param F = [p_1 -&gt; e_1, ..., p_k -&gt; e_k].
274     * @return sum_{i=1,...,k} e_i.
275     */
276    public long factorCount(SortedMap<GenPolynomial<C>, Long> F) {
277        if (F == null || F.isEmpty()) {
278            return 0L;
279        }
280        long f = 0L;
281        for (Long e : F.values()) {
282            f += e;
283        }
284        return f;
285    }
286
287
288    /**
289     * GenPolynomial is (squarefree) factorization.
290     * @param P GenPolynomial.
291     * @param F = [p_1 -&gt; e_1, ..., p_k -&gt; e_k].
292     * @return true if P = prod_{i=1,...,k} p_i**e_i, else false.
293     */
294    public boolean isFactorization(GenPolynomial<C> P, SortedMap<GenPolynomial<C>, Long> F) {
295        if (P == null || F == null) {
296            throw new IllegalArgumentException("P and F may not be null");
297        }
298        if (P.isZERO() && F.size() == 0) {
299            return true;
300        }
301        GenPolynomial<C> t = P.ring.getONE();
302        for (Map.Entry<GenPolynomial<C>, Long> me : F.entrySet()) {
303            GenPolynomial<C> f = me.getKey();
304            Long E = me.getValue(); 
305            long e = E.longValue();
306            GenPolynomial<C> g = f.power(e);
307            t = t.multiply(g);
308        }
309        boolean f = P.equals(t) || P.equals(t.negate());
310        if (!f) {
311            P = P.monic();
312            t = t.monic();
313            f = P.equals(t) || P.equals(t.negate());
314            if (f) {
315                return f;
316            }
317            logger.info("no factorization(map): F = " + F + ", P = " + P + ", t = " + t);
318            //RuntimeException e = new RuntimeException("fac-map");
319            //e.printStackTrace();
320            //throw e;
321        }
322        return f;
323    }
324
325
326    /**
327     * GenPolynomial is (squarefree) factorization.
328     * @param P GenPolynomial.
329     * @param F = [p_1 -&gt; e_1, ..., p_k -&gt; e_k].
330     * @return true if P = prod_{i=1,...,k} p_i**e_i, else false.
331     */
332    public boolean isRecursiveFactorization(GenPolynomial<GenPolynomial<C>> P,
333                    SortedMap<GenPolynomial<GenPolynomial<C>>, Long> F) {
334        if (P == null || F == null) {
335            throw new IllegalArgumentException("P and F may not be null");
336        }
337        if (P.isZERO() && F.size() == 0) {
338            return true;
339        }
340        GenPolynomial<GenPolynomial<C>> t = P.ring.getONE();
341        for (Map.Entry<GenPolynomial<GenPolynomial<C>>, Long> me : F.entrySet()) {
342            GenPolynomial<GenPolynomial<C>> f = me.getKey();
343            Long E = me.getValue(); // F.get(f);
344            long e = E.longValue();
345            GenPolynomial<GenPolynomial<C>> g = f.power(e);
346            t = t.multiply(g);
347        }
348        boolean f = P.equals(t) || P.equals(t.negate());
349        if (!f) {
350            GenPolynomialRing<C> cf = (GenPolynomialRing<C>) P.ring.coFac;
351            GreatestCommonDivisorAbstract<C> engine = GCDFactory.getProxy(cf.coFac);
352            GenPolynomial<GenPolynomial<C>> Pp = engine.recursivePrimitivePart(P);
353            Pp = PolyUtil.<C> monic(Pp);
354            GenPolynomial<GenPolynomial<C>> tp = engine.recursivePrimitivePart(t);
355            tp = PolyUtil.<C> monic(tp);
356            f = Pp.equals(tp) || Pp.equals(tp.negate());
357            if (f) {
358                return f;
359            }
360            logger.info("no factorization(map): F  = " + F + ", P  = " + P + ", t  = " + t 
361                        + ", Pp = " + Pp + ", tp = " + tp);
362            //RuntimeException e = new RuntimeException("fac-map");
363            //e.printStackTrace();
364            //throw e;
365        }
366        return f;
367    }
368
369
370    /**
371     * GenPolynomial recursive polynomial greatest squarefree divisor.
372     * @param P recursive GenPolynomial.
373     * @return squarefree(pp(P)).
374     */
375    public GenPolynomial<GenPolynomial<C>> recursiveSquarefreePart(GenPolynomial<GenPolynomial<C>> P) {
376        if (P == null || P.isZERO()) {
377            return P;
378        }
379        if (P.ring.nvar <= 1) {
380            return recursiveUnivariateSquarefreePart(P);
381        }
382        // distributed polynomials squarefree part
383        GenPolynomialRing<GenPolynomial<C>> rfac = P.ring;
384        RingFactory<GenPolynomial<C>> rrfac = rfac.coFac;
385        GenPolynomialRing<C> cfac = (GenPolynomialRing<C>) rrfac;
386        GenPolynomialRing<C> dfac = cfac.extend(rfac.nvar);
387        GenPolynomial<C> Pd = PolyUtil.<C> distribute(dfac, P);
388        GenPolynomial<C> Dd = squarefreePart(Pd);
389        // convert to recursive
390        GenPolynomial<GenPolynomial<C>> C = PolyUtil.<C> recursive(rfac, Dd);
391        return C;
392    }
393
394
395    /**
396     * GenPolynomial recursive polynomial squarefree factorization.
397     * @param P recursive GenPolynomial.
398     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k}
399     *         p_i^{e_i} and p_i squarefree.
400     */
401    public SortedMap<GenPolynomial<GenPolynomial<C>>, Long> recursiveSquarefreeFactors(
402                    GenPolynomial<GenPolynomial<C>> P) {
403        SortedMap<GenPolynomial<GenPolynomial<C>>, Long> factors;
404        factors = new TreeMap<GenPolynomial<GenPolynomial<C>>, Long>();
405        if (P == null || P.isZERO()) {
406            return factors;
407        }
408        if (P.ring.nvar <= 1) {
409            return recursiveUnivariateSquarefreeFactors(P);
410        }
411        // distributed polynomials squarefree part
412        GenPolynomialRing<GenPolynomial<C>> rfac = P.ring;
413        RingFactory<GenPolynomial<C>> rrfac = rfac.coFac;
414        GenPolynomialRing<C> cfac = (GenPolynomialRing<C>) rrfac;
415        GenPolynomialRing<C> dfac = cfac.extend(rfac.nvar);
416        GenPolynomial<C> Pd = PolyUtil.<C> distribute(dfac, P);
417        SortedMap<GenPolynomial<C>, Long> dfacs = squarefreeFactors(Pd);
418        // convert to recursive
419        for (Map.Entry<GenPolynomial<C>, Long> Dm : dfacs.entrySet()) {
420            GenPolynomial<C> Dd = Dm.getKey();
421            Long e = Dm.getValue();
422            GenPolynomial<GenPolynomial<C>> C = PolyUtil.<C> recursive(rfac, Dd);
423            factors.put(C, e);
424        }
425        return factors;
426    }
427
428
429    /**
430     * Univariate GenPolynomial partial fraction decomposition.
431     * @param A univariate GenPolynomial.
432     * @param D sorted map [d_1 -&gt; e_1, ..., d_k -&gt; e_k] with d_i
433     *            squarefree.
434     * @return [ [Ai0, Ai1,..., Aie_i], i=0,...,k ] with A/prod(D) = A0 + sum(
435     *         sum ( Aij/di^j ) ) with deg(Aij) < deg(di).
436     */
437    public List<List<GenPolynomial<C>>> basePartialFraction(GenPolynomial<C> A,
438                    SortedMap<GenPolynomial<C>, Long> D) {
439        if (D == null || A == null) {
440            throw new IllegalArgumentException("null A or D not allowed");
441        }
442        List<List<GenPolynomial<C>>> pf = new ArrayList<List<GenPolynomial<C>>>(D.size() + 1);
443        if (D.size() == 0) {
444            return pf;
445        }
446        //List<GenPolynomial<C>> fi;
447        if (A.isZERO()) {
448            for (Map.Entry<GenPolynomial<C>, Long> me : D.entrySet()) {
449                long e = me.getValue();
450                int e1 = (int) e + 1;
451                List<GenPolynomial<C>> fi = new ArrayList<GenPolynomial<C>>(e1);
452                for (int i = 0; i < e1; i++) {
453                    fi.add(A);
454                }
455                pf.add(fi);
456            }
457            List<GenPolynomial<C>> fi = new ArrayList<GenPolynomial<C>>(1);
458            fi.add(A);
459            pf.add(0, fi);
460            return pf;
461        }
462        // A != 0, D != empty
463        List<GenPolynomial<C>> Dp = new ArrayList<GenPolynomial<C>>(D.size());
464        for (Map.Entry<GenPolynomial<C>, Long> me : D.entrySet()) {
465            GenPolynomial<C> d = me.getKey();
466            long e = me.getValue(); //D.get(d);
467            GenPolynomial<C> f = d.power(e);
468            Dp.add(f);
469        }
470        List<GenPolynomial<C>> F = engine.basePartialFraction(A, Dp);
471        //System.out.println("fraction list = " + F.size());
472        GenPolynomial<C> A0 = F.remove(0);
473        List<GenPolynomial<C>> fi = new ArrayList<GenPolynomial<C>>(1);
474        fi.add(A0);
475        pf.add(fi);
476        int i = 0;
477        for (Map.Entry<GenPolynomial<C>, Long> me : D.entrySet()) { // assume fixed sequence order
478            GenPolynomial<C> d = me.getKey();
479            long e = me.getValue(); 
480            int ei = (int) e;
481            GenPolynomial<C> gi = F.get(i); // assume fixed sequence order
482            List<GenPolynomial<C>> Fi = engine.basePartialFraction(gi, d, ei);
483            pf.add(Fi);
484            i++;
485        }
486        return pf;
487    }
488
489
490    /**
491     * Test for Univariate GenPolynomial partial fraction decomposition.
492     * @param A univariate GenPolynomial.
493     * @param D sorted map [d_1 -&gt; e_1, ..., d_k -&gt; e_k] with d_i
494     *            squarefree.
495     * @param F a list of lists [ [Ai0, Ai1,..., Aie_i], i=0,...,k ]
496     * @return true, if A/prod(D) = A0 + sum( sum ( Aij/di^j ) ), else false.
497     */
498    public boolean isBasePartialFraction(GenPolynomial<C> A, SortedMap<GenPolynomial<C>, Long> D,
499                    List<List<GenPolynomial<C>>> F) {
500        if (D == null || A == null || F == null) {
501            throw new IllegalArgumentException("null A, D or F not allowed");
502        }
503        if (D.isEmpty() && F.isEmpty()) {
504            return true;
505        }
506        if (D.isEmpty() || F.isEmpty()) {
507            return false;
508        }
509        List<GenPolynomial<C>> Dp = new ArrayList<GenPolynomial<C>>(D.size());
510        for (Map.Entry<GenPolynomial<C>, Long> me : D.entrySet()) {
511            GenPolynomial<C> d = me.getKey();
512            long e = me.getValue(); // D.get(d);
513            GenPolynomial<C> f = d.power(e);
514            Dp.add(f);
515        }
516        List<GenPolynomial<C>> fi = F.get(0);
517        if (fi.size() != 1) {
518            logger.info("size(fi) != 1 " + fi);
519            return false;
520        }
521        boolean t;
522        GenPolynomial<C> A0 = fi.get(0);
523        //System.out.println("A0 = " + A0);
524        List<GenPolynomial<C>> Qp = new ArrayList<GenPolynomial<C>>(D.size() + 1);
525        Qp.add(A0);
526
527        //         List<GenPolynomial<C>> Fp = engine.basePartialFraction(A,Dp);
528        //         System.out.println("fraction list = " + F.size());
529        //         t = engine.isBasePartialFraction(A,Dp,Fp);
530        //         if ( ! t ) {
531        //             System.out.println("not recursion isPartFrac = " + Fp);
532        //             return false;
533        //         }
534        //         GenPolynomial<C> A0p = Fp.remove(0);
535        //         if ( ! A0.equals(A0p) ) {
536        //             System.out.println("A0 != A0p " + A0p);
537        //             return false;
538        //         }
539
540        int i = 0;
541        for (Map.Entry<GenPolynomial<C>, Long> me : D.entrySet()) { // assume fixed sequence order
542            GenPolynomial<C> d = me.getKey();
543            long e = me.getValue(); 
544            int ei = (int) e;
545            List<GenPolynomial<C>> Fi = F.get(i + 1); // assume fixed sequence order
546
547            //            GenPolynomial<C> pi = Fp.get(i);        // assume fixed sequence order
548            //             t = engine.isBasePartialFraction(pi,d,ei,Fi);
549            //             if ( ! t ) {
550            //                 System.out.println("not isPartFrac exp = " + pi + ", d = " + d + ", e = " + ei);
551            //                 System.out.println("not isPartFrac exp = " + Fi);
552            //                 return false;
553            //             }
554
555            GenPolynomial<C> qi = engine.basePartialFractionValue(d, ei, Fi);
556            Qp.add(qi);
557
558            //             t = qi.equals(pi);
559            //             if ( ! t ) {
560            //                 System.out.println("not isPartFrac exp = " + pi + ", d = " + d + ", e = " + ei + ", qi = " + qi);
561            //             }
562
563            i++;
564        }
565
566        t = engine.isBasePartialFraction(A, Dp, Qp);
567        if (!t) {
568            System.out.println("not final isPartFrac " + Qp);
569        }
570        return t;
571    }
572
573
574    /**
575     * Coefficients greatest squarefree divisor.
576     * @param P coefficient.
577     * @return squarefree part of P.
578     */
579    public C squarefreePart(C P) {
580        if (P == null) {
581            return null;
582        }
583        C s = null;
584        SortedMap<C, Long> factors = squarefreeFactors(P);
585        //if (logger.isWarnEnabled()) {
586        //    logger.warn("sqfPart, better use sqfFactors, factors = " + factors);
587        //}
588        for (C sp : factors.keySet()) {
589            if (s == null) {
590                s = sp;
591            } else {
592                s = s.multiply(sp);
593            }
594        }
595        return s;
596    }
597
598
599    /**
600     * Coefficients squarefree factorization.
601     * @param P coefficient.
602     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k}
603     *         p_i^{e_i} and p_i squarefree.
604     */
605    public abstract SortedMap<C, Long> squarefreeFactors(C P);
606    /* not possible:
607    {
608        if (P == null) {
609            return null;
610        }
611        SortedMap<C, Long> factors = new TreeMap<C, Long>();
612        SquarefreeAbstract<C> reng = SquarefreeFactory.getImplementation((RingFactory<C>) P.factory());
613            System.out.println("fcp,reng = " + reng);
614            SortedMap<C, Long> rfactors = reng.squarefreeFactors(P);
615            for (C c : rfactors.keySet()) {
616                if (!c.isONE()) {
617                    C cr = (C) (Object) c;
618                    Long rk = rfactors.get(c);
619                    factors.put(cr, rk);
620                }
621            }
622    
623        return factors;
624    }
625    */
626
627}