001/*
002 * $Id: SquarefreeFieldCharP.java 5845 2018-05-31 09:24:18Z 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.log4j.Logger;
013
014import edu.jas.poly.AlgebraicNumber;
015import edu.jas.poly.AlgebraicNumberRing;
016import edu.jas.poly.ExpVector;
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 * Squarefree decomposition for coefficient fields of characteristic p.
026 * @author Heinz Kredel
027 */
028
029public abstract class SquarefreeFieldCharP<C extends GcdRingElem<C>> extends SquarefreeAbstract<C> {
030
031
032    private static final Logger logger = Logger.getLogger(SquarefreeFieldCharP.class);
033
034
035    private static final boolean debug = logger.isDebugEnabled();
036
037
038    /*
039     * Squarefree engine for characteristic p base coefficients.
040     */
041    //protected final SquarefreeAbstract<C> rengine;
042
043
044    /**
045     * Factory for finite field of characteristic p coefficients.
046     */
047    protected final RingFactory<C> coFac;
048
049
050    /**
051     * Factory for a algebraic extension of a finite field of characteristic p
052     * coefficients. If <code>coFac</code> is an algebraic extension, then
053     * <code>aCoFac</code> is equal to <code>coFac</code>, else
054     * <code>aCoFac</code> is <code>null</code>.
055     */
056    protected final AlgebraicNumberRing<C> aCoFac;
057
058
059    /**
060     * Factory for a transcendental extension of a finite field of
061     * characteristic p coefficients. If <code>coFac</code> is an transcendental
062     * extension, then <code>qCoFac</code> is equal to <code>coFac</code>, else
063     * <code>qCoFac</code> is <code>null</code>.
064     */
065    protected final QuotientRing<C> qCoFac;
066
067
068    /**
069     * Constructor.
070     */
071    @SuppressWarnings("unchecked")
072    public SquarefreeFieldCharP(RingFactory<C> fac) {
073        super(GCDFactory.<C> getProxy(fac));
074        if (!fac.isField()) {
075            //throw new IllegalArgumentException("fac must be a field: "  + fac.toScript());
076            logger.warn("fac should be a field: " + fac.toScript());
077        }
078        if (fac.characteristic().signum() == 0) {
079            throw new IllegalArgumentException("characterisic(fac) must be non-zero");
080        }
081        coFac = fac;
082        Object oFac = coFac;
083        if (oFac instanceof AlgebraicNumberRing) {
084            aCoFac = (AlgebraicNumberRing<C>) oFac; // <C> is not correct
085            //rengine = (SquarefreeAbstract) SquarefreeFactory.getImplementation(aCoFac.ring);
086            qCoFac = null;
087        } else {
088            aCoFac = null;
089            if (oFac instanceof QuotientRing) {
090                qCoFac = (QuotientRing<C>) oFac; // <C> is not correct
091                //rengine = (SquarefreeAbstract) SquarefreeFactory.getImplementation(qCoFac.ring);
092            } else {
093                qCoFac = null;
094            }
095        }
096    }
097
098
099    /**
100     * Get the String representation.
101     * @see java.lang.Object#toString()
102     */
103    @Override
104    public String toString() {
105        return getClass().getName() + " with " + engine + " over " + coFac;
106    }
107
108
109    /**
110     * GenPolynomial polynomial greatest squarefree divisor.
111     * @param P GenPolynomial.
112     * @return squarefree(pp(P)).
113     */
114    @Override
115    public GenPolynomial<C> baseSquarefreePart(GenPolynomial<C> P) {
116        if (P == null || P.isZERO()) {
117            return P;
118        }
119        GenPolynomialRing<C> pfac = P.ring;
120        if (pfac.nvar > 1) {
121            throw new IllegalArgumentException(
122                            this.getClass().getName() + " only for univariate polynomials");
123        }
124        GenPolynomial<C> s = pfac.getONE();
125        SortedMap<GenPolynomial<C>, Long> factors = baseSquarefreeFactors(P);
126        if (logger.isWarnEnabled()) {
127           logger.warn("sqfPart, better use sqfFactors, factors = " + factors);
128        }
129        for (GenPolynomial<C> sp : factors.keySet()) {
130            s = s.multiply(sp);
131        }
132        s = s.monic();
133        return s;
134    }
135
136
137    /**
138     * GenPolynomial polynomial squarefree factorization.
139     * @param A GenPolynomial.
140     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k}
141     *         p_i^{e_i} and p_i squarefree.
142     */
143    @Override
144    public SortedMap<GenPolynomial<C>, Long> baseSquarefreeFactors(GenPolynomial<C> A) {
145        SortedMap<GenPolynomial<C>, Long> sfactors = new TreeMap<GenPolynomial<C>, Long>();
146        if (A == null || A.isZERO()) {
147            return sfactors;
148        }
149        GenPolynomialRing<C> pfac = A.ring;
150        if (A.isConstant()) {
151            C coeff = A.leadingBaseCoefficient();
152            //System.out.println("coeff = " + coeff + " @ " + coeff.factory());
153            SortedMap<C, Long> rfactors = squarefreeFactors(coeff);
154            //System.out.println("rfactors,const = " + rfactors);
155            if (rfactors != null && rfactors.size() > 0) {
156                for (Map.Entry<C, Long> me : rfactors.entrySet()) {
157                    C c = me.getKey();
158                    if (!c.isONE()) {
159                        GenPolynomial<C> cr = pfac.getONE().multiply(c);
160                        Long rk = me.getValue(); // rfactors.get(c);
161                        sfactors.put(cr, rk);
162                    }
163                }
164            } else {
165                sfactors.put(A, 1L);
166            }
167            return sfactors;
168        }
169        if (pfac.nvar > 1) {
170            throw new IllegalArgumentException(
171                            this.getClass().getName() + " only for univariate polynomials");
172        }
173        C ldbcf = A.leadingBaseCoefficient();
174        if (!ldbcf.isONE()) {
175            A = A.divide(ldbcf);
176            SortedMap<C, Long> rfactors = squarefreeFactors(ldbcf);
177            //System.out.println("rfactors,ldbcf = " + rfactors);
178            if (rfactors != null && rfactors.size() > 0) {
179                for (Map.Entry<C, Long> me : rfactors.entrySet()) {
180                    C c = me.getKey();
181                    if (!c.isONE()) {
182                        GenPolynomial<C> cr = pfac.getONE().multiply(c);
183                        Long rk = me.getValue(); //rfactors.get(c);
184                        sfactors.put(cr, rk);
185                    }
186                }
187            } else {
188                GenPolynomial<C> f1 = pfac.getONE().multiply(ldbcf);
189                //System.out.println("gcda sqf f1 = " + f1);
190                sfactors.put(f1, 1L);
191            }
192            ldbcf = pfac.coFac.getONE();
193        }
194        GenPolynomial<C> T0 = A;
195        long e = 1L;
196        GenPolynomial<C> Tp;
197        GenPolynomial<C> T = null;
198        GenPolynomial<C> V = null;
199        long k = 0L;
200        long mp = 0L;
201        boolean init = true;
202        while (true) {
203            //System.out.println("T0 = " + T0);
204            if (init) {
205                if (T0.isConstant() || T0.isZERO()) {
206                    break;
207                }
208                Tp = PolyUtil.<C> baseDeriviative(T0);
209                T = engine.baseGcd(T0, Tp);
210                T = T.monic();
211                V = PolyUtil.<C> basePseudoDivide(T0, T);
212                //System.out.println("iT0 = " + T0);
213                //System.out.println("iTp = " + Tp);
214                //System.out.println("iT  = " + T);
215                //System.out.println("iV  = " + V);
216                //System.out.println("const(iV)  = " + V.isConstant());
217                k = 0L;
218                mp = 0L;
219                init = false;
220            }
221            if (V.isConstant()) {
222                mp = pfac.characteristic().longValue(); // assert != 0
223                //T0 = PolyUtil.<C> baseModRoot(T,mp);
224                T0 = baseRootCharacteristic(T);
225                logger.info("char root: T0 = " + T0 + ", T = " + T);
226                if (T0 == null) {
227                    //break;
228                    T0 = pfac.getZERO();
229                }
230                e = e * mp;
231                init = true;
232                continue;
233            }
234            k++;
235            if (mp != 0L && k % mp == 0L) {
236                T = PolyUtil.<C> basePseudoDivide(T, V);
237                System.out.println("k = " + k);
238                //System.out.println("T = " + T);
239                k++;
240            }
241            GenPolynomial<C> W = engine.baseGcd(T, V);
242            W = W.monic();
243            GenPolynomial<C> z = PolyUtil.<C> basePseudoDivide(V, W);
244            //System.out.println("W = " + W);
245            //System.out.println("z = " + z);
246            V = W;
247            T = PolyUtil.<C> basePseudoDivide(T, V);
248            //System.out.println("V = " + V);
249            //System.out.println("T = " + T);
250            if (z.degree(0) > 0) {
251                if (ldbcf.isONE() && !z.leadingBaseCoefficient().isONE()) {
252                    z = z.monic();
253                    logger.info("z,monic = " + z);
254                }
255                sfactors.put(z, (e * k));
256            }
257        }
258        logger.info("exit char root: T0 = " + T0 + ", T = " + T);
259        return sfactors;
260    }
261
262
263    /**
264     * GenPolynomial recursive univariate polynomial greatest squarefree
265     * divisor.
266     * @param P recursive univariate GenPolynomial.
267     * @return squarefree(pp(P)).
268     */
269    @Override
270    public GenPolynomial<GenPolynomial<C>> recursiveUnivariateSquarefreePart(
271                    GenPolynomial<GenPolynomial<C>> P) {
272        if (P == null || P.isZERO()) {
273            return P;
274        }
275        GenPolynomialRing<GenPolynomial<C>> pfac = P.ring;
276        if (pfac.nvar > 1) {
277            throw new IllegalArgumentException(
278                            this.getClass().getName() + " only for univariate polynomials");
279        }
280        GenPolynomial<GenPolynomial<C>> s = pfac.getONE();
281        SortedMap<GenPolynomial<GenPolynomial<C>>, Long> factors = recursiveUnivariateSquarefreeFactors(P);
282        if (logger.isWarnEnabled()) {
283            logger.warn("sqfPart, better use sqfFactors, factors = " + factors);
284        }
285        for (GenPolynomial<GenPolynomial<C>> sp : factors.keySet()) {
286            s = s.multiply(sp);
287        }
288        return PolyUtil.<C> monic(s);
289    }
290
291
292    /**
293     * GenPolynomial recursive univariate polynomial squarefree factorization.
294     * @param P recursive univariate GenPolynomial.
295     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k}
296     *         p_i^{e_i} and p_i squarefree.
297     */
298    @Override
299    public SortedMap<GenPolynomial<GenPolynomial<C>>, Long> recursiveUnivariateSquarefreeFactors(
300                    GenPolynomial<GenPolynomial<C>> P) {
301        SortedMap<GenPolynomial<GenPolynomial<C>>, Long> sfactors = new TreeMap<GenPolynomial<GenPolynomial<C>>, Long>();
302        if (P == null || P.isZERO()) {
303            return sfactors;
304        }
305        GenPolynomialRing<GenPolynomial<C>> pfac = P.ring;
306        if (pfac.nvar > 1) {
307            // recursiveContent not possible by return type
308            throw new IllegalArgumentException(
309                            this.getClass().getName() + " only for univariate polynomials");
310        }
311        // if base coefficient ring is a field, make monic
312        GenPolynomialRing<C> cfac = (GenPolynomialRing<C>) pfac.coFac;
313        C ldbcf = P.leadingBaseCoefficient().leadingBaseCoefficient();
314        if (!ldbcf.isONE()) {
315            GenPolynomial<C> lc = cfac.getONE().multiply(ldbcf);
316            GenPolynomial<GenPolynomial<C>> pl = pfac.getONE().multiply(lc);
317            sfactors.put(pl, 1L);
318            C li = ldbcf.inverse();
319            //System.out.println("li = " + li);
320            P = P.multiply(cfac.getONE().multiply(li));
321            //System.out.println("P,monic = " + P);
322            ldbcf = P.leadingBaseCoefficient().leadingBaseCoefficient();
323            if (debug) {
324                logger.debug("new ldbcf: " + ldbcf);
325            }
326        }
327        // factors of content
328        GenPolynomial<C> Pc = engine.recursiveContent(P);
329        if (logger.isInfoEnabled()) {
330            logger.info("Pc = " + Pc);
331        }
332        Pc = Pc.monic();
333        if (!Pc.isONE()) {
334            P = PolyUtil.<C> coefficientPseudoDivide(P, Pc);
335        }
336        SortedMap<GenPolynomial<C>, Long> rsf = squarefreeFactors(Pc);
337        if (logger.isInfoEnabled()) {
338            logger.info("rsf = " + rsf);
339        }
340        // add factors of content
341        for (Map.Entry<GenPolynomial<C>, Long> me : rsf.entrySet()) {
342            GenPolynomial<C> c = me.getKey();
343            if (!c.isONE()) {
344                GenPolynomial<GenPolynomial<C>> cr = pfac.getONE().multiply(c);
345                Long rk = me.getValue(); //rsf.get(c);
346                sfactors.put(cr, rk);
347            }
348        }
349        // divide by trailing term
350        ExpVector et = P.trailingExpVector();
351        if (!et.isZERO()) {
352            GenPolynomial<GenPolynomial<C>> tr = pfac.valueOf(et);
353            if (logger.isInfoEnabled()) {
354                logger.info("trailing term = " + tr);
355            }
356            P = PolyUtil.<C> recursivePseudoDivide(P, tr);
357            long ep = et.getVal(0); // univariate
358            et = et.subst(0, 1);
359            tr = pfac.valueOf(et);
360            sfactors.put(tr, ep);
361        }
362
363        // factors of recursive polynomial
364        GenPolynomial<GenPolynomial<C>> T0 = P;
365        long e = 1L;
366        GenPolynomial<GenPolynomial<C>> Tp;
367        GenPolynomial<GenPolynomial<C>> T = null;
368        GenPolynomial<GenPolynomial<C>> V = null;
369        long k = 0L;
370        long mp = 0L;
371        boolean init = true;
372        while (true) {
373            if (init) {
374                if (T0.isConstant() || T0.isZERO()) {
375                    break;
376                }
377                Tp = PolyUtil.<C> recursiveDeriviative(T0);
378                T = engine.recursiveUnivariateGcd(T0, Tp);
379                T = PolyUtil.<C> monic(T);
380                V = PolyUtil.<C> recursivePseudoDivide(T0, T);
381                //System.out.println("iT0 = " + T0);
382                //System.out.println("iTp = " + Tp);
383                //System.out.println("iT = " + T);
384                //System.out.println("iV = " + V);
385                k = 0L;
386                mp = 0L;
387                init = false;
388            }
389            if (V.isConstant()) {
390                mp = pfac.characteristic().longValue(); // assert != 0
391                //T0 = PolyUtil.<C> recursiveModRoot(T,mp);
392                T0 = recursiveUnivariateRootCharacteristic(T);
393                logger.info("char root: T0r = " + T0 + ", Tr = " + T);
394                if (T0 == null) {
395                    //break;
396                    T0 = pfac.getZERO();
397                }
398                e = e * mp;
399                init = true;
400                //continue;
401            }
402            k++;
403            if (mp != 0L && k % mp == 0L) {
404                T = PolyUtil.<C> recursivePseudoDivide(T, V);
405                System.out.println("k = " + k);
406                //System.out.println("T = " + T);
407                k++;
408            }
409            GenPolynomial<GenPolynomial<C>> W = engine.recursiveUnivariateGcd(T, V);
410            W = PolyUtil.<C> monic(W);
411            GenPolynomial<GenPolynomial<C>> z = PolyUtil.<C> recursivePseudoDivide(V, W);
412            //System.out.println("W = " + W);
413            //System.out.println("z = " + z);
414            V = W;
415            T = PolyUtil.<C> recursivePseudoDivide(T, V);
416            //System.out.println("V = " + V);
417            //System.out.println("T = " + T);
418            //was: if ( z.degree(0) > 0 ) {
419            if (!z.isONE() && !z.isZERO()) {
420                z = PolyUtil.<C> monic(z);
421                logger.info("z,put = " + z);
422                sfactors.put(z, (e * k));
423            }
424        }
425        logger.info("exit char root: T0 = " + T0 + ", T = " + T);
426        if (sfactors.size() == 0) {
427            sfactors.put(pfac.getONE(), 1L);
428        }
429        return sfactors;
430    }
431
432
433    /**
434     * GenPolynomial greatest squarefree divisor.
435     * @param P GenPolynomial.
436     * @return squarefree(pp(P)).
437     */
438    @Override
439    public GenPolynomial<C> squarefreePart(GenPolynomial<C> P) {
440        if (P == null) {
441            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
442        }
443        if (P.isZERO()) {
444            return P;
445        }
446        GenPolynomialRing<C> pfac = P.ring;
447        if (pfac.nvar <= 1) {
448            return baseSquarefreePart(P);
449        }
450        GenPolynomial<C> s = pfac.getONE();
451        SortedMap<GenPolynomial<C>, Long> factors = squarefreeFactors(P);
452        if (logger.isWarnEnabled()) {
453            logger.warn("sqfPart, better use sqfFactors, factors = " + factors);
454        }
455        for (GenPolynomial<C> sp : factors.keySet()) {
456            if (sp.isConstant()) {
457                continue;
458            }
459            s = s.multiply(sp);
460        }
461        return s.monic();
462    }
463
464
465    /**
466     * GenPolynomial squarefree factorization.
467     * @param P GenPolynomial.
468     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k}
469     *         p_i^{e_i} and p_i squarefree.
470     */
471    @Override
472    public SortedMap<GenPolynomial<C>, Long> squarefreeFactors(GenPolynomial<C> P) {
473        if (P == null) {
474            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
475        }
476        GenPolynomialRing<C> pfac = P.ring;
477        if (pfac.nvar <= 1) {
478            return baseSquarefreeFactors(P);
479        }
480        SortedMap<GenPolynomial<C>, Long> sfactors = new TreeMap<GenPolynomial<C>, Long>();
481        if (P.isZERO()) {
482            return sfactors;
483        }
484        if (P.isONE()) {
485            sfactors.put(P, 1L);
486            return sfactors;
487        }
488        GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1);
489        GenPolynomial<GenPolynomial<C>> Pr = PolyUtil.<C> recursive(rfac, P);
490        SortedMap<GenPolynomial<GenPolynomial<C>>, Long> PP = recursiveUnivariateSquarefreeFactors(Pr);
491        for (Map.Entry<GenPolynomial<GenPolynomial<C>>, Long> m : PP.entrySet()) {
492            Long i = m.getValue();
493            GenPolynomial<GenPolynomial<C>> Dr = m.getKey();
494            GenPolynomial<C> D = PolyUtil.<C> distribute(pfac, Dr);
495            sfactors.put(D, i);
496        }
497        return sfactors;
498    }
499
500
501    /**
502     * Coefficient squarefree factorization.
503     * @param coeff coefficient.
504     * @return [p_1 -&gt; e_1, ..., p_k -&gt; e_k] with P = prod_{i=1,...,k}
505     *         p_i^{e_i} and p_i squarefree.
506     */
507    @SuppressWarnings("unchecked")
508    @Override
509    public SortedMap<C, Long> squarefreeFactors(C coeff) {
510        if (coeff == null) {
511            return null;
512        }
513        SortedMap<C, Long> factors = new TreeMap<C, Long>();
514        RingFactory<C> cfac = (RingFactory<C>) coeff.factory();
515        if (aCoFac != null) {
516            AlgebraicNumber<C> an = (AlgebraicNumber<C>) (Object) coeff;
517            if (cfac.isFinite()) {
518                SquarefreeFiniteFieldCharP<C> reng = (SquarefreeFiniteFieldCharP) SquarefreeFactory
519                                .getImplementation(cfac);
520                SortedMap<C, Long> rfactors = reng.rootCharacteristic(coeff); // ??
521                logger.info("rfactors,finite = " + rfactors);
522                factors.putAll(rfactors);
523                //return factors;
524            } else {
525                SquarefreeInfiniteAlgebraicFieldCharP<C> reng = (SquarefreeInfiniteAlgebraicFieldCharP) SquarefreeFactory
526                                .getImplementation(cfac);
527                SortedMap<AlgebraicNumber<C>, Long> rfactors = reng.squarefreeFactors(an);
528                logger.info("rfactors,infinite,algeb = " + rfactors);
529                for (Map.Entry<AlgebraicNumber<C>, Long> me : rfactors.entrySet()) {
530                    AlgebraicNumber<C> c = me.getKey();
531                    if (!c.isONE()) {
532                        C cr = (C) (Object) c;
533                        Long rk = me.getValue();
534                        factors.put(cr, rk);
535                    }
536                }
537            }
538        } else if (qCoFac != null) {
539            Quotient<C> q = (Quotient<C>) (Object) coeff;
540            SquarefreeInfiniteFieldCharP<C> reng = (SquarefreeInfiniteFieldCharP) SquarefreeFactory
541                            .getImplementation(cfac);
542            SortedMap<Quotient<C>, Long> rfactors = reng.squarefreeFactors(q);
543            logger.info("rfactors,infinite = " + rfactors);
544            for (Map.Entry<Quotient<C>, Long> me : rfactors.entrySet()) {
545                Quotient<C> c = me.getKey();
546                if (!c.isONE()) {
547                    C cr = (C) (Object) c;
548                    Long rk = me.getValue();
549                    factors.put(cr, rk);
550                }
551            }
552        } else if (cfac.isFinite()) {
553            SquarefreeFiniteFieldCharP<C> reng = (SquarefreeFiniteFieldCharP) SquarefreeFactory
554                            .getImplementation(cfac);
555            SortedMap<C, Long> rfactors = reng.rootCharacteristic(coeff); // ??
556            logger.info("rfactors,finite = " + rfactors);
557            factors.putAll(rfactors);
558            //return factors;
559        } else {
560            logger.warn("case " + cfac + " not implemented");
561        }
562        return factors;
563    }
564
565
566    /* --------- char-th roots --------------------- */
567
568
569    /**
570     * GenPolynomial char-th root univariate polynomial.
571     * @param P GenPolynomial.
572     * @return char-th_rootOf(P), or null if no char-th root.
573     */
574    public abstract GenPolynomial<C> baseRootCharacteristic(GenPolynomial<C> P);
575
576
577    /**
578     * GenPolynomial char-th root univariate polynomial with polynomial
579     * coefficients.
580     * @param P recursive univariate GenPolynomial.
581     * @return char-th_rootOf(P), or null if P is no char-th root.
582     */
583    public abstract GenPolynomial<GenPolynomial<C>> recursiveUnivariateRootCharacteristic(
584                    GenPolynomial<GenPolynomial<C>> P);
585
586
587    /**
588     * Polynomial is char-th root.
589     * @param P polynomial.
590     * @param F = [p_1 -&gt; e_1, ..., p_k -&gt; e_k].
591     * @return true if P = prod_{i=1,...,k} p_i**(e_i*p), else false.
592     */
593    public boolean isCharRoot(GenPolynomial<C> P, SortedMap<GenPolynomial<C>, Long> F) {
594        if (P == null || F == null) {
595            throw new IllegalArgumentException("P and F may not be null");
596        }
597        if (P.isZERO() && F.size() == 0) {
598            return true;
599        }
600        GenPolynomial<C> t = P.ring.getONE();
601        long p = P.ring.characteristic().longValue();
602        for (Map.Entry<GenPolynomial<C>, Long> me : F.entrySet()) {
603            GenPolynomial<C> f = me.getKey();
604            Long E = me.getValue();
605            long e = E.longValue();
606            GenPolynomial<C> g = f.power(e);
607            if (!f.isConstant()) {
608                g = g.power(p);
609            }
610            t = t.multiply(g);
611        }
612        boolean f = P.equals(t) || P.equals(t.negate());
613        if (!f) {
614            System.out.println("\nfactorization(map): " + f);
615            System.out.println("P = " + P);
616            System.out.println("t = " + t);
617            P = P.monic();
618            t = t.monic();
619            f = P.equals(t) || P.equals(t.negate());
620            if (f) {
621                return f;
622            }
623            System.out.println("\nfactorization(map): " + f);
624            System.out.println("P = " + P);
625            System.out.println("t = " + t);
626        }
627        return f;
628    }
629
630
631    /**
632     * Recursive polynomial is char-th root.
633     * @param P recursive polynomial.
634     * @param F = [p_1 -&gt; e_1, ..., p_k -&gt; e_k].
635     * @return true if P = prod_{i=1,...,k} p_i**(e_i*p), else false.
636     */
637    public boolean isRecursiveCharRoot(GenPolynomial<GenPolynomial<C>> P,
638                    SortedMap<GenPolynomial<GenPolynomial<C>>, Long> F) {
639        if (P == null || F == null) {
640            throw new IllegalArgumentException("P and F may not be null");
641        }
642        if (P.isZERO() && F.size() == 0) {
643            return true;
644        }
645        GenPolynomial<GenPolynomial<C>> t = P.ring.getONE();
646        long p = P.ring.characteristic().longValue();
647        for (Map.Entry<GenPolynomial<GenPolynomial<C>>, Long> me : F.entrySet()) {
648            GenPolynomial<GenPolynomial<C>> f = me.getKey();
649            Long E = me.getValue();
650            long e = E.longValue();
651            GenPolynomial<GenPolynomial<C>> g = f.power(e);
652            if (!f.isConstant()) {
653                g = g.power(p);
654            }
655            t = t.multiply(g);
656        }
657        boolean f = P.equals(t) || P.equals(t.negate());
658        if (!f) {
659            System.out.println("\nfactorization(map): " + f);
660            System.out.println("P = " + P);
661            System.out.println("t = " + t);
662            P = P.monic();
663            t = t.monic();
664            f = P.equals(t) || P.equals(t.negate());
665            if (f) {
666                return f;
667            }
668            System.out.println("\nfactorization(map): " + f);
669            System.out.println("P = " + P);
670            System.out.println("t = " + t);
671        }
672        return f;
673    }
674
675
676    /**
677     * Recursive polynomial is char-th root.
678     * @param P recursive polynomial.
679     * @param r = recursive polynomial.
680     * @return true if P = r**p, else false.
681     */
682    public boolean isRecursiveCharRoot(GenPolynomial<GenPolynomial<C>> P, GenPolynomial<GenPolynomial<C>> r) {
683        if (P == null || r == null) {
684            throw new IllegalArgumentException("P and r may not be null");
685        }
686        if (P.isZERO() && r.isZERO()) {
687            return true;
688        }
689        long p = P.ring.characteristic().longValue();
690        GenPolynomial<GenPolynomial<C>> t = r.power(p);
691
692        boolean f = P.equals(t) || P.equals(t.negate());
693        if (!f) {
694            System.out.println("\nisCharRoot: " + f);
695            System.out.println("P = " + P);
696            System.out.println("t = " + t);
697            P = P.monic();
698            t = t.monic();
699            f = P.equals(t) || P.equals(t.negate());
700            if (f) {
701                return f;
702            }
703            System.out.println("\nisCharRoot: " + f);
704            System.out.println("P = " + P);
705            System.out.println("t = " + t);
706        }
707        return f;
708    }
709
710}