001/* 002 * $Id: GreatestCommonDivisorModEval.java 6007 2020-03-29 13:34:49Z 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 // convert polynomials 138 GenPolynomial<GenPolynomial<MOD>> qr; 139 GenPolynomial<GenPolynomial<MOD>> rr; 140 qr = PolyUtil.<MOD> recursive(rfac, q); 141 rr = PolyUtil.<MOD> recursive(rfac, r); 142 143 // compute univariate contents and primitive parts 144 GenPolynomial<MOD> a = recursiveContent(rr); 145 GenPolynomial<MOD> b = recursiveContent(qr); 146 // gcd of univariate coefficient contents 147 GenPolynomial<MOD> c = gcd(a, b); 148 rr = PolyUtil.<MOD> recursiveDivide(rr, a); 149 qr = PolyUtil.<MOD> recursiveDivide(qr, b); 150 if (rr.isONE()) { 151 rr = rr.multiply(c); 152 r = PolyUtil.<MOD> distribute(fac, rr); 153 return r; 154 } 155 if (qr.isONE()) { 156 qr = qr.multiply(c); 157 q = PolyUtil.<MOD> distribute(fac, qr); 158 return q; 159 } 160 // compute normalization factor 161 GenPolynomial<MOD> ac = rr.leadingBaseCoefficient(); 162 GenPolynomial<MOD> bc = qr.leadingBaseCoefficient(); 163 GenPolynomial<MOD> cc = gcd(ac, bc); 164 // compute degrees and degree vectors 165 ExpVector rdegv = rr.degreeVector(); 166 ExpVector qdegv = qr.degreeVector(); 167 long rd0 = PolyUtil.<MOD> coeffMaxDegree(rr); 168 long qd0 = PolyUtil.<MOD> coeffMaxDegree(qr); 169 long cd0 = cc.degree(0); 170 long G = (rd0 >= qd0 ? rd0 : qd0) + cd0; 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().longValue() - 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); 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("prime list exhausted"); 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 //System.out.println("cm = " + cm); 218 // test for constant g.c.d 219 if (cm.isConstant()) { 220 logger.debug("cm.isConstant = " + cm + ", c = " + c); 221 if (c.ring.nvar < cm.ring.nvar) { 222 c = c.extend(mfac, 0, 0); 223 } 224 cm = cm.abs().multiply(c); 225 q = cm.extend(fac, 0, 0); 226 logger.debug("q = " + q + ", c = " + c); 227 return q; 228 } 229 // test for unlucky evaluation point 230 ExpVector mdegv = cm.degreeVector(); 231 if (wdegv.equals(mdegv)) { // TL = 0 232 // evaluation point ok, next round 233 if (M != null) { 234 if (M.degree(0) > G) { 235 logger.info("deg(M) > G: " + M.degree(0) + " > " + G); 236 // continue; // why should this be required? 237 } 238 } 239 } else { // TL = 3 240 boolean ok = false; 241 if (wdegv.multipleOf(mdegv)) { // TL = 2 242 M = null; // init chinese remainder 243 ok = true; // evaluation point ok 244 } 245 if (mdegv.multipleOf(wdegv)) { // TL = 1 246 continue; // skip this evaluation point 247 } 248 if (!ok) { 249 M = null; // discard chinese remainder and previous work 250 continue; // evaluation point not ok 251 } 252 } 253 // prepare interpolation algorithm 254 cm = cm.multiply(nf); 255 if (M == null) { 256 // initialize interpolation 257 M = ufac.getONE(); 258 cp = rfac.getZERO(); 259 wdegv = wdegv.gcd(mdegv); //EVGCD(wdegv,mdegv); 260 } 261 // interpolate 262 mi = PolyUtil.<MOD> evaluateMain(cofac, M, d); 263 mi = mi.inverse(); // mod p 264 cp = PolyUtil.interpolate(rfac, cp, M, mi, cm, d); 265 mn = ufac.getONE().multiply(d); 266 mn = ufac.univariate(0).subtract(mn); 267 M = M.multiply(mn); 268 // test for completion 269 if (M.degree(0) > G) { 270 break; 271 } 272 //long cmn = PolyUtil.<MOD>coeffMaxDegree(cp); 273 //if ( M.degree(0) > cmn ) { 274 // does not work: only if cofactors are also considered? 275 // break; 276 //} 277 } 278 // remove normalization 279 cp = recursivePrimitivePart(cp).abs(); 280 cp = cp.multiply(c); 281 q = PolyUtil.<MOD> distribute(fac, cp); 282 return q; 283 } 284 285 286 /** 287 * Univariate GenPolynomial resultant. 288 * @param P univariate GenPolynomial. 289 * @param S univariate GenPolynomial. 290 * @return res(P,S). 291 */ 292 @Override 293 public GenPolynomial<MOD> baseResultant(GenPolynomial<MOD> P, GenPolynomial<MOD> S) { 294 // required as recursion base 295 return mufd.baseResultant(P, S); 296 } 297 298 299 /** 300 * Univariate GenPolynomial recursive resultant. 301 * @param P univariate recursive GenPolynomial. 302 * @param S univariate recursive GenPolynomial. 303 * @return res(P,S). 304 */ 305 @Override 306 public GenPolynomial<GenPolynomial<MOD>> recursiveUnivariateResultant(GenPolynomial<GenPolynomial<MOD>> P, 307 GenPolynomial<GenPolynomial<MOD>> S) { 308 // only in this class 309 return recursiveResultant(P,S); 310 } 311 312 313 /** 314 * GenPolynomial resultant, modular evaluation algorithm. 315 * @param P GenPolynomial. 316 * @param S GenPolynomial. 317 * @return res(P,S). 318 */ 319 @Override 320 public GenPolynomial<MOD> resultant(GenPolynomial<MOD> P, GenPolynomial<MOD> S) { 321 if (S == null || S.isZERO()) { 322 return S; 323 } 324 if (P == null || P.isZERO()) { 325 return P; 326 } 327 GenPolynomialRing<MOD> fac = P.ring; 328 // recusion base case for univariate polynomials 329 if (fac.nvar <= 1) { 330 GenPolynomial<MOD> T = baseResultant(P, S); 331 return T; 332 } 333 long e = P.degree(fac.nvar-1); 334 long f = S.degree(fac.nvar-1); 335 if ( e == 0 && f == 0 ) { 336 GenPolynomialRing<GenPolynomial<MOD>> rfac = fac.recursive(1); 337 GenPolynomial<MOD> Pc = PolyUtil.<MOD> recursive(rfac, P).leadingBaseCoefficient(); 338 GenPolynomial<MOD> Sc = PolyUtil.<MOD> recursive(rfac, S).leadingBaseCoefficient(); 339 GenPolynomial<MOD> r = resultant(Pc,Sc); 340 return r.extend(fac,0,0L); 341 } 342 GenPolynomial<MOD> q; 343 GenPolynomial<MOD> r; 344 if (f > e) { 345 r = P; 346 q = S; 347 long g = f; 348 f = e; 349 e = g; 350 } else { 351 q = P; 352 r = S; 353 } 354 if (debug) { 355 logger.debug("degrees: e = " + e + ", f = " + f); 356 } 357 // setup factories 358 ModularRingFactory<MOD> cofac = (ModularRingFactory<MOD>) P.ring.coFac; 359 if (!cofac.isField()) { 360 logger.warn("cofac is not a field: " + cofac); 361 } 362 GenPolynomialRing<GenPolynomial<MOD>> rfac = fac.recursive(fac.nvar - 1); 363 GenPolynomialRing<MOD> mfac = new GenPolynomialRing<MOD>(cofac, rfac); 364 GenPolynomialRing<MOD> ufac = (GenPolynomialRing<MOD>) rfac.coFac; 365 366 // convert polynomials 367 GenPolynomial<GenPolynomial<MOD>> qr = PolyUtil.<MOD> recursive(rfac, q); 368 GenPolynomial<GenPolynomial<MOD>> rr = PolyUtil.<MOD> recursive(rfac, r); 369 370 // compute degrees and degree vectors 371 ExpVector qdegv = qr.degreeVector(); 372 ExpVector rdegv = rr.degreeVector(); 373 374 long qd0 = PolyUtil.<MOD> coeffMaxDegree(qr); 375 long rd0 = PolyUtil.<MOD> coeffMaxDegree(rr); 376 qd0 = ( qd0 == 0 ? 1 : qd0 ); 377 rd0 = ( rd0 == 0 ? 1 : rd0 ); 378 long qd1 = qr.degree(); 379 long rd1 = rr.degree(); 380 qd1 = ( qd1 == 0 ? 1 : qd1 ); 381 rd1 = ( rd1 == 0 ? 1 : rd1 ); 382 long G = qd0 * rd1 + rd0 * qd1 + 1; 383 384 // initialize element 385 MOD inc = cofac.getONE(); 386 long i = 0; 387 long en = cofac.getIntegerModul().longValue() - 1; // just a stopper 388 MOD end = cofac.fromInteger(en); 389 MOD mi; 390 GenPolynomial<MOD> M = null; 391 GenPolynomial<MOD> mn; 392 GenPolynomial<MOD> qm; 393 GenPolynomial<MOD> rm; 394 GenPolynomial<MOD> cm; 395 GenPolynomial<GenPolynomial<MOD>> cp = null; 396 if (debug) { 397 //logger.info("qr = " + qr + ", q = " + q); 398 //logger.info("rr = " + rr + ", r = " + r); 399 //logger.info("qd0 = " + qd0); 400 //logger.info("rd0 = " + rd0); 401 logger.info("G = " + G); 402 //logger.info("rdegv = " + rdegv); // + ", rr.degree(0) = " + rr.degree(0)); 403 //logger.info("qdegv = " + qdegv); // + ", qr.degree(0) = " + qr.degree(0)); 404 } 405 for (MOD d = cofac.getZERO(); d.compareTo(end) <= 0; d = d.sum(inc)) { 406 if (++i >= en) { 407 logger.warn("elements of Z_p exhausted, en = " + en + ", p = " + cofac.getIntegerModul()); 408 return mufd.resultant(P, S); 409 //throw new ArithmeticException("prime list exhausted"); 410 } 411 // map polynomials 412 qm = PolyUtil.<MOD> evaluateFirstRec(ufac, mfac, qr, d); 413 //logger.info("qr(" + d + ") = " + qm + ", qr = " + qr); 414 if (qm.isZERO() || !qm.degreeVector().equals(qdegv)) { 415 if (debug) { 416 logger.info("un-lucky evaluation point " + d + ", qm = " + qm.degreeVector() + " < " + qdegv); 417 } 418 continue; 419 } 420 rm = PolyUtil.<MOD> evaluateFirstRec(ufac, mfac, rr, d); 421 //logger.info("rr(" + d + ") = " + rm + ", rr = " + rr); 422 if (rm.isZERO() || !rm.degreeVector().equals(rdegv)) { 423 if (debug) { 424 logger.info("un-lucky evaluation point " + d + ", rm = " + rm.degreeVector() + " < " + rdegv); 425 } 426 continue; 427 } 428 // compute modular resultant in recursion 429 cm = resultant(rm, qm); 430 //System.out.println("cm = " + cm); 431 432 // prepare interpolation algorithm 433 if (M == null) { 434 // initialize interpolation 435 M = ufac.getONE(); 436 cp = rfac.getZERO(); 437 } 438 // interpolate 439 mi = PolyUtil.<MOD> evaluateMain(cofac, M, d); 440 mi = mi.inverse(); // mod p 441 cp = PolyUtil.interpolate(rfac, cp, M, mi, cm, d); 442 //logger.info("cp = " + cp); 443 mn = ufac.getONE().multiply(d); 444 mn = ufac.univariate(0).subtract(mn); 445 M = M.multiply(mn); 446 // test for completion 447 if (M.degree(0) > G) { 448 if (debug) { 449 logger.info("last lucky evaluation point " + d); 450 } 451 break; 452 } 453 //logger.info("M = " + M); 454 } 455 // distribute 456 q = PolyUtil.<MOD> distribute(fac, cp); 457 return q; 458 } 459 460}