package jscl.math.polynomial; import jscl.math.Expression; import jscl.math.Generic; import jscl.math.JsclInteger; import jscl.math.Literal; import jscl.util.ArrayUtils; import javax.annotation.Nonnull; import java.util.*; final class ListPolynomial extends Polynomial { final List content = new LinkedList(); int degree; boolean mutable = true; ListPolynomial(Monomial monomialFactory, Generic coefFactory) { super(monomialFactory, coefFactory); } public int size() { return content.size(); } public final Iterator iterator(boolean direction, Monomial current) { return new ContentIterator(direction, current); } int indexOf(Monomial monomial, boolean direction) { if (monomial == null) return direction ? content.size() : 0; int n = ArrayUtils.binarySearch(content, new Term(monomial, null)); return n < 0 ? -n - 1 : direction ? n : n + 1; } @Nonnull public Polynomial subtract(@Nonnull Polynomial that) { if (that.signum() == 0) return this; if (mutable) { ListPolynomial q = (ListPolynomial) that; ListIterator it1 = content.listIterator(content.size()); ListIterator it2 = q.content.listIterator(q.content.size()); Term t1 = it1.hasPrevious() ? (Term) it1.previous() : null; Term t2 = it2.hasPrevious() ? (Term) it2.previous() : null; while (t2 != null) { int c = t1 == null ? 1 : (t2 == null ? -1 : -ordering.compare(t1.monomial(), t2.monomial())); if (c < 0) { t1 = it1.hasPrevious() ? (Term) it1.previous() : null; } else { if (c > 0) { if (t1 != null) it1.next(); it1.add(t2.negate()); } else { Term t = t1.subtract(t2); if (t.signum() == 0) it1.remove(); else it1.set(t); } t1 = it1.hasPrevious() ? (Term) it1.previous() : null; t2 = it2.hasPrevious() ? (Term) it2.previous() : null; } } degree = degree(this); sugar = Math.max(sugar, q.sugar); normalized = false; return this; } else return copy().subtract(that); } public Polynomial multiplyAndSubtract(Generic generic, Polynomial polynomial) { if (generic.signum() == 0) return this; if (generic.compareTo(JsclInteger.valueOf(1)) == 0) return subtract(polynomial); if (mutable) { ListPolynomial q = (ListPolynomial) polynomial; ListIterator it1 = content.listIterator(content.size()); ListIterator it2 = q.content.listIterator(q.content.size()); Term t1 = it1.hasPrevious() ? (Term) it1.previous() : null; Term t2 = it2.hasPrevious() ? ((Term) it2.previous()).multiply(generic) : null; while (t2 != null) { int c = t1 == null ? 1 : (t2 == null ? -1 : -ordering.compare(t1.monomial(), t2.monomial())); if (c < 0) { t1 = it1.hasPrevious() ? (Term) it1.previous() : null; } else { if (c > 0) { if (t1 != null) it1.next(); it1.add(t2.negate()); } else { Term t = t1.subtract(t2); if (t.signum() == 0) it1.remove(); else it1.set(t); } t1 = it1.hasPrevious() ? (Term) it1.previous() : null; t2 = it2.hasPrevious() ? ((Term) it2.previous()).multiply(generic) : null; } } degree = degree(this); sugar = Math.max(sugar, q.sugar); normalized = false; return this; } else return copy().multiplyAndSubtract(generic, polynomial); } public Polynomial multiplyAndSubtract(Monomial monomial, Generic generic, Polynomial polynomial) { if (defined) throw new UnsupportedOperationException(); if (generic.signum() == 0) return this; if (monomial.degree() == 0) return multiplyAndSubtract(generic, polynomial); if (mutable) { ListPolynomial q = (ListPolynomial) polynomial; ListIterator it1 = content.listIterator(content.size()); ListIterator it2 = q.content.listIterator(q.content.size()); Term t1 = it1.hasPrevious() ? (Term) it1.previous() : null; Term t2 = it2.hasPrevious() ? ((Term) it2.previous()).multiply(monomial, generic) : null; while (t2 != null) { int c = t1 == null ? 1 : (t2 == null ? -1 : -ordering.compare(t1.monomial(), t2.monomial())); if (c < 0) { t1 = it1.hasPrevious() ? (Term) it1.previous() : null; } else { if (c > 0) { if (t1 != null) it1.next(); it1.add(t2.negate()); } else { Term t = t1.subtract(t2); if (t.signum() == 0) it1.remove(); else it1.set(t); } t1 = it1.hasPrevious() ? (Term) it1.previous() : null; t2 = it2.hasPrevious() ? ((Term) it2.previous()).multiply(monomial, generic) : null; } } degree = degree(this); sugar = Math.max(sugar, q.sugar + monomial.degree()); normalized = false; return this; } else return copy().multiplyAndSubtract(monomial, generic, polynomial); } public Polynomial multiply(Generic generic) { if (generic.signum() == 0) return valueOf(JsclInteger.valueOf(0)); if (generic.compareTo(JsclInteger.valueOf(1)) == 0) return this; if (mutable) { ListIterator it = content.listIterator(); while (it.hasNext()) it.set(((Term) it.next()).multiply(generic)); normalized = false; return this; } else return copy().multiply(generic); } public Polynomial multiply(Monomial monomial) { if (defined) throw new UnsupportedOperationException(); if (monomial.degree() == 0) return this; if (mutable) { ListIterator it = content.listIterator(); while (it.hasNext()) it.set(((Term) it.next()).multiply(monomial)); degree += monomial.degree(); sugar += monomial.degree(); return this; } else return copy().multiply(monomial); } public Polynomial divide(Generic generic) throws ArithmeticException { if (generic.compareTo(JsclInteger.valueOf(1)) == 0) return this; if (mutable) { ListIterator it = content.listIterator(); while (it.hasNext()) it.set(((Term) it.next()).divide(generic)); normalized = false; return this; } else return copy().divide(generic); } public Polynomial divide(Monomial monomial) throws ArithmeticException { if (monomial.degree() == 0) return this; if (mutable) { ListIterator it = content.listIterator(); while (it.hasNext()) it.set(((Term) it.next()).divide(monomial)); degree -= monomial.degree(); sugar -= monomial.degree(); return this; } else return copy().divide(monomial); } public Polynomial gcd(Polynomial polynomial) { throw new UnsupportedOperationException(); } public int degree() { return degree; } public Polynomial valueOf(Polynomial polynomial) { ListPolynomial p = newinstance(0); p.init(polynomial); return p; } public Polynomial valueOf(Generic generic) { ListPolynomial p = newinstance(0); p.init(generic); return p; } public Polynomial valueOf(Monomial monomial) { ListPolynomial p = newinstance(0); p.init(monomial); return p; } public Polynomial freeze() { mutable = false; return this; } public Term head() { int size = content.size(); return size > 0 ? (Term) content.get(size - 1) : null; } public Term tail() { int size = content.size(); return size > 0 ? (Term) content.get(0) : null; } void init(Polynomial polynomial) { ListPolynomial q = (ListPolynomial) polynomial; content.addAll(q.content); degree = q.degree; sugar = q.sugar; } void init(Expression expression) { Map map = new TreeMap(ordering); 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()); Generic a2 = coefficient(l.degree() > 0 ? en.multiply(Expression.valueOf(l)) : en); Generic a1 = (Generic) map.get(m); Generic a = a1 == null ? a2 : a1.add(a2); if (a.signum() == 0) map.remove(m); else map.put(m, a); } int sugar = 0; Iterator it = map.entrySet().iterator(); while (it.hasNext()) { Map.Entry e = (Map.Entry) it.next(); Monomial m = (Monomial) e.getKey(); Generic a = (Generic) e.getValue(); content.add(new Term(m, a)); sugar = Math.max(sugar, m.degree()); } degree = degree(this); this.sugar = sugar; } void init(Generic generic) { if (generic instanceof Expression) { init((Expression) generic); } else { Generic a = coefficient(generic); if (a.signum() != 0) { content.add(new Term(monomial(Literal.newInstance()), a)); } degree = 0; sugar = 0; } } void init(Monomial monomial) { content.add(new Term(monomial, coefficient(JsclInteger.valueOf(1)))); degree = monomial.degree(); sugar = monomial.degree(); } protected ListPolynomial newinstance(int n) { return new ListPolynomial(monomialFactory, coefFactory); } class ContentIterator implements ListIterator { final ListIterator iterator; final boolean direction; ContentIterator(boolean direction, Monomial current) { this.direction = direction; iterator = content.listIterator(indexOf(current, direction)); } public boolean hasNext() { return direction ? iterator.hasPrevious() : iterator.hasNext(); } public Object next() { return direction ? iterator.previous() : iterator.next(); } public boolean hasPrevious() { return direction ? iterator.hasNext() : iterator.hasPrevious(); } public Object previous() { return direction ? iterator.next() : iterator.previous(); } public int nextIndex() { return direction ? iterator.previousIndex() : iterator.nextIndex(); } public int previousIndex() { return direction ? iterator.nextIndex() : iterator.previousIndex(); } public void remove() { iterator.remove(); } public void set(Object o) { iterator.set(o); } public void add(Object o) { iterator.add(o); } } }