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