001/*
002 * $Id: FactorModular.java 5774 2017-11-05 17:04:30Z 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.SortedSet;
013import java.util.TreeMap;
014import java.util.TreeSet;
015
016import org.apache.log4j.Logger;
017
018import edu.jas.arith.BigInteger;
019import edu.jas.arith.ModLongRing;
020import edu.jas.arith.Modular;
021import edu.jas.arith.ModularRingFactory;
022import edu.jas.poly.GenPolynomial;
023import edu.jas.poly.GenPolynomialRing;
024import edu.jas.poly.PolyUtil;
025import edu.jas.structure.GcdRingElem;
026import edu.jas.structure.Power;
027import edu.jas.structure.RingFactory;
028
029
030/**
031 * Modular coefficients factorization algorithms. This class implements
032 * factorization methods for polynomials over (prime) modular integers.
033 * @author Heinz Kredel
034 */
035
036public class FactorModular<MOD extends GcdRingElem<MOD> & Modular> extends FactorAbsolute<MOD> {
037
038
039    private static final Logger logger = Logger.getLogger(FactorModular.class);
040
041
042    private static final boolean debug = logger.isDebugEnabled();
043
044
045    /**
046     * No argument constructor, do not use.
047     */
048    @SuppressWarnings({ "cast", "unused" })
049    private FactorModular() {
050        this((RingFactory<MOD>) (Object) new ModLongRing(13, true)); // hack, 13 unimportant
051    }
052
053
054    /**
055     * Constructor.
056     * @param cfac coefficient ring factory.
057     */
058    public FactorModular(RingFactory<MOD> cfac) {
059        super(cfac);
060    }
061
062
063    /**
064     * GenPolynomial base distinct degree factorization.
065     * @param P squarefree and monic GenPolynomial.
066     * @return [e_1 -&gt; p_1, ..., e_k -&gt; p_k] with P = prod_{i=1,...,k} p_i
067     *         and p_i has only irreducible factors of degree e_i.
068     */
069    public SortedMap<Long, GenPolynomial<MOD>> baseDistinctDegreeFactors(GenPolynomial<MOD> P) {
070        if (P == null) {
071            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
072        }
073        SortedMap<Long, GenPolynomial<MOD>> facs = new TreeMap<Long, GenPolynomial<MOD>>();
074        if (P.isZERO()) {
075            return facs;
076        }
077        GenPolynomialRing<MOD> pfac = P.ring;
078        if (pfac.nvar > 1) {
079            throw new IllegalArgumentException(
080                            this.getClass().getName() + " only for univariate polynomials");
081        }
082        ModularRingFactory<MOD> mr = (ModularRingFactory<MOD>) pfac.coFac;
083        java.math.BigInteger m = mr.getIntegerModul().getVal();
084        //if (m.longValue() == 2L) {
085        //    logger.warn(this.getClass().getName() + " case p = 2 not implemented");
086        //}
087        GenPolynomial<MOD> x = pfac.univariate(0);
088        GenPolynomial<MOD> h = x;
089        GenPolynomial<MOD> f = P;
090        GenPolynomial<MOD> g;
091        Power<GenPolynomial<MOD>> pow = new Power<GenPolynomial<MOD>>(pfac);
092        long d = 0;
093        while (d + 1 <= f.degree(0) / 2) {
094            d++;
095            h = pow.modPower(h, m, f);
096            g = engine.gcd(h.subtract(x), f);
097            if (!g.isONE()) {
098                facs.put(d, g);
099                f = f.divide(g);
100            }
101        }
102        if (!f.isONE()) {
103            d = f.degree(0);
104            facs.put(d, f);
105        }
106        return facs;
107    }
108
109
110    /**
111     * GenPolynomial base equal degree factorization.
112     * @param P squarefree and monic GenPolynomial.
113     * @param deg such that P has only irreducible factors of degree deg.
114     * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i.
115     */
116    public List<GenPolynomial<MOD>> baseEqualDegreeFactors(GenPolynomial<MOD> P, long deg) {
117        if (P == null) {
118            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
119        }
120        List<GenPolynomial<MOD>> facs = new ArrayList<GenPolynomial<MOD>>();
121        if (P.isZERO()) {
122            return facs;
123        }
124        GenPolynomialRing<MOD> pfac = P.ring;
125        if (pfac.nvar > 1) {
126            throw new IllegalArgumentException(
127                            this.getClass().getName() + " only for univariate polynomials");
128        }
129        if (P.degree(0) == deg) {
130            facs.add(P);
131            return facs;
132        }
133        ModularRingFactory<MOD> mr = (ModularRingFactory<MOD>) pfac.coFac;
134        java.math.BigInteger m = mr.getIntegerModul().getVal();
135        //System.out.println("m = " + m);
136        boolean p2 = false;
137        if (m.equals(java.math.BigInteger.valueOf(2L))) {
138            p2 = true;
139            //throw new RuntimeException(this.getClass().getName() + " case p = 2 not implemented");
140        }
141        GenPolynomial<MOD> one = pfac.getONE();
142        GenPolynomial<MOD> t = pfac.univariate(0, 1L);
143        GenPolynomial<MOD> r;
144        GenPolynomial<MOD> h;
145        GenPolynomial<MOD> f = P;
146        //GreatestCommonDivisor<MOD> engine = GCDFactory.<MOD> getImplementation(pfac.coFac);
147        Power<GenPolynomial<MOD>> pow = new Power<GenPolynomial<MOD>>(pfac);
148        GenPolynomial<MOD> g = null;
149        int degi = (int) deg; //f.degree(0);
150        //System.out.println("deg = " + deg);
151        BigInteger di = (new BigInteger(m)).power(deg);
152        //System.out.println("di = " + di);
153        java.math.BigInteger d = di.getVal(); //.longValue()-1;
154        //System.out.println("d = " + d);
155        d = d.shiftRight(1); // divide by 2
156        do {
157            if (p2) {
158                h = t;
159                for (int i = 1; i < degi; i++) {
160                    h = t.sum(h.multiply(h));
161                    h = h.remainder(f);
162                }
163                t = t.multiply(pfac.univariate(0, 2L));
164                //System.out.println("h = " + h);
165            } else {
166                r = pfac.random(17, degi, 2 * degi, 1.0f);
167                if (r.degree(0) >= f.degree(0)) {
168                    r = r.remainder(f);
169                }
170                r = r.monic();
171                //System.out.println("r = " + r);
172                h = pow.modPower(r, d, f).subtract(one);
173                degi++;
174            }
175            g = engine.gcd(h, f);
176            //System.out.println("g = " + g);
177        } while (g.degree(0) == 0 || g.degree(0) == f.degree(0));
178        f = f.divide(g);
179        facs.addAll(baseEqualDegreeFactors(f, deg));
180        facs.addAll(baseEqualDegreeFactors(g, deg));
181        return facs;
182    }
183
184
185    /**
186     * GenPolynomial base factorization of a squarefree polynomial.
187     * @param P squarefree and monic! GenPolynomial.
188     * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i.
189     */
190    @Override
191    public List<GenPolynomial<MOD>> baseFactorsSquarefree(GenPolynomial<MOD> P) {
192        if (P == null) {
193            throw new IllegalArgumentException(this.getClass().getName() + " P == null");
194        }
195        List<GenPolynomial<MOD>> factors = new ArrayList<GenPolynomial<MOD>>();
196        if (P.isZERO()) {
197            return factors;
198        }
199        if (P.isONE()) {
200            factors.add(P);
201            return factors;
202        }
203        GenPolynomialRing<MOD> pfac = P.ring;
204        if (pfac.nvar > 1) {
205            throw new IllegalArgumentException(
206                            this.getClass().getName() + " only for univariate polynomials");
207        }
208        if (!P.leadingBaseCoefficient().isONE()) {
209            throw new IllegalArgumentException("ldcf(P) != 1: " + P);
210        }
211        SortedMap<Long, GenPolynomial<MOD>> dfacs = baseDistinctDegreeFactors(P);
212        if (debug) {
213            logger.info("dfacs    = " + dfacs);
214            //System.out.println("dfacs    = " + dfacs);
215        }
216        for (Map.Entry<Long, GenPolynomial<MOD>> me : dfacs.entrySet()) {
217            Long e = me.getKey();
218            GenPolynomial<MOD> f = me.getValue(); // dfacs.get(e);
219            List<GenPolynomial<MOD>> efacs = baseEqualDegreeFactors(f, e);
220            if (debug) {
221                logger.info("efacs " + e + "   = " + efacs);
222                //System.out.println("efacs " + e + "   = " + efacs);
223            }
224            factors.addAll(efacs);
225        }
226        //System.out.println("factors  = " + factors);
227        factors = PolyUtil.<MOD> monic(factors);
228        SortedSet<GenPolynomial<MOD>> ss = new TreeSet<GenPolynomial<MOD>>(factors);
229        //System.out.println("sorted   = " + ss);
230        factors.clear();
231        factors.addAll(ss);
232        return factors;
233    }
234
235}