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