package jscl.math.polynomial;
import jscl.math.*;
import jscl.math.function.Inverse;
import jscl.util.ArrayUtils;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class UnivariatePolynomial extends Polynomial {
protected final Variable variable;
Generic content[] = new Generic[8];
int degree;
protected UnivariatePolynomial(Variable variable) {
this(variable, null);
}
UnivariatePolynomial(Variable variable, Generic coefFactory) {
super(Monomial.factory(new Variable[]{variable}), coefFactory);
this.variable = variable;
}
public Variable variable() {
return variable;
}
public int size() {
return degree + 1;
}
public Iterator iterator(boolean direction, Monomial current) {
return new ContentIterator(direction, current);
}
Term term(int n) {
return new Term(monomial(Literal.valueOf(variable, n)), get(n));
}
int indexOf(Monomial monomial, boolean direction) {
if (monomial == null) return direction ? degree + 1 : 0;
return monomial.degree();
}
@Nonnull
public Polynomial add(@Nonnull Polynomial that) {
UnivariatePolynomial p = newinstance();
UnivariatePolynomial q = (UnivariatePolynomial) that;
int d = Math.max(degree, q.degree);
for (int i = d; i >= 0; i--) {
p.put(i, get(i).add(q.get(i)));
}
return p;
}
@Nonnull
public Polynomial subtract(@Nonnull Polynomial that) {
UnivariatePolynomial p = newinstance();
UnivariatePolynomial q = (UnivariatePolynomial) that;
int d = Math.max(degree, q.degree);
for (int i = d; i >= 0; i--) {
p.put(i, get(i).subtract(q.get(i)));
}
return p;
}
@Nonnull
public Polynomial multiply(@Nonnull Polynomial that) {
UnivariatePolynomial p = newinstance();
UnivariatePolynomial q = (UnivariatePolynomial) that;
for (int i = degree; i >= 0; i--) {
for (int j = q.degree; j >= 0; j--) {
p.put(i + j, get(i).multiply(q.get(j)));
}
}
return p;
}
public Polynomial multiply(Generic generic) {
UnivariatePolynomial p = newinstance();
for (int i = degree; i >= 0; i--) {
p.put(i, get(i).multiply(generic));
}
return p;
}
public Polynomial multiply(Monomial monomial, Generic generic) {
UnivariatePolynomial p = newinstance();
int d = monomial.degree();
for (int i = degree; i >= 0; i--) {
p.put(i + d, get(i).multiply(generic));
}
for (int i = d - 1; i >= 0; i--) {
p.put(i, JsclInteger.valueOf(0));
}
return p;
}
public Polynomial multiply(Monomial monomial) {
return multiply(monomial, JsclInteger.valueOf(1));
}
public Polynomial divide(Generic generic) throws ArithmeticException {
UnivariatePolynomial p = newinstance();
for (int i = degree; i >= 0; i--) {
p.put(i, get(i).divide(generic));
}
return p;
}
public Polynomial divide(Monomial monomial) throws ArithmeticException {
UnivariatePolynomial p = newinstance();
int d = monomial.degree();
for (int i = d - 1; i >= 0; i--) {
if (get(i).signum() == 0) ;
else throw new NotDivisibleException();
}
for (int i = degree; i >= d; i--) {
p.put(i - d, get(i));
}
return p;
}
public Polynomial[] divideAndRemainder(Polynomial polynomial) throws ArithmeticException {
UnivariatePolynomial p[] = {newinstance(), this};
UnivariatePolynomial q = (UnivariatePolynomial) polynomial;
if (p[1].signum() == 0) return p;
for (int i = p[1].degree - q.degree; i >= 0; i--) {
p[0].put(i, p[1].get(i + q.degree).divide(q.get(q.degree)));
UnivariatePolynomial r = newinstance();
for (int j = i + q.degree - 1; j >= 0; j--) {
Generic a = p[1].get(j);
r.put(j, a.subtract(q.get(j - i).multiply(p[0].get(i))));
}
p[1] = r;
}
return p;
}
public Polynomial remainderUpToCoefficient(Polynomial polynomial) throws ArithmeticException {
UnivariatePolynomial p = this;
UnivariatePolynomial q = (UnivariatePolynomial) polynomial;
if (p.signum() == 0) return p;
for (int i = p.degree - q.degree; i >= 0; i--) {
UnivariatePolynomial r = newinstance();
for (int j = i + q.degree - 1; j >= 0; j--) {
Generic a = p.get(j).multiply(q.get(q.degree));
r.put(j, a.subtract(q.get(j - i).multiply(p.get(i + q.degree))));
}
p = r;
}
return p;
}
public Polynomial gcd(Polynomial polynomial) {
UnivariatePolynomial p = this;
UnivariatePolynomial q = (UnivariatePolynomial) polynomial;
if (p.signum() == 0) return q;
else if (q.signum() == 0) return p;
if (p.degree < q.degree) {
UnivariatePolynomial r = p;
p = q;
q = r;
}
int d = p.degree - q.degree;
Generic phi = JsclInteger.valueOf(-1);
Generic beta = JsclInteger.valueOf(-1).pow(d + 1);
Polynomial a1[] = p.gcdAndNormalize();
Polynomial a2[] = q.gcdAndNormalize();
Generic gcd1 = a1[0].genericValue();
Generic gcd2 = a2[0].genericValue();
p = (UnivariatePolynomial) a1[1];
q = (UnivariatePolynomial) a2[1];
while (q.degree > 0) {
UnivariatePolynomial r = (UnivariatePolynomial) p.remainderUpToCoefficient(q).divide(beta);
if (d > 1) phi = q.get(q.degree).negate().pow(d).divide(phi.pow(d - 1));
else phi = q.get(q.degree).negate().pow(d).multiply(phi.pow(1 - d));
p = q;
q = r;
d = p.degree - q.degree;
beta = p.get(p.degree).negate().multiply(phi.pow(d));
}
if (q.signum() == 0) {
p = (UnivariatePolynomial) p.normalize();
} else {
p = newinstance();
p.put(0, JsclInteger.valueOf(1));
}
return p.multiply(gcd1.gcd(gcd2));
}
public Generic gcd() {
Generic a = coefficient(JsclInteger.valueOf(0));
for (int i = degree; i >= 0; i--) a = a.gcd(get(i));
return a.signum() == signum() ? a : a.negate();
}
public Monomial monomialGcd() {
return monomial(tail());
}
public int degree() {
return degree;
}
public UnivariatePolynomial valueof(Generic generic[]) {
UnivariatePolynomial p = newinstance();
p.init(generic);
return p;
}
public Polynomial valueOf(Polynomial polynomial) {
throw new UnsupportedOperationException();
}
public Polynomial valueOf(Generic generic) {
UnivariatePolynomial p = newinstance();
p.init(generic);
return p;
}
public Polynomial valueOf(Monomial monomial) {
throw new UnsupportedOperationException();
}
public Polynomial freeze() {
return this;
}
public Term head() {
return term(degree);
}
public Generic coefficient(Monomial monomial) {
return term(monomial.degree()).coef();
}
public Polynomial reduce(Generic generic, Monomial monomial, Polynomial polynomial, boolean inPlace) {
throw new UnsupportedOperationException();
}
public Generic genericValue() {
Generic s = JsclInteger.valueOf(0);
for (int i = degree; i >= 0; i--) {
Generic a = get(i).expressionValue();
s = s.add(i > 0 ? a.multiply(Expression.valueOf(Literal.valueOf(variable, i))) : a);
}
return s;
}
public Generic[] elements() {
Generic a[] = new Generic[degree + 1];
for (int i = degree; i >= 0; i--) a[i] = get(i);
return a;
}
public UnivariatePolynomial derivative(Variable variable) {
return (UnivariatePolynomial) derivative().multiply(this.variable.derivative(variable));
}
public Generic substitute(Generic generic) {
Generic s = JsclInteger.valueOf(0);
for (int i = degree; i >= 0; i--) {
s = s.add(get(i).multiply(generic.pow(i)));
}
return s;
}
public Generic solve() {
if (degree == 1) {
return get(0).multiply(new Inverse(get(1)).selfExpand()).negate();
} else return null;
}
public Generic[] identification(UnivariatePolynomial polynomial) {
UnivariatePolynomial p = this;
UnivariatePolynomial q = polynomial;
if (p.degree < q.degree || (p.degree == 0 && q.signum() == 0)) {
UnivariatePolynomial r = p;
p = q;
q = r;
}
UnivariatePolynomial r = (UnivariatePolynomial) p.remainderUpToCoefficient(q);
Generic a[] = new Generic[r.degree + 1];
for (int i = r.degree; i >= 0; i--) a[r.degree - i] = r.get(i);
return a;
}
public Generic resultant(UnivariatePolynomial polynomial) {
UnivariatePolynomial p = this;
UnivariatePolynomial q = polynomial;
if (p.degree < q.degree || (p.degree == 0 && q.signum() == 0)) {
UnivariatePolynomial r = p;
p = q;
q = r;
}
int d = p.degree - q.degree;
Generic phi = JsclInteger.valueOf(-1);
Generic beta = JsclInteger.valueOf(-1).pow(d + 1);
while (q.degree > 0) {
UnivariatePolynomial r = (UnivariatePolynomial) p.remainderUpToCoefficient(q).divide(beta);
if (d > 1) phi = q.get(q.degree).negate().pow(d).divide(phi.pow(d - 1));
else phi = q.get(q.degree).negate().pow(d).multiply(phi.pow(1 - d));
p = q;
q = r;
d = p.degree - q.degree;
beta = p.get(p.degree).negate().multiply(phi.pow(d));
}
return q.get(0);
}
public UnivariatePolynomial[] remainderSequence(UnivariatePolynomial polynomial) {
UnivariatePolynomial p = this;
UnivariatePolynomial q = polynomial;
if (p.degree < q.degree || (p.degree == 0 && q.signum() == 0)) {
UnivariatePolynomial r = p;
p = q;
q = r;
}
UnivariatePolynomial s[] = new UnivariatePolynomial[q.degree + 1];
s[q.degree] = q;
int d = p.degree - q.degree;
Generic phi = JsclInteger.valueOf(-1);
Generic beta = JsclInteger.valueOf(-1).pow(d + 1);
while (q.degree > 0) {
UnivariatePolynomial r = (UnivariatePolynomial) p.remainderUpToCoefficient(q).divide(beta);
if (d > 1) phi = q.get(q.degree).negate().pow(d).divide(phi.pow(d - 1));
else phi = q.get(q.degree).negate().pow(d).multiply(phi.pow(1 - d));
p = q;
q = r;
s[q.degree] = q;
d = p.degree - q.degree;
beta = p.get(p.degree).negate().multiply(phi.pow(d));
}
return s;
}
public UnivariatePolynomial squarefree() {
return (UnivariatePolynomial) divide(gcd(derivative()));
}
public UnivariatePolynomial[] squarefreeDecomposition() {
return SquarefreeDecomposition.compute(this);
}
public UnivariatePolynomial antiderivative() {
UnivariatePolynomial p = newinstance();
for (int i = degree; i >= 0; i--) {
p.put(i + 1, get(i).multiply(new Inverse(JsclInteger.valueOf(i + 1)).selfExpand()));
}
return p;
}
public UnivariatePolynomial derivative() {
UnivariatePolynomial p = newinstance();
for (int i = degree - 1; i >= 0; i--) {
p.put(i, get(i + 1).multiply(JsclInteger.valueOf(i + 1)));
}
return p;
}
public int compareTo(Polynomial polynomial) {
UnivariatePolynomial p = (UnivariatePolynomial) polynomial;
int d = Math.max(degree, p.degree);
for (int i = d; i >= 0; i--) {
Generic a1 = get(i);
Generic a2 = p.get(i);
int c = a1.compareTo(a2);
if (c < 0) return -1;
else if (c > 0) return 1;
}
return 0;
}
void init(Generic generic[]) {
for (int i = 0; i < generic.length; i++) put(i, coefficient(generic[i]));
}
void init(Expression expression) {
int n = expression.size();
for (int i = 0; i < n; i++) {
Literal l = expression.literal(i);
JsclInteger en = expression.coef(i);
Monomial m = monomial(l);
l = l.divide(m.literalValue());
if (l.degree() > 0) put(m.degree(), coefficient(en.multiply(Expression.valueOf(l))));
else put(m.degree(), coefficient(en));
}
}
protected void init(Generic generic) {
if (generic instanceof Expression) {
init((Expression) generic);
} else put(0, coefficient(generic));
}
void put(int n, Generic generic) {
Generic a = generic.add(get(n));
if (a.signum() == 0) {
if (n <= degree) content[n] = null;
if (n == degree) {
while (n > 0 && content[n] == null) n--;
degree = n;
}
} else {
if (n >= content.length) resize(n);
content[n] = a;
degree = Math.max(degree, n);
}
}
void resize(int n) {
int length = content.length << 1;
while (n >= length) length <<= 1;
Generic content[] = new Generic[length];
System.arraycopy(this.content, 0, content, 0, this.content.length);
this.content = content;
}
public Generic get(int n) {
Generic a = n < 0 || n > degree ? null : content[n];
return a == null ? JsclInteger.valueOf(0) : a;
}
protected UnivariatePolynomial newinstance() {
return new UnivariatePolynomial(variable, coefFactory);
}
class ContentIterator implements Iterator {
final boolean direction;
int index;
ContentIterator(boolean direction, Monomial current) {
this.direction = direction;
if (direction) {
index = indexOf(current, true);
} else {
index = indexOf(current, false);
if (current != null && get(index).signum() != 0) index++;
}
seek();
}
void seek() {
if (direction) while (index > 0 && get(index).signum() == 0) index--;
else while (index <= degree && get(index).signum() == 0) index++;
}
public boolean hasNext() {
return direction ? index > 0 : index <= degree;
}
public Object next() {
Term t = direction ? term(--index) : term(index++);
seek();
return t;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}
class SquarefreeDecomposition {
final List list = new ArrayList();
static UnivariatePolynomial[] compute(UnivariatePolynomial polynomial) {
SquarefreeDecomposition sd = new SquarefreeDecomposition();
Polynomial p[] = polynomial.gcdAndNormalize();
sd.init((UnivariatePolynomial) p[0]);
sd.process((UnivariatePolynomial) p[1]);
return sd.getValue();
}
void init(UnivariatePolynomial polynomial) {
list.add(polynomial);
}
void process(UnivariatePolynomial polynomial) {
UnivariatePolynomial r = (UnivariatePolynomial) polynomial.gcd(polynomial.derivative());
UnivariatePolynomial s = (UnivariatePolynomial) polynomial.divide(r);
list.add(s.divide(s.gcd(r)));
if (r.degree() == 0) ;
else process(r);
}
UnivariatePolynomial[] getValue() {
return (UnivariatePolynomial[]) ArrayUtils.toArray(list, new UnivariatePolynomial[list.size()]);
}
}