package jscl.math.polynomial; import jscl.math.Expression; import jscl.math.Generic; import jscl.math.JsclInteger; import jscl.math.Literal; import javax.annotation.Nonnull; import java.util.Arrays; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; final class ArrayPolynomial extends Polynomial { Term content[]; int size; int degree; ArrayPolynomial(Monomial monomialFactory, Generic coefFactory) { super(monomialFactory, coefFactory); } ArrayPolynomial(int size, Monomial monomialFactory, Generic coefFactory) { this(monomialFactory, coefFactory); init(size); } public int size() { return size; } void init(int size) { content = new Term[size]; this.size = size; } void resize(int size) { int length = content.length; if (size < length) { Term content[] = new Term[size]; System.arraycopy(this.content, length - size, content, 0, size); this.content = content; this.size = size; } } public Iterator iterator(boolean direction, Monomial current) { return new ContentIterator(direction, current); } int indexOf(Monomial monomial, boolean direction) { if (monomial == null) return direction ? size : 0; int n = Arrays.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; ArrayPolynomial q = (ArrayPolynomial) that; ArrayPolynomial p = newinstance(size + q.size); int i = p.size; int i1 = size; int i2 = q.size; Term t1 = i1 > 0 ? content[--i1] : null; Term t2 = i2 > 0 ? q.content[--i2] : null; while (t1 != null || t2 != null) { int c = t1 == null ? 1 : (t2 == null ? -1 : -ordering.compare(t1.monomial(), t2.monomial())); if (c < 0) { p.content[--i] = t1; t1 = i1 > 0 ? content[--i1] : null; } else if (c > 0) { p.content[--i] = t2.negate(); t2 = i2 > 0 ? q.content[--i2] : null; } else { Term t = t1.subtract(t2); if (t.signum() != 0) p.content[--i] = t; t1 = i1 > 0 ? content[--i1] : null; t2 = i2 > 0 ? q.content[--i2] : null; } } p.resize(p.size - i); p.degree = degree(p); p.sugar = Math.max(sugar, q.sugar); return p; } public Polynomial multiplyAndSubtract(Generic generic, Polynomial polynomial) { if (generic.signum() == 0) return this; if (generic.compareTo(JsclInteger.valueOf(1)) == 0) return subtract(polynomial); ArrayPolynomial q = (ArrayPolynomial) polynomial; ArrayPolynomial p = newinstance(size + q.size); int i = p.size; int i1 = size; int i2 = q.size; Term t1 = i1 > 0 ? content[--i1] : null; Term t2 = i2 > 0 ? q.content[--i2].multiply(generic) : null; while (t1 != null || t2 != null) { int c = t1 == null ? 1 : (t2 == null ? -1 : -ordering.compare(t1.monomial(), t2.monomial())); if (c < 0) { p.content[--i] = t1; t1 = i1 > 0 ? content[--i1] : null; } else if (c > 0) { p.content[--i] = t2.negate(); t2 = i2 > 0 ? q.content[--i2].multiply(generic) : null; } else { Term t = t1.subtract(t2); if (t.signum() != 0) p.content[--i] = t; t1 = i1 > 0 ? content[--i1] : null; t2 = i2 > 0 ? q.content[--i2].multiply(generic) : null; } } p.resize(p.size - i); p.degree = degree(p); p.sugar = Math.max(sugar, q.sugar); return p; } 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); ArrayPolynomial q = (ArrayPolynomial) polynomial; ArrayPolynomial p = newinstance(size + q.size); int i = p.size; int i1 = size; int i2 = q.size; Term t1 = i1 > 0 ? content[--i1] : null; Term t2 = i2 > 0 ? q.content[--i2].multiply(monomial, generic) : null; while (t1 != null || t2 != null) { int c = t1 == null ? 1 : (t2 == null ? -1 : -ordering.compare(t1.monomial(), t2.monomial())); if (c < 0) { p.content[--i] = t1; t1 = i1 > 0 ? content[--i1] : null; } else if (c > 0) { p.content[--i] = t2.negate(); t2 = i2 > 0 ? q.content[--i2].multiply(monomial, generic) : null; } else { Term t = t1.subtract(t2); if (t.signum() != 0) p.content[--i] = t; t1 = i1 > 0 ? content[--i1] : null; t2 = i2 > 0 ? q.content[--i2].multiply(monomial, generic) : null; } } p.resize(p.size - i); p.degree = degree(p); p.sugar = Math.max(sugar, q.sugar + monomial.degree()); return p; } @Nonnull public Polynomial multiply(@Nonnull Polynomial that) { Polynomial p = valueOf(JsclInteger.valueOf(0)); for (int i = 0; i < size; i++) { Term t = content[i]; p = p.multiplyAndSubtract(t.monomial(), t.coef().negate(), that); } return p; } public Polynomial multiply(Generic generic) { if (generic.signum() == 0) return valueOf(JsclInteger.valueOf(0)); if (generic.compareTo(JsclInteger.valueOf(1)) == 0) return this; ArrayPolynomial p = newinstance(size); for (int i = 0; i < size; i++) p.content[i] = content[i].multiply(generic); p.degree = degree; p.sugar = sugar; return p; } public Polynomial multiply(Monomial monomial) { if (defined) throw new UnsupportedOperationException(); if (monomial.degree() == 0) return this; ArrayPolynomial p = newinstance(size); for (int i = 0; i < size; i++) p.content[i] = content[i].multiply(monomial); p.degree = degree + monomial.degree(); p.sugar = sugar + monomial.degree(); return p; } public Polynomial divide(Generic generic) throws ArithmeticException { if (generic.compareTo(JsclInteger.valueOf(1)) == 0) return this; ArrayPolynomial p = newinstance(size); for (int i = 0; i < size; i++) p.content[i] = content[i].divide(generic); p.degree = degree; p.sugar = sugar; return p; } public Polynomial divide(Monomial monomial) throws ArithmeticException { if (monomial.degree() == 0) return this; ArrayPolynomial p = newinstance(size); for (int i = 0; i < size; i++) p.content[i] = content[i].divide(monomial); p.degree = degree - monomial.degree(); p.sugar = sugar - monomial.degree(); return p; } public Polynomial gcd(Polynomial polynomial) { throw new UnsupportedOperationException(); } public Generic gcd() { if (field) return coefficient(tail()); Generic a = coefficient(JsclInteger.valueOf(0)); for (int i = size - 1; i >= 0; i--) a = a.gcd(content[i].coef()); return a.signum() == signum() ? a : a.negate(); } public Monomial monomialGcd() { Monomial m = monomial(tail()); for (int i = 0; i < size; i++) m = m.gcd(content[i].monomial()); return m; } public int degree() { return degree; } public Polynomial valueOf(Polynomial polynomial) { ArrayPolynomial p = newinstance(0); p.init(polynomial); return p; } public Polynomial valueOf(Generic generic) { ArrayPolynomial p = newinstance(0); p.init(generic); return p; } public Polynomial valueOf(Monomial monomial) { ArrayPolynomial p = newinstance(0); p.init(monomial); return p; } public Polynomial freeze() { return this; } public Term head() { return size > 0 ? content[size - 1] : null; } public Term tail() { return size > 0 ? content[0] : null; } void init(Polynomial polynomial) { ArrayPolynomial q = (ArrayPolynomial) polynomial; init(q.size); System.arraycopy(q.content, 0, content, 0, size); 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); } init(map.size()); int sugar = 0; Iterator it = map.entrySet().iterator(); for (int i = 0; i < size; i++) { Map.Entry e = (Map.Entry) it.next(); Monomial m = (Monomial) e.getKey(); Generic a = (Generic) e.getValue(); content[i] = 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) { init(1); content[0] = new Term(monomial(Literal.newInstance()), a); } else init(0); degree = 0; sugar = 0; } } void init(Monomial monomial) { init(1); content[0] = new Term(monomial, coefficient(JsclInteger.valueOf(1))); degree = monomial.degree(); sugar = monomial.degree(); } protected ArrayPolynomial newinstance(int n) { return new ArrayPolynomial(n, monomialFactory, coefFactory); } class ContentIterator implements Iterator { final boolean direction; int index; ContentIterator(boolean direction, Monomial current) { this.direction = direction; index = indexOf(current, direction); } public boolean hasNext() { return direction ? index > 0 : index < size; } public Object next() { return direction ? content[--index] : content[index++]; } public void remove() { throw new UnsupportedOperationException(); } } }