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