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