001/* 002 * $Id: GreatestCommonDivisorHensel.java 4067 2012-07-27 16:17:35Z kredel $ 003 */ 004 005package edu.jas.ufd; 006 007 008import java.util.ArrayList; 009import java.util.Iterator; 010import java.util.List; 011 012import org.apache.log4j.Logger; 013 014import edu.jas.arith.BigInteger; 015import edu.jas.arith.ModIntegerRing; 016import edu.jas.arith.ModLongRing; 017import edu.jas.arith.Modular; 018import edu.jas.arith.ModularRingFactory; 019import edu.jas.arith.PrimeList; 020import edu.jas.poly.ExpVector; 021import edu.jas.poly.GenPolynomial; 022import edu.jas.poly.GenPolynomialRing; 023import edu.jas.poly.PolyUtil; 024import edu.jas.structure.GcdRingElem; 025import edu.jas.structure.Power; 026import edu.jas.structure.RingFactory; 027 028 029/** 030 * Greatest common divisor algorithms with subresultant polynomial remainder 031 * sequence and univariate Hensel lifting. 032 * @author Heinz Kredel 033 */ 034 035public class GreatestCommonDivisorHensel<MOD extends GcdRingElem<MOD> & Modular> extends 036 GreatestCommonDivisorAbstract<BigInteger> { 037 038 039 private static final Logger logger = Logger.getLogger(GreatestCommonDivisorHensel.class); 040 041 042 private final boolean debug = logger.isDebugEnabled(); 043 044 045 /** 046 * Flag for linear or quadratic Hensel lift. 047 */ 048 public final boolean quadratic; 049 050 051 /** 052 * Fall back gcd algorithm. 053 */ 054 public final GreatestCommonDivisorAbstract<BigInteger> iufd; 055 056 057 /** 058 * Constructor. 059 */ 060 public GreatestCommonDivisorHensel() { 061 this(true); 062 } 063 064 065 /** 066 * Constructor. 067 * @param quadratic use quadratic Hensel lift. 068 */ 069 public GreatestCommonDivisorHensel(boolean quadratic) { 070 this.quadratic = quadratic; 071 iufd = new GreatestCommonDivisorSubres<BigInteger>(); 072 } 073 074 075 /** 076 * Univariate GenPolynomial greatest comon divisor. Uses univariate Hensel 077 * lifting. 078 * @param P univariate GenPolynomial. 079 * @param S univariate GenPolynomial. 080 * @return gcd(P,S). 081 */ 082 @Override 083 public GenPolynomial<BigInteger> baseGcd(GenPolynomial<BigInteger> P, GenPolynomial<BigInteger> S) { 084 if (S == null || S.isZERO()) { 085 return P; 086 } 087 if (P == null || P.isZERO()) { 088 return S; 089 } 090 if (P.ring.nvar > 1) { 091 throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); 092 } 093 GenPolynomialRing<BigInteger> fac = P.ring; 094 long e = P.degree(0); 095 long f = S.degree(0); 096 GenPolynomial<BigInteger> q; 097 GenPolynomial<BigInteger> r; 098 if (f > e) { 099 r = P; 100 q = S; 101 long g = f; 102 f = e; 103 e = g; 104 } else { 105 q = P; 106 r = S; 107 } 108 if (debug) { 109 logger.debug("degrees: e = " + e + ", f = " + f); 110 } 111 r = r.abs(); 112 q = q.abs(); 113 // compute contents and primitive parts 114 BigInteger a = baseContent(r); 115 BigInteger b = baseContent(q); 116 // gcd of coefficient contents 117 BigInteger c = gcd(a, b); // indirection 118 r = divide(r, a); // indirection 119 q = divide(q, b); // indirection 120 if (r.isONE()) { 121 return r.multiply(c); 122 } 123 if (q.isONE()) { 124 return q.multiply(c); 125 } 126 // compute normalization factor 127 BigInteger ac = r.leadingBaseCoefficient(); 128 BigInteger bc = q.leadingBaseCoefficient(); 129 BigInteger cc = gcd(ac, bc); // indirection 130 // compute degree vectors, only univeriate 131 ExpVector rdegv = r.degreeVector(); 132 ExpVector qdegv = q.degreeVector(); 133 //initialize prime list and degree vector 134 PrimeList primes = new PrimeList(PrimeList.Range.medium); 135 int pn = 50; //primes.size(); 136 137 ModularRingFactory<MOD> cofac; 138 GenPolynomial<MOD> qm; 139 GenPolynomial<MOD> qmf; 140 GenPolynomial<MOD> rm; 141 GenPolynomial<MOD> rmf; 142 GenPolynomial<MOD> cmf; 143 GenPolynomialRing<MOD> mfac; 144 GenPolynomial<MOD> cm = null; 145 GenPolynomial<MOD>[] ecm = null; 146 GenPolynomial<MOD> sm = null; 147 GenPolynomial<MOD> tm = null; 148 HenselApprox<MOD> lift = null; 149 if (debug) { 150 logger.debug("c = " + c); 151 logger.debug("cc = " + cc); 152 logger.debug("primes = " + primes); 153 } 154 155 int i = 0; 156 for (java.math.BigInteger p : primes) { 157 //System.out.println("next run ++++++++++++++++++++++++++++++++++"); 158 if (++i >= pn) { 159 logger.error("prime list exhausted, pn = " + pn); 160 logger.info("primes = " + primes); 161 return iufd.baseGcd(P, S); 162 //throw new ArithmeticException("prime list exhausted"); 163 } 164 // initialize coefficient factory and map normalization factor 165 //cofac = new ModIntegerRing(p, true); 166 if (ModLongRing.MAX_LONG.compareTo(p) > 0) { 167 cofac = (ModularRingFactory) new ModLongRing(p, true); 168 } else { 169 cofac = (ModularRingFactory) new ModIntegerRing(p, true); 170 } 171 MOD nf = cofac.fromInteger(cc.getVal()); 172 if (nf.isZERO()) { 173 continue; 174 } 175 nf = cofac.fromInteger(q.leadingBaseCoefficient().getVal()); 176 if (nf.isZERO()) { 177 continue; 178 } 179 nf = cofac.fromInteger(r.leadingBaseCoefficient().getVal()); 180 if (nf.isZERO()) { 181 continue; 182 } 183 // initialize polynomial factory and map polynomials 184 mfac = new GenPolynomialRing<MOD>(cofac, fac.nvar, fac.tord, fac.getVars()); 185 qm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, q); 186 if (!qm.degreeVector().equals(qdegv)) { 187 continue; 188 } 189 rm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, r); 190 if (!rm.degreeVector().equals(rdegv)) { 191 continue; 192 } 193 if (debug) { 194 logger.info("cofac = " + cofac.getIntegerModul()); 195 } 196 197 // compute univariate modular gcd 198 cm = qm.gcd(rm); 199 200 // test for constant g.c.d 201 if (cm.isConstant()) { 202 logger.debug("cm, constant = " + cm); 203 return fac.getONE().multiply(c); 204 } 205 206 // compute factors and gcd with factor 207 GenPolynomial<BigInteger> crq; 208 rmf = rm.divide(cm); // rm = cm * rmf 209 ecm = cm.egcd(rmf); 210 if (ecm[0].isONE()) { 211 //logger.debug("gcd() first factor " + rmf); 212 crq = r; 213 cmf = rmf; 214 sm = ecm[1]; 215 tm = ecm[2]; 216 } else { 217 qmf = qm.divide(cm); // qm = cm * qmf 218 ecm = cm.egcd(qmf); 219 if (ecm[0].isONE()) { 220 //logger.debug("gcd() second factor " + qmf); 221 crq = q; 222 cmf = qmf; 223 sm = ecm[1]; 224 tm = ecm[2]; 225 } else { 226 logger.info("giving up on Hensel gcd reverting to Subres gcd"); 227 return iufd.baseGcd(P, S); 228 } 229 } 230 BigInteger cn = crq.maxNorm(); 231 cn = cn.multiply(crq.leadingBaseCoefficient().abs()); 232 cn = cn.multiply(cn.fromInteger(2)); 233 if (debug) { 234 System.out.println("crq = " + crq); 235 System.out.println("cm = " + cm); 236 System.out.println("cmf = " + cmf); 237 System.out.println("sm = " + sm); 238 System.out.println("tm = " + tm); 239 System.out.println("cn = " + cn); 240 } 241 try { 242 if (quadratic) { 243 lift = HenselUtil.liftHenselQuadratic(crq, cn, cm, cmf, sm, tm); 244 } else { 245 lift = HenselUtil.liftHensel(crq, cn, cm, cmf, sm, tm); 246 } 247 } catch (NoLiftingException nle) { 248 logger.info("giving up on Hensel gcd reverting to Subres gcd " + nle); 249 return iufd.baseGcd(P, S); 250 } 251 q = lift.A; 252 if (debug) { 253 System.out.println("q = " + q); 254 System.out.println("qf = " + lift.B); 255 } 256 q = basePrimitivePart(q); 257 q = q.multiply(c).abs(); 258 if (PolyUtil.<BigInteger> baseSparsePseudoRemainder(P, q).isZERO() 259 && PolyUtil.<BigInteger> baseSparsePseudoRemainder(S, q).isZERO()) { 260 break; 261 } 262 logger.info("final devision not successfull"); 263 //System.out.println("P rem q = " + PolyUtil.<BigInteger>basePseudoRemainder(P,q)); 264 //System.out.println("S rem q = " + PolyUtil.<BigInteger>basePseudoRemainder(S,q)); 265 //break; 266 } 267 return q; 268 } 269 270 271 /** 272 * Univariate GenPolynomial recursive greatest comon divisor. Uses 273 * multivariate Hensel list. 274 * @param P univariate recursive GenPolynomial. 275 * @param S univariate recursive GenPolynomial. 276 * @return gcd(P,S). 277 */ 278 @Override 279 public GenPolynomial<GenPolynomial<BigInteger>> recursiveUnivariateGcd( 280 GenPolynomial<GenPolynomial<BigInteger>> P, GenPolynomial<GenPolynomial<BigInteger>> S) { 281 if (S == null || S.isZERO()) { 282 return P; 283 } 284 if (P == null || P.isZERO()) { 285 return S; 286 } 287 if (P.ring.nvar > 1) { 288 throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); 289 } 290 long e = P.degree(0); 291 long f = S.degree(0); 292 GenPolynomial<GenPolynomial<BigInteger>> q; 293 GenPolynomial<GenPolynomial<BigInteger>> r; 294 if (f > e) { 295 r = P; 296 q = S; 297 long g = f; 298 f = e; 299 e = g; 300 } else { 301 q = P; 302 r = S; 303 } 304 if (debug) { 305 logger.debug("degrees: e = " + e + ", f = " + f); 306 } 307 r = r.abs(); 308 q = q.abs(); 309 GenPolynomial<BigInteger> a = recursiveContent(r); 310 GenPolynomial<BigInteger> b = recursiveContent(q); 311 312 GenPolynomial<BigInteger> c = gcd(a, b); // go to recursion 313 //System.out.println("rgcd c = " + c); 314 r = PolyUtil.<BigInteger> recursiveDivide(r, a); 315 q = PolyUtil.<BigInteger> recursiveDivide(q, b); 316 a = PolyUtil.<BigInteger> basePseudoDivide(a, c); 317 b = PolyUtil.<BigInteger> basePseudoDivide(b, c); 318 if (r.isONE()) { 319 return r.multiply(c); 320 } 321 if (q.isONE()) { 322 return q.multiply(c); 323 } 324 // convert from Z[y1,...,yr][x] to Z[x][y1,...,yr] to Z[x,y1,...,yr] 325 GenPolynomial<GenPolynomial<BigInteger>> qs = PolyUtil.<BigInteger> switchVariables(q); 326 GenPolynomial<GenPolynomial<BigInteger>> rs = PolyUtil.<BigInteger> switchVariables(r); 327 328 GenPolynomialRing<GenPolynomial<BigInteger>> rfac = qs.ring; 329 RingFactory<GenPolynomial<BigInteger>> rrfac = rfac.coFac; 330 GenPolynomialRing<BigInteger> cfac = (GenPolynomialRing<BigInteger>) rrfac; 331 GenPolynomialRing<BigInteger> dfac = cfac.extend(rfac.getVars()); 332 //System.out.println("pfac = " + P.ring.toScript()); 333 //System.out.println("rfac = " + rfac.toScript()); 334 //System.out.println("dfac = " + dfac.toScript()); 335 336 GenPolynomial<BigInteger> qd = PolyUtil.<BigInteger> distribute(dfac, qs); 337 GenPolynomial<BigInteger> rd = PolyUtil.<BigInteger> distribute(dfac, rs); 338 //System.out.println("qd = " + qd); 339 //System.out.println("rd = " + rd); 340 //System.out.println("a = " + a); 341 //System.out.println("b = " + b); 342 //System.out.println("c = " + c); 343 344 // compute normalization factor 345 BigInteger ac = rd.leadingBaseCoefficient(); 346 BigInteger bc = qd.leadingBaseCoefficient(); 347 BigInteger cc = gcd(ac, bc); // indirection 348 349 //initialize prime list 350 PrimeList primes = new PrimeList(PrimeList.Range.medium); // PrimeList.Range.medium); 351 Iterator<java.math.BigInteger> primeIter = primes.iterator(); 352 int pn = 50; //primes.size(); 353 354 // double check variables 355 // need qe,re,qd,rd,a,b 356 GenPolynomial<MOD> qe0; 357 GenPolynomial<MOD> re0; 358 GenPolynomial<MOD> ce0 = null; 359 360 for (int i = 0; i < 11; i++) { // meta loop 361 //System.out.println("======================================================= run " 362 // + dfac.nvar + ", " + i); 363 java.math.BigInteger p = null; //new java.math.BigInteger("19"); //primes.next(); 364 // 5 small, 5 medium and 1 large size primes 365 if (i == 0) { // medium size 366 primes = new PrimeList(PrimeList.Range.medium); 367 primeIter = primes.iterator(); 368 } 369 if (i == 5) { // smal size 370 primes = new PrimeList(PrimeList.Range.small); 371 primeIter = primes.iterator(); 372 p = primeIter.next(); // 2 373 p = primeIter.next(); // 3 374 p = primeIter.next(); // 5 375 p = primeIter.next(); // 7 376 } 377 if (i == 10) { // large size 378 primes = new PrimeList(PrimeList.Range.large); 379 primeIter = primes.iterator(); 380 } 381 ModularRingFactory<MOD> cofac = null; 382 int pi = 0; 383 while (pi < pn && primeIter.hasNext()) { 384 p = primeIter.next(); 385 //p = new java.math.BigInteger("19"); 386 logger.info("prime = " + p); 387 // initialize coefficient factory and map normalization factor and polynomials 388 ModularRingFactory<MOD> cf = null; 389 if (ModLongRing.MAX_LONG.compareTo(p) > 0) { 390 cf = (ModularRingFactory) new ModLongRing(p, true); 391 } else { 392 cf = (ModularRingFactory) new ModIntegerRing(p, true); 393 } 394 MOD nf = cf.fromInteger(cc.getVal()); 395 if (nf.isZERO()) { 396 continue; 397 } 398 nf = cf.fromInteger(q.leadingBaseCoefficient().leadingBaseCoefficient().getVal()); 399 if (nf.isZERO()) { 400 continue; 401 } 402 nf = cf.fromInteger(r.leadingBaseCoefficient().leadingBaseCoefficient().getVal()); 403 if (nf.isZERO()) { 404 continue; 405 } 406 cofac = cf; 407 break; 408 } 409 if (cofac == null) { // no lucky prime found 410 System.out.println("giving up on Hensel gcd reverting to Subres gcd"); 411 GenPolynomial<GenPolynomial<BigInteger>> T = iufd.recursiveUnivariateGcd(P, S); 412 return T.abs().multiply(c); //.abs(); 413 } 414 //System.out.println("cofac = " + cofac); 415 416 List<MOD> V = new ArrayList<MOD>(P.ring.nvar); 417 GenPolynomialRing<MOD> mfac = new GenPolynomialRing<MOD>(cofac, dfac); 418 //System.out.println("mfac = " + mfac.toScript()); 419 GenPolynomial<MOD> qm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, qd); 420 GenPolynomial<MOD> rm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, rd); 421 //System.out.println("qm = " + qm); 422 //System.out.println("rm = " + rm); 423 424 // search evaluation point and evaluate 425 GenPolynomialRing<MOD> ckfac = mfac; 426 GenPolynomial<MOD> qe = qm; 427 GenPolynomial<MOD> re = rm; 428 GenPolynomial<MOD> qep; 429 GenPolynomial<MOD> rep; 430 for (int j = dfac.nvar; j > 1; j--) { 431 // evaluation to univariate case 432 long degq = qe.degree(ckfac.nvar - 2); 433 long degr = re.degree(ckfac.nvar - 2); 434 ckfac = ckfac.contract(1); 435 long vi = 1L; //(long)(dfac.nvar-j); // 1L; 0 not so good for small p 436 if (p.longValue() > 1000L) { 437 //vi = (long)j+1L; 438 vi = 0L; 439 } 440 // search small evaluation point 441 while (true) { 442 MOD vp = cofac.fromInteger(vi++); 443 //System.out.println("vp = " + vp); 444 if (vp.isZERO() && vi != 1L) { // all elements of Z_p exhausted 445 qe = null; 446 re = null; 447 break; 448 //GenPolynomial<GenPolynomial<BigInteger>> T = iufd.recursiveUnivariateGcd(P, S); 449 //return T.abs().multiply(c); //.abs(); 450 } 451 qep = PolyUtil.<MOD> evaluateMain(ckfac, qe, vp); 452 rep = PolyUtil.<MOD> evaluateMain(ckfac, re, vp); 453 //System.out.println("qep = " + qep); 454 //System.out.println("rep = " + rep); 455 456 // check lucky evaluation point 457 MOD ql = qep.leadingBaseCoefficient(); 458 MOD rl = rep.leadingBaseCoefficient(); 459 if (ql.isZERO() || rl.isZERO()) { // nearly non sense 460 continue; 461 } 462 if (degq != qep.degree(ckfac.nvar - 1)) { 463 //System.out.println("degv(qe) = " + qe.degreeVector()); 464 //System.out.println("deg(qe) = " + degq + ", deg(qe) = " + qep.degree(ckfac.nvar-1)); 465 continue; 466 } 467 if (degr != rep.degree(ckfac.nvar - 1)) { 468 //System.out.println("degv(re) = " + re.degreeVector()); 469 //System.out.println("deg(re) = " + degr + ", deg(re) = " + rep.degree(ckfac.nvar-1)); 470 continue; 471 } 472 V.add(vp); 473 qe = qep; 474 re = rep; 475 break; 476 } 477 if (qe == null && re == null) { 478 break; 479 } 480 } 481 if (qe == null && re == null) { 482 continue; 483 } 484 logger.info("evaluation points = " + V); 485 //System.out.println("qe = " + qe); 486 //System.out.println("re = " + re); 487 488 // recursion base: 489 GreatestCommonDivisorAbstract<MOD> mufd = GCDFactory.getImplementation(cofac); 490 GenPolynomial<MOD> ce = mufd.baseGcd(qe, re); 491 if (ce.isConstant()) { 492 return P.ring.getONE().multiply(c); 493 } 494 //System.out.println("ce = " + ce); 495 logger.info("base gcd = " + ce); 496 //System.out.println("c = " + c); 497 498 // double check 499 // need qe,re,qd,rd,a,b 500 if (i == 0) { 501 qe0 = qe; 502 re0 = re; 503 ce0 = ce; 504 continue; 505 } 506 long d0 = ce0.degree(0); 507 long d1 = ce.degree(0); 508 //System.out.println("d0, d1 = " + d0 + ", " + d1); 509 if (d1 < d0) { 510 qe0 = qe; 511 re0 = re; 512 ce0 = ce; 513 continue; 514 } else if (d1 > d0) { 515 continue; 516 } 517 // d0 == d1 is ok 518 long dx = r.degree(0); 519 //System.out.println("d0, dx = " + d0 + ", " + dx); 520 if (d0 == dx) { // gcd == r ?? 521 if (PolyUtil.<BigInteger> recursivePseudoRemainder(q, r).isZERO()) { 522 r = r.abs().multiply(c); //.abs(); 523 logger.info("exit with r | q : " + r); 524 return r; 525 } 526 continue; 527 } 528 529 // norm 530 BigInteger mn = null; 531 //mn = mn.multiply(cc).multiply(mn.fromInteger(2)); 532 533 // prepare lifting 534 GenPolynomial<MOD> re1 = PolyUtil.<MOD> basePseudoDivide(re, ce); 535 GenPolynomial<MOD> qe1 = PolyUtil.<MOD> basePseudoDivide(qe, ce); 536 GenPolynomial<BigInteger> ui; 537 GenPolynomial<MOD> he; 538 GenPolynomial<BigInteger> g; 539 if (mufd.baseGcd(re1, ce).isONE()) { 540 ui = rd; 541 he = re1; 542 BigInteger an = rd.maxNorm(); 543 mn = an.multiply(cc).multiply(new BigInteger(2L)); 544 g = a; 545 } else if (mufd.baseGcd(qe1, ce).isONE()) { 546 ui = qd; 547 he = qe1; 548 BigInteger bn = qd.maxNorm(); 549 mn = bn.multiply(cc).multiply(new BigInteger(2L)); 550 g = b; 551 } else { 552 break; 553 //System.out.println("giving up on Hensel gcd reverting to Subres gcd"); 554 } 555 //System.out.println("ui = " + ui); 556 557 long k = Power.logarithm(new BigInteger(p), mn); 558 //System.out.println("mn = " + mn); 559 //System.out.println("k = " + k); 560 561 List<GenPolynomial<MOD>> F = new ArrayList<GenPolynomial<MOD>>(2); 562 F.add(ce); 563 F.add(he); 564 List<GenPolynomial<BigInteger>> G = new ArrayList<GenPolynomial<BigInteger>>(2); 565 G.add(g.ring.getONE()); // TODO 566 G.add(g.ring.getONE()); 567 List<GenPolynomial<MOD>> lift; 568 try { 569 lift = HenselMultUtil.<MOD> liftHenselFull(ui, F, V, k, G); 570 logger.info("lift = " + lift); 571 } catch (NoLiftingException nle) { 572 //System.out.println("exception : " + nle); 573 continue; 574 } catch (ArithmeticException ae) { 575 //System.out.println("exception : " + ae); 576 continue; 577 } 578 579 // convert Ci from Z_{p^k}[x,y1,...,yr] to Z[x,y1,...,yr] to Z[x][y1,...,yr] to Z[y1,...,yr][x] 580 GenPolynomial<BigInteger> ci = PolyUtil.integerFromModularCoefficients(dfac, lift.get(0)); 581 GenPolynomial<GenPolynomial<BigInteger>> Cr = PolyUtil.<BigInteger> recursive(rfac, ci); 582 GenPolynomial<GenPolynomial<BigInteger>> Cs = PolyUtil.<BigInteger> switchVariables(Cr); 583 if (!Cs.ring.equals(P.ring)) { 584 System.out.println("Cs.ring = " + Cs.ring + ", P.ring = " + P.ring); 585 } 586 q = recursivePrimitivePart(Cs); 587 q = q.abs().multiply(c); //.abs(); 588 if (PolyUtil.<BigInteger> recursivePseudoRemainder(P, q).isZERO() 589 && PolyUtil.<BigInteger> recursivePseudoRemainder(S, q).isZERO()) { 590 return q; 591 } 592 //System.out.println("bad q = " + q); 593 //System.out.println("bad P/q = " + PolyUtil.<BigInteger> recursivePseudoRemainder(P,q)); 594 //System.out.println("bad S/q = " + PolyUtil.<BigInteger> recursivePseudoRemainder(S,q)); 595 } // end for meta loop 596 // Hensel gcd failed 597 GenPolynomial<GenPolynomial<BigInteger>> T = iufd.recursiveUnivariateGcd(P, S); 598 T = T.abs().multiply(c); //.abs(); 599 logger.info("giving up on Hensel gcd reverting to Subres gcd " + T); 600 //System.out.println("giving up on Hensel gcd reverted to Subres gcd: " + T); 601 return T; 602 } 603 604}