001/* 002 * $Id: GreatestCommonDivisorSimple.java 5543 2016-07-24 18:45:47Z kredel $ 003 */ 004 005package edu.jas.fd; 006 007 008import org.apache.log4j.Logger; 009 010import edu.jas.poly.GenPolynomial; 011import edu.jas.poly.GenSolvablePolynomial; 012import edu.jas.poly.PolyUtil; 013import edu.jas.structure.GcdRingElem; 014import edu.jas.structure.RingFactory; 015 016 017/** 018 * (Non-unique) factorization domain greatest common divisor common algorithms 019 * with monic polynomial remainder sequence. If C is a field, then the monic PRS 020 * (on coefficients) is computed otherwise no simplifications in the reduction 021 * are made. 022 * @param <C> coefficient type 023 * @author Heinz Kredel 024 */ 025 026public class GreatestCommonDivisorSimple<C extends GcdRingElem<C>> extends GreatestCommonDivisorAbstract<C> { 027 028 029 private static final Logger logger = Logger.getLogger(GreatestCommonDivisorSimple.class); 030 031 032 private static final boolean debug = logger.isDebugEnabled(); 033 034 035 /** 036 * Constructor. 037 * @param cf coefficient ring. 038 */ 039 public GreatestCommonDivisorSimple(RingFactory<C> cf) { 040 super(cf); 041 } 042 043 044 /** 045 * Univariate GenSolvablePolynomial greatest common divisor. Uses 046 * pseudoRemainder for remainder. 047 * @param P univariate GenSolvablePolynomial. 048 * @param S univariate GenSolvablePolynomial. 049 * @return gcd(P,S) with P = P'*gcd(P,S) and S = S'*gcd(P,S). 050 */ 051 @Override 052 public GenSolvablePolynomial<C> leftBaseGcd(GenSolvablePolynomial<C> P, GenSolvablePolynomial<C> S) { 053 if (S == null || S.isZERO()) { 054 return P; 055 } 056 if (P == null || P.isZERO()) { 057 return S; 058 } 059 if (P.ring.nvar > 1) { 060 throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); 061 } 062 boolean field = P.ring.coFac.isField(); 063 long e = P.degree(0); 064 long f = S.degree(0); 065 GenSolvablePolynomial<C> q; 066 GenSolvablePolynomial<C> r; 067 if (f > e) { 068 r = P; 069 q = S; 070 long g = f; 071 f = e; 072 e = g; 073 } else { 074 q = P; 075 r = S; 076 } 077 if (debug) { 078 logger.debug("degrees: e = " + e + ", f = " + f); 079 } 080 C c; 081 if (field) { 082 r = r.monic(); 083 q = q.monic(); 084 c = P.ring.getONECoefficient(); 085 } else { 086 r = (GenSolvablePolynomial<C>) r.abs(); 087 q = (GenSolvablePolynomial<C>) q.abs(); 088 C a = rightBaseContent(r); 089 C b = rightBaseContent(q); 090 r = divide(r, a); // indirection 091 q = divide(q, b); // indirection 092 c = gcd(a, b); // indirection 093 } 094 //System.out.println("baseCont: gcd(cont) = " + b); 095 if (r.isONE()) { 096 return r.multiply(c); 097 } 098 if (q.isONE()) { 099 return q.multiply(c); 100 } 101 GenSolvablePolynomial<C> x; 102 //System.out.println("baseGCD: q = " + q); 103 //System.out.println("baseGCD: r = " + r); 104 while (!r.isZERO()) { 105 x = FDUtil.<C> leftBaseSparsePseudoRemainder(q, r); 106 q = r; 107 if (field) { 108 r = x.monic(); 109 } else { 110 r = x; 111 } 112 //System.out.println("baseGCD: q = " + q); 113 //System.out.println("baseGCD: r = " + r); 114 } 115 ///q = leftBasePrimitivePart(q); 116 q = rightBasePrimitivePart(q); 117 return (GenSolvablePolynomial<C>) (q.multiply(c)).abs(); 118 } 119 120 121 /** 122 * Univariate GenSolvablePolynomial right greatest common divisor. Uses 123 * pseudoRemainder for remainder. 124 * @param P univariate GenSolvablePolynomial. 125 * @param S univariate GenSolvablePolynomial. 126 * @return gcd(P,S) with P = gcd(P,S)*P' and S = gcd(P,S)*S'. 127 */ 128 @Override 129 public GenSolvablePolynomial<C> rightBaseGcd(GenSolvablePolynomial<C> P, GenSolvablePolynomial<C> S) { 130 if (S == null || S.isZERO()) { 131 return P; 132 } 133 if (P == null || P.isZERO()) { 134 return S; 135 } 136 if (P.ring.nvar > 1) { 137 throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); 138 } 139 boolean field = P.ring.coFac.isField(); 140 long e = P.degree(0); 141 long f = S.degree(0); 142 GenSolvablePolynomial<C> q; 143 GenSolvablePolynomial<C> r; 144 if (f > e) { 145 r = P; 146 q = S; 147 long g = f; 148 f = e; 149 e = g; 150 } else { 151 q = P; 152 r = S; 153 } 154 if (debug) { 155 logger.debug("degrees: e = " + e + ", f = " + f); 156 } 157 C c; 158 if (field) { 159 r = r.monic(); 160 q = q.monic(); 161 c = P.ring.getONECoefficient(); 162 } else { 163 r = (GenSolvablePolynomial<C>) r.abs(); 164 q = (GenSolvablePolynomial<C>) q.abs(); 165 C a = leftBaseContent(r); 166 C b = leftBaseContent(q); 167 r = divide(r, a); // indirection 168 q = divide(q, b); // indirection 169 c = gcd(a, b); // indirection 170 } 171 //System.out.println("baseCont: gcd(cont) = " + b); 172 if (r.isONE()) { 173 return r.multiply(c); 174 } 175 if (q.isONE()) { 176 return q.multiply(c); 177 } 178 GenSolvablePolynomial<C> x; 179 //System.out.println("baseGCD: q = " + q); 180 //System.out.println("baseGCD: r = " + r); 181 while (!r.isZERO()) { 182 x = FDUtil.<C> rightBaseSparsePseudoRemainder(q, r); 183 q = r; 184 if (field) { 185 r = x.monic(); 186 } else { 187 r = x; 188 } 189 //System.out.println("baseGCD: q = " + q); 190 //System.out.println("baseGCD: r = " + r); 191 } 192 ///q = rightBasePrimitivePart(q); 193 q = leftBasePrimitivePart(q); 194 return (GenSolvablePolynomial<C>) (q.multiplyLeft(c)).abs(); 195 } 196 197 198 /** 199 * Univariate GenSolvablePolynomial left recursive greatest common divisor. 200 * Uses pseudoRemainder for remainder. 201 * @param P univariate recursive GenSolvablePolynomial. 202 * @param S univariate recursive GenSolvablePolynomial. 203 * @return gcd(P,S) with P = P'*gcd(P,S)*p and S = S'*gcd(P,S)*s, where 204 * deg_main(p) = deg_main(s) == 0. 205 */ 206 @Override 207 public GenSolvablePolynomial<GenPolynomial<C>> leftRecursiveUnivariateGcd( 208 GenSolvablePolynomial<GenPolynomial<C>> P, GenSolvablePolynomial<GenPolynomial<C>> S) { 209 if (S == null || S.isZERO()) { 210 return P; 211 } 212 if (P == null || P.isZERO()) { 213 return S; 214 } 215 if (P.ring.nvar > 1) { 216 throw new IllegalArgumentException("no univariate polynomial"); 217 } 218 boolean field = P.leadingBaseCoefficient().ring.coFac.isField(); 219 long e = P.degree(0); 220 long f = S.degree(0); 221 GenSolvablePolynomial<GenPolynomial<C>> q, r, x, qs, rs, qp, rp; 222 if (f > e) { 223 r = P; 224 q = S; 225 long g = f; 226 f = e; 227 e = g; 228 } else if (f < e) { 229 q = P; 230 r = S; 231 } else { // f == e 232 if (P.leadingBaseCoefficient().degree() > S.leadingBaseCoefficient().degree()) { 233 q = P; 234 r = S; 235 } else { 236 r = P; 237 q = S; 238 } 239 } 240 if (debug) { 241 logger.debug("degrees: e = " + e + ", f = " + f); 242 } 243 if (field) { 244 r = PolyUtil.<C> monic(r); 245 q = PolyUtil.<C> monic(q); 246 } else { 247 r = (GenSolvablePolynomial<GenPolynomial<C>>) r.abs(); 248 q = (GenSolvablePolynomial<GenPolynomial<C>>) q.abs(); 249 } 250 GenSolvablePolynomial<C> a = rightRecursiveContent(r); 251 ///rs = FDUtil.<C> recursiveDivideRightEval(r, a); 252 rs = FDUtil.<C> recursiveLeftDivide(r, a); 253 //rs = FDUtil.<C> recursiveRightDivide(r, a); 254 if (debug) { 255 logger.info("recCont a = " + a + ", r = " + r); 256 logger.info("recCont r/a = " + rs + ", r%a = " + r.subtract(rs.multiply(a))); 257 if (!r.equals(rs.multiply(a))) { 258 if (!rs.multiplyLeft(a).equals(r)) { 259 System.out.println("recGcd, r = " + r); 260 System.out.println("recGcd, cont(r) = " + a); 261 System.out.println("recGcd, pp(r) = " + rs); 262 System.out.println("recGcd, pp(r)c(r) = " + rs.multiply(a)); 263 System.out.println("recGcd, c(r)pp(r) = " + rs.multiplyLeft(a)); 264 throw new RuntimeException("recGcd, pp: not divisible"); 265 } 266 } 267 } 268 r = rs; 269 GenSolvablePolynomial<C> b = rightRecursiveContent(q); 270 ///qs = FDUtil.<C> recursiveDivideRightEval(q, b); 271 qs = FDUtil.<C> recursiveLeftDivide(q, b); 272 //qs = FDUtil.<C> recursiveRightDivide(q, b); 273 if (debug) { 274 logger.info("recCont b = " + b + ", q = " + q); 275 logger.info("recCont q/b = " + qs + ", q%b = " + q.subtract(qs.multiply(b))); 276 if (!q.equals(qs.multiply(b))) { 277 if (!qs.multiplyLeft(b).equals(q)) { 278 System.out.println("recGcd, q = " + q); 279 System.out.println("recGcd, cont(q) = " + b); 280 System.out.println("recGcd, pp(q) = " + qs); 281 System.out.println("recGcd, pp(q)c(q) = " + qs.multiply(b)); 282 System.out.println("recGcd, c(q)pp(q) = " + qs.multiplyLeft(b)); 283 throw new RuntimeException("recGcd, pp: not divisible"); 284 } 285 } 286 } 287 q = qs; 288 logger.info("Gcd(content).ring = " + a.ring.toScript() + ", a = " + a + ", b = " + b); 289 //no: GenSolvablePolynomial<C> c = leftGcd(a, b); // go to recursion 290 GenSolvablePolynomial<C> c = rightGcd(a, b); // go to recursion 291 logger.info("Gcd(contents) c = " + c + ", a = " + a + ", b = " + b); 292 if (r.isONE()) { 293 return r.multiply(c); 294 } 295 if (q.isONE()) { 296 return q.multiply(c); 297 } 298 if (debug) { 299 logger.info("r.ring = " + r.ring.toScript()); 300 logger.info("gcd-loop, start: q = " + q + ", r = " + r); 301 } 302 while (!r.isZERO()) { 303 x = FDUtil.<C> recursiveSparsePseudoRemainder(q, r); 304 q = r; 305 if (field) { 306 r = PolyUtil.<C> monic(x); 307 } else { 308 r = x; 309 } 310 if (debug) { 311 logger.info("gcd-loop, rem: q = " + q + ", r = " + r); 312 } 313 } 314 if (debug) { 315 logger.info("gcd(div) = " + q + ", rs = " + rs + ", qs = " + qs); 316 rp = FDUtil.<C> recursiveSparsePseudoRemainder(rs, q); 317 qp = FDUtil.<C> recursiveSparsePseudoRemainder(qs, q); 318 if (!qp.isZERO() || !rp.isZERO()) { 319 logger.info("gcd(div): rem(r,g) = " + rp + ", rem(q,g) = " + qp); 320 rp = FDUtil.<C> recursivePseudoQuotient(rs, q); 321 qp = FDUtil.<C> recursivePseudoQuotient(qs, q); 322 logger.info("gcd(div): r/g = " + rp + ", q/g = " + qp); 323 throw new RuntimeException("recGcd, div: not divisible"); 324 } 325 } 326 qp = q; 327 q = rightRecursivePrimitivePart(q); 328 if (!qp.equals(q)) { 329 logger.info("gcd(pp) = " + q + ", qp = " + qp); 330 } 331 q = (GenSolvablePolynomial<GenPolynomial<C>>) q.multiply(c).abs(); 332 return q; 333 } 334 335 336 /** 337 * Univariate GenSolvablePolynomial right recursive greatest common divisor. 338 * Uses pseudoRemainder for remainder. 339 * @param P univariate recursive GenSolvablePolynomial. 340 * @param S univariate recursive GenSolvablePolynomial. 341 * @return gcd(P,S) with P = p*gcd(P,S)*P' and S = s*gcd(P,S)*S', where 342 * deg_main(p) = deg_main(s) == 0. 343 */ 344 @Override 345 public GenSolvablePolynomial<GenPolynomial<C>> rightRecursiveUnivariateGcd( 346 GenSolvablePolynomial<GenPolynomial<C>> P, GenSolvablePolynomial<GenPolynomial<C>> S) { 347 if (S == null || S.isZERO()) { 348 return P; 349 } 350 if (P == null || P.isZERO()) { 351 return S; 352 } 353 if (P.ring.nvar > 1) { 354 throw new IllegalArgumentException("no univariate polynomial"); 355 } 356 boolean field = P.leadingBaseCoefficient().ring.coFac.isField(); 357 long e = P.degree(0); 358 long f = S.degree(0); 359 GenSolvablePolynomial<GenPolynomial<C>> q, r, x, qs, rs, qp, rp; 360 if (f > e) { 361 r = P; 362 q = S; 363 long g = f; 364 f = e; 365 e = g; 366 } else if (f < e) { 367 q = P; 368 r = S; 369 } else { // f == e 370 if (P.leadingBaseCoefficient().degree() > S.leadingBaseCoefficient().degree()) { 371 q = P; 372 r = S; 373 } else { 374 r = P; 375 q = S; 376 } 377 } 378 if (debug) { 379 logger.debug("RI-degrees: e = " + e + ", f = " + f); 380 } 381 if (field) { 382 r = PolyUtil.<C> monic(r); 383 q = PolyUtil.<C> monic(q); 384 } else { 385 r = (GenSolvablePolynomial<GenPolynomial<C>>) r.abs(); 386 q = (GenSolvablePolynomial<GenPolynomial<C>>) q.abs(); 387 } 388 GenSolvablePolynomial<C> a = leftRecursiveContent(r); 389 rs = FDUtil.<C> recursiveRightDivide(r, a); 390 //no: rs = FDUtil.<C> recursiveLeftDivide(r, a); 391 //no: rs = FDUtil.<C> recursiveRightPseudoQuotient(r, a); 392 if (debug) { 393 logger.info("RI-recCont a = " + a + ", r = " + r); 394 logger.info("RI-recCont r/a = " + r + ", r%a = " + r.subtract(rs.multiplyLeft(a))); 395 if (!r.equals(rs.multiplyLeft(a))) { // Left 396 System.out.println("RI-recGcd, r = " + r); 397 System.out.println("RI-recGcd, cont(r) = " + a); 398 System.out.println("RI-recGcd, pp(r) = " + rs); 399 System.out.println("RI-recGcd, pp(r)c(r) = " + rs.multiply(a)); 400 System.out.println("RI-recGcd, c(r)pp(r) = " + rs.multiplyLeft(a)); 401 throw new RuntimeException("RI-recGcd, pp: not divisible"); 402 } 403 } 404 r = rs; 405 GenSolvablePolynomial<C> b = leftRecursiveContent(q); 406 qs = FDUtil.<C> recursiveRightDivide(q, b); 407 if (debug) { 408 logger.info("RI-recCont b = " + b + ", q = " + q); 409 logger.info("RI-recCont q/b = " + qs + ", q%b = " + q.subtract(qs.multiplyLeft(b))); 410 if (!q.equals(qs.multiplyLeft(b))) { // Left 411 System.out.println("RI-recGcd, q = " + q); 412 System.out.println("RI-recGcd, cont(q) = " + b); 413 System.out.println("RI-recGcd, pp(q) = " + qs); 414 System.out.println("RI-recGcd, pp(q)c(q) = " + qs.multiply(b)); 415 System.out.println("RI-recGcd, c(q)pp(q) = " + qs.multiplyLeft(b)); 416 throw new RuntimeException("RI-recGcd, pp: not divisible"); 417 } 418 } 419 q = qs; 420 //no: GenSolvablePolynomial<C> c = rightGcd(a, b); // go to recursion 421 GenSolvablePolynomial<C> c = leftGcd(a, b); // go to recursion 422 logger.info("RI-Gcd(contents) c = " + c + ", a = " + a + ", b = " + b); 423 if (r.isONE()) { 424 return r.multiplyLeft(c); 425 } 426 if (q.isONE()) { 427 return q.multiplyLeft(c); 428 } 429 if (debug) { 430 logger.info("RI-r.ring = " + r.ring.toScript()); 431 logger.info("RI-gcd-loop, start: q = " + q + ", r = " + r); 432 } 433 while (!r.isZERO()) { 434 x = FDUtil.<C> recursiveRightSparsePseudoRemainder(q, r); 435 q = r; 436 if (field) { 437 r = PolyUtil.<C> monic(x); 438 } else { 439 r = x; 440 } 441 if (debug) { 442 logger.info("RI-gcd-loop, rem: q = " + q + ", r = " + r); 443 } 444 } 445 if (debug) { 446 logger.info("RI-gcd(div) = " + q + ", rs = " + rs + ", qs = " + qs); 447 rp = FDUtil.<C> recursiveRightSparsePseudoRemainder(rs, q); 448 qp = FDUtil.<C> recursiveRightSparsePseudoRemainder(qs, q); 449 if (!qp.isZERO() || !rp.isZERO()) { 450 logger.info("RI-gcd(div): rem(r,g) = " + rp + ", rem(q,g) = " + qp); 451 rp = FDUtil.<C> recursivePseudoQuotient(rs, q); 452 qp = FDUtil.<C> recursivePseudoQuotient(qs, q); 453 logger.info("RI-gcd(div): r/g = " + rp + ", q/g = " + qp); 454 //logger.info("gcd(div): rp*g = " + rp.multiply(q) + ", qp*g = " + qp.multiply(q)); 455 throw new RuntimeException("recGcd, div: not divisible"); 456 } 457 } 458 qp = q; 459 logger.info("RI-recGcd(P,S) pre pp okay: qp = " + qp); 460 //q = rightRecursivePrimitivePart(q); 461 q = leftRecursivePrimitivePart(q); // sic 462 if (!qp.equals(q)) { 463 logger.info("RI-gcd(pp) = " + q + ", qp = " + qp); // + ", ring = " + P.ring.toScript()); 464 } 465 q = (GenSolvablePolynomial<GenPolynomial<C>>) q.multiplyLeft(c).abs(); 466 return q; 467 } 468 469}