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