001/* 002 * $Id: GreatestCommonDivisorModular.java 4111 2012-08-19 12:30:30Z kredel $ 003 */ 004 005package edu.jas.ufd; 006 007 008import org.apache.log4j.Logger; 009 010import edu.jas.arith.BigInteger; 011import edu.jas.arith.Combinatoric; 012import edu.jas.arith.ModIntegerRing; 013import edu.jas.arith.ModLongRing; 014import edu.jas.arith.Modular; 015import edu.jas.arith.ModularRingFactory; 016import edu.jas.arith.PrimeList; 017import edu.jas.poly.ExpVector; 018import edu.jas.poly.GenPolynomial; 019import edu.jas.poly.GenPolynomialRing; 020import edu.jas.poly.PolyUtil; 021import edu.jas.structure.GcdRingElem; 022import edu.jas.structure.Power; 023 024 025/** 026 * Greatest common divisor algorithms with modular computation and chinese 027 * remainder algorithm. 028 * @author Heinz Kredel 029 */ 030 031public class GreatestCommonDivisorModular<MOD extends GcdRingElem<MOD> & Modular> extends 032 GreatestCommonDivisorAbstract<BigInteger> { 033 034 035 private static final Logger logger = Logger.getLogger(GreatestCommonDivisorModular.class); 036 037 038 private final boolean debug = logger.isDebugEnabled(); //logger.isInfoEnabled(); 039 040 041 /* 042 * Modular gcd algorithm to use. 043 */ 044 protected final GreatestCommonDivisorAbstract<MOD> mufd; 045 046 047 /* 048 * Integer gcd algorithm for fall back. 049 */ 050 protected final GreatestCommonDivisorAbstract<BigInteger> iufd = new GreatestCommonDivisorSubres<BigInteger>(); 051 052 053 /** 054 * Constructor to set recursive algorithm. Use modular evaluation GCD 055 * algorithm. 056 */ 057 public GreatestCommonDivisorModular() { 058 this(false); 059 } 060 061 062 /** 063 * Constructor to set recursive algorithm. 064 * @param simple , true if the simple PRS should be used. 065 */ 066 public GreatestCommonDivisorModular(boolean simple) { 067 if (simple) { 068 mufd = new GreatestCommonDivisorSimple<MOD>(); 069 } else { 070 mufd = new GreatestCommonDivisorModEval<MOD>(); 071 } 072 } 073 074 075 /** 076 * Univariate GenPolynomial greatest comon divisor. Delegate to subresultant 077 * baseGcd, should not be needed. 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 return iufd.baseGcd(P, S); 085 } 086 087 088 /** 089 * Univariate GenPolynomial recursive greatest comon divisor. Delegate to 090 * subresultant recursiveGcd, should not be needed. 091 * @param P univariate recursive GenPolynomial. 092 * @param S univariate recursive GenPolynomial. 093 * @return gcd(P,S). 094 */ 095 @Override 096 public GenPolynomial<GenPolynomial<BigInteger>> recursiveUnivariateGcd( 097 GenPolynomial<GenPolynomial<BigInteger>> P, GenPolynomial<GenPolynomial<BigInteger>> S) { 098 return iufd.recursiveUnivariateGcd(P, S); 099 } 100 101 102 /** 103 * GenPolynomial greatest comon divisor, modular algorithm. 104 * @param P GenPolynomial. 105 * @param S GenPolynomial. 106 * @return gcd(P,S). 107 */ 108 @Override 109 public GenPolynomial<BigInteger> gcd(GenPolynomial<BigInteger> P, GenPolynomial<BigInteger> S) { 110 if (S == null || S.isZERO()) { 111 return P; 112 } 113 if (P == null || P.isZERO()) { 114 return S; 115 } 116 GenPolynomialRing<BigInteger> fac = P.ring; 117 // special case for univariate polynomials 118 if (fac.nvar <= 1) { 119 GenPolynomial<BigInteger> T = baseGcd(P, S); 120 return T; 121 } 122 long e = P.degree(0); 123 long f = S.degree(0); 124 GenPolynomial<BigInteger> q; 125 GenPolynomial<BigInteger> r; 126 if (f > e) { 127 r = P; 128 q = S; 129 long g = f; 130 f = e; 131 e = g; 132 } else { 133 q = P; 134 r = S; 135 } 136 if (debug) { 137 logger.debug("degrees: e = " + e + ", f = " + f); 138 } 139 r = r.abs(); 140 q = q.abs(); 141 // compute contents and primitive parts 142 BigInteger a = baseContent(r); 143 BigInteger b = baseContent(q); 144 // gcd of coefficient contents 145 BigInteger c = gcd(a, b); // indirection 146 r = divide(r, a); // indirection 147 q = divide(q, b); // indirection 148 if (r.isONE()) { 149 return r.multiply(c); 150 } 151 if (q.isONE()) { 152 return q.multiply(c); 153 } 154 // compute normalization factor 155 BigInteger ac = r.leadingBaseCoefficient(); 156 BigInteger bc = q.leadingBaseCoefficient(); 157 BigInteger cc = gcd(ac, bc); // indirection 158 // compute norms 159 BigInteger an = r.maxNorm(); 160 BigInteger bn = q.maxNorm(); 161 BigInteger n = (an.compareTo(bn) < 0 ? bn : an); 162 n = n.multiply(cc).multiply(n.fromInteger(2)); 163 // compute degree vectors 164 ExpVector rdegv = r.degreeVector(); 165 ExpVector qdegv = q.degreeVector(); 166 //compute factor coefficient bounds 167 BigInteger af = an.multiply(PolyUtil.factorBound(rdegv)); 168 BigInteger bf = bn.multiply(PolyUtil.factorBound(qdegv)); 169 BigInteger cf = (af.compareTo(bf) < 0 ? bf : af); 170 cf = cf.multiply(cc.multiply(cc.fromInteger(8))); 171 //initialize prime list and degree vector 172 PrimeList primes = new PrimeList(); 173 int pn = 10; //primes.size(); 174 ExpVector wdegv = rdegv.subst(0, rdegv.getVal(0) + 1); 175 // +1 seems to be a hack for the unlucky prime test 176 ModularRingFactory<MOD> cofac; 177 ModularRingFactory<MOD> cofacM = null; 178 GenPolynomial<MOD> qm; 179 GenPolynomial<MOD> rm; 180 GenPolynomialRing<MOD> mfac; 181 GenPolynomialRing<MOD> rfac = null; 182 int i = 0; 183 BigInteger M = null; 184 BigInteger cfe = null; 185 GenPolynomial<MOD> cp = null; 186 GenPolynomial<MOD> cm = null; 187 GenPolynomial<BigInteger> cpi = null; 188 if (debug) { 189 logger.debug("c = " + c); 190 logger.debug("cc = " + cc); 191 logger.debug("n = " + n); 192 logger.debug("cf = " + cf); 193 logger.info("wdegv = " + wdegv); 194 } 195 for (java.math.BigInteger p : primes) { 196 //System.out.println("next run ++++++++++++++++++++++++++++++++++"); 197 if (p.longValue() == 2L) { // skip 2 198 continue; 199 } 200 if (++i >= pn) { 201 logger.warn("prime list exhausted, pn = " + pn); 202 return iufd.gcd(P, S); 203 //throw new ArithmeticException("prime list exhausted"); 204 } 205 // initialize coefficient factory and map normalization factor 206 if (ModLongRing.MAX_LONG.compareTo(p) > 0) { 207 cofac = (ModularRingFactory) new ModLongRing(p, true); 208 } else { 209 cofac = (ModularRingFactory) new ModIntegerRing(p, true); 210 } 211 MOD nf = cofac.fromInteger(cc.getVal()); 212 if (nf.isZERO()) { 213 continue; 214 } 215 // initialize polynomial factory and map polynomials 216 mfac = new GenPolynomialRing<MOD>(cofac, fac.nvar, fac.tord, fac.getVars()); 217 qm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, q); 218 if (qm.isZERO() || !qm.degreeVector().equals(qdegv)) { 219 continue; 220 } 221 rm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, r); 222 if (rm.isZERO() || !rm.degreeVector().equals(rdegv)) { 223 continue; 224 } 225 if (debug) { 226 logger.info("cofac = " + cofac.getIntegerModul()); 227 } 228 // compute modular gcd 229 cm = mufd.gcd(rm, qm); 230 // test for constant g.c.d 231 if (cm.isConstant()) { 232 logger.debug("cm, constant = " + cm); 233 return fac.getONE().multiply(c); 234 //return cm.abs().multiply( c ); 235 } 236 // test for unlucky prime 237 ExpVector mdegv = cm.degreeVector(); 238 if (wdegv.equals(mdegv)) { // TL = 0 239 // prime ok, next round 240 if (M != null) { 241 if (M.compareTo(cfe) > 0) { 242 System.out.println("M > cfe: " + M + " > " + cfe); 243 // continue; // why should this be required? 244 } 245 } 246 } else { // TL = 3 247 boolean ok = false; 248 if (wdegv.multipleOf(mdegv)) { // TL = 2 // EVMT(wdegv,mdegv) 249 M = null; // init chinese remainder 250 ok = true; // prime ok 251 } 252 if (mdegv.multipleOf(wdegv)) { // TL = 1 // EVMT(mdegv,wdegv) 253 continue; // skip this prime 254 } 255 if (!ok) { 256 M = null; // discard chinese remainder and previous work 257 continue; // prime not ok 258 } 259 } 260 //--wdegv = mdegv; 261 // prepare chinese remainder algorithm 262 cm = cm.multiply(nf); 263 if (M == null) { 264 // initialize chinese remainder algorithm 265 M = new BigInteger(p); 266 cofacM = cofac; 267 rfac = mfac; 268 cp = cm; 269 wdegv = wdegv.gcd(mdegv); //EVGCD(wdegv,mdegv); 270 cfe = cf; 271 for (int k = 0; k < wdegv.length(); k++) { 272 cfe = cfe.multiply(new BigInteger(wdegv.getVal(k) + 1)); 273 } 274 } else { 275 // apply chinese remainder algorithm 276 BigInteger Mp = M; 277 MOD mi = cofac.fromInteger(Mp.getVal()); 278 mi = mi.inverse(); // mod p 279 M = M.multiply(new BigInteger(p)); 280 if (ModLongRing.MAX_LONG.compareTo(M.getVal()) > 0) { 281 cofacM = (ModularRingFactory) new ModLongRing(M.getVal()); 282 } else { 283 cofacM = (ModularRingFactory) new ModIntegerRing(M.getVal()); 284 } 285 rfac = new GenPolynomialRing<MOD>(cofacM, fac); 286 if (!cofac.getClass().equals(cofacM.getClass())) { 287 logger.info("adjusting coefficents: cofacM = " + cofacM.getClass() + ", cofacP = " 288 + cofac.getClass()); 289 cofac = (ModularRingFactory) new ModIntegerRing(p); 290 mfac = new GenPolynomialRing<MOD>(cofac, fac); 291 GenPolynomial<BigInteger> mm = PolyUtil.<MOD> integerFromModularCoefficients(fac, cm); 292 cm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, mm); 293 mi = cofac.fromInteger(Mp.getVal()); 294 mi = mi.inverse(); // mod p 295 } 296 if (!cp.ring.coFac.getClass().equals(cofacM.getClass())) { 297 logger.info("adjusting coefficents: cofacM = " + cofacM.getClass() + ", cofacM' = " 298 + cp.ring.coFac.getClass()); 299 ModularRingFactory cop = (ModularRingFactory) cp.ring.coFac; 300 cofac = (ModularRingFactory) new ModIntegerRing(cop.getIntegerModul().getVal()); 301 mfac = new GenPolynomialRing<MOD>(cofac, fac); 302 GenPolynomial<BigInteger> mm = PolyUtil.<MOD> integerFromModularCoefficients(fac, cp); 303 cp = PolyUtil.<MOD> fromIntegerCoefficients(mfac, mm); 304 } 305 cp = PolyUtil.<MOD> chineseRemainder(rfac, cp, mi, cm); 306 } 307 // test for completion 308 if (n.compareTo(M) <= 0) { 309 break; 310 } 311 // must use integer.sumNorm 312 cpi = PolyUtil.<MOD> integerFromModularCoefficients(fac, cp); 313 BigInteger cmn = cpi.sumNorm(); 314 cmn = cmn.multiply(cmn.fromInteger(4)); 315 //if ( cmn.compareTo( M ) <= 0 ) { 316 // does not work: only if cofactors are also considered? 317 // break; 318 //} 319 if (i % 2 != 0 && !cp.isZERO()) { 320 // check if done on every second prime 321 GenPolynomial<BigInteger> x; 322 x = PolyUtil.<MOD> integerFromModularCoefficients(fac, cp); 323 x = basePrimitivePart(x); 324 if (!PolyUtil.<BigInteger> baseSparsePseudoRemainder(q, x).isZERO()) { 325 continue; 326 } 327 if (!PolyUtil.<BigInteger> baseSparsePseudoRemainder(r, x).isZERO()) { 328 continue; 329 } 330 logger.info("done on exact division, #primes = " + i); 331 break; 332 } 333 } 334 if (debug) { 335 logger.info("done on M = " + M + ", #primes = " + i); 336 } 337 // remove normalization 338 q = PolyUtil.<MOD> integerFromModularCoefficients(fac, cp); 339 q = basePrimitivePart(q); 340 return q.abs().multiply(c); 341 } 342 343 344 /** 345 * Univariate GenPolynomial resultant. 346 * @param P univariate GenPolynomial. 347 * @param S univariate GenPolynomial. 348 * @return res(P,S). 349 */ 350 @Override 351 public GenPolynomial<BigInteger> baseResultant(GenPolynomial<BigInteger> P, GenPolynomial<BigInteger> S) { 352 // not a special case here 353 return resultant(P,S); 354 } 355 356 357 /** 358 * Univariate GenPolynomial recursive resultant. 359 * @param P univariate recursive GenPolynomial. 360 * @param S univariate recursive GenPolynomial. 361 * @return res(P,S). 362 */ 363 public GenPolynomial<GenPolynomial<BigInteger>> recursiveUnivariateResultant(GenPolynomial<GenPolynomial<BigInteger>> P, 364 GenPolynomial<GenPolynomial<BigInteger>> S) { 365 // only in this class 366 return recursiveResultant(P,S); 367 } 368 369 370 /** 371 * GenPolynomial resultant, modular algorithm. 372 * @param P GenPolynomial. 373 * @param S GenPolynomial. 374 * @return res(P,S). 375 */ 376 @Override 377 public GenPolynomial<BigInteger> resultant(GenPolynomial<BigInteger> P, GenPolynomial<BigInteger> S) { 378 if (S == null || S.isZERO()) { 379 return S; 380 } 381 if (P == null || P.isZERO()) { 382 return P; 383 } 384 GenPolynomialRing<BigInteger> fac = P.ring; 385 // no special case for univariate polynomials in this class ! 386 //if (fac.nvar <= 1) { 387 // GenPolynomial<BigInteger> T = iufd.baseResultant(P, S); 388 // return T; 389 //} 390 long e = P.degree(0); 391 long f = S.degree(0); 392 GenPolynomial<BigInteger> q; 393 GenPolynomial<BigInteger> r; 394 if (f > e) { 395 r = P; 396 q = S; 397 long g = f; 398 f = e; 399 e = g; 400 } else { 401 q = P; 402 r = S; 403 } 404 // compute norms 405 BigInteger an = r.maxNorm(); 406 BigInteger bn = q.maxNorm(); 407 an = Power.<BigInteger> power(fac.coFac, an, f); 408 bn = Power.<BigInteger> power(fac.coFac, bn, e); 409 BigInteger cn = Combinatoric.factorial(e + f); 410 BigInteger n = cn.multiply(an).multiply(bn); 411 412 // compute degree vectors 413 ExpVector rdegv = r.leadingExpVector(); //degreeVector(); 414 ExpVector qdegv = q.leadingExpVector(); //degreeVector(); 415 416 //initialize prime list and degree vector 417 PrimeList primes = new PrimeList(); 418 int pn = 30; //primes.size(); 419 ModularRingFactory<MOD> cofac; 420 ModularRingFactory<MOD> cofacM = null; 421 GenPolynomial<MOD> qm; 422 GenPolynomial<MOD> rm; 423 GenPolynomialRing<MOD> mfac; 424 GenPolynomialRing<MOD> rfac = null; 425 int i = 0; 426 BigInteger M = null; 427 GenPolynomial<MOD> cp = null; 428 GenPolynomial<MOD> cm = null; 429 GenPolynomial<BigInteger> cpi = null; 430 if (debug) { 431 logger.debug("an = " + an); 432 logger.debug("bn = " + bn); 433 logger.debug("e+f = " + (e+f)); 434 logger.debug("cn = " + cn); 435 logger.info("n = " + n); 436 //logger.info("q = " + q); 437 //logger.info("r = " + r); 438 //logger.info("rdegv = " + rdegv.toString(fac.getVars())); 439 //logger.info("qdegv = " + qdegv.toString(fac.getVars())); 440 } 441 for (java.math.BigInteger p : primes) { 442 //System.out.println("next run ++++++++++++++++++++++++++++++++++"); 443 if (p.longValue() == 2L) { // skip 2 444 continue; 445 } 446 if (++i >= pn) { 447 logger.warn("prime list exhausted, pn = " + pn); 448 return iufd.resultant(P, S); 449 //throw new ArithmeticException("prime list exhausted"); 450 } 451 // initialize coefficient factory and map normalization factor 452 if (ModLongRing.MAX_LONG.compareTo(p) > 0) { 453 cofac = (ModularRingFactory) new ModLongRing(p, true); 454 } else { 455 cofac = (ModularRingFactory) new ModIntegerRing(p, true); 456 } 457 // initialize polynomial factory and map polynomials 458 mfac = new GenPolynomialRing<MOD>(cofac, fac); 459 qm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, q); 460 if (qm.isZERO() || !qm.leadingExpVector().equals(qdegv)) { //degreeVector() 461 //logger.info("qm = " + qm); 462 if (debug) { 463 logger.info("unlucky prime = " + cofac.getIntegerModul() + ", degv = " + qm.leadingExpVector()); 464 } 465 continue; 466 } 467 rm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, r); 468 if (rm.isZERO() || !rm.leadingExpVector().equals(rdegv)) { //degreeVector() 469 //logger.info("rm = " + rm); 470 if (debug) { 471 logger.info("unlucky prime = " + cofac.getIntegerModul() + ", degv = " + rm.leadingExpVector()); 472 } 473 continue; 474 } 475 logger.info("lucky prime = " + cofac.getIntegerModul()); 476 477 // compute modular resultant 478 cm = mufd.resultant(qm, rm); 479 if (debug) { 480 logger.info("res_p = " + cm); 481 } 482 483 // prepare chinese remainder algorithm 484 if (M == null) { 485 // initialize chinese remainder algorithm 486 M = new BigInteger(p); 487 cofacM = cofac; 488 //rfac = mfac; 489 cp = cm; 490 } else { 491 // apply chinese remainder algorithm 492 BigInteger Mp = M; 493 MOD mi = cofac.fromInteger(Mp.getVal()); 494 mi = mi.inverse(); // mod p 495 M = M.multiply(new BigInteger(p)); 496 if (ModLongRing.MAX_LONG.compareTo(M.getVal()) > 0) { 497 cofacM = (ModularRingFactory) new ModLongRing(M.getVal()); 498 } else { 499 cofacM = (ModularRingFactory) new ModIntegerRing(M.getVal()); 500 } 501 rfac = new GenPolynomialRing<MOD>(cofacM, fac); 502 if (!cofac.getClass().equals(cofacM.getClass())) { 503 logger.info("adjusting coefficents: cofacM = " + cofacM.getClass() + ", cofacP = " 504 + cofac.getClass()); 505 cofac = (ModularRingFactory) new ModIntegerRing(p); 506 mfac = new GenPolynomialRing<MOD>(cofac, fac); 507 GenPolynomial<BigInteger> mm = PolyUtil.<MOD> integerFromModularCoefficients(fac, cm); 508 cm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, mm); 509 mi = cofac.fromInteger(Mp.getVal()); 510 mi = mi.inverse(); // mod p 511 } 512 if (!cp.ring.coFac.getClass().equals(cofacM.getClass())) { 513 logger.info("adjusting coefficents: cofacM = " + cofacM.getClass() + ", cofacM' = " 514 + cp.ring.coFac.getClass()); 515 ModularRingFactory cop = (ModularRingFactory) cp.ring.coFac; 516 cofac = (ModularRingFactory) new ModIntegerRing(cop.getIntegerModul().getVal()); 517 mfac = new GenPolynomialRing<MOD>(cofac, fac); 518 GenPolynomial<BigInteger> mm = PolyUtil.<MOD> integerFromModularCoefficients(fac, cp); 519 cp = PolyUtil.<MOD> fromIntegerCoefficients(mfac, mm); 520 } 521 cp = PolyUtil.<MOD> chineseRemainder(rfac, cp, mi, cm); 522 } 523 // test for completion 524 if (n.compareTo(M) <= 0) { 525 break; 526 } 527 } 528 if (debug) { 529 logger.info("done on M = " + M + ", #primes = " + i); 530 } 531 // convert to integer polynomial 532 q = PolyUtil.<MOD> integerFromModularCoefficients(fac, cp); 533 return q; 534 } 535 536}