001/* 002 * $Id: FactorInteger.java 5871 2018-07-20 15:58:45Z kredel $ 003 */ 004 005package edu.jas.ufd; 006 007 008import java.util.ArrayList; 009import java.util.BitSet; 010import java.util.Iterator; 011import java.util.List; 012import java.util.SortedMap; 013 014import org.apache.logging.log4j.Logger; 015import org.apache.logging.log4j.LogManager; 016 017import edu.jas.arith.BigInteger; 018import edu.jas.arith.ModIntegerRing; 019import edu.jas.arith.ModLongRing; 020import edu.jas.arith.Modular; 021import edu.jas.arith.ModularRingFactory; 022import edu.jas.arith.PrimeInteger; 023import edu.jas.arith.PrimeList; 024import edu.jas.poly.ExpVector; 025import edu.jas.poly.GenPolynomial; 026import edu.jas.poly.GenPolynomialRing; 027import edu.jas.poly.OptimizedPolynomialList; 028import edu.jas.poly.PolyUtil; 029import edu.jas.poly.TermOrderOptimization; 030import edu.jas.structure.GcdRingElem; 031import edu.jas.structure.Power; 032import edu.jas.structure.RingElem; 033import edu.jas.structure.RingFactory; 034import edu.jas.util.KsubSet; 035 036 037/** 038 * Integer coefficients factorization algorithms. This class implements 039 * factorization methods for polynomials over integers. 040 * @param <MOD> 041 * @author Heinz Kredel 042 */ 043public class FactorInteger<MOD extends GcdRingElem<MOD> & Modular> extends FactorAbstract<BigInteger> { 044 045 046 private static final Logger logger = LogManager.getLogger(FactorInteger.class); 047 048 049 private static final boolean debug = logger.isDebugEnabled(); 050 051 052 /** 053 * Factorization engine for modular base coefficients. 054 */ 055 protected final FactorAbstract<MOD> mfactor; 056 057 058 /** 059 * Gcd engine for modular base coefficients. 060 */ 061 protected final GreatestCommonDivisorAbstract<MOD> mengine; 062 063 064 /** 065 * No argument constructor. 066 */ 067 public FactorInteger() { 068 this(BigInteger.ONE); 069 } 070 071 072 /** 073 * Constructor. 074 * @param cfac coefficient ring factory. 075 */ 076 @SuppressWarnings("unchecked") 077 public FactorInteger(RingFactory<BigInteger> cfac) { 078 super(cfac); 079 ModularRingFactory<MOD> mcofac = (ModularRingFactory<MOD>) (Object) new ModLongRing(13, true); // hack 080 mfactor = FactorFactory.getImplementation(mcofac); //new FactorModular(mcofac); 081 mengine = GCDFactory.getImplementation(mcofac); 082 //mengine = GCDFactory.getProxy(mcofac); 083 } 084 085 086 /** 087 * GenPolynomial test if is irreducible. 088 * @param P GenPolynomial. 089 * @return true if P is irreducible, else false. 090 */ 091 @Override 092 public boolean isIrreducible(GenPolynomial<BigInteger> P) { 093 if (P.ring.nvar == 1) { 094 if (isIrreducibleEisenstein(P)) { 095 return true; 096 } // else unknown 097 } 098 return super.isIrreducible(P); 099 } 100 101 102 /** 103 * GenPolynomial test if is irreducible with Eisenstein criterion. 104 * @param P univariate polynomial. 105 * @return true if P is irreducible, else false if it is unknown. 106 */ 107 public boolean isIrreducibleEisenstein(GenPolynomial<BigInteger> P) { 108 if (P.ring.nvar != 1) { 109 throw new IllegalArgumentException("only for univariate polynomials"); 110 } 111 if (P.degree(0) <= 1L) { // linear or constant is irreducible 112 return true; 113 } 114 BigInteger rcont = engine.baseContent(P.reductum()); 115 if (rcont.isZERO() || rcont.isONE()) { // case x**n 116 return false; 117 } 118 // todo test 119 if (rcont.compareTo(BigInteger.valueOf(PrimeInteger.BETA)) >= 0) { // integer too big 120 return false; 121 } 122 long lcont = rcont.getVal().longValue(); 123 BigInteger lc = P.leadingBaseCoefficient().abs(); 124 BigInteger tc = P.trailingBaseCoefficient().abs(); 125 SortedMap<Long, Integer> fac = PrimeInteger.factors(lcont); 126 for (Long p : fac.keySet()) { 127 BigInteger pi = BigInteger.valueOf(p); 128 if (!lc.remainder(pi).isZERO() && !tc.remainder(pi.power(2)).isZERO()) { 129 logger.info("isIrreducibleEisenstein: fac = " + fac + ", lc = " + lc + ", tc = " + tc); 130 return true; 131 } 132 } 133 return false; 134 } 135 136 137 /** 138 * GenPolynomial base factorization of a squarefree polynomial. 139 * @param P squarefree and primitive! GenPolynomial. 140 * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i. 141 */ 142 @SuppressWarnings("unchecked") 143 @Override 144 public List<GenPolynomial<BigInteger>> baseFactorsSquarefree(GenPolynomial<BigInteger> P) { 145 if (P == null) { 146 throw new IllegalArgumentException(this.getClass().getName() + " P == null"); 147 } 148 List<GenPolynomial<BigInteger>> factors = new ArrayList<GenPolynomial<BigInteger>>(); 149 if (P.isZERO()) { 150 return factors; 151 } 152 if (P.isONE()) { 153 factors.add(P); 154 return factors; 155 } 156 GenPolynomialRing<BigInteger> pfac = P.ring; 157 if (pfac.nvar > 1) { 158 throw new IllegalArgumentException( 159 this.getClass().getName() + " only for univariate polynomials"); 160 } 161 if (!engine.baseContent(P).isONE()) { 162 throw new IllegalArgumentException(this.getClass().getName() + " P not primitive"); 163 } 164 if (P.degree(0) <= 1L) { // linear is irreducible 165 factors.add(P); 166 return normalizeFactorization(factors); 167 } 168 if (isIrreducibleEisenstein(P)) { 169 factors.add(P); 170 return normalizeFactorization(factors); 171 } 172 // check cyclotomic factorization 173 //if (CycloUtil.isCyclotomicPolynomial(P)) { 174 //System.out.println("isCyclotomicPolynomial = " + P); 175 factors = CycloUtil.cyclotomicFactors(P); 176 if (factors.size() > 0) { 177 logger.info("cyclotomicFactors: #factors = " + factors.size()); 178 return normalizeFactorization(factors); 179 } 180 //} 181 // compute norm 182 BigInteger an = P.maxNorm(); 183 BigInteger ac = P.leadingBaseCoefficient(); 184 //compute factor coefficient bounds 185 ExpVector degv = P.degreeVector(); 186 int degi = (int) P.degree(0); 187 BigInteger M = an.multiply(PolyUtil.factorBound(degv)); 188 M = M.multiply(ac.abs().multiply(ac.fromInteger(8))); 189 //System.out.println("M = " + M); 190 //M = M.multiply(M); // test 191 192 //initialize prime list and degree vector 193 PrimeList primes = new PrimeList(PrimeList.Range.small); 194 int pn = 30; //primes.size(); 195 ModularRingFactory<MOD> cofac = null; 196 GenPolynomial<MOD> am = null; 197 GenPolynomialRing<MOD> mfac = null; 198 int TT = 5; // 7 199 if (degi > 100) { 200 TT += 2; 201 } 202 List<GenPolynomial<MOD>>[] modfac = new List[TT]; 203 List<GenPolynomial<BigInteger>>[] intfac = new List[TT]; 204 BigInteger[] plist = new BigInteger[TT]; 205 List<GenPolynomial<MOD>> mlist = null; 206 List<GenPolynomial<BigInteger>> ilist = null; 207 int i = 0; 208 if (debug) { 209 logger.debug("an = " + an); 210 logger.debug("ac = " + ac); 211 logger.debug("M = " + M); 212 logger.info("degv = " + degv); 213 } 214 Iterator<java.math.BigInteger> pit = primes.iterator(); 215 pit.next(); // skip p = 2 216 pit.next(); // skip p = 3 217 MOD nf = null; 218 for (int k = 0; k < TT; k++) { 219 if (k == TT - 1) { // -2 220 primes = new PrimeList(PrimeList.Range.medium); 221 pit = primes.iterator(); 222 } 223 //if (k == TT + 1) { // -1 224 // primes = new PrimeList(PrimeList.Range.large); 225 // pit = primes.iterator(); 226 //} 227 while (pit.hasNext()) { 228 java.math.BigInteger p = pit.next(); 229 //System.out.println("next run ++++++++++++++++++++++++++++++++++"); 230 if (++i >= pn) { 231 logger.error("prime list exhausted, pn = " + pn); 232 throw new ArithmeticException("prime list exhausted"); 233 } 234 if (ModLongRing.MAX_LONG.compareTo(p) > 0) { 235 cofac = (ModularRingFactory) new ModLongRing(p, true); 236 } else { 237 cofac = (ModularRingFactory) new ModIntegerRing(p, true); 238 } 239 logger.info("prime = " + cofac); 240 nf = cofac.fromInteger(ac.getVal()); 241 if (nf.isZERO()) { 242 logger.info("unlucky prime (nf) = " + p); 243 continue; 244 } 245 // initialize polynomial factory and map polynomial 246 mfac = new GenPolynomialRing<MOD>(cofac, pfac); 247 am = PolyUtil.<MOD> fromIntegerCoefficients(mfac, P); 248 if (!am.degreeVector().equals(degv)) { // allways true 249 logger.info("unlucky prime (deg) = " + p); 250 continue; 251 } 252 GenPolynomial<MOD> ap = PolyUtil.<MOD> baseDeriviative(am); 253 if (ap.isZERO()) { 254 logger.info("unlucky prime (a')= " + p); 255 continue; 256 } 257 GenPolynomial<MOD> g = mengine.baseGcd(am, ap); 258 if (g.isONE()) { 259 logger.info("**lucky prime = " + p); 260 break; 261 } 262 } 263 // now am is squarefree mod p, make monic and factor mod p 264 if (!nf.isONE()) { 265 //System.out.println("nf = " + nf); 266 am = am.divide(nf); // make monic 267 } 268 mlist = mfactor.baseFactorsSquarefree(am); 269 if (logger.isInfoEnabled()) { 270 logger.info("modlist = " + mlist); 271 } 272 if (mlist.size() <= 1) { 273 factors.add(P); 274 return factors; 275 } 276 if (!nf.isONE()) { 277 GenPolynomial<MOD> mp = mfac.getONE(); //mlist.get(0); 278 //System.out.println("mp = " + mp); 279 mp = mp.multiply(nf); 280 //System.out.println("mp = " + mp); 281 mlist.add(0, mp); // set(0,mp); 282 } 283 modfac[k] = mlist; 284 plist[k] = cofac.getIntegerModul(); // p 285 } 286 287 // search shortest factor list 288 int min = Integer.MAX_VALUE; 289 BitSet AD = null; 290 for (int k = 0; k < TT; k++) { 291 List<ExpVector> ev = PolyUtil.<MOD> leadingExpVector(modfac[k]); 292 BitSet D = factorDegrees(ev, degi); 293 if (AD == null) { 294 AD = D; 295 } else { 296 AD.and(D); 297 } 298 int s = modfac[k].size(); 299 logger.info("mod(" + plist[k] + ") #s = " + s + ", D = " + D /*+ ", lt = " + ev*/); 300 //System.out.println("mod s = " + s); 301 if (s < min) { 302 min = s; 303 mlist = modfac[k]; 304 } 305 } 306 logger.info("min = " + min + ", AD = " + AD); 307 if (mlist.size() <= 1) { 308 logger.info("mlist.size() = 1"); 309 factors.add(P); 310 return factors; 311 } 312 if (AD.cardinality() <= 2) { // only one possible factor 313 logger.info("degree set cardinality = " + AD.cardinality()); 314 factors.add(P); 315 return factors; 316 } 317 318 final boolean allLists = false; //true; //false; 319 if (allLists) { 320 // try each factor list 321 for (int k = 0; k < TT; k++) { 322 mlist = modfac[k]; 323 if (debug) { 324 logger.info("lifting from " + mlist); 325 } 326 if (P.leadingBaseCoefficient().isONE()) { // monic case 327 factors = searchFactorsMonic(P, M, mlist, AD); // does now work in all cases 328 if (factors.size() == 1) { 329 factors = searchFactorsNonMonic(P, M, mlist, AD); 330 } 331 } else { 332 factors = searchFactorsNonMonic(P, M, mlist, AD); 333 } 334 intfac[k] = factors; 335 } 336 } else { 337 // try only shortest factor list 338 if (debug) { 339 logger.info("lifting shortest from " + mlist); 340 } 341 if (P.leadingBaseCoefficient().isONE()) { 342 long t = System.currentTimeMillis(); 343 try { 344 mlist = PolyUtil.<MOD> monic(mlist); 345 factors = searchFactorsMonic(P, M, mlist, AD); // does now work in all cases 346 t = System.currentTimeMillis() - t; 347 //System.out.println("monic time = " + t); 348 intfac[0] = factors; 349 if (debug) { 350 t = System.currentTimeMillis(); 351 List<GenPolynomial<BigInteger>> fnm = searchFactorsNonMonic(P, M, mlist, AD); 352 t = System.currentTimeMillis() - t; 353 System.out.println("non monic time = " + t); 354 if (!factors.equals(fnm)) { 355 System.out.println("monic factors = " + intfac[0]); //factors); 356 System.out.println("non monic factors = " + fnm); 357 } 358 } 359 } catch (RuntimeException e) { 360 t = System.currentTimeMillis(); 361 factors = searchFactorsNonMonic(P, M, mlist, AD); 362 t = System.currentTimeMillis() - t; 363 //System.out.println("only non monic time = " + t); 364 } 365 } else { 366 long t = System.currentTimeMillis(); 367 factors = searchFactorsNonMonic(P, M, mlist, AD); 368 t = System.currentTimeMillis() - t; 369 //System.out.println("non monic time = " + t); 370 } 371 return normalizeFactorization(factors); 372 } 373 374 // search longest factor list 375 int max = 0; 376 for (int k = 0; k < TT; k++) { 377 int s = intfac[k].size(); 378 logger.info("int s = " + s); 379 if (s > max) { 380 max = s; 381 ilist = intfac[k]; 382 } 383 } 384 factors = normalizeFactorization(ilist); 385 return factors; 386 } 387 388 389 /** 390 * BitSet for factor degree list. 391 * @param E exponent vector list. 392 * @return b_0,...,b_k} a BitSet of possible factor degrees. 393 */ 394 public BitSet factorDegrees(List<ExpVector> E, int deg) { 395 BitSet D = new BitSet(deg + 1); 396 D.set(0); // constant factor 397 for (ExpVector e : E) { 398 int i = (int) e.getVal(0); 399 BitSet s = new BitSet(deg + 1); 400 for (int k = 0; k < deg + 1 - i; k++) { // shift by i places 401 s.set(i + k, D.get(k)); 402 } 403 //System.out.println("s = " + s); 404 D.or(s); 405 //System.out.println("D = " + D); 406 } 407 return D; 408 } 409 410 411 /** 412 * Sum of all degrees. 413 * @param L univariate polynomial list. 414 * @return sum deg(p) for p in L. 415 */ 416 public static <C extends RingElem<C>> long degreeSum(List<GenPolynomial<C>> L) { 417 long s = 0L; 418 for (GenPolynomial<C> p : L) { 419 ExpVector e = p.leadingExpVector(); 420 long d = e.getVal(0); 421 s += d; 422 } 423 return s; 424 } 425 426 427 /** 428 * Factor search with modular Hensel lifting algorithm. Let p = 429 * f_i.ring.coFac.modul() i = 0, ..., n-1 and assume C == prod_{0,...,n-1} 430 * f_i mod p with ggt(f_i,f_j) == 1 mod p for i != j 431 * @param C GenPolynomial. 432 * @param M bound on the coefficients of g_i as factors of C. 433 * @param F = [f_0,...,f_{n-1}] List<GenPolynomial>. 434 * @param D bit set of possible factor degrees. 435 * @return [g_0,...,g_{n-1}] = lift(C,F), with C = prod_{0,...,n-1} g_i mod 436 * p**e. <b>Note:</b> does not work in all cases. 437 */ 438 List<GenPolynomial<BigInteger>> searchFactorsMonic(GenPolynomial<BigInteger> C, BigInteger M, 439 List<GenPolynomial<MOD>> F, BitSet D) { 440 //System.out.println("*** monic factor combination ***"); 441 if (C == null || C.isZERO() || F == null || F.size() == 0) { 442 throw new IllegalArgumentException("C must be nonzero and F must be nonempty"); 443 } 444 GenPolynomialRing<BigInteger> pfac = C.ring; 445 if (pfac.nvar != 1) { // assert ? 446 throw new IllegalArgumentException("polynomial ring not univariate"); 447 } 448 List<GenPolynomial<BigInteger>> factors = new ArrayList<GenPolynomial<BigInteger>>(F.size()); 449 List<GenPolynomial<MOD>> mlist = F; 450 List<GenPolynomial<MOD>> lift; 451 452 //MOD nf = null; 453 GenPolynomial<MOD> ct = mlist.get(0); 454 if (ct.isConstant()) { 455 //nf = ct.leadingBaseCoefficient(); 456 mlist.remove(ct); 457 //System.out.println("=== nf = " + nf); 458 if (mlist.size() <= 1) { 459 factors.add(C); 460 return factors; 461 } 462 } else { 463 //nf = ct.ring.coFac.getONE(); 464 } 465 //System.out.println("modlist = " + mlist); // includes not ldcf 466 ModularRingFactory<MOD> mcfac = (ModularRingFactory<MOD>) ct.ring.coFac; 467 BigInteger m = mcfac.getIntegerModul(); 468 long k = 1; 469 BigInteger pi = m; 470 while (pi.compareTo(M) < 0) { 471 k++; 472 pi = pi.multiply(m); 473 } 474 logger.info("p^k = " + m + "^" + k); 475 GenPolynomial<BigInteger> PP = C, P = C; 476 // lift via Hensel 477 try { 478 lift = HenselUtil.<MOD> liftHenselMonic(PP, mlist, k); 479 //System.out.println("lift = " + lift); 480 } catch (NoLiftingException e) { 481 throw new RuntimeException(e); 482 } 483 if (logger.isInfoEnabled()) { 484 logger.info("lifted modlist = " + lift); 485 } 486 GenPolynomialRing<MOD> mpfac = lift.get(0).ring; 487 488 // combine trial factors 489 int dl = (lift.size() + 1) / 2; 490 //System.out.println("dl = " + dl); 491 GenPolynomial<BigInteger> u = PP; 492 long deg = (u.degree(0) + 1L) / 2L; 493 //System.out.println("deg = " + deg); 494 //BigInteger ldcf = u.leadingBaseCoefficient(); 495 //System.out.println("ldcf = " + ldcf); 496 for (int j = 1; j <= dl; j++) { 497 //System.out.println("j = " + j + ", dl = " + dl + ", lift = " + lift); 498 KsubSet<GenPolynomial<MOD>> ps = new KsubSet<GenPolynomial<MOD>>(lift, j); 499 for (List<GenPolynomial<MOD>> flist : ps) { 500 //System.out.println("degreeSum = " + degreeSum(flist)); 501 if (!D.get((int) FactorInteger.<MOD> degreeSum(flist))) { 502 logger.info("skipped by degree set " + D + ", deg = " + degreeSum(flist)); 503 continue; 504 } 505 GenPolynomial<MOD> mtrial = Power.<GenPolynomial<MOD>> multiply(mpfac, flist); 506 //GenPolynomial<MOD> mtrial = mpfac.getONE(); 507 //for (int kk = 0; kk < flist.size(); kk++) { 508 // GenPolynomial<MOD> fk = flist.get(kk); 509 // mtrial = mtrial.multiply(fk); 510 //} 511 //System.out.println("+flist = " + flist + ", mtrial = " + mtrial); 512 if (mtrial.degree(0) > deg) { // this test is sometimes wrong 513 logger.info("degree " + mtrial.degree(0) + " > deg " + deg); 514 //continue; 515 } 516 //System.out.println("+flist = " + flist); 517 GenPolynomial<BigInteger> trial = PolyUtil.integerFromModularCoefficients(pfac, mtrial); 518 //System.out.println("+trial = " + trial); 519 //trial = engine.basePrimitivePart( trial.multiply(ldcf) ); 520 trial = engine.basePrimitivePart(trial); 521 //System.out.println("pp(trial)= " + trial); 522 if (PolyUtil.<BigInteger> baseSparsePseudoRemainder(u, trial).isZERO()) { 523 logger.info("successful trial = " + trial); 524 //System.out.println("trial = " + trial); 525 //System.out.println("flist = " + flist); 526 //trial = engine.basePrimitivePart(trial); 527 //System.out.println("pp(trial)= " + trial); 528 factors.add(trial); 529 u = PolyUtil.<BigInteger> basePseudoDivide(u, trial); //u.divide( trial ); 530 //System.out.println("u = " + u); 531 //if (lift.removeAll(flist)) { 532 lift = removeOnce(lift, flist); 533 logger.info("new lift= " + lift); 534 dl = (lift.size() + 1) / 2; 535 //System.out.println("dl = " + dl); 536 j = 0; // since j++ 537 break; 538 //} logger.error("error removing flist from lift = " + lift); 539 } 540 } 541 } 542 if (!u.isONE() && !u.equals(P)) { 543 logger.info("rest u = " + u); 544 //System.out.println("rest u = " + u); 545 factors.add(u); 546 } 547 if (factors.size() == 0) { 548 logger.info("irred u = " + u); 549 //System.out.println("irred u = " + u); 550 factors.add(PP); 551 } 552 return normalizeFactorization(factors); 553 } 554 555 556 /** 557 * Factor search with modular Hensel lifting algorithm. Let p = 558 * f_i.ring.coFac.modul() i = 0, ..., n-1 and assume C == prod_{0,...,n-1} 559 * f_i mod p with ggt(f_i,f_j) == 1 mod p for i != j 560 * @param C GenPolynomial. 561 * @param M bound on the coefficients of g_i as factors of C. 562 * @param F = [f_0,...,f_{n-1}] List<GenPolynomial>. 563 * @param D bit set of possible factor degrees. 564 * @return [g_0,...,g_{n-1}] = lift(C,F), with C = prod_{0,...,n-1} g_i mod 565 * p**e. 566 */ 567 List<GenPolynomial<BigInteger>> searchFactorsNonMonic(GenPolynomial<BigInteger> C, BigInteger M, 568 List<GenPolynomial<MOD>> F, BitSet D) { 569 //System.out.println("*** non monic factor combination ***"); 570 if (C == null || C.isZERO() || F == null || F.size() == 0) { 571 throw new IllegalArgumentException("C must be nonzero and F must be nonempty"); 572 } 573 GenPolynomialRing<BigInteger> pfac = C.ring; 574 if (pfac.nvar != 1) { // assert ? 575 throw new IllegalArgumentException("polynomial ring not univariate"); 576 } 577 List<GenPolynomial<BigInteger>> factors = new ArrayList<GenPolynomial<BigInteger>>(F.size()); 578 List<GenPolynomial<MOD>> mlist = F; 579 580 MOD nf = null; 581 GenPolynomial<MOD> ct = mlist.get(0); 582 if (ct.isConstant()) { 583 nf = ct.leadingBaseCoefficient(); 584 mlist.remove(ct); 585 //System.out.println("=== nf = " + nf); 586 //System.out.println("=== ldcf = " + C.leadingBaseCoefficient()); 587 if (mlist.size() <= 1) { 588 factors.add(C); 589 return factors; 590 } 591 } else { 592 nf = ct.ring.coFac.getONE(); 593 } 594 //System.out.println("modlist = " + mlist); // includes not ldcf 595 GenPolynomialRing<MOD> mfac = ct.ring; 596 GenPolynomial<MOD> Pm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, C); 597 GenPolynomial<BigInteger> PP = C, P = C; 598 599 // combine trial factors 600 int dl = (mlist.size() + 1) / 2; 601 GenPolynomial<BigInteger> u = PP; 602 long deg = (u.degree(0) + 1L) / 2L; 603 GenPolynomial<MOD> um = Pm; 604 //BigInteger ldcf = u.leadingBaseCoefficient(); 605 //System.out.println("ldcf = " + ldcf); 606 HenselApprox<MOD> ilist = null; 607 for (int j = 1; j <= dl; j++) { 608 //System.out.println("j = " + j + ", dl = " + dl + ", ilist = " + ilist); 609 KsubSet<GenPolynomial<MOD>> ps = new KsubSet<GenPolynomial<MOD>>(mlist, j); 610 for (List<GenPolynomial<MOD>> flist : ps) { 611 //System.out.println("degreeSum = " + degreeSum(flist)); 612 if (!D.get((int) FactorInteger.<MOD> degreeSum(flist))) { 613 logger.info("skipped by degree set " + D + ", deg = " + degreeSum(flist)); 614 continue; 615 } 616 GenPolynomial<MOD> trial = mfac.getONE().multiply(nf); 617 for (int kk = 0; kk < flist.size(); kk++) { 618 GenPolynomial<MOD> fk = flist.get(kk); 619 trial = trial.multiply(fk); 620 } 621 if (trial.degree(0) > deg) { // this test is sometimes wrong 622 logger.info("degree > deg " + deg + ", degree = " + trial.degree(0)); 623 //continue; 624 } 625 GenPolynomial<MOD> cofactor = um.divide(trial); 626 //System.out.println("trial = " + trial); 627 //System.out.println("cofactor = " + cofactor); 628 629 // lift via Hensel 630 try { 631 // ilist = HenselUtil.liftHenselQuadraticFac(PP, M, trial, cofactor); 632 ilist = HenselUtil.<MOD> liftHenselQuadratic(PP, M, trial, cofactor); 633 //ilist = HenselUtil.<MOD> liftHensel(PP, M, trial, cofactor); 634 } catch (NoLiftingException e) { 635 // no liftable factors 636 if ( /*debug*/logger.isDebugEnabled()) { 637 logger.info("no liftable factors " + e); 638 //e.printStackTrace(); 639 } 640 continue; 641 } 642 GenPolynomial<BigInteger> itrial = ilist.A; 643 GenPolynomial<BigInteger> icofactor = ilist.B; 644 if (logger.isDebugEnabled()) { 645 logger.info(" modlist = " + trial + ", cofactor " + cofactor); 646 logger.info("lifted intlist = " + itrial + ", cofactor " + icofactor); 647 } 648 //System.out.println("lifted intlist = " + itrial + ", cofactor " + icofactor); 649 650 itrial = engine.basePrimitivePart(itrial); 651 //System.out.println("pp(trial)= " + itrial); 652 if (PolyUtil.<BigInteger> baseSparsePseudoRemainder(u, itrial).isZERO()) { 653 logger.info("successful trial = " + itrial); 654 //System.out.println("trial = " + itrial); 655 //System.out.println("cofactor = " + icofactor); 656 //System.out.println("flist = " + flist); 657 //itrial = engine.basePrimitivePart(itrial); 658 //System.out.println("pp(itrial)= " + itrial); 659 factors.add(itrial); 660 //u = PolyUtil.<BigInteger> basePseudoDivide(u, itrial); //u.divide( trial ); 661 u = icofactor; 662 PP = u; // fixed finally on 2009-05-03 663 um = cofactor; 664 //System.out.println("u = " + u); 665 //System.out.println("um = " + um); 666 //if (mlist.removeAll(flist)) { 667 mlist = removeOnce(mlist, flist); 668 logger.info("new mlist= " + mlist); 669 dl = (mlist.size() + 1) / 2; 670 j = 0; // since j++ 671 break; 672 //} logger.error("error removing flist from ilist = " + mlist); 673 } 674 } 675 } 676 if (!u.isONE() && !u.equals(P)) { 677 logger.info("rest u = " + u); 678 factors.add(u); 679 } 680 if (factors.size() == 0) { 681 logger.info("irred u = " + PP); 682 factors.add(PP); 683 } 684 return normalizeFactorization(factors); 685 } 686 687 688 /** 689 * GenPolynomial factorization of a multivariate squarefree polynomial, 690 * using Hensel lifting if possible. 691 * @param P squarefree and primitive! (respectively monic) multivariate 692 * GenPolynomial over the integers. 693 * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. 694 */ 695 @Override 696 public List<GenPolynomial<BigInteger>> factorsSquarefree(GenPolynomial<BigInteger> P) { 697 GenPolynomialRing<BigInteger> pfac = P.ring; 698 if (pfac.nvar <= 1) { 699 return baseFactorsSquarefree(P); 700 } 701 OptimizedPolynomialList<BigInteger> opt = null; 702 List<Integer> iperm = null; 703 final boolean USE_OPT = true; 704 if (USE_OPT) { 705 List<GenPolynomial<BigInteger>> topt = new ArrayList<GenPolynomial<BigInteger>>(1); 706 topt.add(P); 707 opt = TermOrderOptimization.<BigInteger> optimizeTermOrder(pfac,topt); 708 P = opt.list.get(0); 709 logger.info("optimized polynomial: " + P); 710 iperm = TermOrderOptimization.inversePermutation(opt.perm); 711 logger.warn("optimized ring: " + opt.ring + ", original ring: " + pfac); 712 } 713 ExpVector degv = P.degreeVector(); 714 int[] donv = degv.dependencyOnVariables(); 715 List<GenPolynomial<BigInteger>> facs = null; 716 if (degv.length() == donv.length) { // all variables appear, hack for Hensel, check 717 try { 718 logger.info("try factorsSquarefreeHensel: " + P); 719 facs = factorsSquarefreeHensel(P); 720 } catch (Exception e) { 721 logger.info("exception " + e); 722 //e.printStackTrace(); 723 } 724 } else { // not all variables appear, remove unused variables, hack for Hensel, check 725 GenPolynomial<BigInteger> pu = PolyUtil.<BigInteger> removeUnusedUpperVariables(P); 726 GenPolynomial<BigInteger> pl = PolyUtil.<BigInteger> removeUnusedLowerVariables(pu); // not useful 727 try { 728 logger.info("try factorsSquarefreeHensel: " + pl); 729 facs = factorsSquarefreeHensel(pu); 730 List<GenPolynomial<BigInteger>> fs = new ArrayList<GenPolynomial<BigInteger>>(facs.size()); 731 GenPolynomialRing<BigInteger> pf = P.ring; 732 GenPolynomialRing<BigInteger> pfu = pu.ring; 733 for (GenPolynomial<BigInteger> p : facs) { 734 GenPolynomial<BigInteger> pel = p.extendLower(pfu, 0, 0L); 735 GenPolynomial<BigInteger> pe = pel.extend(pf, 0, 0L); 736 fs.add(pe); 737 } 738 //System.out.println("fs = " + fs); 739 facs = fs; 740 } catch (Exception e) { 741 logger.info("exception " + e); 742 //e.printStackTrace(); 743 } 744 } 745 if (facs == null) { 746 logger.warn("factorsSquarefreeHensel not applicable or failed, reverting to Kronecker for: " + P); 747 facs = super.factorsSquarefree(P); 748 } 749 if (USE_OPT) { 750 facs = TermOrderOptimization.<BigInteger> permutation(iperm, pfac, facs); 751 logger.info("de-optimized polynomials: " + facs); 752 } 753 facs = normalizeFactorization(facs); 754 return facs; 755 } 756 757 758 /** 759 * GenPolynomial factorization of a multivariate squarefree polynomial, 760 * using Hensel lifting. 761 * @param P squarefree and primitive! (respectively monic) multivariate 762 * GenPolynomial over the integers. 763 * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. 764 */ 765 @SuppressWarnings("unchecked") 766 public List<GenPolynomial<BigInteger>> factorsSquarefreeHensel(GenPolynomial<BigInteger> P) { 767 if (P == null) { 768 throw new IllegalArgumentException(this.getClass().getName() + " P != null"); 769 } 770 GenPolynomialRing<BigInteger> pfac = P.ring; 771 if (pfac.nvar == 1) { 772 return baseFactorsSquarefree(P); 773 } 774 List<GenPolynomial<BigInteger>> factors = new ArrayList<GenPolynomial<BigInteger>>(); 775 if (P.isZERO()) { 776 return factors; 777 } 778 if (P.degreeVector().totalDeg() <= 1L) { 779 factors.add(P); 780 return factors; 781 } 782 GenPolynomial<BigInteger> pd = P; 783 //System.out.println("pd = " + pd); 784 // ldcf(pd) 785 BigInteger ac = pd.leadingBaseCoefficient(); 786 787 // factor leading coefficient as polynomial in the lowest! variable 788 GenPolynomialRing<GenPolynomial<BigInteger>> rnfac = pfac.recursive(pfac.nvar - 1); 789 GenPolynomial<GenPolynomial<BigInteger>> pr = PolyUtil.<BigInteger> recursive(rnfac, pd); 790 GenPolynomial<GenPolynomial<BigInteger>> prr = PolyUtil.<BigInteger> switchVariables(pr); 791 792 GenPolynomial<BigInteger> prrc = engine.recursiveContent(prr); // can have content wrt this variable 793 List<GenPolynomial<BigInteger>> cfactors = null; 794 if (!prrc.isONE()) { 795 prr = PolyUtil.<BigInteger> recursiveDivide(prr, prrc); 796 GenPolynomial<BigInteger> prrcu = prrc.extendLower(pfac, 0, 0L); // since switched vars 797 pd = PolyUtil.<BigInteger> basePseudoDivide(pd, prrcu); 798 logger.info("recursive content = " + prrc + ", new P = " + pd); 799 cfactors = factorsSquarefree(prrc); 800 List<GenPolynomial<BigInteger>> cff = new ArrayList<GenPolynomial<BigInteger>>(cfactors.size()); 801 for (GenPolynomial<BigInteger> fs : cfactors) { 802 GenPolynomial<BigInteger> fsp = fs.extendLower(pfac, 0, 0L); // since switched vars 803 cff.add(fsp); 804 } 805 cfactors = cff; 806 logger.info("cfactors = " + cfactors); 807 } 808 GenPolynomial<BigInteger> lprr = prr.leadingBaseCoefficient(); 809 //System.out.println("prr = " + prr); 810 logger.info("leading coeffcient = " + lprr); 811 boolean isMonic = false; // multivariate monic 812 if (lprr.isConstant()) { // isONE ? 813 isMonic = true; 814 } 815 SortedMap<GenPolynomial<BigInteger>, Long> lfactors = factors(lprr); 816 //System.out.println("lfactors = " + lfactors); 817 List<GenPolynomial<BigInteger>> lfacs = new ArrayList<GenPolynomial<BigInteger>>(lfactors.keySet()); 818 logger.info("leading coefficient factors = " + lfacs); 819 820 // search evaluation point and evaluate 821 GenPolynomialRing<BigInteger> cpfac = pfac; 822 GenPolynomial<BigInteger> pe = pd; 823 GenPolynomial<BigInteger> pep; 824 GenPolynomialRing<BigInteger> ccpfac = lprr.ring; 825 List<GenPolynomial<BigInteger>> ce = lfacs; 826 List<GenPolynomial<BigInteger>> cep = null; 827 List<BigInteger> cei = null; 828 List<BigInteger> dei = new ArrayList<BigInteger>(); 829 BigInteger pec = null; 830 BigInteger pecw = null; 831 BigInteger ped = null; 832 833 List<GenPolynomial<BigInteger>> ufactors = null; 834 List<TrialParts> tParts = new ArrayList<TrialParts>(); 835 List<GenPolynomial<BigInteger>> lf = null; 836 GenPolynomial<BigInteger> lpx = null; 837 List<GenPolynomial<BigInteger>> ln = null; 838 List<GenPolynomial<BigInteger>> un = null; 839 GenPolynomial<BigInteger> pes = null; 840 841 List<BigInteger> V = null; 842 long evStart = 0L; //3L * 5L; 843 List<Long> Evs = new ArrayList<Long>(pfac.nvar + 1); // Evs(0), Evs(1) unused 844 for (int j = 0; j <= pfac.nvar; j++) { 845 Evs.add(evStart); 846 } 847 final int trials = 4; 848 int countSeparate = 0; 849 final int COUNT_MAX = 50; 850 double ran = 1.001; // higher values not good 851 boolean isPrimitive = true; 852 boolean notLucky = true; 853 while (notLucky) { // for Wang's test 854 if (Math.abs(evStart) > 371L) { 855 logger.warn("no evaluation point for: P = " + P + ", lprr = " + lprr + ", lfacs = " 856 + lfacs); 857 throw new RuntimeException( 858 "no evaluation point found after " + Math.abs(evStart) + " iterations"); 859 } 860 if (Math.abs(evStart) % 100L <= 3L) { 861 ran = ran * (Math.PI - 2.14); 862 } 863 //System.out.println("-------------------------------------------- Evs = " + Evs); 864 notLucky = false; 865 V = new ArrayList<BigInteger>(); 866 cpfac = pfac; 867 pe = pd; 868 ccpfac = lprr.ring; 869 ce = lfacs; 870 cep = null; 871 cei = null; 872 pec = null; 873 ped = null; 874 long vi = 0L; 875 for (int j = pfac.nvar; j > 1; j--) { 876 // evaluation up to univariate case 877 long degp = pe.degree(cpfac.nvar - 2); 878 cpfac = cpfac.contract(1); 879 ccpfac = ccpfac.contract(1); 880 //vi = evStart; // + j;//0L; //(long)(pfac.nvar-j); // 1L; 0 not so good for small p 881 vi = Evs.get(j); //evStart + j;//0L; //(long)(pfac.nvar-j); // 1L; 0 not so good for small p 882 BigInteger Vi; 883 884 // search evaluation point 885 boolean doIt = true; 886 Vi = null; 887 pep = null; 888 while (doIt) { 889 logger.info("vi(" + j + ") = " + vi); 890 Vi = new BigInteger(vi); 891 pep = PolyUtil.<BigInteger> evaluateMain(cpfac, pe, Vi); 892 //System.out.println("pep = " + pep); 893 // check lucky evaluation point 894 if (degp == pep.degree(cpfac.nvar - 1)) { 895 logger.info("pep = " + pep); 896 //System.out.println("deg(pe) = " + degp + ", deg(pep) = " + pep.degree(cpfac.nvar-1)); 897 // check squarefree 898 if (sengine.isSquarefree(pep)) { // cpfac.nvar == 1 && ?? no, must test on each variable 899 //if ( isNearlySquarefree(pep) ) { 900 //System.out.println("squarefeee(pep)"); // + pep); 901 doIt = false; //break; 902 } else { 903 logger.info("pep not squarefree "); 904 } 905 } 906 if (vi > 0L) { 907 vi = -vi; 908 } else { 909 vi = 1L - vi; 910 } 911 } 912 //if ( !isMonic ) { 913 if (ccpfac.nvar >= 1) { 914 cep = PolyUtil.<BigInteger> evaluateMain(ccpfac, ce, Vi); 915 } else { 916 cei = PolyUtil.<BigInteger> evaluateMain(ccpfac.coFac, ce, Vi); 917 } 918 //} 919 int jj = (int) Math.round(ran + 0.52 * Math.random()); // j, random increment 920 //jj = 0; // ...4 test 921 //System.out.println("minimal jj = " + jj + ", vi " + vi); 922 if (vi > 0L) { 923 Evs.set(j, vi + jj); // record last tested value plus increment 924 evStart = vi + jj; 925 } else { 926 Evs.set(j, vi - jj); // record last tested value minus increment 927 evStart = vi - jj; 928 } 929 //evStart = vi+1L; 930 V.add(Vi); 931 pe = pep; 932 ce = cep; 933 } 934 //System.out.println("ce = " + ce + ", pe = " + pe); 935 pecw = engine.baseContent(pe); // original Wang 936 isPrimitive = pecw.isONE(); 937 ped = ccpfac.coFac.getONE(); 938 pec = pe.ring.coFac.getONE(); 939 //System.out.println("cei = " + cei + ", pecw = " + pecw); 940 if (!isMonic) { 941 if (countSeparate > COUNT_MAX) { 942 pec = pe.ring.coFac.getONE(); // hack is sometimes better 943 } else { 944 pec = pecw; 945 } 946 //pec = pecw; 947 //System.out.println("cei = " + cei + ", pec = " + pec + ", pe = " + pe); 948 if (lfacs.get(0).isConstant()) { 949 ped = cei.remove(0); 950 //lfacs.remove(0); // later 951 } 952 //System.out.println("lfacs = " + lfacs + ", cei = " + cei + ", ped = " + ped + ", pecw = " + pecw); 953 // test Wang's condition 954 dei = new ArrayList<BigInteger>(); 955 dei.add(pec.multiply(ped).abs()); // .abs() 956 int i = 1; 957 for (BigInteger ci : cei) { 958 if (ci.isZERO()) { 959 logger.info("condition (0) not met for cei = " + cei); // + ", dei = " + dei); 960 notLucky = true; 961 break; 962 } 963 BigInteger q = ci.abs(); 964 //System.out.println("q = " + q); 965 for (int ii = i - 1; ii >= 0; ii--) { 966 BigInteger r = dei.get(ii); 967 //System.out.println("r = " + r); 968 while (!r.isONE()) { 969 r = r.gcd(q); 970 q = q.divide(r); 971 //System.out.println("r = " + r + ", q = " + q); 972 } 973 } 974 dei.add(q); 975 if (q.isONE()) { 976 logger.info("condition (1) not met for dei = " + dei + ", cei = " + cei); 977 if (!testSeparate(cei, pecw)) { 978 countSeparate++; 979 if (countSeparate > COUNT_MAX) { 980 logger.info("too many inseparable evaluation points: " + countSeparate 981 + ", removing " + pecw); 982 } 983 } 984 notLucky = true; 985 break; 986 } 987 i++; 988 } 989 //System.out.println("dei = " + dei); 990 } 991 if (notLucky) { 992 continue; 993 } 994 logger.info("evaluation points = " + V + ", dei = " + dei); 995 //System.out.println("Evs = " + Evs); 996 logger.info("univariate polynomial = " + pe + ", pecw = " + pecw); 997 //pe = pe.abs(); 998 //ufactors = baseFactorsRadical(pe); //baseFactorsSquarefree(pe); wrong since not primitive 999 ufactors = baseFactorsSquarefree(pe.divide(pecw)); //wrong if not primitive 1000 if (!pecw.isONE()) { 1001 ufactors.add(0, cpfac.getONE().multiply(pecw)); 1002 } 1003 if (ufactors.size() <= 1) { 1004 logger.info("irreducible univariate polynomial"); 1005 factors.add(pd); // P 1006 if (cfactors != null) { 1007 cfactors.addAll(factors); 1008 factors = cfactors; 1009 } 1010 return factors; 1011 } 1012 logger.info("univariate factors = " + ufactors); // + ", of " + pe); 1013 //System.out.println("lfacs = " + lfacs); 1014 //System.out.println("cei = " + cei); 1015 //System.out.println("pecw = " + pecw); 1016 1017 // determine leading coefficient polynomials for factors 1018 lf = new ArrayList<GenPolynomial<BigInteger>>(); 1019 lpx = lprr.ring.getONE(); 1020 for (int i = 0; i < ufactors.size(); i++) { 1021 lf.add(lprr.ring.getONE()); 1022 } 1023 //System.out.println("lf = " + lf); 1024 if (!isMonic || !pecw.isONE()) { 1025 if (lfacs.size() > 0 && lfacs.get(0).isConstant()) { 1026 //GenPolynomial<BigInteger> unused = 1027 lfacs.remove(0); 1028 //BigInteger xxi = xx.leadingBaseCoefficient(); 1029 //System.out.println("xx = " + xx + " == ped = " +ped); 1030 } 1031 for (int i = ufactors.size() - 1; i >= 0; i--) { 1032 GenPolynomial<BigInteger> pp = ufactors.get(i); 1033 BigInteger ppl = pp.leadingBaseCoefficient(); 1034 //System.out.println("ppl = " + ppl + ", pp = " + pp); 1035 ppl = ppl.multiply(pec); // content 1036 GenPolynomial<BigInteger> lfp = lf.get(i); 1037 int ii = 0; 1038 for (BigInteger ci : cei) { 1039 //System.out.println("ci = " + ci + ", lfp = " + lfp + ", lfacs.get(ii) = " + lfacs.get(ii)); 1040 if (ci.abs().isONE()) { 1041 System.out.println("ppl = " + ppl + ", ci = " + ci + ", lfp = " + lfp 1042 + ", lfacs.get(ii) = " + lfacs.get(ii)); 1043 notLucky = true; 1044 throw new RuntimeException("something is wrong, ci is a unit"); 1045 } 1046 while (ppl.remainder(ci).isZERO() && lfacs.size() > ii) { 1047 ppl = ppl.divide(ci); 1048 lfp = lfp.multiply(lfacs.get(ii)); 1049 } 1050 ii++; 1051 } 1052 //System.out.println("ppl = " + ppl + ", lfp = " + lfp); 1053 lfp = lfp.multiply(ppl); 1054 lf.set(i, lfp); 1055 } 1056 // adjust if pec != 1 1057 pec = pecw; 1058 lpx = Power.<GenPolynomial<BigInteger>> multiply(lprr.ring, lf); // test only, not used 1059 //System.out.println("lpx = " + lpx); 1060 if (!lprr.degreeVector().equals(lpx.degreeVector())) { 1061 logger.info("deg(lprr) != deg(lpx): lprr = " + lprr + ", lpx = " + lpx); 1062 notLucky = true; 1063 continue; 1064 } 1065 if (!pec.isONE()) { // content, was always false by hack 1066 // evaluate factors of ldcf 1067 List<GenPolynomial<BigInteger>> lfe = lf; 1068 List<BigInteger> lfei = null; 1069 ccpfac = lprr.ring; 1070 for (int j = lprr.ring.nvar; j > 0; j--) { 1071 ccpfac = ccpfac.contract(1); 1072 BigInteger Vi = V.get(lprr.ring.nvar - j); 1073 if (ccpfac.nvar >= 1) { 1074 lfe = PolyUtil.<BigInteger> evaluateMain(ccpfac, lfe, Vi); 1075 } else { 1076 lfei = PolyUtil.<BigInteger> evaluateMain(ccpfac.coFac, lfe, Vi); 1077 } 1078 } 1079 //System.out.println("lfe = " + lfe + ", lfei = " + lfei + ", V = " + V); 1080 1081 ln = new ArrayList<GenPolynomial<BigInteger>>(lf.size()); 1082 un = new ArrayList<GenPolynomial<BigInteger>>(lf.size()); 1083 for (int jj = 0; jj < lf.size(); jj++) { 1084 GenPolynomial<BigInteger> up = ufactors.get(jj); 1085 BigInteger ui = up.leadingBaseCoefficient(); 1086 BigInteger li = lfei.get(jj); 1087 BigInteger di = ui.gcd(li).abs(); 1088 BigInteger udi = ui.divide(di); 1089 BigInteger ldi = li.divide(di); 1090 GenPolynomial<BigInteger> lp = lf.get(jj); 1091 GenPolynomial<BigInteger> lpd = lp.multiply(udi); 1092 GenPolynomial<BigInteger> upd = up.multiply(ldi); 1093 if (pec.isONE()) { 1094 ln.add(lp); 1095 un.add(up); 1096 } else { 1097 ln.add(lpd); 1098 un.add(upd); 1099 BigInteger pec1 = pec.divide(ldi); 1100 //System.out.println("pec = " + pec + ", pec1 = " + pec1); 1101 pec = pec1; 1102 } 1103 } 1104 if (!lf.equals(ln) || !un.equals(ufactors)) { 1105 logger.debug("!lf.equals(ln) || !un.equals(ufactors)"); 1106 //System.out.println("pe = " + pe); 1107 //System.out.println("#ln = " + ln + ", #lf = " + lf); 1108 //System.out.println("#un = " + un + ", #ufactors = " + ufactors); 1109 //lf = ln; 1110 //ufactors = un; 1111 // adjust pe 1112 } 1113 if (!pec.isONE()) { // still not 1 1114 ln = new ArrayList<GenPolynomial<BigInteger>>(lf.size()); 1115 un = new ArrayList<GenPolynomial<BigInteger>>(lf.size()); 1116 pes = pe; 1117 for (int jj = 0; jj < lf.size(); jj++) { 1118 GenPolynomial<BigInteger> up = ufactors.get(jj); 1119 GenPolynomial<BigInteger> lp = lf.get(jj); 1120 //System.out.println("up = " + up + ", lp = " + lp); 1121 if (!up.isConstant()) { 1122 up = up.multiply(pec); 1123 } 1124 lp = lp.multiply(pec); 1125 if (jj != 0) { 1126 pes = pes.multiply(pec); 1127 } 1128 un.add(up); 1129 ln.add(lp); 1130 } 1131 if (pes.equals(Power.<GenPolynomial<BigInteger>> multiply(pe.ring, un))) { 1132 //System.out.println("*pe = " + pes + ", pec = " + pec); 1133 //ystem.out.println("*ln = " + ln + ", *lf = " + lf); 1134 //System.out.println("*un = " + un + ", *ufactors = " + ufactors); 1135 //System.out.println("*pe == prod(un) "); 1136 isPrimitive = false; 1137 //pe = pes; 1138 //lf = ln; 1139 //ufactors = un; 1140 } else { 1141 //System.out.println("*pe != prod(un): " + Power.<GenPolynomial<BigInteger>> multiply(pe.ring,un)); 1142 } 1143 } 1144 } 1145 //if (notLucky) { 1146 // continue; 1147 //} 1148 logger.info("distributed factors of leading coefficient = " + lf); 1149 lpx = Power.<GenPolynomial<BigInteger>> multiply(lprr.ring, lf); 1150 if (!lprr.abs().equals(lpx.abs())) { // not correctly distributed 1151 if (!lprr.degreeVector().equals(lpx.degreeVector())) { 1152 logger.info("lprr != lpx: lprr = " + lprr + ", lpx = " + lpx); 1153 notLucky = true; 1154 } 1155 } 1156 } // end determine leading coefficients for factors 1157 1158 if (!notLucky) { 1159 TrialParts tp = null; 1160 if (isPrimitive) { 1161 tp = new TrialParts(V, pe, ufactors, cei, lf); 1162 } else { 1163 tp = new TrialParts(V, pes, un, cei, ln); 1164 } 1165 //System.out.println("trialParts = " + tp); 1166 if (tp.univPoly != null) { 1167 if (tp.ldcfEval.size() != 0) { 1168 tParts.add(tp); 1169 } 1170 } 1171 if (tParts.size() < trials) { 1172 notLucky = true; 1173 } 1174 } 1175 } // end notLucky loop 1176 1177 // search TrialParts with shortest factorization of univariate polynomial 1178 int min = Integer.MAX_VALUE; 1179 TrialParts tpmin = null; 1180 for (TrialParts tp : tParts) { 1181 logger.info("tp.univFactors.size() = " + tp.univFactors.size()); 1182 if (tp.univFactors.size() < min) { 1183 min = tp.univFactors.size(); 1184 tpmin = tp; 1185 } 1186 } 1187 for (TrialParts tp : tParts) { 1188 //logger.info("tp.univFactors.get(0) = " + tp.univFactors.get(0)); 1189 if (tp.univFactors.size() == min) { 1190 if (!tp.univFactors.get(0).isConstant()) { 1191 tpmin = tp; 1192 break; 1193 } 1194 } 1195 } 1196 // set to (first) shortest 1197 V = tpmin.evalPoints; 1198 pe = tpmin.univPoly; 1199 ufactors = tpmin.univFactors; 1200 cei = tpmin.ldcfEval; // unused 1201 lf = tpmin.ldcfFactors; 1202 logger.info("iterations = " + Math.abs(evStart)); 1203 logger.info("minimal trial = " + tpmin); 1204 1205 GenPolynomialRing<BigInteger> ufac = pe.ring; 1206 1207 //initialize prime list 1208 PrimeList primes = new PrimeList(PrimeList.Range.medium); // PrimeList.Range.medium); 1209 Iterator<java.math.BigInteger> primeIter = primes.iterator(); 1210 int pn = 50; //primes.size(); 1211 BigInteger ae = pe.leadingBaseCoefficient(); 1212 GenPolynomial<MOD> Pm = null; 1213 ModularRingFactory<MOD> cofac = null; 1214 GenPolynomialRing<MOD> mufac = null; 1215 1216 // search lucky prime 1217 for (int i = 0; i < 11; i++) { // prime meta loop 1218 //for ( int i = 0; i < 1; i++ ) { // meta loop 1219 java.math.BigInteger p = null; //new java.math.BigInteger("19"); //primes.next(); 1220 // 2 small, 5 medium and 4 large size primes 1221 if (i == 0) { // medium size 1222 primes = new PrimeList(PrimeList.Range.medium); 1223 primeIter = primes.iterator(); 1224 } 1225 if (i == 5) { // small size 1226 primes = new PrimeList(PrimeList.Range.small); 1227 primeIter = primes.iterator(); 1228 p = primeIter.next(); // 2 1229 p = primeIter.next(); // 3 1230 p = primeIter.next(); // 5 1231 p = primeIter.next(); // 7 1232 } 1233 if (i == 7) { // large size 1234 primes = new PrimeList(PrimeList.Range.large); 1235 primeIter = primes.iterator(); 1236 } 1237 int pi = 0; 1238 while (pi < pn && primeIter.hasNext()) { 1239 p = primeIter.next(); 1240 logger.info("prime = " + p); 1241 // initialize coefficient factory and map normalization factor and polynomials 1242 ModularRingFactory<MOD> cf = null; 1243 if (ModLongRing.MAX_LONG.compareTo(p) > 0) { 1244 cf = (ModularRingFactory) new ModLongRing(p, true); 1245 } else { 1246 cf = (ModularRingFactory) new ModIntegerRing(p, true); 1247 } 1248 MOD nf = cf.fromInteger(ae.getVal()); 1249 if (nf.isZERO()) { 1250 continue; 1251 } 1252 mufac = new GenPolynomialRing<MOD>(cf, ufac); 1253 //System.out.println("mufac = " + mufac.toScript()); 1254 Pm = PolyUtil.<MOD> fromIntegerCoefficients(mufac, pe); 1255 //System.out.println("Pm = " + Pm); 1256 if (!mfactor.isSquarefree(Pm)) { 1257 continue; 1258 } 1259 cofac = cf; 1260 break; 1261 } 1262 if (cofac != null) { 1263 break; 1264 } 1265 } // end prime meta loop 1266 if (cofac == null) { // no lucky prime found 1267 throw new RuntimeException("giving up on Hensel preparation, no lucky prime found"); 1268 } 1269 logger.info("lucky prime = " + cofac.getIntegerModul()); 1270 if (logger.isDebugEnabled()) { 1271 logger.debug("univariate modulo p: = " + Pm); 1272 } 1273 1274 // coefficient bound 1275 BigInteger an = pd.maxNorm(); 1276 BigInteger mn = an.multiply(ac.abs()).multiply(new BigInteger(2L)); 1277 long k = Power.logarithm(cofac.getIntegerModul(), mn) + 1L; 1278 //System.out.println("mn = " + mn + ", k = " +k); 1279 1280 BigInteger q = cofac.getIntegerModul().power(k); 1281 ModularRingFactory<MOD> muqfac; 1282 if (ModLongRing.MAX_LONG.compareTo(q.getVal()) > 0) { 1283 muqfac = (ModularRingFactory) new ModLongRing(q.getVal()); 1284 } else { 1285 muqfac = (ModularRingFactory) new ModIntegerRing(q.getVal()); 1286 } 1287 //System.out.println("muqfac = " + muqfac); 1288 GenPolynomialRing<MOD> mucpfac = new GenPolynomialRing<MOD>(muqfac, ufac); 1289 1290 List<GenPolynomial<MOD>> muqfactors = PolyUtil.<MOD> fromIntegerCoefficients(mucpfac, ufactors); 1291 GenPolynomial<MOD> peqq = PolyUtil.<MOD> fromIntegerCoefficients(mucpfac, pe); 1292 if (debug) { 1293 if (!mfactor.isFactorization(peqq, muqfactors)) { // should not happen 1294 System.out.println("muqfactors = " + muqfactors); 1295 System.out.println("peqq = " + peqq); 1296 throw new RuntimeException("something is wrong, no modular p^k factorization"); 1297 } 1298 } 1299 logger.info("univariate modulo p^k: " + peqq + " = " + muqfactors); 1300 1301 // convert C from Z[...] to Z_q[...] 1302 GenPolynomialRing<MOD> qcfac = new GenPolynomialRing<MOD>(muqfac, pd.ring); 1303 GenPolynomial<MOD> pq = PolyUtil.<MOD> fromIntegerCoefficients(qcfac, pd); 1304 //System.out.println("pd = " + pd); 1305 logger.info("multivariate modulo p^k: " + pq); 1306 1307 //List<MOD> Vm = new ArrayList<MOD>(V.size()); 1308 //for (BigInteger v : V) { 1309 // MOD vm = muqfac.fromInteger(v.getVal()); 1310 // Vm.add(vm); 1311 //} 1312 //System.out.println("Vm = " + Vm); 1313 1314 // Hensel lifting of factors 1315 List<GenPolynomial<MOD>> mlift; 1316 try { 1317 mlift = HenselMultUtil.<MOD> liftHensel(pd, pq, muqfactors, V, k, lf); 1318 logger.info("mlift = " + mlift); 1319 } catch (NoLiftingException nle) { 1320 //System.out.println("exception : " + nle); 1321 //nle.printStackTrace(); 1322 //mlift = new ArrayList<GenPolynomial<MOD>>(); 1323 throw new RuntimeException(nle); 1324 } catch (ArithmeticException aex) { 1325 //System.out.println("exception : " + aex); 1326 //aex.printStackTrace(); 1327 //mlift = new ArrayList<GenPolynomial<MOD>>(); 1328 throw aex; 1329 } 1330 if (mlift.size() <= 1) { // irreducible mod I, p^k, can this happen? 1331 logger.info("modular lift size == 1: " + mlift); 1332 factors.add(pd); // P 1333 if (cfactors != null) { 1334 cfactors.addAll(factors); 1335 factors = cfactors; 1336 } 1337 return factors; 1338 } 1339 1340 // combine trial factors 1341 GenPolynomialRing<MOD> mfac = mlift.get(0).ring; 1342 int dl = (mlift.size() + 1) / 2; 1343 GenPolynomial<BigInteger> u = P; 1344 long deg = (u.degree() + 1L) / 2L; 1345 1346 GenPolynomial<BigInteger> ui = pd; 1347 for (int j = 1; j <= dl; j++) { 1348 //System.out.println("j = " + j + ", dl = " + dl + ", mlift = " + mlift); 1349 KsubSet<GenPolynomial<MOD>> subs = new KsubSet<GenPolynomial<MOD>>(mlift, j); 1350 for (List<GenPolynomial<MOD>> flist : subs) { 1351 //System.out.println("degreeSum = " + degreeSum(flist)); 1352 GenPolynomial<MOD> mtrial = Power.<GenPolynomial<MOD>> multiply(mfac, flist); 1353 if (mtrial.degree() > deg) { // this test is sometimes wrong 1354 logger.info("degree > deg " + deg + ", degree = " + mtrial.degree()); 1355 //continue; 1356 } 1357 GenPolynomial<BigInteger> trial = PolyUtil.integerFromModularCoefficients(pfac, mtrial); 1358 trial = engine.basePrimitivePart(trial); 1359 //if ( ! isPrimitive ) { 1360 //} 1361 if (debug) { 1362 logger.info("trial = " + trial); // + ", mtrial = " + mtrial); 1363 } 1364 if (PolyUtil.<BigInteger> baseSparsePseudoRemainder(ui, trial).isZERO()) { 1365 logger.info("successful trial = " + trial); 1366 factors.add(trial); 1367 ui = PolyUtil.<BigInteger> basePseudoDivide(ui, trial); 1368 //System.out.println("ui = " + ui); 1369 mlift = removeOnce(mlift, flist); 1370 logger.info("new mlift= " + mlift); 1371 //System.out.println("dl = " + dl); 1372 if (mlift.size() > 1) { 1373 dl = (mlift.size() + 1) / 2; 1374 j = 0; // since j++ 1375 break; 1376 } 1377 logger.info("last factor = " + ui); 1378 factors.add(ui); 1379 if (cfactors != null) { 1380 cfactors.addAll(factors); 1381 factors = cfactors; 1382 } 1383 return normalizeFactorization(factors); 1384 } 1385 } 1386 } 1387 if (!ui.isONE() && !ui.equals(pd)) { 1388 logger.info("rest factor = " + ui); 1389 // pp(ui) ?? no ?? 1390 factors.add(ui); 1391 } 1392 if (factors.size() == 0) { 1393 logger.info("irreducible P = " + P); 1394 factors.add(pd); // P 1395 } 1396 if (cfactors != null) { 1397 cfactors.addAll(factors); 1398 factors = cfactors; 1399 } 1400 return normalizeFactorization(factors); 1401 } 1402 1403 1404 /** 1405 * Test if b has a prime factor different to the elements of A. 1406 * @param A list of integer with at least one different prime factor. 1407 * @param b integer to test with A. 1408 * @return true, if b hase a prime factor different to elements of A 1409 */ 1410 boolean testSeparate(List<BigInteger> A, BigInteger b) { 1411 int i = 0; 1412 //List<BigInteger> gei = new ArrayList<BigInteger>(A.size()); 1413 for (BigInteger c : A) { 1414 BigInteger g = c.gcd(b).abs(); 1415 //gei.add(g); 1416 if (!g.isONE()) { 1417 i++; 1418 } 1419 } 1420 //if ( i >= 1 ) { 1421 //System.out.println("gei = " + gei + ", cei = " + cei + ", pec(w) = " + pec); 1422 //} 1423 return (i <= 1); 1424 } 1425 1426 1427 // not useable 1428 boolean isNearlySquarefree(GenPolynomial<BigInteger> P) { // unused 1429 // in main variable 1430 GenPolynomialRing<BigInteger> pfac = P.ring; 1431 if (pfac.nvar >= 0) { // allways true 1432 return sengine.isSquarefree(P); 1433 } 1434 GenPolynomialRing<GenPolynomial<BigInteger>> rfac = pfac.recursive(1); 1435 GenPolynomial<GenPolynomial<BigInteger>> Pr = PolyUtil.<BigInteger> recursive(rfac, P); 1436 GenPolynomial<GenPolynomial<BigInteger>> Ps = PolyUtil.<BigInteger> recursiveDeriviative(Pr); 1437 System.out.println("Pr = " + Pr); 1438 System.out.println("Ps = " + Ps); 1439 GenPolynomial<GenPolynomial<BigInteger>> g = engine.recursiveUnivariateGcd(Pr, Ps); 1440 System.out.println("g_m = " + g); 1441 if (!g.isONE()) { 1442 return false; 1443 } 1444 // in lowest variable 1445 rfac = pfac.recursive(pfac.nvar - 1); 1446 Pr = PolyUtil.<BigInteger> recursive(rfac, P); 1447 Pr = PolyUtil.<BigInteger> switchVariables(Pr); 1448 Ps = PolyUtil.<BigInteger> recursiveDeriviative(Pr); 1449 System.out.println("Pr = " + Pr); 1450 System.out.println("Ps = " + Ps); 1451 g = engine.recursiveUnivariateGcd(Pr, Ps); 1452 System.out.println("g_1 = " + g); 1453 if (!g.isONE()) { 1454 return false; 1455 } 1456 return true; 1457 } 1458 1459} 1460 1461 1462/** 1463 * Container for factorization trial lifting parameters. 1464 */ 1465class TrialParts { 1466 1467 1468 /** 1469 * evaluation points 1470 */ 1471 public final List<BigInteger> evalPoints; 1472 1473 1474 /** 1475 * univariate polynomial 1476 */ 1477 public final GenPolynomial<BigInteger> univPoly; 1478 1479 1480 /** 1481 * irreducible factors of univariate polynomial 1482 */ 1483 public final List<GenPolynomial<BigInteger>> univFactors; 1484 1485 1486 /** 1487 * irreducible factors of leading coefficient 1488 */ 1489 public final List<GenPolynomial<BigInteger>> ldcfFactors; 1490 1491 1492 /** 1493 * evaluated factors of leading coefficient factors by evaluation points 1494 */ 1495 public final List<BigInteger> ldcfEval; 1496 1497 1498 /** 1499 * Constructor. 1500 * @param ev evaluation points. 1501 * @param up univariate polynomial. 1502 * @param uf irreducible factors of up. 1503 * @param le irreducible factors of leading coefficient. 1504 * @param lf evaluated le by evaluation points. 1505 */ 1506 public TrialParts(List<BigInteger> ev, GenPolynomial<BigInteger> up, List<GenPolynomial<BigInteger>> uf, 1507 List<BigInteger> le, List<GenPolynomial<BigInteger>> lf) { 1508 evalPoints = ev; 1509 univPoly = up; 1510 univFactors = uf; 1511 //ldcfPoly = lp; 1512 ldcfFactors = lf; 1513 ldcfEval = le; 1514 } 1515 1516 1517 /** 1518 * @see java.lang.Object#toString() 1519 */ 1520 @Override 1521 public String toString() { 1522 StringBuffer sb = new StringBuffer(); 1523 sb.append("TrialParts["); 1524 sb.append("evalPoints = " + evalPoints); 1525 sb.append(", univPoly = " + univPoly); 1526 sb.append(", univFactors = " + univFactors); 1527 sb.append(", ldcfEval = " + ldcfEval); 1528 sb.append(", ldcfFactors = " + ldcfFactors); 1529 sb.append("]"); 1530 return sb.toString(); 1531 } 1532 1533}