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