package jscl.math.polynomial; import jscl.math.*; import jscl.math.function.Constant; import jscl.mathml.MathML; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.Set; public abstract class Polynomial implements Arithmetic<Polynomial>, Comparable { final Monomial monomialFactory; final Generic coefFactory; final Ordering ordering; final boolean defined; final boolean field; boolean normalized; int sugar; int index = -1; Polynomial(Monomial monomialFactory, Generic coefFactory) { this.monomialFactory = monomialFactory; this.coefFactory = coefFactory; ordering = monomialFactory.ordering(); defined = monomialFactory instanceof DefinedBooleanMonomial; field = coefFactory instanceof Field; } static int degree(Polynomial polynomial) { return polynomial.monomial(polynomial.head()).degree(); } public static Polynomial factory(Variable variable) { return new UnivariatePolynomial(variable); } public static Polynomial factory(Variable variable[]) { return new NestedPolynomial(variable); } public static Polynomial factory(Variable unknown[], Ordering ordering) { return factory(unknown, ordering, 0); } public static Polynomial factory(Variable unknown[], Ordering ordering, int modulo) { return factory(unknown, ordering, modulo, 0); } public static Polynomial factory(Variable unknown[], Ordering ordering, int modulo, int flags) { return factory(Monomial.factory(unknown, ordering, flags & Basis.POWER_SIZE), modulo, flags & Basis.DATA_STRUCT, (flags & Basis.GEO_BUCKETS) > 0); } static Polynomial factory(Monomial monomialFactory, int modulo, int data_struct, boolean buckets) { if (buckets) return new GeoBucket(factory(monomialFactory, modulo, data_struct, false)); else switch (data_struct) { case Basis.ARRAY: return new ArrayPolynomial(monomialFactory, generic(modulo)); case Basis.TREE: return new TreePolynomial(monomialFactory, generic(modulo)); case Basis.LIST: return new ListPolynomial(monomialFactory, generic(modulo)); default: switch (modulo) { case -1: return new ArrayPolynomialGeneric(monomialFactory, null); case 0: return new ArrayPolynomialInteger(monomialFactory); case 1: return new ArrayPolynomialRational(monomialFactory); case 2: return new ArrayPolynomialBoolean(monomialFactory); default: return new ArrayPolynomialModular(monomialFactory, ModularInteger.factory(modulo)); } } } static Generic generic(int modulo) { switch (modulo) { case -1: return null; case 0: return JsclInteger.factory; case 1: return Rational.factory; case 2: return JsclBoolean.factory; default: return ModularInteger.factory(modulo); } } static Polynomial factory(Polynomial polynomial, int modulo) { Monomial m = polynomial.monomialFactory; return factory(m.unknown(), m.ordering(), modulo); } public abstract int size(); public Ordering ordering() { return ordering; } public final Iterator iterator() { return iterator(false); } public final Iterator iterator(boolean direction) { return iterator(direction, null); } public final Iterator iterator(Monomial current) { return iterator(true, current); } public abstract Iterator iterator(boolean direction, Monomial current); @Nonnull public Polynomial add(@Nonnull Polynomial that) { return multiplyAndSubtract(coefficient(JsclInteger.valueOf(-1)), that); } @Nonnull public abstract Polynomial subtract(@Nonnull Polynomial that); /* public Arithmetic add(@Nonnull Arithmetic arithmetic) { return add((Polynomial)arithmetic); } public Arithmetic subtract(@Nonnull Arithmetic arithmetic) { return subtract((Polynomial)arithmetic); } public Arithmetic multiply(@Nonnull Arithmetic arithmetic) { return multiply((Polynomial)arithmetic); } public Arithmetic divide(@Nonnull Arithmetic arithmetic) throws ArithmeticException { return divide((Polynomial)arithmetic); }*/ public Polynomial multiplyAndSubtract(Generic generic, Polynomial polynomial) { return subtract(polynomial.multiply(generic)); } public Polynomial multiplyAndSubtract(Monomial monomial, Generic generic, Polynomial polynomial) { return subtract(polynomial.multiply(monomial).multiply(generic)); } @Nonnull public Polynomial multiply(@Nonnull Polynomial that) { Polynomial p = valueOf(JsclInteger.valueOf(0)); Iterator it = iterator(); while (it.hasNext()) { Term t = (Term) it.next(); p = p.multiplyAndSubtract(t.monomial(), t.coef().negate(), that); } return p; } public abstract Polynomial multiply(Generic generic); public abstract Polynomial multiply(Monomial monomial); public boolean multiple(Polynomial polynomial) throws ArithmeticException { return remainder(polynomial).signum() == 0; } @Nonnull public Polynomial divide(@Nonnull Polynomial that) throws NotDivisibleException { Polynomial p[] = divideAndRemainder(that); if (p[1].signum() == 0) return p[0]; else throw new NotDivisibleException(); } public abstract Polynomial divide(Generic generic) throws ArithmeticException; public abstract Polynomial divide(Monomial monomial) throws ArithmeticException; public Polynomial[] divideAndRemainder(Polynomial polynomial) throws ArithmeticException { Polynomial p[] = {valueOf(JsclInteger.valueOf(0)), this}; Polynomial q = polynomial; Iterator it = p[1].iterator(true); while (it.hasNext()) { Term t = (Term) it.next(); Monomial m1 = t.monomial(); Monomial m2 = q.head().monomial(); if (m1.multiple(m2)) { Monomial m = m1.divide(m2); Generic c1 = t.coef(); Generic c2 = q.head().coef(); Generic c = c1.divide(c2); p[0] = p[0].multiplyAndSubtract(m, c, valueOf(JsclInteger.valueOf(-1))); p[1] = p[1].multiplyAndSubtract(m, c, q); it = p[1].iterator(true); } } return p; } public Polynomial remainder(Polynomial polynomial) throws ArithmeticException { return divideAndRemainder(polynomial)[1]; } public Polynomial remainderUpToCoefficient(Polynomial polynomial) throws ArithmeticException { Polynomial p = this; Polynomial q = polynomial; Iterator it = p.iterator(true); while (it.hasNext()) { Term t = (Term) it.next(); Monomial m1 = t.monomial(); Monomial m2 = q.head().monomial(); if (m1.multiple(m2)) { Monomial m = m1.divide(m2); Generic c1 = t.coef(); Generic c2 = q.head().coef(); // Generic c=c1.gcd(c2); // c1=c1.divide(c); // c2=c2.divide(c); p = p.multiply(c2).multiplyAndSubtract(m, c1, q); it = p.iterator(true); } } return p; } public abstract Polynomial gcd(Polynomial polynomial); public Polynomial scm(Polynomial polynomial) { return divide(gcd(polynomial)).multiply(polynomial); } public Generic gcd() { if (field) return coefficient(tail()); Generic a = coefficient(JsclInteger.valueOf(0)); for (Iterator it = iterator(); it.hasNext(); ) a = a.gcd(((Term) it.next()).coef()); return a.signum() == signum() ? a : a.negate(); } public final Polynomial[] gcdAndNormalize() { Generic gcd = gcd(); return new Polynomial[]{valueOf(gcd), gcd.signum() == 0 ? this : divide(gcd)}; } public final Polynomial normalize() { if (normalized) return this; else { Polynomial p = gcdAndNormalize()[1]; p.normalized = true; return p; } } public Monomial monomialGcd() { Monomial m = monomial(tail()); for (Iterator it = iterator(); it.hasNext(); ) m = m.gcd(((Term) it.next()).monomial()); return m; } public Polynomial pow(int exponent) { Polynomial a = valueOf(JsclInteger.valueOf(1)); for (int i = 0; i < exponent; i++) a = a.multiply(this); return a; } public Polynomial abs() { return signum() < 0 ? negate() : this; } public Polynomial negate() { return multiply(coefficient(JsclInteger.valueOf(-1))); } public final int signum() { return coefficient(tail()).signum(); } public abstract int degree(); public abstract Polynomial valueOf(Polynomial polynomial); public abstract Polynomial valueOf(Generic generic); public abstract Polynomial valueOf(Monomial monomial); public final Polynomial copy() { return valueOf(this); } public abstract Polynomial freeze(); public Term head() { Iterator it = iterator(true); return it.hasNext() ? (Term) it.next() : null; } public Term tail() { Iterator it = iterator(); return it.hasNext() ? (Term) it.next() : null; } public Generic coefficient(Monomial monomial) { Iterator it = iterator(false, monomial); Term t = it.hasNext() ? (Term) it.next() : null; return coefficient(t == null || ordering.compare(t.monomial(), monomial) == 0 ? t : null); } Monomial monomial(Term term) { return term == null ? monomial(Literal.newInstance()) : term.monomial(); } Generic coefficient(Term term) { return term == null ? coefficient(JsclInteger.valueOf(0)) : term.coef(); } protected Monomial monomial(Literal literal) { return monomialFactory.valueof(literal); } protected Generic coefficient(Generic generic) { return coefFactory == null ? generic : coefFactory.valueOf(generic); } public Polynomial reduce(Collection ideal, boolean tail) { Polynomial p = this; Iterator it = tail ? p.iterator(p.head().monomial()) : p.iterator(true); loop: while (it.hasNext()) { Term t = (Term) it.next(); Monomial m1 = t.monomial(); Iterator iq = ideal.iterator(); while (iq.hasNext()) { Polynomial q = (Polynomial) iq.next(); Monomial m2 = q.head().monomial(); if (m1.multiple(m2)) { Monomial m = m1.divide(m2); p = p.reduce(t.coef(), m, q); it = tail ? p.iterator(m1) : p.iterator(true); continue loop; } } tail = true; } return p; } public Polynomial reduce(Generic generic, Monomial monomial, Polynomial polynomial) { if (field) return multiplyAndSubtract(monomial, generic.divide(polynomial.head().coef()), polynomial); else { Generic c1 = generic; Generic c2 = polynomial.head().coef(); Generic c = c1.gcd(c2); c1 = c1.divide(c); c2 = c2.divide(c); return multiply(c2).multiplyAndSubtract(monomial, c1, polynomial).normalize(); } } public Polynomial reduce(Generic generic, Polynomial polynomial) { return reduce(generic, monomial(Literal.newInstance()), polynomial); } public int sugar() { return sugar; } public int index() { return index; } public void setSugar(int n) { sugar = n; } public void setIndex(int n) { if (index != -1) throw new ArithmeticException(); index = n; } public Generic genericValue() { Generic s = JsclInteger.valueOf(0); Iterator it = iterator(); while (it.hasNext()) { Term t = (Term) it.next(); Monomial m = t.monomial(); Generic a = t.coef().expressionValue(); s = s.add(m.degree() > 0 ? a.multiply(Expression.valueOf(m.literalValue())) : a); } return s; } public Generic[] elements() { int size = size(); Generic a[] = new Generic[size]; Iterator it = iterator(); for (int i = 0; i < size; i++) a[i] = ((Term) it.next()).coef(); return a; } public int compareTo(Polynomial polynomial) { Iterator it1 = iterator(true); Iterator it2 = polynomial.iterator(true); Term t1 = it1.hasNext() ? (Term) it1.next() : null; Term t2 = it2.hasNext() ? (Term) it2.next() : null; while (t1 != null || t2 != null) { int c = t1 == null ? 1 : (t2 == null ? -1 : ordering.compare(t1.monomial(), t2.monomial())); if (c < 0) return -1; else if (c > 0) return 1; else { c = t1.coef().compareTo(t2.coef()); if (c < 0) return -1; else if (c > 0) return 1; t1 = it1.hasNext() ? (Term) it1.next() : null; t2 = it2.hasNext() ? (Term) it2.next() : null; } } return 0; } public int compareTo(Object o) { return compareTo((Polynomial) o); } public boolean equals(Object obj) { if (obj instanceof Polynomial) { return compareTo((Polynomial) obj) == 0; } else return false; } public String toString() { StringBuffer buffer = new StringBuffer(); if (signum() == 0) buffer.append("0"); int i = 0; for (Iterator it = iterator(); it.hasNext(); i++) { Term t = (Term) it.next(); Monomial m = t.monomial(); Generic a = t.coef(); if (a instanceof Expression) a = a.signum() > 0 ? GenericVariable.valueOf(a).expressionValue() : GenericVariable.valueOf(a.negate()).expressionValue().negate(); if (a.signum() > 0 && i > 0) buffer.append("+"); if (m.degree() == 0) buffer.append(a); else { if (a.abs().compareTo(JsclInteger.valueOf(1)) == 0) { if (a.signum() < 0) buffer.append("-"); } else buffer.append(a).append("*"); buffer.append(m); } } return buffer.toString(); } public void toMathML(MathML element, @Nullable Object data) { MathML e1 = element.element("mrow"); if (signum() == 0) { MathML e2 = element.element("mn"); e2.appendChild(element.text("0")); e1.appendChild(e2); } int i = 0; for (Iterator it = iterator(); it.hasNext(); i++) { Term t = (Term) it.next(); Monomial m = t.monomial(); Generic a = t.coef(); if (a instanceof Expression) a = a.signum() > 0 ? GenericVariable.valueOf(a).expressionValue() : GenericVariable.valueOf(a.negate()).expressionValue().negate(); if (a.signum() > 0 && i > 0) { MathML e2 = element.element("mo"); e2.appendChild(element.text("+")); e1.appendChild(e2); } if (m.degree() == 0) Expression.separateSign(e1, a); else { if (a.abs().compareTo(JsclInteger.valueOf(1)) == 0) { if (a.signum() < 0) { MathML e2 = element.element("mo"); e2.appendChild(element.text("-")); e1.appendChild(e2); } } else Expression.separateSign(e1, a); m.toMathML(e1, null); } } element.appendChild(e1); } // todo serso: make abstract and implement in extensions @Nonnull public Set<? extends Constant> getConstants() { return Collections.emptySet(); } }