765 lines
19 KiB
Java
765 lines
19 KiB
Java
package org.nevec.rjm;
|
|
|
|
import java.math.BigDecimal;
|
|
import java.math.BigInteger;
|
|
import java.util.Scanner;
|
|
import java.util.Vector;
|
|
|
|
import it.cavallium.warppi.util.Error;
|
|
|
|
/**
|
|
* Polynomial with integer coefficients.
|
|
* Alternatively to be interpreted as a sequence which has the polynomial as an
|
|
* (approximate)
|
|
* generating function.
|
|
*
|
|
* @since 2010-08-27
|
|
* @author Richard J. Mathar
|
|
*/
|
|
public class BigIntegerPoly implements Cloneable {
|
|
/**
|
|
* The list of all coefficients, starting with a0, then a1, as in
|
|
* poly=a0+a1*x+a2*x^2+a3*x^3+...
|
|
*/
|
|
Vector<BigInteger> a;
|
|
|
|
/**
|
|
* Default ctor.
|
|
* Creates the polynomial p(x)=0.
|
|
*/
|
|
public BigIntegerPoly() {
|
|
a = new Vector<>();
|
|
}
|
|
|
|
/**
|
|
* Ctor 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 BigIntegerPoly(final String L) throws NumberFormatException {
|
|
a = new Vector<>();
|
|
final Scanner sc = new Scanner(L);
|
|
sc.useDelimiter(",");
|
|
while (sc.hasNextBigInteger()) {
|
|
a.add(sc.nextBigInteger());
|
|
}
|
|
simplify();
|
|
sc.close();
|
|
} /* ctor */
|
|
|
|
/**
|
|
* Ctor with a list of coefficients.
|
|
*
|
|
* @param c
|
|
* The coefficients a0, a1, a2 etc in a0+a1*x+a2*x^2+...
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
public BigIntegerPoly(final Vector<BigInteger> c) {
|
|
a = (Vector<BigInteger>) c.clone();
|
|
simplify();
|
|
} /* ctor */
|
|
|
|
/**
|
|
* Ctor with a list of coefficients.
|
|
*
|
|
* @param c
|
|
* The coefficients a0, a1, a2 etc in a0+a1*x+a2*x^2+...
|
|
*/
|
|
public BigIntegerPoly(final BigInteger[] c) {
|
|
for (final BigInteger element : c) {
|
|
a.add(element.add(BigInteger.ZERO));
|
|
}
|
|
simplify();
|
|
} /* ctor */
|
|
|
|
/**
|
|
* Create a copy of this.
|
|
*
|
|
* @since 2010-08-27
|
|
*/
|
|
@Override
|
|
public BigIntegerPoly clone() {
|
|
return new BigIntegerPoly(a);
|
|
} /* clone */
|
|
|
|
/**
|
|
* Translate into a RatPoly copy.
|
|
*
|
|
* @since 2012-03-02
|
|
*/
|
|
public RatPoly toRatPoly() {
|
|
final RatPoly bd = new RatPoly();
|
|
for (int i = 0; i < a.size(); i++) {
|
|
bd.set(i, a.elementAt(i));
|
|
}
|
|
return bd;
|
|
} /* toRatPoly */
|
|
|
|
/**
|
|
* 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 BigInteger at(final int n) {
|
|
if (n < a.size()) {
|
|
return a.elementAt(n);
|
|
} else {
|
|
return BigInteger.ZERO;
|
|
}
|
|
} /* at */
|
|
|
|
/**
|
|
* Evaluate at some integer argument.
|
|
*
|
|
* @param x
|
|
* The abscissa point of the evaluation
|
|
* @return The polynomial value.
|
|
* @since 2010-08-27
|
|
* @author Richard J. Mathar
|
|
*/
|
|
public BigInteger valueOf(final BigInteger x) {
|
|
if (a.size() == 0) {
|
|
return BigInteger.ZERO;
|
|
}
|
|
BigInteger res = a.lastElement();
|
|
/*
|
|
* Heron casted form
|
|
*/
|
|
for (int i = a.size() - 2; i >= 0; i--) {
|
|
res = res.multiply(x).add(a.elementAt(i));
|
|
}
|
|
return res;
|
|
} /* valueOf */
|
|
|
|
/**
|
|
* Horner scheme to find the function value at the argument x
|
|
*
|
|
* @param x
|
|
* The argument x.
|
|
* @return Value of the polynomial at x.
|
|
* @since 2008-11-13
|
|
*/
|
|
public BigInteger valueOf(final int x) {
|
|
return valueOf(new BigInteger("" + 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 set to zero.
|
|
* @param value
|
|
* the new value of the coefficient.
|
|
*/
|
|
public void set(final int n, final BigInteger value) {
|
|
if (n < a.size()) {
|
|
a.set(n, value);
|
|
} else {
|
|
/*
|
|
* fill intermediate powers with coefficients of zero
|
|
*/
|
|
while (a.size() < n) {
|
|
a.add(BigInteger.ZERO);
|
|
}
|
|
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 int value) {
|
|
final BigInteger val2 = new BigInteger("" + value);
|
|
set(n, val2);
|
|
} /* set */
|
|
|
|
/**
|
|
* Count of coefficients.
|
|
*
|
|
* @return the number of polynomial coefficients.
|
|
* Differs from the polynomial degree by one.
|
|
*/
|
|
public int size() {
|
|
return a.size();
|
|
} /* size */
|
|
|
|
/**
|
|
* Polynomial degree.
|
|
*
|
|
* @return the polynomial degree.
|
|
*/
|
|
public int degree() {
|
|
return a.size() - 1;
|
|
} /* degree */
|
|
|
|
/**
|
|
* Polynomial lower degree.
|
|
*
|
|
* @return power of the smallest non-zero coefficient.
|
|
* If the polynomial is identical to 0, 0 is returned.
|
|
*/
|
|
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.
|
|
* @since 2010-08-27
|
|
*/
|
|
public BigIntegerPoly multiply(final BigInteger val) {
|
|
final BigIntegerPoly resul = new BigIntegerPoly();
|
|
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 BigIntegerPoly multiply(final BigIntegerPoly val) {
|
|
final BigIntegerPoly resul = new BigIntegerPoly();
|
|
/*
|
|
* 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++) {
|
|
BigInteger coef = BigInteger.ZERO;
|
|
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 exponent of the power
|
|
* @return the n-th power of this.
|
|
*/
|
|
public BigIntegerPoly pow(final int n) throws ArithmeticException {
|
|
BigIntegerPoly resul = new BigIntegerPoly("1");
|
|
if (n < 0) {
|
|
throw new ArithmeticException("negative polynomial power " + n);
|
|
} else {
|
|
for (int i = 1; i <= n; i++) {
|
|
resul = resul.multiply(this);
|
|
}
|
|
resul.simplify();
|
|
return resul;
|
|
}
|
|
} /* pow */
|
|
|
|
/**
|
|
* Add another polynomial
|
|
*
|
|
* @param val
|
|
* the other polynomial
|
|
* @return the sum of this with the other polynomial
|
|
* @since 2010-08-27
|
|
*/
|
|
public BigIntegerPoly add(final BigIntegerPoly val) {
|
|
final BigIntegerPoly resul = new BigIntegerPoly();
|
|
/*
|
|
* 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 BigInteger 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 BigIntegerPoly subtract(final BigIntegerPoly val) {
|
|
final BigIntegerPoly resul = new BigIntegerPoly();
|
|
/*
|
|
* 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 BigInteger coef = at(n).subtract(val.at(n));
|
|
resul.set(n, coef);
|
|
}
|
|
resul.simplify();
|
|
return resul;
|
|
} /* subtract */
|
|
|
|
/**
|
|
* Divide by another polynomial.
|
|
*
|
|
* @param val
|
|
* the other polynomial
|
|
* @return A vector with [0] containg the polynomial of degree which is the
|
|
* difference of the degree of this and the degree of val. [1] the
|
|
* remainder polynomial.
|
|
* This = returnvalue[0] + returnvalue[1]/val .
|
|
* @since 2012-03-01
|
|
*/
|
|
public BigIntegerPoly[] divideAndRemainder(final BigIntegerPoly val) {
|
|
final BigIntegerPoly[] ret = new BigIntegerPoly[2];
|
|
/*
|
|
* remove any high-order zeros. note that the clone() operation calls
|
|
* simplify().
|
|
*/
|
|
final BigIntegerPoly valSimpl = val.clone();
|
|
final BigIntegerPoly thisSimpl = clone();
|
|
|
|
/*
|
|
* catch the case with val equal to zero
|
|
*/
|
|
if (valSimpl.degree() == 0 && valSimpl.a.firstElement().compareTo(BigInteger.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 BigIntegerPoly();
|
|
ret[1] = thisSimpl;
|
|
} else {
|
|
/*
|
|
* long division. Highest degree by dividing the highest degree
|
|
* of this thru val. At this point an exception is thrown if the
|
|
* polynomial division cannot be done with integer coefficients.
|
|
*/
|
|
ret[0] = new BigIntegerPoly();
|
|
final BigInteger[] newc = thisSimpl.a.lastElement().divideAndRemainder(valSimpl.a.lastElement());
|
|
if (newc[1].compareTo(BigInteger.ZERO) != 0) {
|
|
throw new ArithmeticException("Incompatible leading term in " + this + " / " + val);
|
|
}
|
|
ret[0].set(thisSimpl.degree() - valSimpl.degree(), newc[0]);
|
|
|
|
/*
|
|
* 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 BigIntegerPoly 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,...
|
|
* @since 2010-08-27
|
|
*/
|
|
@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();
|
|
}
|
|
}
|
|
if (str.length() == 0) {
|
|
str = "0";
|
|
}
|
|
return str;
|
|
} /* toString */
|
|
|
|
/**
|
|
* Print as a polyomial in x.
|
|
*
|
|
* @return The representation a0+a1*x+a2*x^2+...
|
|
* The terms with zero coefficients are not mentioned.
|
|
* @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);
|
|
if (num.compareTo(BigInteger.ZERO) != 0) {
|
|
str += " ";
|
|
if (num.compareTo(BigInteger.ZERO) > 0 && n > 0) {
|
|
str += "+";
|
|
}
|
|
str += a.elementAt(n).toString();
|
|
if (n > 0) {
|
|
str += "*x";
|
|
if (n > 1) {
|
|
str += "^" + n;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (str.length() == 0) {
|
|
str = "0";
|
|
}
|
|
return str;
|
|
} /* toPString */
|
|
|
|
/**
|
|
* Simplify the representation.
|
|
* Trailing values with zero coefficients (at high powers) are deleted.
|
|
*/
|
|
protected void simplify() {
|
|
int n = a.size() - 1;
|
|
if (n >= 0) {
|
|
while (a.elementAt(n).compareTo(BigInteger.ZERO) == 0) {
|
|
a.removeElementAt(n);
|
|
if (--n < 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} /* simplify */
|
|
|
|
/**
|
|
* First derivative.
|
|
*
|
|
* @return The first derivative with respect to the indeterminate variable.
|
|
* @since 2008-10-26
|
|
*/
|
|
public BigIntegerPoly derive() {
|
|
if (a.size() <= 1) {
|
|
/*
|
|
* derivative of the constant is just zero
|
|
*/
|
|
return new BigIntegerPoly();
|
|
} else {
|
|
final BigIntegerPoly d = new BigIntegerPoly();
|
|
for (int i = 1; i <= degree(); i++) {
|
|
final BigInteger c = a.elementAt(i).multiply(new BigInteger("" + i));
|
|
d.set(i - 1, c);
|
|
}
|
|
return d;
|
|
}
|
|
} /* derive */
|
|
|
|
/**
|
|
* Truncate polynomial degree.
|
|
*
|
|
* @return The polynomial with all coefficients beyond deg set to zero.
|
|
* @since 2010-08-27
|
|
*/
|
|
public BigIntegerPoly trunc(final int newdeg) {
|
|
final BigIntegerPoly t = new BigIntegerPoly();
|
|
for (int i = 0; i <= newdeg; i++) {
|
|
t.set(i, at(i));
|
|
}
|
|
t.simplify();
|
|
return t;
|
|
} /* trunc */
|
|
|
|
/**
|
|
* 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 2010-08-29
|
|
*/
|
|
public BigIntegerPoly binomialTInv(final int maxdeg) {
|
|
final BigIntegerPoly r = new BigIntegerPoly();
|
|
for (int i = 0; i <= maxdeg; i++) {
|
|
BigInteger c = BigInteger.ZERO;
|
|
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 */
|
|
|
|
/**
|
|
* Compute the order of the root r.
|
|
*
|
|
* @return 1 for simple roots, 2 for order 2 etc., 0 if not a root
|
|
* @since 2010-08-27
|
|
*/
|
|
public int rootDeg(final BigInteger r) {
|
|
int o = 0;
|
|
BigIntegerPoly d = clone();
|
|
BigInteger roo = d.valueOf(r);
|
|
while (roo.compareTo(BigInteger.ZERO) == 0) {
|
|
o++;
|
|
d = d.derive();
|
|
roo = d.valueOf(r);
|
|
}
|
|
return o;
|
|
} /* rootDeg */
|
|
|
|
/**
|
|
* Generate the integer roots of the polynomial.
|
|
*
|
|
* @return The vector of integer roots, without their multiplicity.
|
|
* @since 2010-08-27
|
|
*/
|
|
public Vector<BigInteger> iroots() {
|
|
/* The vector of the roots */
|
|
final Vector<BigInteger> res = new Vector<>();
|
|
|
|
/*
|
|
* collect the zero
|
|
*/
|
|
if (a.firstElement().compareTo(BigInteger.ZERO) == 0) {
|
|
res.add(BigInteger.ZERO);
|
|
}
|
|
|
|
/*
|
|
* collect the divisors of the constant element (or the reduced
|
|
* polynomial)
|
|
*/
|
|
final int l = ldegree();
|
|
if (a.elementAt(l).compareTo(BigInteger.ZERO) != 0) {
|
|
@SuppressWarnings("deprecation")
|
|
final Vector<BigInteger> cand = BigIntegerMath.divisors(a.elementAt(l).abs());
|
|
|
|
/* check the divisors (both signs) */
|
|
for (int i = 0; i < cand.size(); i++) {
|
|
BigInteger roo = valueOf(cand.elementAt(i));
|
|
if (roo.compareTo(BigInteger.ZERO) == 0) {
|
|
/* found a root cand[i] */
|
|
res.add(cand.elementAt(i));
|
|
}
|
|
roo = valueOf(cand.elementAt(i).negate());
|
|
if (roo.compareTo(BigInteger.ZERO) == 0) {
|
|
res.add(cand.elementAt(i).negate());
|
|
}
|
|
}
|
|
}
|
|
return res;
|
|
} /* iroots */
|
|
|
|
/**
|
|
* Generate the factors which are 2nd degree polynomials.
|
|
*
|
|
* @return A (potentially empty) vector of factors, without multiplicity.
|
|
* Only factors with non-zero absolute coefficient are generated.
|
|
* This means the factors are of the form x^2+a*x+b=0 with nonzero
|
|
* b.
|
|
* @throws Error
|
|
* @since 2012-03-01
|
|
*/
|
|
protected Vector<BigIntegerPoly> i2roots() throws Error {
|
|
/*
|
|
* The vector of the factors to be returned
|
|
*/
|
|
final Vector<BigIntegerPoly> res = new Vector<>();
|
|
|
|
if (degree() < 2) {
|
|
return res;
|
|
}
|
|
|
|
final BigInteger bsco = a.firstElement().abs();
|
|
@SuppressWarnings("deprecation")
|
|
final Vector<BigInteger> b = BigIntegerMath.divisors(bsco);
|
|
final BigInteger csco = a.lastElement().abs();
|
|
@SuppressWarnings("deprecation")
|
|
final Vector<BigInteger> c = BigIntegerMath.divisors(csco);
|
|
|
|
/*
|
|
* Generate the floating point values of roots. To have some reasonable
|
|
* accuracy in the results, add zeros to the integer coefficients,
|
|
* scaled
|
|
* by the expected division with values of b (which are all <=
|
|
* a.firstele).
|
|
* Number of decimal digits in bsco by using a log2->log10 rough
|
|
* estimate
|
|
* and adding 6 safety digits
|
|
*/
|
|
final RatPoly thisDec = toRatPoly();
|
|
final Vector<BigComplex> roo = thisDec.roots(6 + (int) (0.3 * bsco.bitCount()));
|
|
|
|
final BigDecimal half = new BigDecimal("0.5");
|
|
|
|
/*
|
|
* for each of the roots z try to see whether c*z^2+a*z+b=0 with integer
|
|
* a, b and c
|
|
* where b is restricted to a signed divisor of the constant
|
|
* coefficient.
|
|
* Solve z*(c*z+a)=-b or c*z+a = -b/z or -b/z-c*z = some integer a.
|
|
*/
|
|
for (final BigComplex z : roo) {
|
|
for (final BigInteger bco : b) {
|
|
for (final BigInteger cco : c) {
|
|
/*
|
|
* the major reason to avoid the case b=0 is that this would
|
|
* require precaution of double counting below. Note that
|
|
* this
|
|
* case is already covered by using iroots().
|
|
*/
|
|
if (bco.signum() != 0) {
|
|
for (int sig = -1; sig <= 1; sig += 2) {
|
|
final BigInteger bcosig = sig > 0 ? bco : bco.negate();
|
|
/*
|
|
* -a = b/z+c*z has real part b*Re(z)/|z|^2+c*Re(z)
|
|
* = Re z *( b/|z|^2+c)
|
|
*/
|
|
BigDecimal negA = BigDecimalMath.add(BigDecimalMath.divideRound(bcosig, z.norm()), cco);
|
|
negA = negA.multiply(z.re);
|
|
/*
|
|
* convert to a with round-to-nearest
|
|
*/
|
|
final BigInteger a = negA.negate().add(half).toBigInteger();
|
|
|
|
/*
|
|
* test the polynomial remainder. if zero, add the
|
|
* term
|
|
* to the results.
|
|
*/
|
|
final BigIntegerPoly dtst = new BigIntegerPoly("" + bcosig + "," + a + "," + cco);
|
|
try {
|
|
final BigIntegerPoly[] rm = divideAndRemainder(dtst);
|
|
if (rm[1].isZero()) {
|
|
res.add(dtst);
|
|
}
|
|
} catch (final ArithmeticException ex) {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
} /* i2roots */
|
|
|
|
/**
|
|
* Test whether this polynomial value is zero.
|
|
*
|
|
* @return If this is a polynomial p(x)=0 for all x.
|
|
*/
|
|
public boolean isZero() {
|
|
simplify();
|
|
return a.size() == 0;
|
|
}
|
|
|
|
/**
|
|
* Factorization into integer polynomials.
|
|
* The current factorization detects only factors which are polynomials of
|
|
* order up to 2.
|
|
*
|
|
* @return The vector of factors. Factors with higher multiplicity are
|
|
* represented by repetition.
|
|
* @throws Error
|
|
* @since 2012-03-01
|
|
*/
|
|
public Vector<BigIntegerPoly> ifactor() throws Error {
|
|
/*
|
|
* this ought be entirely rewritten in terms of the LLL algorithm
|
|
*/
|
|
final Vector<BigIntegerPoly> fac = new Vector<>();
|
|
|
|
/* collect integer roots (polynomial factors of degree 1) */
|
|
final Vector<BigInteger> r = iroots();
|
|
BigIntegerPoly[] res = new BigIntegerPoly[2];
|
|
res[0] = this;
|
|
for (final BigInteger i : r) {
|
|
final int deg = rootDeg(i);
|
|
/* construct the factor x-i */
|
|
final BigIntegerPoly f = new BigIntegerPoly("" + i.negate() + ",1");
|
|
for (int mu = 0; mu < deg; mu++) {
|
|
fac.add(f);
|
|
res = res[0].divideAndRemainder(f);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* collect factors which are polynomials of degree 2
|
|
*/
|
|
final Vector<BigIntegerPoly> pol2 = i2roots();
|
|
for (final BigIntegerPoly i : pol2) {
|
|
/*
|
|
* the internal loop catches cases with higher
|
|
* powers of individual polynomials (of actual degree 2 or 4...)
|
|
*/
|
|
while (res[0].degree() >= 2) {
|
|
try {
|
|
final BigIntegerPoly[] dtst = res[0].divideAndRemainder(i);
|
|
if (dtst[1].isZero()) {
|
|
fac.add(i);
|
|
res = dtst;
|
|
} else {
|
|
break;
|
|
}
|
|
} catch (final ArithmeticException ex) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* add remaining factor, if not equal to 1
|
|
*/
|
|
if (res[0].degree() > 0 || res[0].a.firstElement().compareTo(BigInteger.ONE) != 0) {
|
|
fac.add(res[0]);
|
|
}
|
|
return fac;
|
|
} /* ifactor */
|
|
|
|
} /* BigIntegerPoly */
|