[Home] DMelt member access. Java source code: edu.jas.ufd.GreatestCommonDivisorAbstract
/*
* $Id$
*/
package edu.jas.ufd;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import edu.jas.poly.GenPolynomial;
import edu.jas.poly.GenPolynomialRing;
import edu.jas.poly.PolyUtil;
import edu.jas.structure.GcdRingElem;
import edu.jas.structure.RingFactory;
/**
* Greatest common divisor algorithms.
* @author Heinz Kredel
*/
public abstract class GreatestCommonDivisorAbstract> implements
GreatestCommonDivisor {
private static final Logger logger = Logger.getLogger(GreatestCommonDivisorAbstract.class);
private final boolean debug = logger.isDebugEnabled();
/**
* Get the String representation.
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return getClass().getName();
}
/**
* GenPolynomial base coefficient content.
* @param P GenPolynomial.
* @return cont(P).
*/
public C baseContent(GenPolynomial P) {
if (P == null) {
throw new IllegalArgumentException(this.getClass().getName() + " P != null");
}
if (P.isZERO()) {
return P.ring.getZEROCoefficient();
}
C d = null;
for (C c : P.getMap().values()) {
if (d == null) {
d = c;
} else {
d = d.gcd(c);
}
if (d.isONE()) {
return d;
}
}
if (d.signum() < 0) {
d = d.negate();
}
return d;
}
/**
* GenPolynomial base coefficient primitive part.
* @param P GenPolynomial.
* @return pp(P).
*/
public GenPolynomial basePrimitivePart(GenPolynomial P) {
if (P == null) {
throw new IllegalArgumentException(this.getClass().getName() + " P != null");
}
if (P.isZERO()) {
return P;
}
C d = baseContent(P);
if (d.isONE()) {
return P;
}
GenPolynomial pp = P.divide(d);
if (debug) {
GenPolynomial p = pp.multiply(d);
if (!p.equals(P)) {
throw new ArithmeticException("pp(p)*cont(p) != p: ");
}
}
return pp;
}
/**
* Univariate GenPolynomial greatest common divisor. Uses sparse
* pseudoRemainder for remainder.
* @param P univariate GenPolynomial.
* @param S univariate GenPolynomial.
* @return gcd(P,S).
*/
public abstract GenPolynomial baseGcd(GenPolynomial P, GenPolynomial S);
/**
* GenPolynomial recursive content.
* @param P recursive GenPolynomial.
* @return cont(P).
*/
public GenPolynomial recursiveContent(GenPolynomial> P) {
if (P == null) {
throw new IllegalArgumentException(this.getClass().getName() + " P != null");
}
if (P.isZERO()) {
return P.ring.getZEROCoefficient();
}
GenPolynomial d = null;
for (GenPolynomial c : P.getMap().values()) {
if (d == null) {
d = c;
} else {
d = gcd(d, c); // go to recursion
}
if (d.isONE()) {
return d;
}
}
return d.abs();
}
/**
* GenPolynomial recursive primitive part.
* @param P recursive GenPolynomial.
* @return pp(P).
*/
public GenPolynomial> recursivePrimitivePart(GenPolynomial> P) {
if (P == null) {
throw new IllegalArgumentException(this.getClass().getName() + " P != null");
}
if (P.isZERO()) {
return P;
}
GenPolynomial d = recursiveContent(P);
if (d.isONE()) {
return P;
}
GenPolynomial> pp = PolyUtil. recursiveDivide(P, d);
return pp;
}
/**
* GenPolynomial base recursive content.
* @param P recursive GenPolynomial.
* @return baseCont(P).
*/
public C baseRecursiveContent(GenPolynomial> P) {
if (P == null) {
throw new IllegalArgumentException(this.getClass().getName() + " P != null");
}
if (P.isZERO()) {
GenPolynomialRing cf = (GenPolynomialRing) P.ring.coFac;
return cf.coFac.getZERO();
}
C d = null;
for (GenPolynomial c : P.getMap().values()) {
C cc = baseContent(c);
if (d == null) {
d = cc;
} else {
d = gcd(d, cc);
}
if (d.isONE()) {
return d;
}
}
if (d.signum() < 0) {
d = d.negate();
}
return d;
}
/**
* GenPolynomial base recursive primitive part.
* @param P recursive GenPolynomial.
* @return basePP(P).
*/
public GenPolynomial> baseRecursivePrimitivePart(GenPolynomial> P) {
if (P == null) {
throw new IllegalArgumentException(this.getClass().getName() + " P != null");
}
if (P.isZERO()) {
return P;
}
C d = baseRecursiveContent(P);
if (d.isONE()) {
return P;
}
GenPolynomial> pp = PolyUtil. baseRecursiveDivide(P, d);
return pp;
}
/**
* GenPolynomial recursive greatest common divisor. Uses pseudoRemainder for
* remainder.
* @param P recursive GenPolynomial.
* @param S recursive GenPolynomial.
* @return gcd(P,S).
*/
public GenPolynomial> recursiveGcd(GenPolynomial> P,
GenPolynomial> S) {
if (S == null || S.isZERO()) {
return P;
}
if (P == null || P.isZERO()) {
return S;
}
if (P.ring.nvar <= 1) {
return recursiveUnivariateGcd(P, S);
}
// distributed polynomials gcd
GenPolynomialRing> rfac = P.ring;
RingFactory> rrfac = rfac.coFac;
GenPolynomialRing cfac = (GenPolynomialRing) rrfac;
GenPolynomialRing dfac = cfac.extend(rfac.nvar);
GenPolynomial Pd = PolyUtil. distribute(dfac, P);
GenPolynomial Sd = PolyUtil. distribute(dfac, S);
GenPolynomial Dd = gcd(Pd, Sd);
// convert to recursive
GenPolynomial> C = PolyUtil. recursive(rfac, Dd);
return C;
}
/**
* Univariate GenPolynomial recursive greatest common divisor. Uses
* pseudoRemainder for remainder.
* @param P univariate recursive GenPolynomial.
* @param S univariate recursive GenPolynomial.
* @return gcd(P,S).
*/
public abstract GenPolynomial> recursiveUnivariateGcd(GenPolynomial> P,
GenPolynomial> S);
/**
* GenPolynomial content.
* @param P GenPolynomial.
* @return cont(P).
*/
public GenPolynomial content(GenPolynomial P) {
if (P == null) {
throw new IllegalArgumentException(this.getClass().getName() + " P != null");
}
GenPolynomialRing pfac = P.ring;
if (pfac.nvar <= 1) {
// baseContent not possible by return type
throw new IllegalArgumentException(this.getClass().getName()
+ " use baseContent for univariate polynomials");
}
GenPolynomialRing cfac = pfac.contract(1);
GenPolynomialRing> rfac = new GenPolynomialRing>(cfac, 1);
GenPolynomial> Pr = PolyUtil. recursive(rfac, P);
GenPolynomial D = recursiveContent(Pr);
return D;
}
/**
* GenPolynomial primitive part.
* @param P GenPolynomial.
* @return pp(P).
*/
public GenPolynomial primitivePart(GenPolynomial P) {
if (P == null) {
throw new IllegalArgumentException(this.getClass().getName() + " P != null");
}
if (P.isZERO()) {
return P;
}
GenPolynomialRing pfac = P.ring;
if (pfac.nvar <= 1) {
return basePrimitivePart(P);
}
GenPolynomialRing cfac = pfac.contract(1);
GenPolynomialRing> rfac = new GenPolynomialRing>(cfac, 1);
GenPolynomial> Pr = PolyUtil. recursive(rfac, P);
GenPolynomial> PP = recursivePrimitivePart(Pr);
GenPolynomial D = PolyUtil. distribute(pfac, PP);
return D;
}
/**
* GenPolynomial division. Indirection to GenPolynomial method.
* @param a GenPolynomial.
* @param b coefficient.
* @return a/b.
*/
public GenPolynomial divide(GenPolynomial a, C b) {
if (b == null || b.isZERO()) {
throw new IllegalArgumentException("division by zero");
}
if (a == null || a.isZERO()) {
return a;
}
return a.divide(b);
}
/**
* Coefficient greatest common divisor. Indirection to coefficient method.
* @param a coefficient.
* @param b coefficient.
* @return gcd(a,b).
*/
public C gcd(C a, C b) {
if (b == null || b.isZERO()) {
return a;
}
if (a == null || a.isZERO()) {
return b;
}
return a.gcd(b);
}
/**
* GenPolynomial greatest common divisor.
* @param P GenPolynomial.
* @param S GenPolynomial.
* @return gcd(P,S).
*/
public GenPolynomial gcd(GenPolynomial P, GenPolynomial S) {
if (S == null || S.isZERO()) {
return P;
}
if (P == null || P.isZERO()) {
return S;
}
GenPolynomialRing pfac = P.ring;
if (pfac.nvar <= 1) {
GenPolynomial T = baseGcd(P, S);
return T;
}
GenPolynomialRing cfac = pfac.contract(1);
GenPolynomialRing> rfac;
if (pfac.getVars() != null && pfac.getVars().length > 0) {
String[] v = new String[] { pfac.getVars()[pfac.nvar - 1] };
rfac = new GenPolynomialRing>(cfac, 1, v);
} else {
rfac = new GenPolynomialRing>(cfac, 1);
}
GenPolynomial> Pr = PolyUtil. recursive(rfac, P);
GenPolynomial> Sr = PolyUtil. recursive(rfac, S);
GenPolynomial> Dr = recursiveUnivariateGcd(Pr, Sr);
GenPolynomial D = PolyUtil. distribute(pfac, Dr);
return D;
}
/**
* GenPolynomial least common multiple.
* @param P GenPolynomial.
* @param S GenPolynomial.
* @return lcm(P,S).
*/
public GenPolynomial lcm(GenPolynomial P, GenPolynomial S) {
if (S == null || S.isZERO()) {
return S;
}
if (P == null || P.isZERO()) {
return P;
}
GenPolynomial C = gcd(P, S);
GenPolynomial A = P.multiply(S);
return PolyUtil. basePseudoDivide(A, C);
}
/**
* List of GenPolynomials greatest common divisor.
* @param A non empty list of GenPolynomials.
* @return gcd(A_i).
*/
public GenPolynomial gcd(List> A) {
if (A == null || A.isEmpty()) {
throw new IllegalArgumentException("A may not be empty");
}
GenPolynomial g = A.get(0);
for (int i = 1; i < A.size(); i++) {
GenPolynomial f = A.get(i);
g = gcd(g, f);
}
return g;
}
/**
* Univariate GenPolynomial resultant.
* @param P univariate GenPolynomial.
* @param S univariate GenPolynomial.
* @return res(P,S).
* @throws UnsupportedOperationException if there is no implementation in
* the sub-class.
*/
@SuppressWarnings("unused")
public GenPolynomial baseResultant(GenPolynomial P, GenPolynomial S) {
// can not be abstract
throw new UnsupportedOperationException("not implmented");
}
/**
* Univariate GenPolynomial recursive resultant.
* @param P univariate recursive GenPolynomial.
* @param S univariate recursive GenPolynomial.
* @return res(P,S).
* @throws UnsupportedOperationException if there is no implementation in
* the sub-class.
*/
@SuppressWarnings("unused")
public GenPolynomial> recursiveUnivariateResultant(GenPolynomial> P,
GenPolynomial> S) {
// can not be abstract
throw new UnsupportedOperationException("not implmented");
}
/**
* GenPolynomial recursive resultant.
* @param P univariate recursive GenPolynomial.
* @param S univariate recursive GenPolynomial.
* @return res(P,S).
* @throws UnsupportedOperationException if there is no implementation in
* the sub-class.
*/
public GenPolynomial> recursiveResultant(GenPolynomial> P,
GenPolynomial> S) {
if (S == null || S.isZERO()) {
return S;
}
if (P == null || P.isZERO()) {
return P;
}
GenPolynomialRing> rfac = P.ring;
GenPolynomialRing cfac = (GenPolynomialRing) rfac.coFac;
GenPolynomialRing dfac = cfac.extend(rfac.getVars());
GenPolynomial Pp = PolyUtil. distribute(dfac, P);
GenPolynomial Sp = PolyUtil. distribute(dfac, S);
GenPolynomial res = resultant(Pp, Sp);
GenPolynomial> Rr = PolyUtil. recursive(rfac, res);
return Rr;
}
/**
* GenPolynomial resultant. The input polynomials are considered as
* univariate polynomials in the main variable.
* @param P GenPolynomial.
* @param S GenPolynomial.
* @return res(P,S).
* @see edu.jas.ufd.GreatestCommonDivisorSubres#recursiveResultant
* @throws UnsupportedOperationException if there is no implementation in
* the sub-class.
*/
public GenPolynomial resultant(GenPolynomial P, GenPolynomial S) {
if (S == null || S.isZERO()) {
return S;
}
if (P == null || P.isZERO()) {
return P;
}
// no more hacked: GreatestCommonDivisorSubres ufd_sr = new GreatestCommonDivisorSubres();
GenPolynomialRing pfac = P.ring;
if (pfac.nvar <= 1) {
return baseResultant(P, S);
}
GenPolynomialRing cfac = pfac.contract(1);
GenPolynomialRing> rfac = new GenPolynomialRing>(cfac, 1);
GenPolynomial> Pr = PolyUtil. recursive(rfac, P);
GenPolynomial> Sr = PolyUtil. recursive(rfac, S);
GenPolynomial> Dr = recursiveUnivariateResultant(Pr, Sr);
GenPolynomial D = PolyUtil. distribute(pfac, Dr);
return D;
}
/**
* GenPolynomial co-prime list.
* @param A list of GenPolynomials.
* @return B with gcd(b,c) = 1 for all b != c in B and for all non-constant
* a in A there exists b in B with b|a. B does not contain zero or
* constant polynomials.
*/
public List> coPrime(List> A) {
if (A == null || A.isEmpty()) {
return A;
}
List> B = new ArrayList>(A.size());
// make a coprime to rest of list
GenPolynomial a = A.get(0);
//System.out.println("a = " + a);
if (!a.isZERO() && !a.isConstant()) {
for (int i = 1; i < A.size(); i++) {
GenPolynomial b = A.get(i);
GenPolynomial g = gcd(a, b).abs();
if (!g.isONE()) {
a = PolyUtil. basePseudoDivide(a, g);
b = PolyUtil. basePseudoDivide(b, g);
GenPolynomial gp = gcd(a, g).abs();
while (!gp.isONE()) {
a = PolyUtil. basePseudoDivide(a, gp);
g = PolyUtil. basePseudoDivide(g, gp);
B.add(g); // gcd(a,g) == 1
g = gp;
gp = gcd(a, gp).abs();
}
if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) {
B.add(g); // gcd(a,g) == 1
}
}
if (!b.isZERO() && !b.isConstant()) {
B.add(b); // gcd(a,b) == 1
}
}
} else {
B.addAll(A.subList(1, A.size()));
}
// make rest coprime
B = coPrime(B);
//System.out.println("B = " + B);
if (!a.isZERO() && !a.isConstant() /*&& !B.contains(a)*/) {
a = a.abs();
B.add(a);
}
return B;
}
/**
* GenPolynomial co-prime list.
* @param A list of GenPolynomials.
* @return B with gcd(b,c) = 1 for all b != c in B and for all non-constant
* a in A there exists b in B with b|a. B does not contain zero or
* constant polynomials.
*/
public List> coPrimeRec(List> A) {
if (A == null || A.isEmpty()) {
return A;
}
List> B = new ArrayList>();
// make a co-prime to rest of list
for (GenPolynomial a : A) {
//System.out.println("a = " + a);
B = coPrime(a, B);
//System.out.println("B = " + B);
}
return B;
}
/**
* GenPolynomial co-prime list.
* @param a GenPolynomial.
* @param P co-prime list of GenPolynomials.
* @return B with gcd(b,c) = 1 for all b != c in B and for non-constant a
* there exists b in P with b|a. B does not contain zero or constant
* polynomials.
*/
public List> coPrime(GenPolynomial a, List> P) {
if (a == null || a.isZERO() || a.isConstant()) {
return P;
}
List> B = new ArrayList>(P.size() + 1);
// make a coprime to elements of the list P
for (int i = 0; i < P.size(); i++) {
GenPolynomial b = P.get(i);
GenPolynomial g = gcd(a, b).abs();
if (!g.isONE()) {
a = PolyUtil. basePseudoDivide(a, g);
b = PolyUtil. basePseudoDivide(b, g);
// make g co-prime to new a, g is co-prime to c != b in P, B
GenPolynomial gp = gcd(a, g).abs();
while (!gp.isONE()) {
a = PolyUtil. basePseudoDivide(a, gp);
g = PolyUtil. basePseudoDivide(g, gp);
if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) {
B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B
}
g = gp;
gp = gcd(a, gp).abs();
}
// make new g co-prime to new b
gp = gcd(b, g).abs();
while (!gp.isONE()) {
b = PolyUtil. basePseudoDivide(b, gp);
g = PolyUtil. basePseudoDivide(g, gp);
if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) {
B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B
}
g = gp;
gp = gcd(b, gp).abs();
}
if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) {
B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B
}
}
if (!b.isZERO() && !b.isConstant() /*&& !B.contains(b)*/) {
B.add(b); // gcd(a,b) == 1 and gcd(b,c) == 1 for c != b in P, B
}
}
if (!a.isZERO() && !a.isConstant() /*&& !B.contains(a)*/) {
B.add(a);
}
return B;
}
/**
* GenPolynomial test for co-prime list.
* @param A list of GenPolynomials.
* @return true if gcd(b,c) = 1 for all b != c in B, else false.
*/
public boolean isCoPrime(List> A) {
if (A == null || A.isEmpty()) {
return true;
}
if (A.size() == 1) {
return true;
}
for (int i = 0; i < A.size(); i++) {
GenPolynomial a = A.get(i);
for (int j = i + 1; j < A.size(); j++) {
GenPolynomial b = A.get(j);
GenPolynomial g = gcd(a, b);
if (!g.isONE()) {
System.out.println("not co-prime, a: " + a);
System.out.println("not co-prime, b: " + b);
System.out.println("not co-prime, g: " + g);
return false;
}
}
}
return true;
}
/**
* GenPolynomial test for co-prime list of given list.
* @param A list of GenPolynomials.
* @param P list of co-prime GenPolynomials.
* @return true if isCoPrime(P) and for all a in A exists p in P with p | a,
* else false.
*/
public boolean isCoPrime(List> P, List> A) {
if (!isCoPrime(P)) {
return false;
}
if (A == null || A.isEmpty()) {
return true;
}
for (GenPolynomial q : A) {
if (q.isZERO() || q.isConstant()) {
continue;
}
boolean divides = false;
for (GenPolynomial p : P) {
GenPolynomial a = PolyUtil. baseSparsePseudoRemainder(q, p);
if (a.isZERO()) { // p divides q
divides = true;
break;
}
}
if (!divides) {
System.out.println("no divisor for: " + q);
return false;
}
}
return true;
}
/**
* Univariate GenPolynomial extended greatest common divisor. Uses sparse
* pseudoRemainder for remainder.
* @param P univariate GenPolynomial.
* @param S univariate GenPolynomial.
* @return [ gcd(P,S), a, b ] with a*P + b*S = gcd(P,S).
*/
@SuppressWarnings("unchecked")
public GenPolynomial[] baseExtendedGcd(GenPolynomial P, GenPolynomial S) {
//return P.egcd(S);
GenPolynomial[] hegcd = baseHalfExtendedGcd(P, S);
GenPolynomial[] ret = (GenPolynomial[]) new GenPolynomial[3];
ret[0] = hegcd[0];
ret[1] = hegcd[1];
GenPolynomial x = hegcd[0].subtract(hegcd[1].multiply(P));
GenPolynomial[] qr = PolyUtil. basePseudoQuotientRemainder(x, S);
// assert qr[1].isZERO()
ret[2] = qr[0];
return ret;
}
/**
* Univariate GenPolynomial half extended greatest comon divisor. Uses
* sparse pseudoRemainder for remainder.
* @param S GenPolynomial.
* @return [ gcd(P,S), a ] with a*P + b*S = gcd(P,S).
*/
@SuppressWarnings("unchecked")
public GenPolynomial[] baseHalfExtendedGcd(GenPolynomial P, GenPolynomial S) {
//if ( P == null ) {
// throw new IllegalArgumentException("null P not allowed");
//}
GenPolynomial[] ret = (GenPolynomial[]) new GenPolynomial[2];
ret[0] = null;
ret[1] = null;
if (S == null || S.isZERO()) {
ret[0] = P;
ret[1] = P.ring.getONE();
return ret;
}
if (P == null || P.isZERO()) {
ret[0] = S;
ret[1] = S.ring.getZERO();
return ret;
}
if (P.ring.nvar != 1) {
throw new IllegalArgumentException(this.getClass().getName() + " not univariate polynomials "
+ P.ring);
}
GenPolynomial q = P;
GenPolynomial r = S;
GenPolynomial c1 = P.ring.getONE().copy();
GenPolynomial d1 = P.ring.getZERO().copy();
while (!r.isZERO()) {
GenPolynomial[] qr = PolyUtil. basePseudoQuotientRemainder(q, r);
//q.divideAndRemainder(r);
q = qr[0];
GenPolynomial x = c1.subtract(q.multiply(d1));
c1 = d1;
d1 = x;
q = r;
r = qr[1];
}
// normalize ldcf(q) to 1, i.e. make monic
C g = q.leadingBaseCoefficient();
if (g.isUnit()) {
C h = g.inverse();
q = q.multiply(h);
c1 = c1.multiply(h);
}
//assert ( ((c1.multiply(P)).remainder(S).equals(q) ));
ret[0] = q;
ret[1] = c1;
return ret;
}
/**
* Univariate GenPolynomial greatest common divisor diophantine version.
* @param P univariate GenPolynomial.
* @param S univariate GenPolynomial.
* @param c univariate GenPolynomial.
* @return [ a, b ] with a*P + b*S = c and deg(a) < deg(S).
*/
@SuppressWarnings("unchecked")
public GenPolynomial[] baseGcdDiophant(GenPolynomial P, GenPolynomial S, GenPolynomial c) {
GenPolynomial[] egcd = baseExtendedGcd(P, S);
GenPolynomial g = egcd[0];
GenPolynomial[] qr = PolyUtil. basePseudoQuotientRemainder(c, g);
if (!qr[1].isZERO()) {
throw new ArithmeticException("not solvable, r = " + qr[1] + ", c = " + c + ", g = " + g);
}
GenPolynomial q = qr[0];
GenPolynomial a = egcd[1].multiply(q);
GenPolynomial b = egcd[2].multiply(q);
if (!a.isZERO() && a.degree(0) >= S.degree(0)) {
qr = PolyUtil. basePseudoQuotientRemainder(a, S);
a = qr[1];
b = b.sum(P.multiply(qr[0]));
}
GenPolynomial[] ret = (GenPolynomial[]) new GenPolynomial[2];
ret[0] = a;
ret[1] = b;
if (debug) {
GenPolynomial y = ret[0].multiply(P).sum(ret[1].multiply(S));
if (!y.equals(c)) {
System.out.println("P = " + P);
System.out.println("S = " + S);
System.out.println("c = " + c);
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("y = " + y);
throw new ArithmeticException("not diophant, x = " + y.subtract(c));
}
}
return ret;
}
/**
* Univariate GenPolynomial partial fraction decomposition.
* @param A univariate GenPolynomial.
* @param P univariate GenPolynomial.
* @param S univariate GenPolynomial.
* @return [ A0, Ap, As ] with A/(P*S) = A0 + Ap/P + As/S with deg(Ap) <
* deg(P) and deg(As) < deg(S).
*/
@SuppressWarnings("unchecked")
public GenPolynomial[] basePartialFraction(GenPolynomial A, GenPolynomial P, GenPolynomial S) {
GenPolynomial[] ret = (GenPolynomial[]) new GenPolynomial[3];
ret[0] = null;
ret[1] = null;
ret[2] = null;
GenPolynomial ps = P.multiply(S);
GenPolynomial[] qr = PolyUtil. basePseudoQuotientRemainder(A, ps);
ret[0] = qr[0];
GenPolynomial r = qr[1];
GenPolynomial[] diop = baseGcdDiophant(S, P, r); // switch arguments
// GenPolynomial x = diop[0].multiply(S).sum( diop[1].multiply(P) );
// if ( !x.equals(r) ) {
// System.out.println("r = " + r);
// System.out.println("x = " + x);
// throw new RuntimeException("not partial fraction, x = " + x);
// }
ret[1] = diop[0];
ret[2] = diop[1];
if (ret[1].degree(0) >= P.degree(0)) {
qr = PolyUtil. basePseudoQuotientRemainder(ret[1], P);
ret[0] = ret[0].sum(qr[0]);
ret[1] = qr[1];
}
if (ret[2].degree(0) >= S.degree(0)) {
qr = PolyUtil. basePseudoQuotientRemainder(ret[2], S);
ret[0] = ret[0].sum(qr[0]);
ret[2] = qr[1];
}
return ret;
}
/**
* Univariate GenPolynomial partial fraction decomposition.
* @param A univariate GenPolynomial.
* @param P univariate GenPolynomial.
* @param e exponent for P.
* @return [ F0, F1, ..., Fe ] with A/(P^e) = sum( Fi / P^i ) with deg(Fi) <
* deg(P).
*/
public List> basePartialFraction(GenPolynomial A, GenPolynomial P, int e) {
if (A == null || P == null || e == 0) {
throw new IllegalArgumentException("null A, P or e = 0 not allowed");
}
List> pf = new ArrayList>(e);
if (A.isZERO()) {
for (int i = 0; i < e; i++) {
pf.add(A);
}
return pf;
}
if (e == 1) {
GenPolynomial[] qr = PolyUtil. basePseudoQuotientRemainder(A, P);
pf.add(qr[0]);
pf.add(qr[1]);
return pf;
}
GenPolynomial a = A;
for (int j = e; j > 0; j--) {
GenPolynomial[] qr = PolyUtil. basePseudoQuotientRemainder(a, P);
a = qr[0];
pf.add(0, qr[1]);
}
pf.add(0, a);
return pf;
}
/**
* Univariate GenPolynomial partial fraction decomposition.
* @param A univariate GenPolynomial.
* @param D list of co-prime univariate GenPolynomials.
* @return [ A0, A1,..., An ] with A/prod(D) = A0 + sum( Ai/Di ) with
* deg(Ai) < deg(Di).
*/
public List> basePartialFraction(GenPolynomial A, List> D) {
if (D == null || A == null) {
throw new IllegalArgumentException("null A or D not allowed");
}
List> pf = new ArrayList>(D.size() + 1);
if (A.isZERO() || D.size() == 0) {
pf.add(A);
for (int i = 0; i < D.size(); i++) {
pf.add(A);
}
return pf;
}
List> Dp = new ArrayList>(D.size() - 1);
GenPolynomial P = A.ring.getONE();
GenPolynomial d1 = null;
for (GenPolynomial d : D) {
if (d1 == null) {
d1 = d;
} else {
P = P.multiply(d);
Dp.add(d);
}
}
GenPolynomial[] qr = PolyUtil. basePseudoQuotientRemainder(A, P.multiply(d1));
GenPolynomial A0 = qr[0];
GenPolynomial r = qr[1];
if (D.size() == 1) {
pf.add(A0);
pf.add(r);
return pf;
}
GenPolynomial[] diop = baseGcdDiophant(P, d1, r); // switch arguments
GenPolynomial A1 = diop[0];
GenPolynomial S = diop[1];
List> Fr = basePartialFraction(S, Dp);
A0 = A0.sum(Fr.remove(0));
pf.add(A0);
pf.add(A1);
pf.addAll(Fr);
return pf;
}
/**
* Test for Univariate GenPolynomial partial fraction decomposition.
* @param A univariate GenPolynomial.
* @param D list of (co-prime) univariate GenPolynomials.
* @param F list of univariate GenPolynomials from a partial fraction
* computation.
* @return true if A/prod(D) = F0 + sum( Fi/Di ) with deg(Fi) < deg(Di), Fi
* in F, else false.
*/
public boolean isBasePartialFraction(GenPolynomial A, List> D,
List> F) {
if (D == null || A == null || F == null) {
throw new IllegalArgumentException("null A, F or D not allowed");
}
if (D.size() != F.size() - 1) {
return false;
}
// A0*prod(D) + sum( Ai * Dip ), Dip = prod(D,j!=i)
GenPolynomial P = A.ring.getONE();
for (GenPolynomial