001 /* 002 * $Id: GreatestCommonDivisorModular.java 3355 2010-10-23 16:01:52Z kredel $ 003 */ 004 005 package edu.jas.ufd; 006 007 008 import org.apache.log4j.Logger; 009 010 import edu.jas.structure.GcdRingElem; 011 import edu.jas.arith.BigInteger; 012 import edu.jas.arith.Modular; 013 import edu.jas.arith.ModLongRing; 014 import edu.jas.arith.ModIntegerRing; 015 import edu.jas.arith.ModularRingFactory; 016 import edu.jas.arith.PrimeList; 017 import edu.jas.poly.ExpVector; 018 import edu.jas.poly.GenPolynomial; 019 import edu.jas.poly.GenPolynomialRing; 020 import edu.jas.poly.PolyUtil; 021 022 023 /** 024 * Greatest common divisor algorithms with modular computation and chinese 025 * remainder algorithm. 026 * @author Heinz Kredel 027 */ 028 029 public class GreatestCommonDivisorModular<MOD extends GcdRingElem<MOD> & Modular> 030 extends GreatestCommonDivisorAbstract<BigInteger> { 031 032 033 private static final Logger logger = Logger.getLogger(GreatestCommonDivisorModular.class); 034 035 036 private final boolean debug = logger.isDebugEnabled(); //logger.isInfoEnabled(); 037 038 039 /* 040 * Modular gcd algorithm to use. 041 */ 042 protected final GreatestCommonDivisorAbstract<MOD> mufd; 043 044 045 /* 046 * Integer gcd algorithm for fall back. 047 */ 048 protected final GreatestCommonDivisorAbstract<BigInteger> iufd = new GreatestCommonDivisorSubres<BigInteger>(); 049 050 051 /** 052 * Constructor to set recursive algorithm. Use modular evaluation GCD 053 * algorithm. 054 */ 055 public GreatestCommonDivisorModular() { 056 this(false); 057 } 058 059 060 /** 061 * Constructor to set recursive algorithm. 062 * @param simple , true if the simple PRS should be used. 063 */ 064 public GreatestCommonDivisorModular(boolean simple) { 065 if (simple) { 066 mufd = new GreatestCommonDivisorSimple<MOD>(); 067 } else { 068 mufd = new GreatestCommonDivisorModEval<MOD>(); 069 } 070 } 071 072 073 /** 074 * Univariate GenPolynomial greatest comon divisor. Delegate to subresultant 075 * baseGcd, should not be needed. 076 * @param P univariate GenPolynomial. 077 * @param S univariate GenPolynomial. 078 * @return gcd(P,S). 079 */ 080 @Override 081 public GenPolynomial<BigInteger> baseGcd(GenPolynomial<BigInteger> P, GenPolynomial<BigInteger> S) { 082 return iufd.baseGcd(P, S); 083 } 084 085 086 /** 087 * Univariate GenPolynomial recursive greatest comon divisor. Delegate to 088 * subresultant recursiveGcd, should not be needed. 089 * @param P univariate recursive GenPolynomial. 090 * @param S univariate recursive GenPolynomial. 091 * @return gcd(P,S). 092 */ 093 @Override 094 public GenPolynomial<GenPolynomial<BigInteger>> recursiveUnivariateGcd( 095 GenPolynomial<GenPolynomial<BigInteger>> P, GenPolynomial<GenPolynomial<BigInteger>> S) { 096 return iufd.recursiveUnivariateGcd(P, S); 097 } 098 099 100 /** 101 * GenPolynomial greatest comon divisor, modular algorithm. 102 * @param P GenPolynomial. 103 * @param S GenPolynomial. 104 * @return gcd(P,S). 105 */ 106 @Override 107 public GenPolynomial<BigInteger> gcd(GenPolynomial<BigInteger> P, GenPolynomial<BigInteger> S) { 108 if (S == null || S.isZERO()) { 109 return P; 110 } 111 if (P == null || P.isZERO()) { 112 return S; 113 } 114 GenPolynomialRing<BigInteger> fac = P.ring; 115 // special case for univariate polynomials 116 if (fac.nvar <= 1) { 117 GenPolynomial<BigInteger> T = baseGcd(P, S); 118 return T; 119 } 120 long e = P.degree(0); 121 long f = S.degree(0); 122 GenPolynomial<BigInteger> q; 123 GenPolynomial<BigInteger> r; 124 if (f > e) { 125 r = P; 126 q = S; 127 long g = f; 128 f = e; 129 e = g; 130 } else { 131 q = P; 132 r = S; 133 } 134 r = r.abs(); 135 q = q.abs(); 136 // compute contents and primitive parts 137 BigInteger a = baseContent(r); 138 BigInteger b = baseContent(q); 139 // gcd of coefficient contents 140 BigInteger c = gcd(a, b); // indirection 141 r = divide(r, a); // indirection 142 q = divide(q, b); // indirection 143 if (r.isONE()) { 144 return r.multiply(c); 145 } 146 if (q.isONE()) { 147 return q.multiply(c); 148 } 149 // compute normalization factor 150 BigInteger ac = r.leadingBaseCoefficient(); 151 BigInteger bc = q.leadingBaseCoefficient(); 152 BigInteger cc = gcd(ac, bc); // indirection 153 // compute norms 154 BigInteger an = r.maxNorm(); 155 BigInteger bn = q.maxNorm(); 156 BigInteger n = (an.compareTo(bn) < 0 ? bn : an); 157 n = n.multiply(cc).multiply(n.fromInteger(2)); 158 // compute degree vectors 159 ExpVector rdegv = r.degreeVector(); 160 ExpVector qdegv = q.degreeVector(); 161 //compute factor coefficient bounds 162 BigInteger af = an.multiply(PolyUtil.factorBound(rdegv)); 163 BigInteger bf = bn.multiply(PolyUtil.factorBound(qdegv)); 164 BigInteger cf = (af.compareTo(bf) < 0 ? bf : af); 165 cf = cf.multiply(cc.multiply(cc.fromInteger(8))); 166 //initialize prime list and degree vector 167 PrimeList primes = new PrimeList(); 168 int pn = 10; //primes.size(); 169 ExpVector wdegv = rdegv.subst(0, rdegv.getVal(0) + 1); 170 // +1 seems to be a hack for the unlucky prime test 171 ModularRingFactory<MOD> cofac; 172 ModularRingFactory<MOD> cofacM = null; 173 GenPolynomial<MOD> qm; 174 GenPolynomial<MOD> rm; 175 GenPolynomialRing<MOD> mfac; 176 GenPolynomialRing<MOD> rfac = null; 177 int i = 0; 178 BigInteger M = null; 179 BigInteger cfe = null; 180 GenPolynomial<MOD> cp = null; 181 GenPolynomial<MOD> cm = null; 182 GenPolynomial<BigInteger> cpi = null; 183 if (debug) { 184 logger.debug("c = " + c); 185 logger.debug("cc = " + cc); 186 logger.debug("n = " + n); 187 logger.debug("cf = " + cf); 188 logger.info("wdegv = " + wdegv); 189 } 190 for (java.math.BigInteger p : primes) { 191 //System.out.println("next run ++++++++++++++++++++++++++++++++++"); 192 if ( p.longValue() == 2L ) { // skip 2 193 continue; 194 } 195 if (++i >= pn) { 196 logger.error("prime list exhausted, pn = " + pn); 197 return iufd.gcd(P, S); 198 //throw new ArithmeticException("prime list exhausted"); 199 } 200 // initialize coefficient factory and map normalization factor 201 if ( ModLongRing.MAX_LONG.compareTo( p ) > 0 ) { 202 cofac = (ModularRingFactory) new ModLongRing(p, true); 203 } else { 204 cofac = (ModularRingFactory) new ModIntegerRing(p, true); 205 } 206 MOD nf = cofac.fromInteger(cc.getVal()); 207 if (nf.isZERO()) { 208 continue; 209 } 210 // initialize polynomial factory and map polynomials 211 mfac = new GenPolynomialRing<MOD>(cofac, fac.nvar, fac.tord, fac.getVars()); 212 qm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, q); 213 if (!qm.degreeVector().equals(qdegv)) { 214 continue; 215 } 216 rm = PolyUtil.<MOD> fromIntegerCoefficients(mfac, r); 217 if (!rm.degreeVector().equals(rdegv)) { 218 continue; 219 } 220 if (debug) { 221 logger.info("cofac = " + cofac.getIntegerModul()); 222 } 223 // compute modular gcd 224 cm = mufd.gcd(rm, qm); 225 // test for constant g.c.d 226 if (cm.isConstant()) { 227 logger.debug("cm, constant = " + cm); 228 return fac.getONE().multiply(c); 229 //return cm.abs().multiply( c ); 230 } 231 // test for unlucky prime 232 ExpVector mdegv = cm.degreeVector(); 233 if (wdegv.equals(mdegv)) { // TL = 0 234 // prime ok, next round 235 if (M != null) { 236 if (M.compareTo(cfe) > 0) { 237 System.out.println("M > cfe: " + M + " > " + cfe); 238 // continue; // why should this be required? 239 } 240 } 241 } else { // TL = 3 242 boolean ok = false; 243 if (wdegv.multipleOf(mdegv)) { // TL = 2 // EVMT(wdegv,mdegv) 244 M = null; // init chinese remainder 245 ok = true; // prime ok 246 } 247 if (mdegv.multipleOf(wdegv)) { // TL = 1 // EVMT(mdegv,wdegv) 248 continue; // skip this prime 249 } 250 if (!ok) { 251 M = null; // discard chinese remainder and previous work 252 continue; // prime not ok 253 } 254 } 255 //--wdegv = mdegv; 256 // prepare chinese remainder algorithm 257 cm = cm.multiply(nf); 258 if (M == null) { 259 // initialize chinese remainder algorithm 260 M = new BigInteger(p); 261 cofacM = cofac; 262 rfac = mfac; 263 cp = cm; 264 wdegv = wdegv.gcd(mdegv); //EVGCD(wdegv,mdegv); 265 cfe = cf; 266 for (int k = 0; k < wdegv.length(); k++) { 267 cfe = cfe.multiply(new BigInteger(wdegv.getVal(k) + 1)); 268 } 269 } else { 270 // apply chinese remainder algorithm 271 MOD mi = cofac.fromInteger(M.getVal()); 272 mi = mi.inverse(); // mod p 273 M = M.multiply(new BigInteger(p)); 274 if ( ModLongRing.MAX_LONG.compareTo( M.getVal() ) > 0 ) { 275 cofacM = (ModularRingFactory) new ModLongRing(M.getVal()); 276 } else { 277 cofacM = (ModularRingFactory) new ModIntegerRing(M.getVal()); 278 } 279 rfac = new GenPolynomialRing<MOD>(cofacM, fac.nvar, fac.tord, fac.getVars()); 280 cp = PolyUtil.<MOD> chineseRemainder(rfac, cp, mi, cm); 281 } 282 // test for completion 283 if (n.compareTo(M) <= 0) { 284 break; 285 } 286 // must use integer.sumNorm 287 cpi = PolyUtil.<MOD>integerFromModularCoefficients(fac, cp); 288 BigInteger cmn = cpi.sumNorm(); 289 cmn = cmn.multiply(cmn.fromInteger(4)); 290 //if ( cmn.compareTo( M ) <= 0 ) { 291 // does not work: only if cofactors are also considered? 292 // break; 293 //} 294 if (i % 2 != 0 && !cp.isZERO()) { 295 // check if done on every second prime 296 GenPolynomial<BigInteger> x; 297 x = PolyUtil.<MOD>integerFromModularCoefficients(fac, cp); 298 x = basePrimitivePart(x); 299 if (!PolyUtil.<BigInteger> basePseudoRemainder(q, x).isZERO()) { 300 continue; 301 } 302 if (!PolyUtil.<BigInteger> basePseudoRemainder(r, x).isZERO()) { 303 continue; 304 } 305 logger.info("done on exact division, #primes = " + i); 306 break; 307 } 308 } 309 if (debug) { 310 logger.info("done on M = " + M + ", #primes = " + i); 311 } 312 // remove normalization 313 q = PolyUtil.<MOD>integerFromModularCoefficients(fac, cp); 314 q = basePrimitivePart(q); 315 return q.abs().multiply(c); 316 } 317 318 }