001 /* 002 * $Id: GreatestCommonDivisorModEval.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.arith.Modular; 011 import edu.jas.arith.ModularRingFactory; 012 import edu.jas.poly.ExpVector; 013 import edu.jas.poly.GenPolynomial; 014 import edu.jas.poly.GenPolynomialRing; 015 import edu.jas.poly.PolyUtil; 016 import edu.jas.structure.GcdRingElem; 017 018 019 /** 020 * Greatest common divisor algorithms with modular evaluation algorithm for 021 * recursion. 022 * @author Heinz Kredel 023 */ 024 025 public class GreatestCommonDivisorModEval <MOD extends GcdRingElem<MOD> & Modular> 026 extends GreatestCommonDivisorAbstract<MOD> { 027 028 029 private static final Logger logger = Logger.getLogger(GreatestCommonDivisorModEval.class); 030 031 032 private final boolean debug = logger.isDebugEnabled(); 033 034 035 /** 036 * Modular gcd algorithm to use. 037 */ 038 protected final GreatestCommonDivisorAbstract<MOD> mufd 039 // == new GreatestCommonDivisorModular(); 040 = new GreatestCommonDivisorSimple<MOD>(); 041 // = new GreatestCommonDivisorPrimitive<MOD>(); 042 // = new GreatestCommonDivisorSubres<MOD>(); 043 044 045 /** 046 * Univariate GenPolynomial greatest comon divisor. Delegate to subresultant 047 * baseGcd, should not be needed. 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 return mufd.baseGcd(P, S); 055 } 056 057 058 /** 059 * Univariate GenPolynomial recursive greatest comon divisor. Delegate to 060 * subresultant recursiveGcd, should not be needed. 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 } 070 071 072 /** 073 * GenPolynomial greatest comon divisor, modular evaluation algorithm. 074 * Method name must be different because of parameter type erasure. 075 * @param P GenPolynomial. 076 * @param S GenPolynomial. 077 * @return gcd(P,S). 078 */ 079 @Override 080 public GenPolynomial<MOD> gcd(GenPolynomial<MOD> P, GenPolynomial<MOD> S) { 081 if (S == null || S.isZERO()) { 082 return P; 083 } 084 if (P == null || P.isZERO()) { 085 return S; 086 } 087 GenPolynomialRing<MOD> fac = P.ring; 088 // special case for univariate polynomials 089 if (fac.nvar <= 1) { 090 GenPolynomial<MOD> T = baseGcd(P, S); 091 return T; 092 } 093 long e = P.degree(0); 094 long f = S.degree(0); 095 GenPolynomial<MOD> q; 096 GenPolynomial<MOD> r; 097 if (f > e) { 098 r = P; 099 q = S; 100 long g = f; 101 f = e; 102 e = g; 103 } else { 104 q = P; 105 r = S; 106 } 107 r = r.abs(); 108 q = q.abs(); 109 // setup factories 110 ModularRingFactory<MOD> cofac = (ModularRingFactory<MOD>) P.ring.coFac; 111 if (!cofac.isField()) { 112 logger.warn("cofac is not a field: " + cofac); 113 } 114 GenPolynomialRing<MOD> mfac = new GenPolynomialRing<MOD>(cofac, fac.nvar - 1, fac.tord); 115 GenPolynomialRing<MOD> ufac = new GenPolynomialRing<MOD>(cofac, 1, fac.tord); 116 GenPolynomialRing<GenPolynomial<MOD>> rfac = new GenPolynomialRing<GenPolynomial<MOD>>( 117 ufac, fac.nvar - 1, fac.tord); 118 // convert polynomials 119 GenPolynomial<GenPolynomial<MOD>> qr; 120 GenPolynomial<GenPolynomial<MOD>> rr; 121 qr = PolyUtil.<MOD> recursive(rfac, q); 122 rr = PolyUtil.<MOD> recursive(rfac, r); 123 124 // compute univariate contents and primitive parts 125 GenPolynomial<MOD> a = recursiveContent(rr); 126 GenPolynomial<MOD> b = recursiveContent(qr); 127 // gcd of univariate coefficient contents 128 GenPolynomial<MOD> c = gcd(a, b); 129 rr = PolyUtil.<MOD> recursiveDivide(rr, a); 130 qr = PolyUtil.<MOD> recursiveDivide(qr, b); 131 if (rr.isONE()) { 132 rr = rr.multiply(c); 133 r = PolyUtil.<MOD> distribute(fac, rr); 134 return r; 135 } 136 if (qr.isONE()) { 137 qr = qr.multiply(c); 138 q = PolyUtil.<MOD> distribute(fac, qr); 139 return q; 140 } 141 // compute normalization factor 142 GenPolynomial<MOD> ac = rr.leadingBaseCoefficient(); 143 GenPolynomial<MOD> bc = qr.leadingBaseCoefficient(); 144 GenPolynomial<MOD> cc = gcd(ac, bc); 145 // compute degrees and degree vectors 146 ExpVector rdegv = rr.degreeVector(); 147 ExpVector qdegv = qr.degreeVector(); 148 long rd0 = PolyUtil.<MOD> coeffMaxDegree(rr); 149 long qd0 = PolyUtil.<MOD> coeffMaxDegree(qr); 150 long cd0 = cc.degree(0); 151 long G = (rd0 >= qd0 ? rd0 : qd0) + cd0; 152 153 // initialize element and degree vector 154 ExpVector wdegv = rdegv.subst(0, rdegv.getVal(0) + 1); 155 // +1 seems to be a hack for the unlucky prime test 156 MOD inc = cofac.getONE(); 157 long i = 0; 158 long en = cofac.getIntegerModul().longValue() - 1; // just a stopper 159 MOD end = cofac.fromInteger(en); 160 MOD mi; 161 GenPolynomial<MOD> M = null; 162 GenPolynomial<MOD> mn; 163 GenPolynomial<MOD> qm; 164 GenPolynomial<MOD> rm; 165 GenPolynomial<MOD> cm; 166 GenPolynomial<GenPolynomial<MOD>> cp = null; 167 if (debug) { 168 logger.debug("c = " + c); 169 logger.debug("cc = " + cc); 170 logger.debug("G = " + G); 171 logger.info("wdegv = " + wdegv); 172 } 173 for (MOD d = cofac.getZERO(); d.compareTo(end) <= 0; d = d.sum(inc)) { 174 if (++i >= en) { 175 logger.error("elements of Z_p exhausted, en = " + en); 176 return mufd.gcd(P, S); 177 //throw new ArithmeticException("prime list exhausted"); 178 } 179 // map normalization factor 180 MOD nf = PolyUtil.<MOD> evaluateMain(cofac, cc, d); 181 if (nf.isZERO()) { 182 continue; 183 } 184 // map polynomials 185 qm = PolyUtil.<MOD> evaluateFirstRec(ufac, mfac, qr, d); 186 if (!qm.degreeVector().equals(qdegv)) { 187 continue; 188 } 189 rm = PolyUtil.<MOD> evaluateFirstRec(ufac, mfac, rr, d); 190 if (!rm.degreeVector().equals(rdegv)) { 191 continue; 192 } 193 if (debug) { 194 logger.debug("eval d = " + d); 195 } 196 // compute modular gcd in recursion 197 //System.out.println("recursion +++++++++++++++++++++++++++++++++++"); 198 cm = gcd(rm, qm); 199 //System.out.println("recursion -----------------------------------"); 200 //System.out.println("cm = " + cm); 201 // test for constant g.c.d 202 if (cm.isConstant()) { 203 logger.debug("cm.isConstant = " + cm + ", c = " + c); 204 if (c.ring.nvar < cm.ring.nvar) { 205 c = c.extend(mfac, 0, 0); 206 } 207 cm = cm.abs().multiply(c); 208 q = cm.extend(fac, 0, 0); 209 logger.debug("q = " + q + ", c = " + c); 210 return q; 211 } 212 // test for unlucky prime 213 ExpVector mdegv = cm.degreeVector(); 214 if (wdegv.equals(mdegv)) { // TL = 0 215 // prime ok, next round 216 if (M != null) { 217 if (M.degree(0) > G) { 218 logger.info("deg(M) > G: " + M.degree(0) + " > " + G); 219 // continue; // why should this be required? 220 } 221 } 222 } else { // TL = 3 223 boolean ok = false; 224 if (wdegv.multipleOf(mdegv)) { // TL = 2 // EVMT(wdegv,mdegv) 225 M = null; // init chinese remainder 226 ok = true; // prime ok 227 } 228 if (mdegv.multipleOf(wdegv)) { // TL = 1 // EVMT(mdegv,wdegv) 229 continue; // skip this prime 230 } 231 if (!ok) { 232 M = null; // discard chinese remainder and previous work 233 continue; // prime not ok 234 } 235 } 236 // prepare interpolation algorithm 237 cm = cm.multiply(nf); 238 if (M == null) { 239 // initialize interpolation 240 M = ufac.getONE(); 241 cp = rfac.getZERO(); 242 wdegv = wdegv.gcd(mdegv); //EVGCD(wdegv,mdegv); 243 } 244 // interpolate 245 mi = PolyUtil.<MOD> evaluateMain(cofac, M, d); 246 mi = mi.inverse(); // mod p 247 cp = PolyUtil.interpolate(rfac, cp, M, mi, cm, d); 248 mn = ufac.getONE().multiply(d); 249 mn = ufac.univariate(0).subtract(mn); 250 M = M.multiply(mn); 251 // test for completion 252 if (M.degree(0) > G) { 253 break; 254 } 255 //long cmn = PolyUtil.<MOD>coeffMaxDegree(cp); 256 //if ( M.degree(0) > cmn ) { 257 // does not work: only if cofactors are also considered? 258 // break; 259 //} 260 } 261 // remove normalization 262 cp = recursivePrimitivePart(cp).abs(); 263 cp = cp.multiply(c); 264 q = PolyUtil.<MOD> distribute(fac, cp); 265 return q; 266 } 267 268 }