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; class ArrayPolynomialGeneric extends Polynomial { Generic coef[]; Monomial monomial[]; int size; int degree; ArrayPolynomialGeneric(Monomial monomialFactory, Generic coefFactory) { super(monomialFactory, coefFactory); } ArrayPolynomialGeneric(int size, Monomial monomialFactory, Generic coefFactory) { this(monomialFactory, coefFactory); init(size); } public int size() { return size; } void init(int size) { monomial = new Monomial[size]; coef = new Generic[size]; this.size = size; } void resize(int size) { int length = monomial.length; if (size < length) { Monomial monomial[] = new Monomial[size]; Generic coef[] = new Generic[size]; System.arraycopy(this.monomial, length - size, monomial, 0, size); System.arraycopy(this.coef, length - size, coef, 0, size); this.monomial = monomial; this.coef = coef; this.size = size; } } public Iterator iterator(boolean direction, Monomial current) { return new ContentIterator(direction, current); } Term term(final int index) { return new Term(monomial[index], null) { public Generic coef() { return coef == null ? getCoef(index) : coef; } }; } int indexOf(Monomial monomial, boolean direction) { if (monomial == null) return direction ? size : 0; int n = Arrays.binarySearch(this.monomial, monomial, ordering); return n < 0 ? -n - 1 : direction ? n : n + 1; } @Nonnull public Polynomial subtract(@Nonnull Polynomial that) { if (that.signum() == 0) return this; ArrayPolynomialGeneric q = (ArrayPolynomialGeneric) that; ArrayPolynomialGeneric p = newinstance(size + q.size); int i = p.size; int i1 = size; int i2 = q.size; Monomial m1 = i1 > 0 ? monomial[--i1] : null; Monomial m2 = i2 > 0 ? q.monomial[--i2] : null; while (m1 != null || m2 != null) { int c = m1 == null ? 1 : (m2 == null ? -1 : -ordering.compare(m1, m2)); if (c < 0) { Generic a = getCoef(i1); --i; p.monomial[i] = m1; p.setCoef(i, a); m1 = i1 > 0 ? monomial[--i1] : null; } else if (c > 0) { Generic a = q.getCoef(i2).negate(); --i; p.monomial[i] = m2; p.setCoef(i, a); m2 = i2 > 0 ? q.monomial[--i2] : null; } else { Generic a = getCoef(i1).subtract(q.getCoef(i2)); if (a.signum() != 0) { --i; p.monomial[i] = m1; p.setCoef(i, a); } m1 = i1 > 0 ? monomial[--i1] : null; m2 = i2 > 0 ? q.monomial[--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); ArrayPolynomialGeneric q = (ArrayPolynomialGeneric) polynomial; ArrayPolynomialGeneric p = newinstance(size + q.size); int i = p.size; int i1 = size; int i2 = q.size; Monomial m1 = i1 > 0 ? monomial[--i1] : null; Monomial m2 = i2 > 0 ? q.monomial[--i2] : null; while (m1 != null || m2 != null) { int c = m1 == null ? 1 : (m2 == null ? -1 : -ordering.compare(m1, m2)); if (c < 0) { Generic a = getCoef(i1); --i; p.monomial[i] = m1; p.setCoef(i, a); m1 = i1 > 0 ? monomial[--i1] : null; } else if (c > 0) { Generic a = q.getCoef(i2).multiply(generic).negate(); --i; p.monomial[i] = m2; p.setCoef(i, a); m2 = i2 > 0 ? q.monomial[--i2] : null; } else { Generic a = getCoef(i1).subtract(q.getCoef(i2).multiply(generic)); if (a.signum() != 0) { --i; p.monomial[i] = m1; p.setCoef(i, a); } m1 = i1 > 0 ? monomial[--i1] : null; m2 = i2 > 0 ? q.monomial[--i2] : 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); ArrayPolynomialGeneric q = (ArrayPolynomialGeneric) polynomial; ArrayPolynomialGeneric p = newinstance(size + q.size); int i = p.size; int i1 = size; int i2 = q.size; Monomial m1 = i1 > 0 ? this.monomial[--i1] : null; Monomial m2 = i2 > 0 ? q.monomial[--i2].multiply(monomial) : null; while (m1 != null || m2 != null) { int c = m1 == null ? 1 : (m2 == null ? -1 : -ordering.compare(m1, m2)); if (c < 0) { Generic a = getCoef(i1); --i; p.monomial[i] = m1; p.setCoef(i, a); m1 = i1 > 0 ? this.monomial[--i1] : null; } else if (c > 0) { Generic a = q.getCoef(i2).multiply(generic).negate(); --i; p.monomial[i] = m2; p.setCoef(i, a); m2 = i2 > 0 ? q.monomial[--i2].multiply(monomial) : null; } else { Generic a = getCoef(i1).subtract(q.getCoef(i2).multiply(generic)); if (a.signum() != 0) { --i; p.monomial[i] = m1; p.setCoef(i, a); } m1 = i1 > 0 ? this.monomial[--i1] : null; m2 = i2 > 0 ? q.monomial[--i2].multiply(monomial) : 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 = newinstance(0); for (int i = 0; i < size; i++) p = p.multiplyAndSubtract(monomial[i], getCoef(i).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; ArrayPolynomialGeneric p = newinstance(size); System.arraycopy(monomial, 0, p.monomial, 0, size); for (int i = 0; i < size; i++) p.setCoef(i, getCoef(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; ArrayPolynomialGeneric p = newinstance(size); for (int i = 0; i < size; i++) { p.monomial[i] = this.monomial[i].multiply(monomial); p.setCoef(i, getCoef(i)); } 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; ArrayPolynomialGeneric p = newinstance(size); System.arraycopy(monomial, 0, p.monomial, 0, size); for (int i = 0; i < size; i++) p.setCoef(i, getCoef(i).divide(generic)); p.degree = degree; p.sugar = sugar; return p; } public Polynomial divide(Monomial monomial) throws ArithmeticException { if (monomial.degree() == 0) return this; ArrayPolynomialGeneric p = newinstance(size); for (int i = 0; i < size; i++) { p.monomial[i] = this.monomial[i].divide(monomial); p.setCoef(i, getCoef(i)); } 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(getCoef(i)); return a.signum() == signum() ? a : a.negate(); } public Monomial monomialGcd() { Monomial m = monomial(tail()); for (int i = 0; i < size; i++) m = m.gcd(monomial[i]); return m; } public int degree() { return degree; } public Polynomial valueOf(Polynomial polynomial) { ArrayPolynomialGeneric p = newinstance(0); p.init(polynomial); return p; } public Polynomial valueOf(Generic generic) { ArrayPolynomialGeneric p = newinstance(0); p.init(generic); return p; } public Polynomial valueOf(Monomial monomial) { ArrayPolynomialGeneric p = newinstance(0); p.init(monomial); return p; } public Polynomial freeze() { return this; } public Term head() { return size > 0 ? term(size - 1) : null; } public Term tail() { return size > 0 ? term(0) : null; } protected Generic getCoef(int n) { return coef[n]; } protected void setCoef(int n, Generic generic) { coef[n] = generic; } public Generic genericValue() { Generic s = JsclInteger.valueOf(0); for (int i = 0; i < size; i++) { Monomial m = monomial[i]; Generic a = getCoef(i).expressionValue(); s = s.add(m.degree() > 0 ? a.multiply(Expression.valueOf(m.literalValue())) : a); } return s; } public Generic[] elements() { Generic a[] = new Generic[size]; for (int i = 0; i < size; i++) a[i] = getCoef(i); return a; } public int compareTo(Polynomial polynomial) { ArrayPolynomialGeneric q = (ArrayPolynomialGeneric) polynomial; int i1 = size; int i2 = q.size; Monomial m1 = i1 == 0 ? null : monomial[--i1]; Monomial m2 = i2 == 0 ? null : q.monomial[--i2]; while (m1 != null || m2 != null) { int c = m1 == null ? -1 : (m2 == null ? 1 : ordering.compare(m1, m2)); if (c < 0) return -1; else if (c > 0) return 1; else { c = getCoef(i1).compareTo(q.getCoef(i2)); if (c < 0) return -1; else if (c > 0) return 1; m1 = i1 == 0 ? null : monomial[--i1]; m2 = i2 == 0 ? null : q.monomial[--i2]; } } return 0; } void init(Polynomial polynomial) { ArrayPolynomialGeneric q = (ArrayPolynomialGeneric) polynomial; init(q.size); System.arraycopy(q.monomial, 0, monomial, 0, size); for (int i = 0; i < size; i++) setCoef(i, q.getCoef(i)); 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(); monomial[i] = m; setCoef(i, 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); monomial[0] = monomial(Literal.newInstance()); setCoef(0, a); } else init(0); degree = 0; sugar = 0; } } void init(Monomial monomial) { init(1); this.monomial[0] = monomial; setCoef(0, coefficient(JsclInteger.valueOf(1))); degree = monomial.degree(); sugar = monomial.degree(); } protected ArrayPolynomialGeneric newinstance(int n) { return new ArrayPolynomialGeneric(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 ? term(--index) : term(index++); } public void remove() { throw new UnsupportedOperationException(); } } }