001/* 002 * $Id: GreatestCommonDivisorAbstract.java 5871 2018-07-20 15:58:45Z kredel $ 003 */ 004 005package edu.jas.ufd; 006 007 008import java.util.ArrayList; 009import java.util.List; 010 011import org.apache.logging.log4j.Logger; 012import org.apache.logging.log4j.LogManager; 013 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. 023 * @author Heinz Kredel 024 */ 025 026public abstract class GreatestCommonDivisorAbstract<C extends GcdRingElem<C>> 027 implements GreatestCommonDivisor<C> { 028 029 030 private static final Logger logger = LogManager.getLogger(GreatestCommonDivisorAbstract.class); 031 032 033 private static final boolean debug = logger.isDebugEnabled(); 034 035 036 /** 037 * Get the String representation. 038 * @see java.lang.Object#toString() 039 */ 040 @Override 041 public String toString() { 042 return getClass().getName(); 043 } 044 045 046 /** 047 * GenPolynomial base coefficient content. 048 * @param P GenPolynomial. 049 * @return cont(P). 050 */ 051 public C baseContent(GenPolynomial<C> P) { 052 if (P == null) { 053 throw new IllegalArgumentException(this.getClass().getName() + " P != null"); 054 } 055 if (P.isZERO()) { 056 return P.ring.getZEROCoefficient(); 057 } 058 C d = null; 059 for (C c : P.getMap().values()) { 060 if (d == null) { 061 d = c; 062 } else { 063 d = d.gcd(c); 064 } 065 if (d.isONE()) { 066 return d; 067 } 068 } 069 if (d.signum() < 0) { 070 d = d.negate(); 071 } 072 return d; 073 } 074 075 076 /** 077 * GenPolynomial base coefficient primitive part. 078 * @param P GenPolynomial. 079 * @return pp(P). 080 */ 081 public GenPolynomial<C> basePrimitivePart(GenPolynomial<C> P) { 082 if (P == null) { 083 throw new IllegalArgumentException(this.getClass().getName() + " P != null"); 084 } 085 if (P.isZERO()) { 086 return P; 087 } 088 C d = baseContent(P); 089 if (d.isONE()) { 090 return P; 091 } 092 GenPolynomial<C> pp = P.divide(d); 093 if (debug) { 094 GenPolynomial<C> p = pp.multiply(d); 095 if (!p.equals(P)) { 096 throw new ArithmeticException("pp(p)*cont(p) != p: "); 097 } 098 } 099 return pp; 100 } 101 102 103 /** 104 * List of GenPolynomial base coefficient primitive part. 105 * @param F list of GenPolynomials. 106 * @return pp(F). 107 */ 108 public List<GenPolynomial<C>> basePrimitivePart(List<GenPolynomial<C>> F) { 109 if (F == null || F.isEmpty()) { 110 return F; 111 } 112 List<GenPolynomial<C>> Pp = new ArrayList<GenPolynomial<C>>(F.size()); 113 for (GenPolynomial<C> f : F) { 114 GenPolynomial<C> p = basePrimitivePart(f); 115 Pp.add(p); 116 } 117 return Pp; 118 } 119 120 121 /** 122 * Univariate GenPolynomial greatest common divisor. Uses sparse 123 * pseudoRemainder for remainder. 124 * @param P univariate GenPolynomial. 125 * @param S univariate GenPolynomial. 126 * @return gcd(P,S). 127 */ 128 public abstract GenPolynomial<C> baseGcd(GenPolynomial<C> P, GenPolynomial<C> S); 129 130 131 /** 132 * GenPolynomial recursive content. 133 * @param P recursive GenPolynomial. 134 * @return cont(P). 135 */ 136 public GenPolynomial<C> recursiveContent(GenPolynomial<GenPolynomial<C>> P) { 137 if (P == null) { 138 throw new IllegalArgumentException(this.getClass().getName() + " P != null"); 139 } 140 if (P.isZERO()) { 141 return P.ring.getZEROCoefficient(); 142 } 143 GenPolynomial<C> d = null; 144 for (GenPolynomial<C> c : P.getMap().values()) { 145 if (d == null) { 146 d = c; 147 } else { 148 d = gcd(d, c); // go to recursion 149 } 150 if (d.isONE()) { 151 return d; 152 } 153 } 154 return d.abs(); 155 } 156 157 158 /** 159 * GenPolynomial recursive primitive part. 160 * @param P recursive GenPolynomial. 161 * @return pp(P). 162 */ 163 public GenPolynomial<GenPolynomial<C>> recursivePrimitivePart(GenPolynomial<GenPolynomial<C>> P) { 164 if (P == null) { 165 throw new IllegalArgumentException(this.getClass().getName() + " P != null"); 166 } 167 if (P.isZERO()) { 168 return P; 169 } 170 GenPolynomial<C> d = recursiveContent(P); 171 if (d.isONE()) { 172 return P; 173 } 174 GenPolynomial<GenPolynomial<C>> pp = PolyUtil.<C> recursiveDivide(P, d); 175 return pp; 176 } 177 178 179 /** 180 * List of recursive GenPolynomial base coefficient primitive part. 181 * @param F list of recursive GenPolynomials. 182 * @return pp(F). 183 */ 184 public List<GenPolynomial<GenPolynomial<C>>> recursivePrimitivePart( 185 List<GenPolynomial<GenPolynomial<C>>> F) { 186 if (F == null || F.isEmpty()) { 187 return F; 188 } 189 List<GenPolynomial<GenPolynomial<C>>> Pp = new ArrayList<GenPolynomial<GenPolynomial<C>>>(F.size()); 190 for (GenPolynomial<GenPolynomial<C>> f : F) { 191 GenPolynomial<GenPolynomial<C>> p = recursivePrimitivePart(f); 192 Pp.add(p); 193 } 194 return Pp; 195 } 196 197 198 /** 199 * GenPolynomial base recursive content. 200 * @param P recursive GenPolynomial. 201 * @return baseCont(P). 202 */ 203 public C baseRecursiveContent(GenPolynomial<GenPolynomial<C>> P) { 204 if (P == null) { 205 throw new IllegalArgumentException(this.getClass().getName() + " P != null"); 206 } 207 if (P.isZERO()) { 208 GenPolynomialRing<C> cf = (GenPolynomialRing<C>) P.ring.coFac; 209 return cf.coFac.getZERO(); 210 } 211 C d = null; 212 for (GenPolynomial<C> c : P.getMap().values()) { 213 C cc = baseContent(c); 214 if (d == null) { 215 d = cc; 216 } else { 217 d = gcd(d, cc); 218 } 219 if (d.isONE()) { 220 return d; 221 } 222 } 223 if (d.signum() < 0) { 224 d = d.negate(); 225 } 226 return d; 227 } 228 229 230 /** 231 * GenPolynomial base recursive primitive part. 232 * @param P recursive GenPolynomial. 233 * @return basePP(P). 234 */ 235 public GenPolynomial<GenPolynomial<C>> baseRecursivePrimitivePart(GenPolynomial<GenPolynomial<C>> P) { 236 if (P == null) { 237 throw new IllegalArgumentException(this.getClass().getName() + " P != null"); 238 } 239 if (P.isZERO()) { 240 return P; 241 } 242 C d = baseRecursiveContent(P); 243 if (d.isONE()) { 244 return P; 245 } 246 GenPolynomial<GenPolynomial<C>> pp = PolyUtil.<C> baseRecursiveDivide(P, d); 247 return pp; 248 } 249 250 251 /** 252 * GenPolynomial recursive greatest common divisor. Uses pseudoRemainder for 253 * remainder. 254 * @param P recursive GenPolynomial. 255 * @param S recursive GenPolynomial. 256 * @return gcd(P,S). 257 */ 258 public GenPolynomial<GenPolynomial<C>> recursiveGcd(GenPolynomial<GenPolynomial<C>> P, 259 GenPolynomial<GenPolynomial<C>> S) { 260 if (S == null || S.isZERO()) { 261 return P; 262 } 263 if (P == null || P.isZERO()) { 264 return S; 265 } 266 if (P.ring.nvar <= 1) { 267 return recursiveUnivariateGcd(P, S); 268 } 269 // distributed polynomials gcd 270 GenPolynomialRing<GenPolynomial<C>> rfac = P.ring; 271 RingFactory<GenPolynomial<C>> rrfac = rfac.coFac; 272 GenPolynomialRing<C> cfac = (GenPolynomialRing<C>) rrfac; 273 GenPolynomialRing<C> dfac = cfac.extend(rfac.nvar); 274 GenPolynomial<C> Pd = PolyUtil.<C> distribute(dfac, P); 275 GenPolynomial<C> Sd = PolyUtil.<C> distribute(dfac, S); 276 GenPolynomial<C> Dd = gcd(Pd, Sd); 277 // convert to recursive 278 GenPolynomial<GenPolynomial<C>> C = PolyUtil.<C> recursive(rfac, Dd); 279 return C; 280 } 281 282 283 /** 284 * Univariate GenPolynomial recursive greatest common divisor. Uses 285 * pseudoRemainder for remainder. 286 * @param P univariate recursive GenPolynomial. 287 * @param S univariate recursive GenPolynomial. 288 * @return gcd(P,S). 289 */ 290 public abstract GenPolynomial<GenPolynomial<C>> recursiveUnivariateGcd(GenPolynomial<GenPolynomial<C>> P, 291 GenPolynomial<GenPolynomial<C>> S); 292 293 294 /** 295 * GenPolynomial content. 296 * @param P GenPolynomial. 297 * @return cont(P). 298 */ 299 public GenPolynomial<C> content(GenPolynomial<C> P) { 300 if (P == null) { 301 throw new IllegalArgumentException(this.getClass().getName() + " P != null"); 302 } 303 GenPolynomialRing<C> pfac = P.ring; 304 if (pfac.nvar <= 1) { 305 // baseContent not possible by return type 306 throw new IllegalArgumentException( 307 this.getClass().getName() + " use baseContent for univariate polynomials"); 308 309 } 310 GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1); 311 GenPolynomial<GenPolynomial<C>> Pr = PolyUtil.<C> recursive(rfac, P); 312 GenPolynomial<C> D = recursiveContent(Pr); 313 return D; 314 } 315 316 317 /** 318 * GenPolynomial primitive part. 319 * @param P GenPolynomial. 320 * @return pp(P). 321 */ 322 public GenPolynomial<C> primitivePart(GenPolynomial<C> P) { 323 return contentPrimitivePart(P)[1]; 324 } 325 326 327 /** 328 * GenPolynomial content and primitive part. 329 * @param P GenPolynomial. 330 * @return { cont(P), pp(P) } 331 */ 332 @SuppressWarnings("unchecked") 333 public GenPolynomial<C>[] contentPrimitivePart(GenPolynomial<C> P) { 334 if (P == null) { 335 throw new IllegalArgumentException(this.getClass().getName() + " P != null"); 336 } 337 GenPolynomial<C>[] ret = new GenPolynomial[2]; 338 GenPolynomialRing<C> pfac = P.ring; 339 if (P.isZERO()) { 340 ret[0] = pfac.getZERO(); 341 ret[1] = pfac.getZERO(); 342 return ret; 343 } 344 if (pfac.nvar <= 1) { 345 C Pc = baseContent(P); 346 GenPolynomial<C> Pp = P; 347 if (!Pc.isONE()) { 348 Pp = P.divide(Pc); 349 } 350 ret[0] = pfac.valueOf(Pc); 351 ret[1] = Pp; 352 return ret; 353 } 354 GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1); 355 //GenPolynomialRing<C> cfac = rfac.coFac; 356 GenPolynomial<GenPolynomial<C>> Pr = PolyUtil.<C> recursive(rfac, P); 357 GenPolynomial<C> Pc = recursiveContent(Pr); 358 // primitive part 359 GenPolynomial<GenPolynomial<C>> Pp = Pr; 360 if (!Pc.isONE()) { 361 Pp = PolyUtil.<C> recursiveDivide(Pr, Pc); 362 } 363 GenPolynomial<C> Ppd = PolyUtil.<C> distribute(pfac, Pp); 364 ret[0] = Pc; // sic! 365 ret[1] = Ppd; 366 return ret; 367 } 368 369 370 /** 371 * GenPolynomial division. Indirection to GenPolynomial method. 372 * @param a GenPolynomial. 373 * @param b coefficient. 374 * @return a/b. 375 */ 376 public GenPolynomial<C> divide(GenPolynomial<C> a, C b) { 377 if (b == null || b.isZERO()) { 378 throw new IllegalArgumentException("division by zero"); 379 380 } 381 if (a == null || a.isZERO()) { 382 return a; 383 } 384 return a.divide(b); 385 } 386 387 388 /** 389 * Coefficient greatest common divisor. Indirection to coefficient method. 390 * @param a coefficient. 391 * @param b coefficient. 392 * @return gcd(a,b). 393 */ 394 public C gcd(C a, C b) { 395 if (b == null || b.isZERO()) { 396 return a; 397 } 398 if (a == null || a.isZERO()) { 399 return b; 400 } 401 return a.gcd(b); 402 } 403 404 405 /** 406 * GenPolynomial greatest common divisor. 407 * @param P GenPolynomial. 408 * @param S GenPolynomial. 409 * @return gcd(P,S). 410 */ 411 public GenPolynomial<C> gcd(GenPolynomial<C> P, GenPolynomial<C> S) { 412 if (S == null || S.isZERO()) { 413 return P; 414 } 415 if (P == null || P.isZERO()) { 416 return S; 417 } 418 GenPolynomialRing<C> pfac = P.ring; 419 if (pfac.nvar <= 1) { 420 GenPolynomial<C> T = baseGcd(P, S); 421 return T; 422 } 423 GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1); 424 /* 425 GenPolynomialRing<C> cfac = pfac.contract(1); 426 GenPolynomialRing<GenPolynomial<C>> rfac; 427 if (pfac.getVars() != null && pfac.getVars().length > 0) { 428 String[] v = new String[] { pfac.getVars()[pfac.nvar - 1] }; 429 rfac = new GenPolynomialRing<GenPolynomial<C>>(cfac, 1, v); 430 } else { 431 rfac = new GenPolynomialRing<GenPolynomial<C>>(cfac, 1); 432 } 433 */ 434 GenPolynomial<GenPolynomial<C>> Pr = PolyUtil.<C> recursive(rfac, P); 435 GenPolynomial<GenPolynomial<C>> Sr = PolyUtil.<C> recursive(rfac, S); 436 GenPolynomial<GenPolynomial<C>> Dr = recursiveUnivariateGcd(Pr, Sr); 437 GenPolynomial<C> D = PolyUtil.<C> distribute(pfac, Dr); 438 return D; 439 } 440 441 442 /** 443 * GenPolynomial least common multiple. 444 * @param P GenPolynomial. 445 * @param S GenPolynomial. 446 * @return lcm(P,S). 447 */ 448 public GenPolynomial<C> lcm(GenPolynomial<C> P, GenPolynomial<C> S) { 449 if (S == null || S.isZERO()) { 450 return S; 451 } 452 if (P == null || P.isZERO()) { 453 return P; 454 } 455 GenPolynomial<C> C = gcd(P, S); 456 GenPolynomial<C> A = P.multiply(S); 457 return PolyUtil.<C> basePseudoDivide(A, C); 458 } 459 460 461 /** 462 * List of GenPolynomials greatest common divisor. 463 * @param A non empty list of GenPolynomials. 464 * @return gcd(A_i). 465 */ 466 public GenPolynomial<C> gcd(List<GenPolynomial<C>> A) { 467 if (A == null || A.isEmpty()) { 468 throw new IllegalArgumentException("A may not be empty"); 469 } 470 GenPolynomial<C> g = A.get(0); 471 for (int i = 1; i < A.size(); i++) { 472 GenPolynomial<C> f = A.get(i); 473 g = gcd(g, f); 474 } 475 return g; 476 } 477 478 479 /** 480 * Univariate GenPolynomial resultant. 481 * @param P univariate GenPolynomial. 482 * @param S univariate GenPolynomial. 483 * @return res(P,S). 484 * @throws UnsupportedOperationException if there is no implementation in 485 * the sub-class. 486 */ 487 @SuppressWarnings("unused") 488 public GenPolynomial<C> baseResultant(GenPolynomial<C> P, GenPolynomial<C> S) { 489 throw new UnsupportedOperationException("not implmented"); 490 } 491 492 493 /** 494 * Univariate GenPolynomial recursive resultant. 495 * @param P univariate recursive GenPolynomial. 496 * @param S univariate recursive GenPolynomial. 497 * @return res(P,S). 498 * @throws UnsupportedOperationException if there is no implementation in 499 * the sub-class. 500 */ 501 @SuppressWarnings("unused") 502 public GenPolynomial<GenPolynomial<C>> recursiveUnivariateResultant(GenPolynomial<GenPolynomial<C>> P, 503 GenPolynomial<GenPolynomial<C>> S) { 504 throw new UnsupportedOperationException("not implmented"); 505 } 506 507 508 /** 509 * GenPolynomial recursive resultant. 510 * @param P univariate recursive GenPolynomial. 511 * @param S univariate recursive GenPolynomial. 512 * @return res(P,S). 513 * @throws UnsupportedOperationException if there is no implementation in 514 * the sub-class. 515 */ 516 public GenPolynomial<GenPolynomial<C>> recursiveResultant(GenPolynomial<GenPolynomial<C>> P, 517 GenPolynomial<GenPolynomial<C>> S) { 518 if (S == null || S.isZERO()) { 519 return S; 520 } 521 if (P == null || P.isZERO()) { 522 return P; 523 } 524 GenPolynomialRing<GenPolynomial<C>> rfac = P.ring; 525 GenPolynomialRing<C> cfac = (GenPolynomialRing<C>) rfac.coFac; 526 GenPolynomialRing<C> dfac = cfac.extend(rfac.getVars()); 527 GenPolynomial<C> Pp = PolyUtil.<C> distribute(dfac, P); 528 GenPolynomial<C> Sp = PolyUtil.<C> distribute(dfac, S); 529 GenPolynomial<C> res = resultant(Pp, Sp); 530 GenPolynomial<GenPolynomial<C>> Rr = PolyUtil.<C> recursive(rfac, res); 531 return Rr; 532 } 533 534 535 /** 536 * GenPolynomial resultant. The input polynomials are considered as 537 * univariate polynomials in the main variable. 538 * @param P GenPolynomial. 539 * @param S GenPolynomial. 540 * @return res(P,S). 541 * @see edu.jas.ufd.GreatestCommonDivisorSubres#recursiveResultant 542 * @throws UnsupportedOperationException if there is no implementation in 543 * the sub-class. 544 */ 545 public GenPolynomial<C> resultant(GenPolynomial<C> P, GenPolynomial<C> S) { 546 if (S == null || S.isZERO()) { 547 return S; 548 } 549 if (P == null || P.isZERO()) { 550 return P; 551 } 552 // no more hacked: GreatestCommonDivisorSubres<C> ufd_sr = new GreatestCommonDivisorSubres<C>(); 553 GenPolynomialRing<C> pfac = P.ring; 554 if (pfac.nvar <= 1) { 555 return baseResultant(P, S); 556 } 557 GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1); 558 GenPolynomial<GenPolynomial<C>> Pr = PolyUtil.<C> recursive(rfac, P); 559 GenPolynomial<GenPolynomial<C>> Sr = PolyUtil.<C> recursive(rfac, S); 560 561 GenPolynomial<GenPolynomial<C>> Dr = recursiveUnivariateResultant(Pr, Sr); 562 GenPolynomial<C> D = PolyUtil.<C> distribute(pfac, Dr); 563 return D; 564 } 565 566 567 /** 568 * GenPolynomial co-prime list. 569 * @param A list of GenPolynomials. 570 * @return B with gcd(b,c) = 1 for all b != c in B and for all non-constant 571 * a in A there exists b in B with b|a. B does not contain zero or 572 * constant polynomials. 573 */ 574 public List<GenPolynomial<C>> coPrime(List<GenPolynomial<C>> A) { 575 if (A == null || A.isEmpty()) { 576 return A; 577 } 578 List<GenPolynomial<C>> B = new ArrayList<GenPolynomial<C>>(A.size()); 579 // make a coprime to rest of list 580 GenPolynomial<C> a = A.get(0); 581 //System.out.println("a = " + a); 582 if (!a.isZERO() && !a.isConstant()) { 583 for (int i = 1; i < A.size(); i++) { 584 GenPolynomial<C> b = A.get(i); 585 GenPolynomial<C> g = gcd(a, b).abs(); 586 if (!g.isONE()) { 587 a = PolyUtil.<C> basePseudoDivide(a, g); 588 b = PolyUtil.<C> basePseudoDivide(b, g); 589 GenPolynomial<C> gp = gcd(a, g).abs(); 590 while (!gp.isONE()) { 591 a = PolyUtil.<C> basePseudoDivide(a, gp); 592 g = PolyUtil.<C> basePseudoDivide(g, gp); 593 B.add(g); // gcd(a,g) == 1 594 g = gp; 595 gp = gcd(a, gp).abs(); 596 } 597 if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) { 598 B.add(g); // gcd(a,g) == 1 599 } 600 } 601 if (!b.isZERO() && !b.isConstant()) { 602 B.add(b); // gcd(a,b) == 1 603 } 604 } 605 } else { 606 B.addAll(A.subList(1, A.size())); 607 } 608 // make rest coprime 609 B = coPrime(B); 610 //System.out.println("B = " + B); 611 if (!a.isZERO() && !a.isConstant() /*&& !B.contains(a)*/) { 612 a = a.abs(); 613 B.add(a); 614 } 615 return B; 616 } 617 618 619 /** 620 * GenPolynomial co-prime list. 621 * @param A list of GenPolynomials. 622 * @return B with gcd(b,c) = 1 for all b != c in B and for all non-constant 623 * a in A there exists b in B with b|a. B does not contain zero or 624 * constant polynomials. 625 */ 626 public List<GenPolynomial<C>> coPrimeRec(List<GenPolynomial<C>> A) { 627 if (A == null || A.isEmpty()) { 628 return A; 629 } 630 List<GenPolynomial<C>> B = new ArrayList<GenPolynomial<C>>(); 631 // make a co-prime to rest of list 632 for (GenPolynomial<C> a : A) { 633 //System.out.println("a = " + a); 634 B = coPrime(a, B); 635 //System.out.println("B = " + B); 636 } 637 return B; 638 } 639 640 641 /** 642 * GenPolynomial co-prime list. 643 * @param a GenPolynomial. 644 * @param P co-prime list of GenPolynomials. 645 * @return B with gcd(b,c) = 1 for all b != c in B and for non-constant a 646 * there exists b in P with b|a. B does not contain zero or constant 647 * polynomials. 648 */ 649 public List<GenPolynomial<C>> coPrime(GenPolynomial<C> a, List<GenPolynomial<C>> P) { 650 if (a == null || a.isZERO() || a.isConstant()) { 651 return P; 652 } 653 List<GenPolynomial<C>> B = new ArrayList<GenPolynomial<C>>(P.size() + 1); 654 // make a coprime to elements of the list P 655 for (int i = 0; i < P.size(); i++) { 656 GenPolynomial<C> b = P.get(i); 657 GenPolynomial<C> g = gcd(a, b).abs(); 658 if (!g.isONE()) { 659 a = PolyUtil.<C> basePseudoDivide(a, g); 660 b = PolyUtil.<C> basePseudoDivide(b, g); 661 // make g co-prime to new a, g is co-prime to c != b in P, B 662 GenPolynomial<C> gp = gcd(a, g).abs(); 663 while (!gp.isONE()) { 664 a = PolyUtil.<C> basePseudoDivide(a, gp); 665 g = PolyUtil.<C> basePseudoDivide(g, gp); 666 if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) { 667 B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B 668 } 669 g = gp; 670 gp = gcd(a, gp).abs(); 671 } 672 // make new g co-prime to new b 673 gp = gcd(b, g).abs(); 674 while (!gp.isONE()) { 675 b = PolyUtil.<C> basePseudoDivide(b, gp); 676 g = PolyUtil.<C> basePseudoDivide(g, gp); 677 if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) { 678 B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B 679 } 680 g = gp; 681 gp = gcd(b, gp).abs(); 682 } 683 if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) { 684 B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B 685 } 686 } 687 if (!b.isZERO() && !b.isConstant() /*&& !B.contains(b)*/) { 688 B.add(b); // gcd(a,b) == 1 and gcd(b,c) == 1 for c != b in P, B 689 } 690 } 691 if (!a.isZERO() && !a.isConstant() /*&& !B.contains(a)*/) { 692 B.add(a); 693 } 694 return B; 695 } 696 697 698 /** 699 * GenPolynomial test for co-prime list. 700 * @param A list of GenPolynomials. 701 * @return true if gcd(b,c) = 1 for all b != c in B, else false. 702 */ 703 public boolean isCoPrime(List<GenPolynomial<C>> A) { 704 if (A == null || A.isEmpty()) { 705 return true; 706 } 707 if (A.size() == 1) { 708 return true; 709 } 710 for (int i = 0; i < A.size(); i++) { 711 GenPolynomial<C> a = A.get(i); 712 for (int j = i + 1; j < A.size(); j++) { 713 GenPolynomial<C> b = A.get(j); 714 GenPolynomial<C> g = gcd(a, b); 715 if (!g.isONE()) { 716 System.out.println("not co-prime, a: " + a); 717 System.out.println("not co-prime, b: " + b); 718 System.out.println("not co-prime, g: " + g); 719 return false; 720 } 721 } 722 } 723 return true; 724 } 725 726 727 /** 728 * GenPolynomial test for co-prime list of given list. 729 * @param A list of GenPolynomials. 730 * @param P list of co-prime GenPolynomials. 731 * @return true if isCoPrime(P) and for all a in A exists p in P with p | a, 732 * else false. 733 */ 734 public boolean isCoPrime(List<GenPolynomial<C>> P, List<GenPolynomial<C>> A) { 735 if (!isCoPrime(P)) { 736 return false; 737 } 738 if (A == null || A.isEmpty()) { 739 return true; 740 } 741 for (GenPolynomial<C> q : A) { 742 if (q.isZERO() || q.isConstant()) { 743 continue; 744 } 745 boolean divides = false; 746 for (GenPolynomial<C> p : P) { 747 GenPolynomial<C> a = PolyUtil.<C> baseSparsePseudoRemainder(q, p); 748 if (a.isZERO()) { // p divides q 749 divides = true; 750 break; 751 } 752 } 753 if (!divides) { 754 System.out.println("no divisor for: " + q); 755 return false; 756 } 757 } 758 return true; 759 } 760 761 762 /** 763 * Univariate GenPolynomial extended greatest common divisor. Uses sparse 764 * pseudoRemainder for remainder. 765 * @param P univariate GenPolynomial. 766 * @param S univariate GenPolynomial. 767 * @return [ gcd(P,S), a, b ] with a*P + b*S = gcd(P,S). 768 */ 769 @SuppressWarnings("cast") 770 public GenPolynomial<C>[] baseExtendedGcd(GenPolynomial<C> P, GenPolynomial<C> S) { 771 //return P.egcd(S); 772 GenPolynomial<C>[] hegcd = baseHalfExtendedGcd(P, S); 773 GenPolynomial<C>[] ret = (GenPolynomial<C>[]) new GenPolynomial[3]; 774 ret[0] = hegcd[0]; 775 ret[1] = hegcd[1]; 776 GenPolynomial<C> x = hegcd[0].subtract(hegcd[1].multiply(P)); 777 GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(x, S); 778 // assert qr[1].isZERO() 779 ret[2] = qr[0]; 780 return ret; 781 } 782 783 784 /** 785 * Univariate GenPolynomial half extended greatest comon divisor. Uses 786 * sparse pseudoRemainder for remainder. 787 * @param S GenPolynomial. 788 * @return [ gcd(P,S), a ] with a*P + b*S = gcd(P,S). 789 */ 790 @SuppressWarnings("cast") 791 public GenPolynomial<C>[] baseHalfExtendedGcd(GenPolynomial<C> P, GenPolynomial<C> S) { 792 //if ( P == null ) { 793 // throw new IllegalArgumentException("null P not allowed"); 794 //} 795 GenPolynomial<C>[] ret = (GenPolynomial<C>[]) new GenPolynomial[2]; 796 ret[0] = null; 797 ret[1] = null; 798 if (S == null || S.isZERO()) { 799 ret[0] = P; 800 ret[1] = P.ring.getONE(); 801 return ret; 802 } 803 if (P == null || P.isZERO()) { 804 ret[0] = S; 805 ret[1] = S.ring.getZERO(); 806 return ret; 807 } 808 if (P.ring.nvar != 1) { 809 throw new IllegalArgumentException( 810 this.getClass().getName() + " not univariate polynomials " + P.ring); 811 } 812 GenPolynomial<C> q = P; 813 GenPolynomial<C> r = S; 814 GenPolynomial<C> c1 = P.ring.getONE().copy(); 815 GenPolynomial<C> d1 = P.ring.getZERO().copy(); 816 while (!r.isZERO()) { 817 GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(q, r); 818 //q.divideAndRemainder(r); 819 q = qr[0]; 820 GenPolynomial<C> x = c1.subtract(q.multiply(d1)); 821 c1 = d1; 822 d1 = x; 823 q = r; 824 r = qr[1]; 825 } 826 // normalize ldcf(q) to 1, i.e. make monic 827 C g = q.leadingBaseCoefficient(); 828 if (g.isUnit()) { 829 C h = g.inverse(); 830 q = q.multiply(h); 831 c1 = c1.multiply(h); 832 } 833 //assert ( ((c1.multiply(P)).remainder(S).equals(q) )); 834 ret[0] = q; 835 ret[1] = c1; 836 return ret; 837 } 838 839 840 /** 841 * Univariate GenPolynomial greatest common divisor diophantine version. 842 * @param P univariate GenPolynomial. 843 * @param S univariate GenPolynomial. 844 * @param c univariate GenPolynomial. 845 * @return [ a, b ] with a*P + b*S = c and deg(a) < deg(S). 846 */ 847 @SuppressWarnings("cast") 848 public GenPolynomial<C>[] baseGcdDiophant(GenPolynomial<C> P, GenPolynomial<C> S, GenPolynomial<C> c) { 849 GenPolynomial<C>[] egcd = baseExtendedGcd(P, S); 850 GenPolynomial<C> g = egcd[0]; 851 GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(c, g); 852 if (!qr[1].isZERO()) { 853 throw new ArithmeticException("not solvable, r = " + qr[1] + ", c = " + c + ", g = " + g); 854 } 855 GenPolynomial<C> q = qr[0]; 856 GenPolynomial<C> a = egcd[1].multiply(q); 857 GenPolynomial<C> b = egcd[2].multiply(q); 858 if (!a.isZERO() && a.degree(0) >= S.degree(0)) { 859 qr = PolyUtil.<C> basePseudoQuotientRemainder(a, S); 860 a = qr[1]; 861 b = b.sum(P.multiply(qr[0])); 862 } 863 GenPolynomial<C>[] ret = (GenPolynomial<C>[]) new GenPolynomial[2]; 864 ret[0] = a; 865 ret[1] = b; 866 867 if (debug) { 868 GenPolynomial<C> y = ret[0].multiply(P).sum(ret[1].multiply(S)); 869 if (!y.equals(c)) { 870 System.out.println("P = " + P); 871 System.out.println("S = " + S); 872 System.out.println("c = " + c); 873 System.out.println("a = " + a); 874 System.out.println("b = " + b); 875 System.out.println("y = " + y); 876 throw new ArithmeticException("not diophant, x = " + y.subtract(c)); 877 } 878 } 879 return ret; 880 } 881 882 883 /** 884 * Univariate GenPolynomial partial fraction decomposition. 885 * @param A univariate GenPolynomial. 886 * @param P univariate GenPolynomial. 887 * @param S univariate GenPolynomial. 888 * @return [ A0, Ap, As ] with A/(P*S) = A0 + Ap/P + As/S with deg(Ap) < 889 * deg(P) and deg(As) < deg(S). 890 */ 891 @SuppressWarnings("cast") 892 public GenPolynomial<C>[] basePartialFraction(GenPolynomial<C> A, GenPolynomial<C> P, 893 GenPolynomial<C> S) { 894 GenPolynomial<C>[] ret = (GenPolynomial<C>[]) new GenPolynomial[3]; 895 ret[0] = null; 896 ret[1] = null; 897 ret[2] = null; 898 GenPolynomial<C> ps = P.multiply(S); 899 GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(A, ps); 900 ret[0] = qr[0]; 901 GenPolynomial<C> r = qr[1]; 902 GenPolynomial<C>[] diop = baseGcdDiophant(S, P, r); // switch arguments 903 904 // GenPolynomial<C> x = diop[0].multiply(S).sum( diop[1].multiply(P) ); 905 // if ( !x.equals(r) ) { 906 // System.out.println("r = " + r); 907 // System.out.println("x = " + x); 908 // throw new RuntimeException("not partial fraction, x = " + x); 909 // } 910 911 ret[1] = diop[0]; 912 ret[2] = diop[1]; 913 if (ret[1].degree(0) >= P.degree(0)) { 914 qr = PolyUtil.<C> basePseudoQuotientRemainder(ret[1], P); 915 ret[0] = ret[0].sum(qr[0]); 916 ret[1] = qr[1]; 917 } 918 if (ret[2].degree(0) >= S.degree(0)) { 919 qr = PolyUtil.<C> basePseudoQuotientRemainder(ret[2], S); 920 ret[0] = ret[0].sum(qr[0]); 921 ret[2] = qr[1]; 922 } 923 return ret; 924 } 925 926 927 /** 928 * Univariate GenPolynomial partial fraction decomposition. 929 * @param A univariate GenPolynomial. 930 * @param P univariate GenPolynomial. 931 * @param e exponent for P. 932 * @return [ F0, F1, ..., Fe ] with A/(P^e) = sum( Fi / P^i ) with deg(Fi) < 933 * deg(P). 934 */ 935 public List<GenPolynomial<C>> basePartialFraction(GenPolynomial<C> A, GenPolynomial<C> P, int e) { 936 if (A == null || P == null || e == 0) { 937 throw new IllegalArgumentException("null A, P or e = 0 not allowed"); 938 } 939 List<GenPolynomial<C>> pf = new ArrayList<GenPolynomial<C>>(e); 940 if (A.isZERO()) { 941 for (int i = 0; i < e; i++) { 942 pf.add(A); 943 } 944 return pf; 945 } 946 if (e == 1) { 947 GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(A, P); 948 pf.add(qr[0]); 949 pf.add(qr[1]); 950 return pf; 951 } 952 GenPolynomial<C> a = A; 953 for (int j = e; j > 0; j--) { 954 GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(a, P); 955 a = qr[0]; 956 pf.add(0, qr[1]); 957 } 958 pf.add(0, a); 959 return pf; 960 } 961 962 963 /** 964 * Univariate GenPolynomial partial fraction decomposition. 965 * @param A univariate GenPolynomial. 966 * @param D list of co-prime univariate GenPolynomials. 967 * @return [ A0, A1,..., An ] with A/prod(D) = A0 + sum( Ai/Di ) with 968 * deg(Ai) < deg(Di). 969 */ 970 public List<GenPolynomial<C>> basePartialFraction(GenPolynomial<C> A, List<GenPolynomial<C>> D) { 971 if (D == null || A == null) { 972 throw new IllegalArgumentException("null A or D not allowed"); 973 } 974 List<GenPolynomial<C>> pf = new ArrayList<GenPolynomial<C>>(D.size() + 1); 975 if (A.isZERO() || D.size() == 0) { 976 pf.add(A); 977 for (int i = 0; i < D.size(); i++) { 978 pf.add(A); 979 } 980 return pf; 981 } 982 List<GenPolynomial<C>> Dp = new ArrayList<GenPolynomial<C>>(D.size() - 1); 983 GenPolynomial<C> P = A.ring.getONE(); 984 GenPolynomial<C> d1 = null; 985 for (GenPolynomial<C> d : D) { 986 if (d1 == null) { 987 d1 = d; 988 } else { 989 P = P.multiply(d); 990 Dp.add(d); 991 } 992 } 993 GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(A, P.multiply(d1)); 994 GenPolynomial<C> A0 = qr[0]; 995 GenPolynomial<C> r = qr[1]; 996 if (D.size() == 1) { 997 pf.add(A0); 998 pf.add(r); 999 return pf; 1000 } 1001 GenPolynomial<C>[] diop = baseGcdDiophant(P, d1, r); // switch arguments 1002 GenPolynomial<C> A1 = diop[0]; 1003 GenPolynomial<C> S = diop[1]; 1004 List<GenPolynomial<C>> Fr = basePartialFraction(S, Dp); 1005 A0 = A0.sum(Fr.remove(0)); 1006 pf.add(A0); 1007 pf.add(A1); 1008 pf.addAll(Fr); 1009 return pf; 1010 } 1011 1012 1013 /** 1014 * Test for Univariate GenPolynomial partial fraction decomposition. 1015 * @param A univariate GenPolynomial. 1016 * @param D list of (co-prime) univariate GenPolynomials. 1017 * @param F list of univariate GenPolynomials from a partial fraction 1018 * computation. 1019 * @return true if A/prod(D) = F0 + sum( Fi/Di ) with deg(Fi) < deg(Di), Fi 1020 * in F, else false. 1021 */ 1022 public boolean isBasePartialFraction(GenPolynomial<C> A, List<GenPolynomial<C>> D, 1023 List<GenPolynomial<C>> F) { 1024 if (D == null || A == null || F == null) { 1025 throw new IllegalArgumentException("null A, F or D not allowed"); 1026 } 1027 if (D.size() != F.size() - 1) { 1028 return false; 1029 } 1030 // A0*prod(D) + sum( Ai * Dip ), Dip = prod(D,j!=i) 1031 GenPolynomial<C> P = A.ring.getONE(); 1032 for (GenPolynomial<C> d : D) { 1033 P = P.multiply(d); 1034 } 1035 List<GenPolynomial<C>> Fp = new ArrayList<GenPolynomial<C>>(F); 1036 GenPolynomial<C> A0 = Fp.remove(0).multiply(P); 1037 //System.out.println("A0 = " + A0); 1038 int j = 0; 1039 for (GenPolynomial<C> Fi : Fp) { 1040 P = A.ring.getONE(); 1041 int i = 0; 1042 for (GenPolynomial<C> d : D) { 1043 if (i != j) { 1044 P = P.multiply(d); 1045 } 1046 i++; 1047 } 1048 //System.out.println("Fi = " + Fi); 1049 //System.out.println("P = " + P); 1050 A0 = A0.sum(Fi.multiply(P)); 1051 //System.out.println("A0 = " + A0); 1052 j++; 1053 } 1054 boolean t = A.equals(A0); 1055 if (!t) { 1056 System.out.println("not isPartFrac = " + A0); 1057 } 1058 return t; 1059 } 1060 1061 1062 /** 1063 * Test for Univariate GenPolynomial partial fraction decomposition. 1064 * @param A univariate GenPolynomial. 1065 * @param P univariate GenPolynomial. 1066 * @param e exponent for P. 1067 * @param F list of univariate GenPolynomials from a partial fraction 1068 * computation. 1069 * @return true if A/(P^e) = F0 + sum( Fi / P^i ) with deg(Fi) < deg(P), Fi 1070 * in F, else false. 1071 */ 1072 public boolean isBasePartialFraction(GenPolynomial<C> A, GenPolynomial<C> P, int e, 1073 List<GenPolynomial<C>> F) { 1074 if (A == null || P == null || F == null || e == 0) { 1075 throw new IllegalArgumentException("null A, P, F or e = 0 not allowed"); 1076 } 1077 GenPolynomial<C> A0 = basePartialFractionValue(P, e, F); 1078 boolean t = A.equals(A0); 1079 if (!t) { 1080 System.out.println("not isPartFrac = " + A0); 1081 } 1082 return t; 1083 } 1084 1085 1086 /** 1087 * Test for Univariate GenPolynomial partial fraction decomposition. 1088 * @param P univariate GenPolynomial. 1089 * @param e exponent for P. 1090 * @param F list of univariate GenPolynomials from a partial fraction 1091 * computation. 1092 * @return (F0 + sum( Fi / P^i )) * P^e. 1093 */ 1094 public GenPolynomial<C> basePartialFractionValue(GenPolynomial<C> P, int e, List<GenPolynomial<C>> F) { 1095 if (P == null || F == null || e == 0) { 1096 throw new IllegalArgumentException("null P, F or e = 0 not allowed"); 1097 } 1098 GenPolynomial<C> A0 = P.ring.getZERO(); 1099 for (GenPolynomial<C> Fi : F) { 1100 A0 = A0.multiply(P); 1101 A0 = A0.sum(Fi); 1102 } 1103 return A0; 1104 } 1105 1106}