001/* 002 * $Id: GreatestCommonDivisorModEval.java 5756 2017-06-05 21:42:52Z kredel $ 003 */ 004 005package edu.jas.ufd; 006 007 008import org.apache.log4j.Logger; 009 010import edu.jas.arith.Modular; 011import edu.jas.arith.ModularRingFactory; 012import edu.jas.poly.ExpVector; 013import edu.jas.poly.GenPolynomial; 014import edu.jas.poly.GenPolynomialRing; 015import edu.jas.poly.PolyUtil; 016import edu.jas.structure.GcdRingElem; 017import edu.jas.structure.RingFactory; 018 019 020/** 021 * Greatest common divisor algorithms with modular evaluation algorithm for 022 * recursion. 023 * @author Heinz Kredel 024 */ 025 026public class GreatestCommonDivisorModEval <MOD extends GcdRingElem<MOD> & Modular> 027 extends GreatestCommonDivisorAbstract<MOD> { 028 029 030 private static final Logger logger = Logger.getLogger(GreatestCommonDivisorModEval.class); 031 032 033 private static final boolean debug = logger.isDebugEnabled(); 034 035 036 /** 037 * Modular gcd algorithm to use. 038 */ 039 protected final GreatestCommonDivisorAbstract<MOD> mufd 040 = 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( 066 GenPolynomial<GenPolynomial<MOD>> P, 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 //GenPolynomialRing<MOD> mfac = new GenPolynomialRing<MOD>(cofac, fac.nvar - 1, fac.tord); 137 //GenPolynomialRing<MOD> ufac = new GenPolynomialRing<MOD>(cofac, 1, fac.tord); 138 //GenPolynomialRing<GenPolynomial<MOD>> rfac = new GenPolynomialRing<GenPolynomial<MOD>>(ufac, fac.nvar - 1, fac.tord); 139 // convert polynomials 140 GenPolynomial<GenPolynomial<MOD>> qr; 141 GenPolynomial<GenPolynomial<MOD>> rr; 142 qr = PolyUtil.<MOD> recursive(rfac, q); 143 rr = PolyUtil.<MOD> recursive(rfac, r); 144 145 // compute univariate contents and primitive parts 146 GenPolynomial<MOD> a = recursiveContent(rr); 147 GenPolynomial<MOD> b = recursiveContent(qr); 148 // gcd of univariate coefficient contents 149 GenPolynomial<MOD> c = gcd(a, b); 150 rr = PolyUtil.<MOD> recursiveDivide(rr, a); 151 qr = PolyUtil.<MOD> recursiveDivide(qr, b); 152 if (rr.isONE()) { 153 rr = rr.multiply(c); 154 r = PolyUtil.<MOD> distribute(fac, rr); 155 return r; 156 } 157 if (qr.isONE()) { 158 qr = qr.multiply(c); 159 q = PolyUtil.<MOD> distribute(fac, qr); 160 return q; 161 } 162 // compute normalization factor 163 GenPolynomial<MOD> ac = rr.leadingBaseCoefficient(); 164 GenPolynomial<MOD> bc = qr.leadingBaseCoefficient(); 165 GenPolynomial<MOD> cc = gcd(ac, bc); 166 // compute degrees and degree vectors 167 ExpVector rdegv = rr.degreeVector(); 168 ExpVector qdegv = qr.degreeVector(); 169 long rd0 = PolyUtil.<MOD> coeffMaxDegree(rr); 170 long qd0 = PolyUtil.<MOD> coeffMaxDegree(qr); 171 long cd0 = cc.degree(0); 172 long G = (rd0 >= qd0 ? rd0 : qd0) + cd0; 173 174 // initialize element and degree vector 175 ExpVector wdegv = rdegv.subst(0, rdegv.getVal(0) + 1); 176 // +1 seems to be a hack for the unlucky evaluation point test 177 MOD inc = cofac.getONE(); 178 long i = 0; 179 long en = cofac.getIntegerModul().longValue() - 1; // just a stopper 180 MOD end = cofac.fromInteger(en); 181 MOD mi; 182 GenPolynomial<MOD> M = null; 183 GenPolynomial<MOD> mn; 184 GenPolynomial<MOD> qm; 185 GenPolynomial<MOD> rm; 186 GenPolynomial<MOD> cm; 187 GenPolynomial<GenPolynomial<MOD>> cp = null; 188 if (debug) { 189 logger.debug("c = " + c); 190 logger.debug("cc = " + cc); 191 logger.debug("G = " + G); 192 logger.info("wdegv = " + wdegv); 193 } 194 for (MOD d = cofac.getZERO(); d.compareTo(end) <= 0; d = d.sum(inc)) { 195 if (++i >= en) { 196 logger.warn("elements of Z_p exhausted, en = " + en); 197 return mufd.gcd(P, S); 198 //throw new ArithmeticException("prime list exhausted"); 199 } 200 // map normalization factor 201 MOD nf = PolyUtil.<MOD> evaluateMain(cofac, cc, d); 202 if (nf.isZERO()) { 203 continue; 204 } 205 // map polynomials 206 qm = PolyUtil.<MOD> evaluateFirstRec(ufac, mfac, qr, d); 207 if (qm.isZERO() || !qm.degreeVector().equals(qdegv)) { 208 continue; 209 } 210 rm = PolyUtil.<MOD> evaluateFirstRec(ufac, mfac, rr, d); 211 if (rm.isZERO() || !rm.degreeVector().equals(rdegv)) { 212 continue; 213 } 214 if (debug) { 215 logger.debug("eval d = " + d); 216 } 217 // compute modular gcd in recursion 218 cm = gcd(rm, qm); 219 //System.out.println("cm = " + cm); 220 // test for constant g.c.d 221 if (cm.isConstant()) { 222 logger.debug("cm.isConstant = " + cm + ", c = " + c); 223 if (c.ring.nvar < cm.ring.nvar) { 224 c = c.extend(mfac, 0, 0); 225 } 226 cm = cm.abs().multiply(c); 227 q = cm.extend(fac, 0, 0); 228 logger.debug("q = " + q + ", c = " + c); 229 return q; 230 } 231 // test for unlucky evaluation point 232 ExpVector mdegv = cm.degreeVector(); 233 if (wdegv.equals(mdegv)) { // TL = 0 234 // evaluation point ok, next round 235 if (M != null) { 236 if (M.degree(0) > G) { 237 logger.info("deg(M) > G: " + M.degree(0) + " > " + G); 238 // continue; // why should this be required? 239 } 240 } 241 } else { // TL = 3 242 boolean ok = false; 243 if (wdegv.multipleOf(mdegv)) { // TL = 2 244 M = null; // init chinese remainder 245 ok = true; // evaluation point ok 246 } 247 if (mdegv.multipleOf(wdegv)) { // TL = 1 248 continue; // skip this evaluation point 249 } 250 if (!ok) { 251 M = null; // discard chinese remainder and previous work 252 continue; // evaluation point not ok 253 } 254 } 255 // prepare interpolation algorithm 256 cm = cm.multiply(nf); 257 if (M == null) { 258 // initialize interpolation 259 M = ufac.getONE(); 260 cp = rfac.getZERO(); 261 wdegv = wdegv.gcd(mdegv); //EVGCD(wdegv,mdegv); 262 } 263 // interpolate 264 mi = PolyUtil.<MOD> evaluateMain(cofac, M, d); 265 mi = mi.inverse(); // mod p 266 cp = PolyUtil.interpolate(rfac, cp, M, mi, cm, d); 267 mn = ufac.getONE().multiply(d); 268 mn = ufac.univariate(0).subtract(mn); 269 M = M.multiply(mn); 270 // test for completion 271 if (M.degree(0) > G) { 272 break; 273 } 274 //long cmn = PolyUtil.<MOD>coeffMaxDegree(cp); 275 //if ( M.degree(0) > cmn ) { 276 // does not work: only if cofactors are also considered? 277 // break; 278 //} 279 } 280 // remove normalization 281 cp = recursivePrimitivePart(cp).abs(); 282 cp = cp.multiply(c); 283 q = PolyUtil.<MOD> distribute(fac, cp); 284 return q; 285 } 286 287 288 /** 289 * Univariate GenPolynomial resultant. 290 * @param P univariate GenPolynomial. 291 * @param S univariate GenPolynomial. 292 * @return res(P,S). 293 */ 294 @Override 295 public GenPolynomial<MOD> baseResultant(GenPolynomial<MOD> P, GenPolynomial<MOD> S) { 296 // required as recursion base 297 return mufd.baseResultant(P, S); 298 } 299 300 301 /** 302 * Univariate GenPolynomial recursive resultant. 303 * @param P univariate recursive GenPolynomial. 304 * @param S univariate recursive GenPolynomial. 305 * @return res(P,S). 306 */ 307 @Override 308 public GenPolynomial<GenPolynomial<MOD>> recursiveUnivariateResultant(GenPolynomial<GenPolynomial<MOD>> P, 309 GenPolynomial<GenPolynomial<MOD>> S) { 310 // only in this class 311 return recursiveResultant(P,S); 312 } 313 314 315 /** 316 * GenPolynomial resultant, modular evaluation algorithm. 317 * @param P GenPolynomial. 318 * @param S GenPolynomial. 319 * @return res(P,S). 320 */ 321 @Override 322 public GenPolynomial<MOD> resultant(GenPolynomial<MOD> P, GenPolynomial<MOD> S) { 323 if (S == null || S.isZERO()) { 324 return S; 325 } 326 if (P == null || P.isZERO()) { 327 return P; 328 } 329 GenPolynomialRing<MOD> fac = P.ring; 330 // recusion base case for univariate polynomials 331 if (fac.nvar <= 1) { 332 GenPolynomial<MOD> T = baseResultant(P, S); 333 return T; 334 } 335 long e = P.degree(fac.nvar-1); 336 long f = S.degree(fac.nvar-1); 337 if ( e == 0 && f == 0 ) { 338 GenPolynomialRing<GenPolynomial<MOD>> rfac = fac.recursive(1); 339 GenPolynomial<MOD> Pc = PolyUtil.<MOD> recursive(rfac, P).leadingBaseCoefficient(); 340 GenPolynomial<MOD> Sc = PolyUtil.<MOD> recursive(rfac, S).leadingBaseCoefficient(); 341 GenPolynomial<MOD> r = resultant(Pc,Sc); 342 return r.extend(fac,0,0L); 343 } 344 GenPolynomial<MOD> q; 345 GenPolynomial<MOD> r; 346 if (f > e) { 347 r = P; 348 q = S; 349 long g = f; 350 f = e; 351 e = g; 352 } else { 353 q = P; 354 r = S; 355 } 356 if (debug) { 357 logger.debug("degrees: e = " + e + ", f = " + f); 358 } 359 // setup factories 360 ModularRingFactory<MOD> cofac = (ModularRingFactory<MOD>) P.ring.coFac; 361 if (!cofac.isField()) { 362 logger.warn("cofac is not a field: " + cofac); 363 } 364 GenPolynomialRing<GenPolynomial<MOD>> rfac = fac.recursive(fac.nvar - 1); 365 GenPolynomialRing<MOD> mfac = new GenPolynomialRing<MOD>(cofac, rfac); 366 GenPolynomialRing<MOD> ufac = (GenPolynomialRing<MOD>) rfac.coFac; 367 368 // convert polynomials 369 GenPolynomial<GenPolynomial<MOD>> qr = PolyUtil.<MOD> recursive(rfac, q); 370 GenPolynomial<GenPolynomial<MOD>> rr = PolyUtil.<MOD> recursive(rfac, r); 371 372 // compute degrees and degree vectors 373 ExpVector qdegv = qr.degreeVector(); 374 ExpVector rdegv = rr.degreeVector(); 375 376 long qd0 = PolyUtil.<MOD> coeffMaxDegree(qr); 377 long rd0 = PolyUtil.<MOD> coeffMaxDegree(rr); 378 qd0 = ( qd0 == 0 ? 1 : qd0 ); 379 rd0 = ( rd0 == 0 ? 1 : rd0 ); 380 long qd1 = qr.degree(); 381 long rd1 = rr.degree(); 382 qd1 = ( qd1 == 0 ? 1 : qd1 ); 383 rd1 = ( rd1 == 0 ? 1 : rd1 ); 384 long G = qd0 * rd1 + rd0 * qd1 + 1; 385 386 // initialize element 387 MOD inc = cofac.getONE(); 388 long i = 0; 389 long en = cofac.getIntegerModul().longValue() - 1; // just a stopper 390 MOD end = cofac.fromInteger(en); 391 MOD mi; 392 GenPolynomial<MOD> M = null; 393 GenPolynomial<MOD> mn; 394 GenPolynomial<MOD> qm; 395 GenPolynomial<MOD> rm; 396 GenPolynomial<MOD> cm; 397 GenPolynomial<GenPolynomial<MOD>> cp = null; 398 if (debug) { 399 //logger.info("qr = " + qr + ", q = " + q); 400 //logger.info("rr = " + rr + ", r = " + r); 401 //logger.info("qd0 = " + qd0); 402 //logger.info("rd0 = " + rd0); 403 logger.info("G = " + G); 404 //logger.info("rdegv = " + rdegv); // + ", rr.degree(0) = " + rr.degree(0)); 405 //logger.info("qdegv = " + qdegv); // + ", qr.degree(0) = " + qr.degree(0)); 406 } 407 for (MOD d = cofac.getZERO(); d.compareTo(end) <= 0; d = d.sum(inc)) { 408 if (++i >= en) { 409 logger.warn("elements of Z_p exhausted, en = " + en + ", p = " + cofac.getIntegerModul()); 410 return mufd.resultant(P, S); 411 //throw new ArithmeticException("prime list exhausted"); 412 } 413 // map polynomials 414 qm = PolyUtil.<MOD> evaluateFirstRec(ufac, mfac, qr, d); 415 //logger.info("qr(" + d + ") = " + qm + ", qr = " + qr); 416 if (qm.isZERO() || !qm.degreeVector().equals(qdegv)) { 417 if (debug) { 418 logger.info("un-lucky evaluation point " + d + ", qm = " + qm.degreeVector() + " < " + qdegv); 419 } 420 continue; 421 } 422 rm = PolyUtil.<MOD> evaluateFirstRec(ufac, mfac, rr, d); 423 //logger.info("rr(" + d + ") = " + rm + ", rr = " + rr); 424 if (rm.isZERO() || !rm.degreeVector().equals(rdegv)) { 425 if (debug) { 426 logger.info("un-lucky evaluation point " + d + ", rm = " + rm.degreeVector() + " < " + rdegv); 427 } 428 continue; 429 } 430 // compute modular resultant in recursion 431 cm = resultant(rm, qm); 432 //System.out.println("cm = " + cm); 433 434 // prepare interpolation algorithm 435 if (M == null) { 436 // initialize interpolation 437 M = ufac.getONE(); 438 cp = rfac.getZERO(); 439 } 440 // interpolate 441 mi = PolyUtil.<MOD> evaluateMain(cofac, M, d); 442 mi = mi.inverse(); // mod p 443 cp = PolyUtil.interpolate(rfac, cp, M, mi, cm, d); 444 //logger.info("cp = " + cp); 445 mn = ufac.getONE().multiply(d); 446 mn = ufac.univariate(0).subtract(mn); 447 M = M.multiply(mn); 448 // test for completion 449 if (M.degree(0) > G) { 450 if (debug) { 451 logger.info("last lucky evaluation point " + d); 452 } 453 break; 454 } 455 //logger.info("M = " + M); 456 } 457 // distribute 458 q = PolyUtil.<MOD> distribute(fac, cp); 459 return q; 460 } 461 462}