001/*
002 * $Id$
003 */
004
005package edu.jas.ufd;
006
007
008import java.util.ArrayList;
009import java.util.List;
010
011import org.apache.logging.log4j.LogManager;
012import org.apache.logging.log4j.Logger;
013
014import edu.jas.poly.AlgebraicNumber;
015import edu.jas.poly.AlgebraicNumberRing;
016import edu.jas.poly.GenPolynomial;
017import edu.jas.poly.GenPolynomialRing;
018import edu.jas.structure.GcdRingElem;
019
020
021/**
022 * Algebraic number coefficients factorization algorithms. This class implements
023 * factorization methods for polynomials over algebraic numbers over rational
024 * numbers or over (prime) modular integers.
025 * @author Heinz Kredel
026 * @param <C> coefficient type
027 */
028
029public class FactorAlgebraic<C extends GcdRingElem<C>> extends FactorAbsolute<AlgebraicNumber<C>> {
030
031
032    private static final Logger logger = LogManager.getLogger(FactorAlgebraic.class);
033
034
035    private static final boolean debug = logger.isDebugEnabled();
036
037
038    /**
039     * Factorization engine for base coefficients.
040     */
041    public final FactorAbstract<C> factorCoeff;
042
043
044    /**
045     * No argument constructor. <b>Note:</b> can't use this constructor.
046     */
047    protected FactorAlgebraic() {
048        throw new IllegalArgumentException("don't use this constructor");
049    }
050
051
052    /**
053     * Constructor.
054     * @param fac algebraic number factory.
055     */
056    public FactorAlgebraic(AlgebraicNumberRing<C> fac) {
057        this(fac, FactorFactory.<C> getImplementation(fac.ring.coFac));
058    }
059
060
061    /**
062     * Constructor.
063     * @param fac algebraic number factory.
064     * @param factorCoeff factorization engine for polynomials over base
065     *            coefficients.
066     */
067    public FactorAlgebraic(AlgebraicNumberRing<C> fac, FactorAbstract<C> factorCoeff) {
068        super(fac);
069        this.factorCoeff = factorCoeff;
070    }
071
072
073    /**
074     * GenPolynomial base factorization of a squarefree polynomial.
075     * @param P squarefree GenPolynomial&lt;AlgebraicNumber&lt;C&gt;&gt;.
076     * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i.
077     */
078    @Override
079    public List<GenPolynomial<AlgebraicNumber<C>>> baseFactorsSquarefree(
080                    GenPolynomial<AlgebraicNumber<C>> P) {
081        if (P == null) {
082            throw new IllegalArgumentException(this.getClass().getName() + " P == null");
083        }
084        List<GenPolynomial<AlgebraicNumber<C>>> factors = new ArrayList<GenPolynomial<AlgebraicNumber<C>>>();
085        if (P.isZERO()) {
086            return factors;
087        }
088        if (P.isONE()) {
089            factors.add(P);
090            return factors;
091        }
092        GenPolynomialRing<AlgebraicNumber<C>> pfac = P.ring; // Q(alpha)[x]
093        if (pfac.nvar > 1) {
094            throw new IllegalArgumentException("only for univariate polynomials");
095        }
096        AlgebraicNumberRing<C> afac = (AlgebraicNumberRing<C>) pfac.coFac;
097        AlgebraicNumber<C> ldcf = P.leadingBaseCoefficient();
098        if (!ldcf.isONE()) {
099            P = P.monic();
100            factors.add(pfac.getONE().multiply(ldcf));
101        }
102        //System.out.println("\nP = " + P);
103        if (debug) {
104            Squarefree<AlgebraicNumber<C>> sqengine = SquarefreeFactory
105                            .<AlgebraicNumber<C>> getImplementation(afac);
106            if (!sqengine.isSquarefree(P)) {
107                throw new RuntimeException("P not squarefree: " + sqengine.squarefreeFactors(P));
108            }
109            GenPolynomial<C> modu = afac.modul;
110            if (!factorCoeff.isIrreducible(modu)) {
111                throw new RuntimeException("modul not irreducible: " + factorCoeff.factors(modu));
112            }
113            System.out.println("P squarefree and modul irreducible");
114            //GreatestCommonDivisor<AlgebraicNumber<C>> aengine //= GCDFactory.<AlgebraicNumber<C>> getProxy(afac);
115            //  = new GreatestCommonDivisorSimple<AlgebraicNumber<C>>( /*cfac.coFac*/ );
116        }
117
118        // search squarefree norm
119        long k = 0L;
120        long ks = k;
121        GenPolynomial<C> res = null;
122        boolean sqf = false;
123        //int[] klist = new int[]{ 0, 1, 2, 3, -1, -2, -3 , 5, -5, 7, -7, 101, -101, 1001, -1001 };
124        //int[] klist = new int[]{ 0, 1, 2, 3, -1, -2, -3 , 5, -5, 7, -7, 23, -23, 167, -167 };
125        //int[] klist = new int[] { 0, -1, -2, 1, 2, -3, 3 };
126        int[] klist = new int[] { 0, -1, -2, 1, 2 };
127        int ki = 0;
128        while (!sqf) {
129            // k = 0,1,2,-1,-2
130            if (ki >= klist.length) {
131                break;
132            }
133            k = klist[ki];
134            ki++;
135            // compute norm with x -> ( y - k x )
136            ks = k;
137            res = PolyUfdUtil.<C> norm(P, ks);
138            //System.out.println("res = " + res);
139            if (res.isZERO() || res.isConstant()) {
140                continue;
141            }
142            sqf = factorCoeff.isSquarefree(res);
143        }
144        // if Res is now squarefree, else must take radical factorization
145        List<GenPolynomial<C>> nfacs;
146        if (!sqf) {
147            //System.out.println("\nres = " + res); 
148            logger.warn("sqf(" + ks + ") = " + res.degree());
149            //res = factorCoeff.squarefreePart(res); // better use obtained factors
150            //res = factorCoeff.baseFactors(res).lastKey();
151        }
152        //res = res.monic();
153        if (logger.isInfoEnabled()) {
154            logger.info("res = " + res);
155        }
156        nfacs = factorCoeff.baseFactorsRadical(res);
157        if (logger.isInfoEnabled()) {
158            logger.info("res facs = " + nfacs); // Q[X]
159        }
160        if (nfacs.size() == 1) {
161            factors.add(P);
162            return factors;
163        }
164
165        // compute gcds of factors with polynomial in Q(alpha)[X]
166        GenPolynomial<AlgebraicNumber<C>> Pp = P;
167        //System.out.println("Pp = " + Pp);
168        GenPolynomial<AlgebraicNumber<C>> Ni;
169        for (GenPolynomial<C> nfi : nfacs) {
170            //System.out.println("nfi = " + nfi);
171            Ni = PolyUfdUtil.<C> substituteConvertToAlgebraicCoefficients(pfac, nfi, ks);
172            if (logger.isInfoEnabled()) {
173                logger.info("Ni = " + Ni);
174                //System.out.println("Pp = " + Pp);
175            }
176            // compute gcds of factors with polynomial
177            GenPolynomial<AlgebraicNumber<C>> pni = engine.gcd(Ni, Pp);
178            if (!pni.leadingBaseCoefficient().isONE()) {
179                pni = pni.monic();
180            }
181            if (logger.isInfoEnabled()) {
182                logger.info("gcd(Ni,Pp) = " + pni);
183            }
184            if (!pni.isONE()) {
185                factors.add(pni);
186                Pp = Pp.divide(pni);
187            }
188        }
189        if (!Pp.isZERO() && !Pp.isONE()) { // irreducible rest
190            factors.add(Pp);
191        }
192        //System.out.println("afactors = " + factors);
193        return factors;
194    }
195
196
197    /**
198     * GenPolynomial factorization of a squarefree polynomial.
199     * @param P squarefree and primitive! (respectively monic)
200     *            GenPolynomial&lt;AlgebraicNumber&lt;C&gt;&gt;.
201     * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i.
202     */
203    @Override
204    public List<GenPolynomial<AlgebraicNumber<C>>> factorsSquarefree(GenPolynomial<AlgebraicNumber<C>> P) {
205        if (P == null) {
206            throw new IllegalArgumentException(this.getClass().getName() + " P == null");
207        }
208        List<GenPolynomial<AlgebraicNumber<C>>> factors = new ArrayList<GenPolynomial<AlgebraicNumber<C>>>();
209        if (P.isZERO()) {
210            return factors;
211        }
212        if (P.isONE()) {
213            factors.add(P);
214            return factors;
215        }
216        GenPolynomialRing<AlgebraicNumber<C>> pfac = P.ring; // Q(alpha)[x1,...,xn]
217        if (pfac.nvar <= 1) {
218            throw new IllegalArgumentException("only for multivariate polynomials");
219        }
220        //AlgebraicNumberRing<C> afac = (AlgebraicNumberRing<C>) pfac.coFac;
221        AlgebraicNumber<C> ldcf = P.leadingBaseCoefficient();
222        if (!ldcf.isONE()) {
223            P = P.monic();
224            factors.add(pfac.getONE().multiply(ldcf));
225        }
226        if (P.degreeVector().totalDeg() <= 1L) {
227            factors.add(P);
228            return factors;
229        }
230        //System.out.println("\nP = " + P);
231
232        // search squarefree norm
233        long k = 0L;
234        long ks = k;
235        GenPolynomial<C> res = null;
236        boolean sqf = false;
237        //int[] klist = new int[]{ 0, 1, 2, 3, -1, -2, -3 , 5, -5, 7, -7, 101, -101, 1001, -1001 };
238        //int[] klist = new int[]{ 0, 1, 2, 3, -1, -2, -3 , 5, -5, 7, -7, 23, -23, 167, -167 };
239        //int[] klist = new int[] { 0, -1, -2, 1, 2, -3, 3 };
240        int[] klist = new int[] { 0, -1, -2, 1, 2 };
241        int ki = 0;
242        while (!sqf) {
243            // k = 0,1,2,-1,-2
244            if (ki >= klist.length) {
245                logger.warn("sqf(" + ks + ") = " + res.degree());
246                break;
247            }
248            k = klist[ki];
249            ki++;
250            // compute norm with x -> ( y - k x )
251            ks = k;
252            res = PolyUfdUtil.<C> norm(P, ks);
253            //System.out.println("res = " + res);
254            if (res.isZERO() || res.isConstant()) {
255                continue;
256            }
257            sqf = factorCoeff.isSquarefree(res);
258            //System.out.println("resfact = " + factorCoeff.factors(res) + "\n");
259        }
260        // if Res is now squarefree, else must take radical factorization
261        List<GenPolynomial<C>> nfacs;
262        if (!sqf) {
263            System.out.println("sqf_" + pfac.nvar + "(" + ks + ") = " + res.degree());
264        }
265        //res = res.monic();
266        if (logger.isInfoEnabled()) {
267            logger.info("res = " + res);
268            logger.info("factorCoeff = " + factorCoeff);
269        }
270        nfacs = factorCoeff.factorsRadical(res);
271        //System.out.println("\nnfacs = " + nfacs); // Q[X]
272        if (logger.isInfoEnabled()) {
273            logger.info("res facs = " + nfacs); // Q[X]
274        }
275        if (nfacs.size() == 1) {
276            factors.add(P);
277            return factors;
278        }
279
280        // compute gcds of factors with polynomial in Q(alpha)[X]
281        GenPolynomial<AlgebraicNumber<C>> Pp = P;
282        //System.out.println("Pp = " + Pp);
283        GenPolynomial<AlgebraicNumber<C>> Ni;
284        for (GenPolynomial<C> nfi : nfacs) {
285            //System.out.println("nfi = " + nfi);
286            Ni = PolyUfdUtil.<C> substituteConvertToAlgebraicCoefficients(pfac, nfi, ks);
287            if (logger.isInfoEnabled()) {
288                logger.info("Ni = " + Ni);
289                //System.out.println("Pp = " + Pp);
290            }
291            // compute gcds of factors with polynomial
292            GenPolynomial<AlgebraicNumber<C>> pni = engine.gcd(Ni, Pp);
293            if (!pni.leadingBaseCoefficient().isONE()) {
294                //System.out.println("gcd(Ni,Pp) not monic " + pni);
295                pni = pni.monic();
296            }
297            if (logger.isInfoEnabled()) {
298                logger.info("gcd(Ni,Pp) = " + pni);
299            }
300            //System.out.println("gcd(Ni,Pp) = " + pni);
301            if (!pni.isONE()) {
302                factors.add(pni);
303                Pp = Pp.divide(pni);
304            }
305        }
306        if (!Pp.isZERO() && !Pp.isONE()) { // irreducible rest
307            factors.add(Pp);
308        }
309        //factors.add(P);
310        return factors;
311    }
312
313}