001/* 002 * $Id$ 003 */ 004 005package edu.jas.ufd; 006 007 008import org.apache.logging.log4j.LogManager; 009import org.apache.logging.log4j.Logger; 010 011import edu.jas.arith.Modular; 012import edu.jas.arith.ModularRingFactory; 013import edu.jas.poly.ExpVector; 014import edu.jas.poly.GenPolynomial; 015import edu.jas.poly.GenPolynomialRing; 016import edu.jas.poly.PolyUtil; 017import edu.jas.structure.GcdRingElem; 018import edu.jas.structure.RingFactory; 019 020 021/** 022 * Greatest common divisor algorithms with modular evaluation algorithm for 023 * recursion. 024 * @author Heinz Kredel 025 */ 026 027public class GreatestCommonDivisorModEval<MOD extends GcdRingElem<MOD> & Modular> 028 extends GreatestCommonDivisorAbstract<MOD> { 029 030 031 private static final Logger logger = LogManager.getLogger(GreatestCommonDivisorModEval.class); 032 033 034 private static final boolean debug = logger.isDebugEnabled(); 035 036 037 /** 038 * Modular gcd algorithm to use. 039 */ 040 protected final GreatestCommonDivisorAbstract<MOD> mufd = new GreatestCommonDivisorSimple<MOD>(); 041 // not okay = new GreatestCommonDivisorPrimitive<MOD>(); 042 // not okay = new GreatestCommonDivisorSubres<MOD>(); 043 044 045 /** 046 * Univariate GenPolynomial greatest common divisor. 047 * @param P univariate GenPolynomial. 048 * @param S univariate GenPolynomial. 049 * @return gcd(P,S). 050 */ 051 @Override 052 public GenPolynomial<MOD> baseGcd(GenPolynomial<MOD> P, GenPolynomial<MOD> S) { 053 // required as recursion base 054 return mufd.baseGcd(P, S); 055 } 056 057 058 /** 059 * Recursive univariate GenPolynomial greatest common divisor. 060 * @param P univariate recursive GenPolynomial. 061 * @param S univariate recursive GenPolynomial. 062 * @return gcd(P,S). 063 */ 064 @Override 065 public GenPolynomial<GenPolynomial<MOD>> recursiveUnivariateGcd(GenPolynomial<GenPolynomial<MOD>> P, 066 GenPolynomial<GenPolynomial<MOD>> S) { 067 //return mufd.recursiveUnivariateGcd(P, S); 068 // distributed polynomials gcd 069 GenPolynomialRing<GenPolynomial<MOD>> rfac = P.ring; 070 RingFactory<GenPolynomial<MOD>> rrfac = rfac.coFac; 071 GenPolynomialRing<MOD> cfac = (GenPolynomialRing<MOD>) rrfac; 072 GenPolynomialRing<MOD> dfac = cfac.extend(rfac.nvar); 073 GenPolynomial<MOD> Pd = PolyUtil.<MOD> distribute(dfac, P); 074 GenPolynomial<MOD> Sd = PolyUtil.<MOD> distribute(dfac, S); 075 GenPolynomial<MOD> Dd = gcd(Pd, Sd); 076 // convert to recursive 077 GenPolynomial<GenPolynomial<MOD>> C = PolyUtil.<MOD> recursive(rfac, Dd); 078 return C; 079 } 080 081 082 /** 083 * GenPolynomial greatest common divisor, modular evaluation algorithm. 084 * @param P GenPolynomial. 085 * @param S GenPolynomial. 086 * @return gcd(P,S). 087 */ 088 @Override 089 public GenPolynomial<MOD> gcd(GenPolynomial<MOD> P, GenPolynomial<MOD> S) { 090 if (S == null || S.isZERO()) { 091 return P; 092 } 093 if (P == null || P.isZERO()) { 094 return S; 095 } 096 GenPolynomialRing<MOD> fac = P.ring; 097 // recusion base case for univariate polynomials 098 if (fac.nvar <= 1) { 099 GenPolynomial<MOD> T = baseGcd(P, S); 100 return T; 101 } 102 long e = P.degree(fac.nvar - 1); 103 long f = S.degree(fac.nvar - 1); 104 if (e == 0 && f == 0) { 105 GenPolynomialRing<GenPolynomial<MOD>> rfac = fac.recursive(1); 106 GenPolynomial<MOD> Pc = PolyUtil.<MOD> recursive(rfac, P).leadingBaseCoefficient(); 107 GenPolynomial<MOD> Sc = PolyUtil.<MOD> recursive(rfac, S).leadingBaseCoefficient(); 108 GenPolynomial<MOD> r = gcd(Pc, Sc); 109 return r.extend(fac, 0, 0L); 110 } 111 GenPolynomial<MOD> q; 112 GenPolynomial<MOD> r; 113 if (f > e) { 114 r = P; 115 q = S; 116 long g = f; 117 f = e; 118 e = g; 119 } else { 120 q = P; 121 r = S; 122 } 123 if (debug) { 124 logger.debug("degrees: e = " + e + ", f = " + f); 125 } 126 r = r.abs(); 127 q = q.abs(); 128 // setup factories 129 ModularRingFactory<MOD> cofac = (ModularRingFactory<MOD>) P.ring.coFac; 130 if (!cofac.isField()) { 131 logger.warn("cofac is not a field: " + cofac); 132 } 133 GenPolynomialRing<GenPolynomial<MOD>> rfac = fac.recursive(fac.nvar - 1); 134 GenPolynomialRing<MOD> mfac = new GenPolynomialRing<MOD>(cofac, rfac); 135 GenPolynomialRing<MOD> ufac = (GenPolynomialRing<MOD>) rfac.coFac; 136 // convert polynomials 137 GenPolynomial<GenPolynomial<MOD>> qr; 138 GenPolynomial<GenPolynomial<MOD>> rr; 139 qr = PolyUtil.<MOD> recursive(rfac, q); 140 rr = PolyUtil.<MOD> recursive(rfac, r); 141 142 // compute univariate contents and primitive parts 143 GenPolynomial<MOD> a = recursiveContent(rr); 144 GenPolynomial<MOD> b = recursiveContent(qr); 145 // gcd of univariate coefficient contents 146 GenPolynomial<MOD> c = gcd(a, b); 147 rr = PolyUtil.<MOD> recursiveDivide(rr, a); 148 qr = PolyUtil.<MOD> recursiveDivide(qr, b); 149 if (rr.isONE()) { 150 rr = rr.multiply(c); 151 r = PolyUtil.<MOD> distribute(fac, rr); 152 return r; 153 } 154 if (qr.isONE()) { 155 qr = qr.multiply(c); 156 q = PolyUtil.<MOD> distribute(fac, qr); 157 return q; 158 } 159 // compute normalization factor 160 GenPolynomial<MOD> ac = rr.leadingBaseCoefficient(); 161 GenPolynomial<MOD> bc = qr.leadingBaseCoefficient(); 162 GenPolynomial<MOD> cc = gcd(ac, bc); 163 // compute degrees and degree vectors 164 ExpVector rdegv = rr.degreeVector(); 165 ExpVector qdegv = qr.degreeVector(); 166 long rd0 = PolyUtil.<MOD> coeffMaxDegree(rr); 167 long qd0 = PolyUtil.<MOD> coeffMaxDegree(qr); 168 long cd0 = cc.degree(0); 169 long G = (rd0 < qd0 ? rd0 : qd0) + cd0 + 1L; // >= 170 //long Gm = (e < f ? e : f); 171 172 // initialize element and degree vector 173 ExpVector wdegv = rdegv.subst(0, rdegv.getVal(0) + 1); 174 // +1 seems to be a hack for the unlucky evaluation point test 175 MOD inc = cofac.getONE(); 176 long i = 0; 177 long en = cofac.getIntegerModul().longValueExact() - 1; // just a stopper 178 MOD end = cofac.fromInteger(en); 179 MOD mi; 180 GenPolynomial<MOD> M = null; 181 GenPolynomial<MOD> mn; 182 GenPolynomial<MOD> qm; 183 GenPolynomial<MOD> rm; 184 GenPolynomial<MOD> cm; 185 GenPolynomial<GenPolynomial<MOD>> cp = null; 186 if (debug) { 187 logger.debug("c = " + c); 188 logger.debug("cc = " + cc); 189 logger.debug("G = " + G); 190 logger.info("wdegv = " + wdegv + ", in " + rfac.toScript()); 191 } 192 for (MOD d = cofac.getZERO(); d.compareTo(end) <= 0; d = d.sum(inc)) { 193 if (++i >= en) { 194 logger.warn("elements of Z_p exhausted, en = " + en); 195 return mufd.gcd(P, S); 196 //throw new ArithmeticException("elements of Z_p exhausted, en = " + en); 197 } 198 // map normalization factor 199 MOD nf = PolyUtil.<MOD> evaluateMain(cofac, cc, d); 200 if (nf.isZERO()) { 201 continue; 202 } 203 // map polynomials 204 qm = PolyUtil.<MOD> evaluateFirstRec(ufac, mfac, qr, d); 205 if (qm.isZERO() || !qm.degreeVector().equals(qdegv)) { 206 continue; 207 } 208 rm = PolyUtil.<MOD> evaluateFirstRec(ufac, mfac, rr, d); 209 if (rm.isZERO() || !rm.degreeVector().equals(rdegv)) { 210 continue; 211 } 212 if (debug) { 213 logger.debug("eval d = " + d); 214 } 215 // compute modular gcd in recursion 216 cm = gcd(rm, qm); 217 if (debug) { 218 logger.debug("cm = " + cm + ", rm = " + rm + ", qm = " + qm); 219 //cm = mufd.gcd(rm,qm); 220 //logger.debug("cm = " + cm + ", rm = " + rm + ", qm = " + qm); 221 } 222 // test for constant g.c.d 223 if (cm.isConstant()) { 224 logger.debug("cm.isConstant = " + cm + ", c = " + c); 225 if (c.ring.nvar < cm.ring.nvar) { 226 c = c.extend(mfac, 0, 0); 227 } 228 cm = cm.abs().multiply(c); 229 q = cm.extend(fac, 0, 0); 230 //logger.debug("q = " + q + ", c = " + c); 231 return q; 232 } 233 // test for unlucky evaluation point 234 ExpVector mdegv = cm.degreeVector(); 235 if (wdegv.equals(mdegv)) { // TL = 0 236 // evaluation point ok, next round 237 if (M != null) { 238 if (M.degree(0) > G) { 239 logger.info("deg(M) > G: " + M.degree(0) + " > " + G); 240 // continue; // why should this be required? 241 } 242 } 243 } else { // TL = 3 244 boolean ok = false; 245 if (wdegv.multipleOf(mdegv)) { // TL = 2 246 M = null; // init chinese remainder 247 ok = true; // evaluation point ok 248 } 249 if (mdegv.multipleOf(wdegv)) { // TL = 1 250 continue; // skip this evaluation point 251 } 252 if (!ok) { 253 M = null; // discard chinese remainder and previous work 254 continue; // evaluation point not ok 255 } 256 } 257 // prepare interpolation algorithm 258 cm = cm.multiply(nf); 259 if (M == null) { 260 // initialize interpolation 261 M = ufac.getONE(); 262 cp = rfac.getZERO(); 263 wdegv = wdegv.gcd(mdegv); //EVGCD(wdegv,mdegv); 264 } 265 // interpolate 266 mi = PolyUtil.<MOD> evaluateMain(cofac, M, d); 267 mi = mi.inverse(); // mod p 268 cp = PolyUtil.interpolate(rfac, cp, M, mi, cm, d); 269 if (debug) { 270 logger.debug("cp = " + cp + ", cm = " + cm + ", M = " + M + " :: " + M.ring.toScript()); 271 } 272 mn = ufac.getONE().multiply(d); 273 mn = ufac.univariate(0).subtract(mn); 274 M = M.multiply(mn); // M * (x-d) 275 // test for divisibility 276 boolean tt = false; 277 if (cp.leadingBaseCoefficient().equals(cc)) { 278 cp = recursivePrimitivePart(cp).abs(); 279 logger.debug("test cp == cc: " + cp + " == " + cc); 280 tt = PolyUtil.<MOD> recursiveSparsePseudoRemainder(qr, cp).isZERO(); 281 tt = tt && PolyUtil.<MOD> recursiveSparsePseudoRemainder(rr, cp).isZERO(); 282 if (tt) { 283 logger.debug("break: is gcd"); 284 break; 285 } 286 if (M.degree(0) > G) { // no && cp.degree(0) > Gm 287 logger.debug("break: fail 1, cp = " + cp); 288 cp = rfac.getONE(); 289 break; 290 } 291 } 292 // test for completion 293 if (M.degree(0) > G) { // no && cp.degree(0) > Gm 294 logger.debug("break: M = " + M + ", G = " + G + ", mn = " + mn + ", M.deg(0) = " 295 + M.degree(0)); 296 cp = recursivePrimitivePart(cp).abs(); 297 tt = PolyUtil.<MOD> recursiveSparsePseudoRemainder(qr, cp).isZERO(); 298 tt = tt && PolyUtil.<MOD> recursiveSparsePseudoRemainder(rr, cp).isZERO(); 299 if (!tt) { 300 logger.debug("break: fail 2, cp = " + cp); 301 cp = rfac.getONE(); 302 } 303 break; 304 } 305 //long cmn = PolyUtil.<MOD>coeffMaxDegree(cp); 306 //if ( M.degree(0) > cmn ) { 307 // does not work: only if cofactors are also considered? 308 // break; 309 //} 310 } 311 // remove normalization 312 cp = recursivePrimitivePart(cp).abs(); 313 cp = cp.multiply(c); 314 q = PolyUtil.<MOD> distribute(fac, cp); 315 return q; 316 } 317 318 319 /** 320 * Univariate GenPolynomial resultant. 321 * @param P univariate GenPolynomial. 322 * @param S univariate GenPolynomial. 323 * @return res(P,S). 324 */ 325 @Override 326 public GenPolynomial<MOD> baseResultant(GenPolynomial<MOD> P, GenPolynomial<MOD> S) { 327 // required as recursion base 328 return mufd.baseResultant(P, S); 329 } 330 331 332 /** 333 * Univariate GenPolynomial recursive resultant. 334 * @param P univariate recursive GenPolynomial. 335 * @param S univariate recursive GenPolynomial. 336 * @return res(P,S). 337 */ 338 @Override 339 public GenPolynomial<GenPolynomial<MOD>> recursiveUnivariateResultant(GenPolynomial<GenPolynomial<MOD>> P, 340 GenPolynomial<GenPolynomial<MOD>> S) { 341 // only in this class 342 return recursiveResultant(P, S); 343 } 344 345 346 /** 347 * GenPolynomial resultant, modular evaluation algorithm. 348 * @param P GenPolynomial. 349 * @param S GenPolynomial. 350 * @return res(P,S). 351 */ 352 @Override 353 public GenPolynomial<MOD> resultant(GenPolynomial<MOD> P, GenPolynomial<MOD> S) { 354 if (S == null || S.isZERO()) { 355 return S; 356 } 357 if (P == null || P.isZERO()) { 358 return P; 359 } 360 GenPolynomialRing<MOD> fac = P.ring; 361 // recusion base case for univariate polynomials 362 if (fac.nvar <= 1) { 363 GenPolynomial<MOD> T = baseResultant(P, S); 364 return T; 365 } 366 long e = P.degree(fac.nvar - 1); 367 long f = S.degree(fac.nvar - 1); 368 if (e == 0 && f == 0) { 369 GenPolynomialRing<GenPolynomial<MOD>> rfac = fac.recursive(1); 370 GenPolynomial<MOD> Pc = PolyUtil.<MOD> recursive(rfac, P).leadingBaseCoefficient(); 371 GenPolynomial<MOD> Sc = PolyUtil.<MOD> recursive(rfac, S).leadingBaseCoefficient(); 372 GenPolynomial<MOD> r = resultant(Pc, Sc); 373 return r.extend(fac, 0, 0L); 374 } 375 GenPolynomial<MOD> q; 376 GenPolynomial<MOD> r; 377 if (f > e) { 378 r = P; 379 q = S; 380 long g = f; 381 f = e; 382 e = g; 383 } else { 384 q = P; 385 r = S; 386 } 387 if (debug) { 388 logger.debug("degrees: e = " + e + ", f = " + f); 389 } 390 // setup factories 391 ModularRingFactory<MOD> cofac = (ModularRingFactory<MOD>) P.ring.coFac; 392 if (!cofac.isField()) { 393 logger.warn("cofac is not a field: " + cofac); 394 } 395 GenPolynomialRing<GenPolynomial<MOD>> rfac = fac.recursive(fac.nvar - 1); 396 GenPolynomialRing<MOD> mfac = new GenPolynomialRing<MOD>(cofac, rfac); 397 GenPolynomialRing<MOD> ufac = (GenPolynomialRing<MOD>) rfac.coFac; 398 399 // convert polynomials 400 GenPolynomial<GenPolynomial<MOD>> qr = PolyUtil.<MOD> recursive(rfac, q); 401 GenPolynomial<GenPolynomial<MOD>> rr = PolyUtil.<MOD> recursive(rfac, r); 402 403 // compute degrees and degree vectors 404 ExpVector qdegv = qr.degreeVector(); 405 ExpVector rdegv = rr.degreeVector(); 406 407 long qd0 = PolyUtil.<MOD> coeffMaxDegree(qr); 408 long rd0 = PolyUtil.<MOD> coeffMaxDegree(rr); 409 qd0 = (qd0 == 0 ? 1 : qd0); 410 rd0 = (rd0 == 0 ? 1 : rd0); 411 long qd1 = qr.degree(); 412 long rd1 = rr.degree(); 413 qd1 = (qd1 == 0 ? 1 : qd1); 414 rd1 = (rd1 == 0 ? 1 : rd1); 415 long G = qd0 * rd1 + rd0 * qd1 + 1; 416 417 // initialize element 418 MOD inc = cofac.getONE(); 419 long i = 0; 420 long en = cofac.getIntegerModul().longValueExact() - 1; // just a stopper 421 MOD end = cofac.fromInteger(en); 422 MOD mi; 423 GenPolynomial<MOD> M = null; 424 GenPolynomial<MOD> mn; 425 GenPolynomial<MOD> qm; 426 GenPolynomial<MOD> rm; 427 GenPolynomial<MOD> cm; 428 GenPolynomial<GenPolynomial<MOD>> cp = null; 429 if (debug) { 430 //logger.info("qr = " + qr + ", q = " + q); 431 //logger.info("rr = " + rr + ", r = " + r); 432 //logger.info("qd0 = " + qd0); 433 //logger.info("rd0 = " + rd0); 434 logger.info("G = " + G); 435 //logger.info("rdegv = " + rdegv); // + ", rr.degree(0) = " + rr.degree(0)); 436 //logger.info("qdegv = " + qdegv); // + ", qr.degree(0) = " + qr.degree(0)); 437 } 438 for (MOD d = cofac.getZERO(); d.compareTo(end) <= 0; d = d.sum(inc)) { 439 if (++i >= en) { 440 logger.warn("elements of Z_p exhausted, en = " + en + ", p = " + cofac.getIntegerModul()); 441 return mufd.resultant(P, S); 442 //throw new ArithmeticException("prime list exhausted"); 443 } 444 // map polynomials 445 qm = PolyUtil.<MOD> evaluateFirstRec(ufac, mfac, qr, d); 446 //logger.info("qr(" + d + ") = " + qm + ", qr = " + qr); 447 if (qm.isZERO() || !qm.degreeVector().equals(qdegv)) { 448 if (debug) { 449 logger.info("un-lucky evaluation point " + d + ", qm = " + qm.degreeVector() + " < " 450 + qdegv); 451 } 452 continue; 453 } 454 rm = PolyUtil.<MOD> evaluateFirstRec(ufac, mfac, rr, d); 455 //logger.info("rr(" + d + ") = " + rm + ", rr = " + rr); 456 if (rm.isZERO() || !rm.degreeVector().equals(rdegv)) { 457 if (debug) { 458 logger.info("un-lucky evaluation point " + d + ", rm = " + rm.degreeVector() + " < " 459 + rdegv); 460 } 461 continue; 462 } 463 // compute modular resultant in recursion 464 cm = resultant(rm, qm); 465 //System.out.println("cm = " + cm); 466 467 // prepare interpolation algorithm 468 if (M == null) { 469 // initialize interpolation 470 M = ufac.getONE(); 471 cp = rfac.getZERO(); 472 } 473 // interpolate 474 mi = PolyUtil.<MOD> evaluateMain(cofac, M, d); 475 mi = mi.inverse(); // mod p 476 cp = PolyUtil.interpolate(rfac, cp, M, mi, cm, d); 477 //logger.info("cp = " + cp); 478 mn = ufac.getONE().multiply(d); 479 mn = ufac.univariate(0).subtract(mn); 480 M = M.multiply(mn); 481 // test for completion 482 if (M.degree(0) > G) { 483 if (debug) { 484 logger.info("last lucky evaluation point " + d); 485 } 486 break; 487 } 488 //logger.info("M = " + M); 489 } 490 // distribute 491 q = PolyUtil.<MOD> distribute(fac, cp); 492 return q; 493 } 494 495}