WarpPI/core/src/main/java/org/nevec/rjm/RatPoly.java

1046 lines
26 KiB
Java

package org.nevec.rjm;
import java.math.BigInteger;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.Random;
import java.util.Scanner;
import java.util.Vector;
import it.cavallium.warppi.util.Error;
/**
* A one-parameter polynomial with rational coefficients.
* Alternatively to be interpreted as a sequence which has the polynomial as an
* (approximate)
* generating function.
*
* @since 2006-06-25
* @author Richard J. Mathar
*/
class RatPoly {
/**
* The list of all coefficients, ascending exponents. Starting with a0, then
* a1, representing
* a value a0+a1*x+a2*x^2+a3*x^3+...
*/
protected Vector<Rational> a;
/**
* Default ctor.
* Initializes the zero-valued polynomial x=0.
*/
public RatPoly() {
a = new Vector<>();
} /* ctor */
/**
* Constructor with an explicit list of coefficients.
*
* @param L
* the coefficients a0, a1, a2, a3,.., A deep copy of the these
* is created.
*/
public RatPoly(final Vector<Rational> L) {
a = new Vector<>();
for (int i = 0; i < L.size(); i++) {
a.add(L.elementAt(i).clone());
}
simplify();
} /* ctor */
/**
* Constructor with a comma-separated list as the list of coefficients.
*
* @param L
* the string of the form a0,a1,a2,a3 with the coefficients
*/
public RatPoly(final String L) throws NumberFormatException {
a = new Vector<>();
final Scanner sc = new Scanner(L);
sc.useDelimiter(",");
while (sc.hasNext()) {
final String tok = sc.next();
a.add(new Rational(tok));
}
simplify();
sc.close();
} /* ctor */
/**
* Constructor from a hypergeometric series.
*
* @param A
* the list of values in the numerator of AFB
* @param B
* the list of values in the denominator of AFB
* @param nmax
* the order of the truncated polynomial representation
* @throws Error
* @since 2008-11-13
*/
public RatPoly(final Vector<BigInteger> A, final Vector<BigInteger> B, final int nmax) throws Error {
/*
* To allow common initialization with the signature below,
* the main body is assembled in a separate function.
*/
init(A, B, nmax);
}
/**
* Constructor from a hypergeometric series.
*
* @param A
* the list of values in the numerator of AFB.
* At least one of these values must be a negative integer, which
* implicitly determines
* the order of the new polynomial.
* @param B
* the list of values in the denominator of AFB
* @throws Error
* @since 2009-08-05
*/
public RatPoly(final Vector<BigInteger> A, final Vector<BigInteger> B) throws Error {
BigInteger Nmax = BigInteger.ONE.negate();
for (int j = 0; j < A.size(); j++) {
if (A.elementAt(j).compareTo(BigInteger.ZERO) <= 0) {
if (Nmax.compareTo(BigInteger.ZERO) < 0) {
Nmax = A.elementAt(j).negate();
} else {
Nmax = Nmax.min(A.elementAt(j).negate());
}
}
}
if (Nmax.compareTo(BigInteger.ZERO) < 0) {
throw new ArithmeticException("Infinite Number of Terms in Series " + Nmax.toString());
}
final int nmax = Nmax.intValue() - 1;
init(A, B, nmax);
} /* ctor */
/**
* Constructor from a hypergeometric series.
*
* @param A
* the list of values in the numerator of AFB
* @param B
* the list of values in the denominator of AFB
* @param nmax
* the order of the truncated polynomial representation
* @throws Error
* @since 2008-11-13
*/
protected void init(final Vector<BigInteger> A, final Vector<BigInteger> B, final int nmax) throws Error {
a = new Vector<>();
final Factorial f = new Factorial();
for (int n = 0; n <= nmax; n++) {
Rational c = new Rational(1, 1);
for (int j = 0; j < A.size(); j++) {
final Rational aEl = new Rational(A.elementAt(j));
c = c.multiply(aEl.Pochhammer(n));
}
for (int j = 0; j < B.size(); j++) {
final Rational bEl = new Rational(B.elementAt(j));
c = c.divide(bEl.Pochhammer(n));
}
c = c.divide(f.at(n));
a.add(c);
}
simplify();
} /* init */
/**
* Create a copy of this.
*
* @since 2008-11-07
*/
@Override
@SuppressWarnings("unchecked")
public RatPoly clone() {
final RatPoly clo = new RatPoly();
clo.a = (Vector<Rational>) a.clone();
return clo;
} /* clone */
/**
* Retrieve a polynomial coefficient.
*
* @param n
* the zero-based index of the coefficient. n=0 for the constant
* term.
* @return the polynomial coefficient in front of x^n.
*/
public Rational at(final int n) {
if (n < a.size()) {
return a.elementAt(n);
} else {
return new Rational(0, 1);
}
} /* at */
/**
* Horner scheme to find the function value at the argument x
*
* @param x
* The argument of the polynomial
* @param mc
* The context determining the precision of the value returned.
* @since 2008-10-26
*/
public BigComplex valueOf(final BigComplex x, final MathContext mc) {
/* result is initialized to zero */
BigComplex f = new BigComplex();
for (int i = degree(); i >= 0; i--) {
f = f.multiply(x, mc).add(a.elementAt(i).BigDecimalValue(mc));
}
return f;
} /* valueOf */
/**
* Horner scheme to find the function value at the argument x
*
* @param x
* The argument of the polynomial
* @since 2008-11-13
*/
public Rational valueOf(final Rational x) {
/* result is initialized to zero */
Rational f = new Rational(0, 1);
for (int i = degree(); i >= 0; i--) {
f = f.multiply(x).add(a.elementAt(i));
}
return f;
} /* valueOf */
/**
* Horner scheme to find the function value at the argument x
*
* @param x
* The argument of the polynomial
* @since 2008-11-13
*/
public Rational valueOf(final int x) {
return valueOf(new Rational(x, 1));
} /* valueOf */
/**
* Horner scheme to evaluate the function at the argument x
*
* @param x
* The argument of the polynomial
* @since 2010-08-27
*/
public Rational valueOf(final BigInteger x) {
return valueOf(new Rational(x));
} /* valueOf */
/*
* Set a polynomial coefficient.
*
* @param n the zero-based index of the coefficient. n=0 for the constant
* term.
* If the polynomial has not yet the degree to need this coefficient,
* the intermediate coefficients are implicitly set to zero.
*
* @param value the new value of the coefficient.
*/
public void set(final int n, final Rational value) {
if (n < a.size()) {
a.set(n, value);
} else {
/*
* fill intermediate powers with coefficients of zero
*/
while (a.size() < n) {
a.add(new Rational(0, 1));
}
a.add(value);
}
} /* set */
/**
* Set a polynomial coefficient.
*
* @param n
* the zero-based index of the coefficient. n=0 for the constant
* term.
* If the polynomial has not yet the degree to need this
* coefficient,
* the intermediate coefficients are implicitly set to zero.
* @param value
* the new value of the coefficient.
*/
public void set(final int n, final BigInteger value) {
final Rational val2 = new Rational(value, BigInteger.ONE);
set(n, val2);
} /* set */
/**
* Set a polynomial coefficient.
*
* @param n
* the zero-based index of the coefficient. n=0 for the constant
* term.
* If the polynomial has not yet the degree to need this
* coefficient,
* the intermediate coefficients are implicitly set to zero.
* @param value
* the new value of the coefficient.
*/
public void set(final int n, final int value) {
final Rational val2 = new Rational(value, 1);
set(n, val2);
} /* set */
/*
* Set to the taylor series of exp(x) up to degree nmax.
*
* @param nmax the maximum polynomial degree
*/
public void setExp(final int nmax) {
a.clear();
final Factorial factorial = new Factorial();
for (int n = 0; n <= nmax; n++) {
set(n, new Rational(BigInteger.ONE, factorial.at(n)));
}
} /* setExp */
/**
* Set to the taylor series representing 0+x.
*/
public void setx() {
a.clear();
/* coefficient 0/1=0 */
a.add(new Rational(0, 1));
/* coefficient 1/1=1 */
a.add(new Rational(1, 1));
} /* setx */
/**
* Count of coefficients. One more than the degree of the polynomial.
*
* @return the number of polynomial coefficients.
*/
public int size() {
return a.size();
} /* size */
/**
* Polynomial degree.
*
* @return the polynomial degree.
*/
public int degree() {
return a.size() - 1;
} /* degree */
/**
* Lower Polynomial degree.
*
* @return The smallest exponent n such that [x^n] of the polynomial is
* nonzero.
* If the polynmial is identical zero, the result is (still) 0.
* @since 2010-08-27
*/
public int ldegree() {
for (int n = 0; n < a.size(); n++) {
if (a.elementAt(n).compareTo(BigInteger.ZERO) != 0) {
return n;
}
}
return 0;
} /* ldegree */
/**
* Multiply by a constant factor.
*
* @param val
* the factor
* @return the product of this with the factor.
* All coefficients of this have been multiplied individually by the
* factor.
*/
public RatPoly multiply(final Rational val) {
final RatPoly resul = new RatPoly();
if (val.compareTo(BigInteger.ZERO) != 0) {
for (int n = 0; n < a.size(); n++) {
resul.set(n, a.elementAt(n).multiply(val));
}
}
return resul;
} /* multiply */
/**
* Multiply by a constant factor.
*
* @param val
* the factor
* @return the product of this with the factor.
* All coefficients of this have been multiplied individually by the
* factor.
* @since 2010-08-27
*/
public RatPoly multiply(final BigInteger val) {
final RatPoly resul = new RatPoly();
if (val.compareTo(BigInteger.ZERO) != 0) {
for (int n = 0; n < a.size(); n++) {
resul.set(n, a.elementAt(n).multiply(val));
}
}
return resul;
} /* multiply */
/**
* Multiply by another polynomial
*
* @param val
* the other polynomial
* @return the product of this with the other polynomial
*/
public RatPoly multiply(final RatPoly val) {
final RatPoly resul = new RatPoly();
/*
* the degree of the result is the sum of the two degrees.
*/
final int nmax = degree() + val.degree();
for (int n = 0; n <= nmax; n++) {
Rational coef = new Rational(0, 1);
for (int nleft = 0; nleft <= n; nleft++) {
coef = coef.add(at(nleft).multiply(val.at(n - nleft)));
}
resul.set(n, coef);
}
resul.simplify();
return resul;
} /* multiply */
/**
* Raise to a positive power.
*
* @param n
* The non-negative exponent of the power
* @return The n-th power of this.
*/
public RatPoly pow(final int n) throws ArithmeticException {
RatPoly resul = new RatPoly("1");
if (n < 0) {
throw new ArithmeticException("negative polynomial power " + n);
} else {
/*
* this ought probably be done with some binary representation
* of the power and a smaller number of multiplications.
*/
for (int i = 1; i <= n; i++) {
resul = resul.multiply(this);
}
resul.simplify();
return resul;
}
} /* pow */
/**
* Raise to a rational power.
* The result is the taylor expansion of this, truncated at the first
* term that remains undetermined based on the current number of
* coefficients.
*
* @param r
* the exponent of the power
* @return This^r .
* @throws Error
* @since 2009-05-18
*/
public RatPoly pow(final Rational r) throws ArithmeticException, Error {
/*
* split (a0+a1*x+a2*x^2+...)^r = a0^r*(1+a1/a0*r+a2/a0*r^2+..)^r
*/
Rational f = at(0);
f = f.pow(r);
/*
* scale the polynomial by division through the expansion coefficient of
* the absolute term
*/
final RatPoly red = divide(a.elementAt(0));
/*
* and remove the leading term (now equal to 1)
*/
red.set(0, 0);
/*
* Binomial expansion of the rest. sum_{l=0..infinity}
* binomial(r,l)*red^l
*/
RatPoly resul = new RatPoly("1");
final int d = degree();
for (int l = 1; l <= d; l++) {
final Rational b = Rational.binomial(r, l);
resul = resul.add(red.pow(l).multiply(b));
}
return resul.multiply(f);
} /* pow */
/**
* Add another polynomial
*
* @param val
* The other polynomial
* @return The sum of this and the other polynomial
* @since 2008-10-25
*/
public RatPoly add(final RatPoly val) {
final RatPoly resul = new RatPoly();
/*
* the degree of the result is the larger of the two degrees (before
* simplify() at least).
*/
final int nmax = degree() > val.degree() ? degree() : val.degree();
for (int n = 0; n <= nmax; n++) {
final Rational coef = at(n).add(val.at(n));
resul.set(n, coef);
}
resul.simplify();
return resul;
} /* add */
/**
* Subtract another polynomial
*
* @param val
* The other polynomial
* @return The difference between this and the other polynomial
* @since 2008-10-25
*/
public RatPoly subtract(final RatPoly val) {
final RatPoly resul = new RatPoly();
/*
* the degree of the result is the larger of the two degrees (before
* simplify() at least).
*/
final int nmax = degree() > val.degree() ? degree() : val.degree();
for (int n = 0; n <= nmax; n++) {
final Rational coef = at(n).subtract(val.at(n));
resul.set(n, coef);
}
resul.simplify();
return resul;
} /* subtract */
/**
* Divide by a constant.
*
* @param val
* the constant through which the coefficients will be divided.
* @return the Taylor expansion of this/val .
* @throws Error
* @since 2009-05-18
*/
public RatPoly divide(final Rational val) throws Error {
if (val.compareTo(Rational.ZERO) != 0) {
final RatPoly resul = new RatPoly();
for (int n = 0; n < a.size(); n++) {
resul.set(n, a.elementAt(n).divide(val));
}
return resul;
} else {
throw new ArithmeticException("Cannot divide " + toPString() + " through zero.");
}
} /* divide */
/**
* Divide by another polynomial.
*
* @param val
* the other polynomial
* @param nmax
* the maximum degree of the Taylor expansion of the result.
* @return the Taylor expansion of this/val up to degree nmax.
* @throws Error
*/
public RatPoly divide(final RatPoly val, final int nmax) throws Error {
final RatPoly num = this;
final RatPoly denom = val;
/*
* divide by a common smallest power/degree
*/
while (num.at(0).compareTo(BigInteger.ZERO) == 0 && denom.at(0).compareTo(BigInteger.ZERO) == 0) {
num.a.remove(0);
denom.a.remove(0);
if (num.size() <= 1 || denom.size() <= 1) {
break;
}
}
final RatPoly resul = new RatPoly();
/*
* todo: If the polynomial division is exact, we could leave
* the loop earlier, indeed
*/
for (int n = 0; n <= nmax; n++) {
Rational coef = num.at(n);
for (int nres = 0; nres < n; nres++) {
coef = coef.subtract(resul.at(nres).multiply(denom.at(n - nres)));
}
coef = coef.divide(denom.at(0));
resul.set(n, coef);
}
resul.simplify();
return resul;
} /* divide */
/**
* Divide by another polynomial.
*
* @param val
* the other polynomial
* @return A vector with [0] containg the polynomial of degree which is the
* difference of thisdegree and the degree of val. [1] the remainder
* polynomial.
* This = returnvalue[0] + returnvalue[1]/val .
* @throws Error
* @since 2012-03-01
*/
public RatPoly[] divideAndRemainder(final RatPoly val) throws Error {
final RatPoly[] ret = new RatPoly[2];
/*
* remove any high-order zeros
*/
final RatPoly valSimpl = val.clone();
valSimpl.simplify();
final RatPoly thisSimpl = clone();
thisSimpl.simplify();
/*
* catch the case with val equal to zero
*/
if (valSimpl.degree() == 0 && valSimpl.a.firstElement().compareTo(Rational.ZERO) == 0) {
throw new ArithmeticException("Division through zero polynomial");
}
/*
* degree of this smaller than degree of val: remainder is this
*/
if (thisSimpl.degree() < valSimpl.degree()) {
/*
* leading polynomial equals zero
*/
ret[0] = new RatPoly();
ret[1] = thisSimpl;
} else {
/*
* long division. Highest degree by dividing the highest degree
* of this thru val.
*/
ret[0] = new RatPoly();
ret[0].set(thisSimpl.degree() - valSimpl.degree(), thisSimpl.a.lastElement().divide(valSimpl.a.lastElement()));
/*
* recurrences: build this - val*(1-termresult) and feed this
* into another round of division. Have intermediate
* ret[0]+ret[1]/val.
*/
ret[1] = thisSimpl.subtract(ret[0].multiply(valSimpl));
/*
* any remainder left ?
*/
if (ret[1].degree() < valSimpl.degree()) {
;
} else {
final RatPoly rem[] = ret[1].divideAndRemainder(val);
ret[0] = ret[0].add(rem[0]);
ret[1] = rem[1];
}
}
return ret;
} /* divideAndRemainder */
/**
* Print as a comma-separated list of coefficients.
*
* @return The representation a0,a1,a2,a3,...
* This is a sort of opposite of the ctor that takes a string as an
* argument.
* @since 2008-10-25
*/
@Override
public String toString() {
String str = new String();
for (int n = 0; n < a.size(); n++) {
if (n == 0) {
str += a.elementAt(n).toString();
} else {
str += "," + a.elementAt(n).toString();
}
}
/*
* print at least a sole zero
*/
if (str.length() == 0) {
str = "0";
}
return str;
} /* toString */
/**
* Print as a polyomial in x.
*
* @return To representation a0+a1*x+a2*x^2+...
* This does not print the terms with coefficients equal to zero.
* @since 2008-10-26
*/
public String toPString() {
String str = new String();
for (int n = 0; n < a.size(); n++) {
final BigInteger num = a.elementAt(n).a;
if (num.compareTo(BigInteger.ZERO) != 0) {
str += " ";
if (num.compareTo(BigInteger.ZERO) > 0) {
str += "+";
}
str += a.elementAt(n).toString();
if (n > 0) {
str += "*x";
if (n > 1) {
str += "^" + n;
}
}
}
}
/*
* print at least a sole zero
*/
if (str.length() == 0) {
str = "0";
}
return str;
} /* toPString */
/**
* Simplify the representation.
* Trailing values with zero coefficients (at high powers) are deleted.
* This modifies the polynomial on the stop (does not return another
* instance)
*/
private void simplify() {
int n = a.size() - 1;
if (n >= 0) {
while (a.elementAt(n).compareTo(BigInteger.ZERO) == 0) {
a.remove(n);
if (--n < 0) {
break;
}
}
}
} /* simplify */
/**
* First derivative.
*
* @return The first derivative with respect to the indeterminate variable.
* @since 2008-10-26
*/
public RatPoly derive() {
if (a.size() <= 1) {
/*
* derivative of the constant is just zero
*/
return new RatPoly();
} else {
final RatPoly d = new RatPoly();
for (int i = 1; i <= degree(); i++) {
final Rational c = a.elementAt(i).multiply(i);
d.set(i - 1, c);
}
return d;
}
} /* derive */
/**
* Scale coefficients such that the coefficient in front of the maximum
* degree is unity.
*
* @return The scaled polynomial
* @throws Error
* @since 2008-10-26
*/
public RatPoly monic() throws Error {
final RatPoly m = new RatPoly();
final int d = degree();
for (int i = 0; i <= d; i++) {
final Rational c = a.elementAt(i).divide(a.elementAt(d));
m.set(i, c);
}
return m;
} /* monic */
/**
* Mobius transform.
*
* @param maxdeg
* the maximum polynomial degree of the result
* @return the sequence of coefficients is the Mobius transform of the
* original sequence.
* @since 2008-12-02
*/
public RatPoly mobiusT(final int maxdeg) {
/*
* Start with the polynomial 0
*/
final RatPoly r = new RatPoly();
for (int i = 1; i <= maxdeg; i++) {
Rational c = new Rational();
for (int d = 1; d <= i && d < a.size(); d++) {
if (i % d == 0) {
final Ifactor m = new Ifactor(i / d);
c = c.add(a.elementAt(d).multiply(m.moebius()));
}
}
r.set(i, c);
}
r.simplify();
return r;
} /* mobiusT */
/**
* Inverse Mobius transform.
*
* @param maxdeg
* the maximum polynomial degree of the result
* @return the sequence of coefficients is the inverse Mobius transform of
* the original sequence.
* @since 2008-12-02
*/
public RatPoly mobiusTInv(final int maxdeg) {
/*
* Start with the polynomial 0
*/
final RatPoly r = new RatPoly();
for (int i = 1; i <= maxdeg; i++) {
Rational c = new Rational();
for (int d = 1; d <= i && d < a.size(); d++) {
if (i % d == 0) {
c = c.add(a.elementAt(d));
}
}
r.set(i, c);
}
r.simplify();
return r;
} /* mobiusTInv */
/**
* Binomial transform.
*
* @param maxdeg
* the maximum polynomial degree of the result
* @return the sequence of coefficients is the binomial transform of the
* original sequence.
* @since 2008-10-26
*/
public RatPoly binomialT(final int maxdeg) {
final RatPoly r = new RatPoly();
for (int i = 0; i <= maxdeg; i++) {
Rational c = new Rational(0, 1);
for (int j = 0; j <= i && j < a.size(); j++) {
c = c.add(a.elementAt(j).multiply(BigIntegerMath.binomial(i, j)));
}
r.set(i, c);
}
r.simplify();
return r;
} /* binomialT */
/**
* Inverse Binomial transform.
*
* @param maxdeg
* the maximum polynomial degree of the result
* @return the sequence of coefficients is the inverse binomial transform of
* the original sequence.
* @since 2008-10-26
*/
public RatPoly binomialTInv(final int maxdeg) {
final RatPoly r = new RatPoly();
for (int i = 0; i <= maxdeg; i++) {
Rational c = new Rational(0, 1);
for (int j = 0; j <= i && j < a.size(); j++) {
if ((j + i) % 2 != 0) {
c = c.subtract(a.elementAt(j).multiply(BigIntegerMath.binomial(i, j)));
} else {
c = c.add(a.elementAt(j).multiply(BigIntegerMath.binomial(i, j)));
}
}
r.set(i, c);
}
r.simplify();
return r;
} /* binomialTInv */
/**
* Truncate polynomial degree.
*
* @param newdeg
* The maximum degree of the result.
* @return The polynomial with all coefficients beyond deg set to zero.
* If newdeg =3, for example the polynomial returned has at most
* degree 3.
* If newdeg is larger than the degree of this, zeros (at the higher
* orders of x)
* are appended. That polynomial would have formal degree larger
* than this.
* @since 2008-10-26
*/
public RatPoly trunc(final int newdeg) {
final RatPoly t = new RatPoly();
for (int i = 0; i <= newdeg; i++) {
t.set(i, at(i));
}
t.simplify();
return t;
} /* trunc */
/**
* Generate the roots of the polynomial in floating point arithmetic.
*
* @see <a href="http://en.wikipedia.org/wiki/Durand-Kerner_method">Durand
* Kerner method</a>
* @param the
* number of floating point digits
* @throws Error
* @since 2008-10-26
*/
public Vector<BigComplex> roots(final int digits) throws Error {
final RatPoly mon = monic();
final Random rand = new Random();
final MathContext mc = new MathContext(digits + 3, RoundingMode.DOWN);
Vector<BigComplex> res = new Vector<>();
final int d = mon.degree();
double randRad = 0.;
for (int i = 0; i <= d; i++) {
/* scale coefficient at maximum degree */
final double absi = Math.abs(mon.at(i).doubleValue());
if (absi > randRad) {
randRad = absi;
}
}
randRad += 1.0;
/*
* initial values randomly in radius 1+randRad
*/
for (int i = 0; i < d; i++) {
final double rad = randRad * rand.nextDouble();
final double phi = 2.0 * 3.14159 * rand.nextDouble();
res.add(i, new BigComplex(rad * Math.cos(phi), rad * Math.sin(phi)));
}
/*
* iterate until convr indicates that all values changed by less than
* the digits
* precision indicates.
*/
boolean convr = false;
for (; !convr;)// ORIGINAL LINE: for(int itr =0 ; ! convr ; itr++)
{
convr = true;
final Vector<BigComplex> resPlus = new Vector<>();
for (int v = 0; v < d; v++) {
/*
* evaluate f(x)/(x-root1)/(x-root2)/... (x-rootdegr), Newton
* method
*/
BigComplex thisx = res.elementAt(v);
BigComplex nv = mon.valueOf(thisx, mc);
for (int j = 0; j < d; j++) {
if (j != v) {
nv = nv.divide(thisx.subtract(res.elementAt(j)), mc);
}
}
/* is this value converged ? */
if (nv.abs(mc).doubleValue() > thisx.abs(mc).doubleValue() * Math.pow(10.0, -digits)) {
convr = false;
}
thisx = thisx.subtract(nv);
/* If unstable, start over */
if (thisx.abs(MathContext.DECIMAL32).doubleValue() > randRad) {
return roots(digits);
}
resPlus.add(thisx);
}
res = resPlus;
}
return res;
} /* roots */
/**
* Generate the integer roots of the polynomial.
*
* @return The vector of integer roots, with multiplicity.
* The shows alternatingly first a root then its multiplicty, then
* another root and multiplicty etc.
* @since 2008-10-26
*/
public Vector<BigInteger> iroots() {
/* The vector of the roots */
final Vector<BigInteger> res = new Vector<>();
final int lowd = ldegree();
if (lowd == 0 && a.elementAt(0).compareTo(BigInteger.ZERO) == 0) {
/*
* Case of polynomial identical to zero:
* reported as a simple root of value 0.
*/
res.add(BigInteger.ZERO);
res.add(BigInteger.ONE);
return res;
}
/*
* multiply all coefs with the lcm() to get an integer polynomial
* start with denominator of first non-zero coefficient.
*/
BigInteger lcmDeno = a.elementAt(lowd).b;
for (int i = lowd + 1; i < degree(); i++) {
lcmDeno = BigIntegerMath.lcm(lcmDeno, a.elementAt(i).b);
}
/*
* and eventually get the integer polynomial by ignoring the
* denominators
*/
final Vector<BigInteger> ipo = new Vector<>();
for (int i = 0; i < a.size(); i++) {
final BigInteger d = a.elementAt(i).a.multiply(lcmDeno).divide(a.elementAt(i).b);
ipo.add(d);
}
final BigIntegerPoly p = new BigIntegerPoly(ipo);
/*
* collect the integer roots (multiple roots only once). Since we
* removed the zero already above, cand does not contain zeros.
*/
final Vector<BigInteger> cand = p.iroots();
for (int i = 0; i < cand.size(); i++) {
final BigInteger r = cand.elementAt(i);
final int deg = p.rootDeg(r);
res.add(r);
res.add(new BigInteger("" + deg));
}
return res;
} /* iroots */
} /* RatPoly */