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