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<AlgebraicNumber<C>>. 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<AlgebraicNumber<C>>. 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}