001    /*
002     * $Id: FactorAlgebraic.java 3670 2011-06-25 19:04:28Z kredel $
003     */
004    
005    package edu.jas.ufd;
006    
007    
008    import java.util.ArrayList;
009    import java.util.List;
010    
011    import org.apache.log4j.Logger;
012    
013    import edu.jas.poly.AlgebraicNumber;
014    import edu.jas.poly.AlgebraicNumberRing;
015    import edu.jas.poly.GenPolynomial;
016    import edu.jas.poly.GenPolynomialRing;
017    import edu.jas.poly.PolyUtil;
018    import edu.jas.poly.TermOrder;
019    import edu.jas.structure.GcdRingElem;
020    
021    
022    /**
023     * Algebraic number coefficients factorization algorithms. This class implements
024     * factorization methods for polynomials over algebraic numbers over rational
025     * numbers or over (prime) modular integers.
026     * @author Heinz Kredel
027     * @param <C> coefficient type
028     */
029    
030    public class FactorAlgebraic<C extends GcdRingElem<C>> extends FactorAbsolute<AlgebraicNumber<C>> {
031    
032    
033        private static final Logger logger = Logger.getLogger(FactorAlgebraic.class);
034    
035    
036        private final boolean debug = true || logger.isInfoEnabled();
037    
038    
039        /**
040         * Factorization engine for base coefficients.
041         */
042        public final FactorAbstract<C> factorCoeff;
043    
044    
045        /**
046         * No argument constructor. <b>Note:</b> can't use this constructor.
047         */
048        protected FactorAlgebraic() {
049            throw new IllegalArgumentException("don't use this constructor");
050        }
051    
052    
053        /**
054         * Constructor.
055         * @param fac algebraic number factory.
056         */
057        public FactorAlgebraic(AlgebraicNumberRing<C> fac) {
058            super(fac);
059            this.factorCoeff = FactorFactory.<C> getImplementation(fac.ring.coFac);
060        }
061    
062    
063        /**
064         * GenPolynomial base factorization of a squarefree polynomial.
065         * @param P squarefree GenPolynomial&lt;AlgebraicNumber&lt;C&gt;&gt;.
066         * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i.
067         */
068        @Override
069        public List<GenPolynomial<AlgebraicNumber<C>>> baseFactorsSquarefree(GenPolynomial<AlgebraicNumber<C>> P) {
070            if (P == null) {
071                throw new IllegalArgumentException(this.getClass().getName() + " P == null");
072            }
073            List<GenPolynomial<AlgebraicNumber<C>>> factors = new ArrayList<GenPolynomial<AlgebraicNumber<C>>>();
074            if (P.isZERO()) {
075                return factors;
076            }
077            if (P.isONE()) {
078                factors.add(P);
079                return factors;
080            }
081            GenPolynomialRing<AlgebraicNumber<C>> pfac = P.ring; // Q(alpha)[x]
082            if (pfac.nvar > 1) {
083                throw new IllegalArgumentException("only for univariate polynomials");
084            }
085            AlgebraicNumberRing<C> afac = (AlgebraicNumberRing<C>) pfac.coFac;
086            AlgebraicNumber<C> ldcf = P.leadingBaseCoefficient();
087            if (!ldcf.isONE()) {
088                P = P.monic();
089                factors.add(pfac.getONE().multiply(ldcf));
090            }
091            //System.out.println("\nP = " + P);
092            if (false && debug) {
093               Squarefree<AlgebraicNumber<C>> sqengine = SquarefreeFactory.<AlgebraicNumber<C>> getImplementation(afac);
094               if ( !sqengine.isSquarefree(P) ) {
095                   throw new RuntimeException("P not squarefree: " + sqengine.squarefreeFactors(P));
096               }
097               GenPolynomial<C> modu = afac.modul;
098               if ( !factorCoeff.isIrreducible(modu) ) {
099                   throw new RuntimeException("modul not irreducible: " + factorCoeff.factors(modu));
100               }
101               System.out.println("P squarefree and modul irreducible");
102               //GreatestCommonDivisor<AlgebraicNumber<C>> aengine //= GCDFactory.<AlgebraicNumber<C>> getProxy(afac);
103               //  = new GreatestCommonDivisorSimple<AlgebraicNumber<C>>( /*cfac.coFac*/ );
104            }
105    
106            // search squarefree norm
107            long k = 0L;
108            long ks = k;
109            GenPolynomial<C> res = null;
110            boolean sqf = false;
111            //int[] klist = new int[]{ 0, 1, 2, 3, -1, -2, -3 , 5, -5, 7, -7, 101, -101, 1001, -1001 };
112            //int[] klist = new int[]{ 0, 1, 2, 3, -1, -2, -3 , 5, -5, 7, -7, 23, -23, 167, -167 };
113            //int[] klist = new int[] { 0, -1, -2, 1, 2, -3, 3 };
114            int[] klist = new int[] { 0, -1, -2, 1, 2 };
115            int ki = 0;
116            while (!sqf) {
117                // k = 0,1,2,-1,-2
118                if (ki >= klist.length) {
119                    break;
120                }
121                k = klist[ki];
122                ki++;
123                // compute norm with x -> ( y - k x )
124                ks = k;
125                res = PolyUfdUtil.<C> norm(P, ks);
126                //System.out.println("res = " + res);
127                if (res.isZERO() || res.isConstant()) {
128                    continue;
129                }
130                sqf = factorCoeff.isSquarefree(res);
131                //System.out.println("sqf("+ks+") = " + res.degree());
132                //System.out.println("resfact = " + factorCoeff.baseFactors(res) + "\n");
133            }
134            // if Res is now squarefree, else must take radical factorization
135            List<GenPolynomial<C>> nfacs;
136            if (!sqf) {
137                //System.out.println("\nres = " + res); 
138                System.out.println("sqf(" + ks + ") = " + res.degree());
139                //res = factorCoeff.squarefreePart(res); // better use obtained factors
140                //res = factorCoeff.baseFactors(res).lastKey();
141            }
142            //res = res.monic();
143            if (logger.isInfoEnabled()) {
144                logger.info("res = " + res);
145                //System.out.println("\nres = " + res); 
146            }
147            nfacs = factorCoeff.baseFactorsRadical(res);
148            if (logger.isInfoEnabled()) {
149                logger.info("res facs = " + nfacs); // Q[X]
150                //System.out.println("\nnfacs = " + nfacs); // Q[X]
151            }
152            if (nfacs.size() == 1) {
153                factors.add(P);
154                return factors;
155            }
156    
157            // compute gcds of factors with polynomial in Q(alpha)[X]
158            GenPolynomial<AlgebraicNumber<C>> Pp = P;
159            //System.out.println("Pp = " + Pp);
160            GenPolynomial<AlgebraicNumber<C>> Ni;
161            for (GenPolynomial<C> nfi : nfacs) {
162                //System.out.println("nfi = " + nfi);
163                Ni = PolyUfdUtil.<C> substituteConvertToAlgebraicCoefficients(pfac, nfi, ks);
164                if (logger.isDebugEnabled()) {
165                    logger.info("Ni = " + Ni);
166                    //System.out.println("Pp = " + Pp);
167                    //System.out.println("Ni = " + Ni);
168                }
169                // compute gcds of factors with polynomial
170                GenPolynomial<AlgebraicNumber<C>> pni = engine.gcd(Ni, Pp);
171                if (!pni.leadingBaseCoefficient().isONE()) {
172                    //System.out.println("gcd(Ni,Pp) not monic " + pni);
173                    pni = pni.monic();
174                }
175                if (logger.isInfoEnabled()) {
176                    logger.info("gcd(Ni,Pp) = " + pni);
177                    //System.out.println("gcd(Ni,Pp) = " + pni);
178                }
179                if (!pni.isONE()) {
180                    factors.add(pni);
181                    Pp = Pp.divide(pni);
182                    //             } else {
183                    //                 GenPolynomial<AlgebraicNumber<C>> qni = Pp.divide(Ni);
184                    //                 GenPolynomial<AlgebraicNumber<C>> rni = Pp.remainder(Ni);
185                    //                 System.out.println("div qni = " + qni);
186                    //                 System.out.println("div rni = " + rni);
187                    //                 continue;
188                    //                 //throw new RuntimeException("gcd(Ni,Pp) == 1");
189                }
190            }
191            if (!Pp.isZERO() && !Pp.isONE()) { // irreducible rest
192                factors.add(Pp);
193            }
194            //System.out.println("afactors = " + factors);
195            return factors;
196        }
197    
198    }