package jscl.math.polynomial; import jscl.math.Literal; import jscl.math.NotDivisibleException; import jscl.math.Variable; import jscl.math.function.Fraction; import jscl.math.function.Pow; import jscl.mathml.MathML; import java.util.Iterator; public class Monomial implements Comparable { public static final Ordering lexicographic = Lexicographic.ordering; public static final Ordering totalDegreeLexicographic = TotalDegreeLexicographic.ordering; public static final Ordering degreeReverseLexicographic = DegreeReverseLexicographic.ordering; public static final Ordering iteratorOrdering = totalDegreeLexicographic; final Variable unknown[]; final Ordering ordering; final int element[]; int degree; Monomial(Variable unknown[], Ordering ordering) { this(unknown.length, unknown, ordering); } Monomial(int length, Variable unknown[], Ordering ordering) { this.unknown = unknown; this.ordering = ordering; element = new int[length]; } public static Ordering kthElimination(int k) { return new KthElimination(k, 1); } static Monomial factory(Variable unknown[]) { return factory(unknown, lexicographic); } static Monomial factory(Variable unknown[], Ordering ordering) { return factory(unknown, ordering, 0); } static Monomial factory(Variable unknown[], Ordering ordering, int power_size) { switch (power_size) { case Basis.POWER_8: return new SmallMonomial(unknown, small(ordering)); case Basis.POWER_2: return new BooleanMonomial(unknown, small(ordering)); case Basis.POWER_2_DEFINED: return new DefinedBooleanMonomial(unknown, small(ordering)); default: return new Monomial(unknown, ordering); } } static Ordering small(Ordering ordering) { if (ordering == lexicographic) return SmallMonomial.lexicographic; else if (ordering == totalDegreeLexicographic) return SmallMonomial.totalDegreeLexicographic; else if (ordering == degreeReverseLexicographic) return SmallMonomial.degreeReverseLexicographic; else throw new UnsupportedOperationException(); } static int variable(Variable v, Variable unknown[]) { int i = 0; for (; i < unknown.length; i++) if (unknown[i].equals(v)) break; return i; } public Variable[] unknown() { return unknown; } public Ordering ordering() { return ordering; } public Monomial multiply(Monomial monomial) { Monomial m = newinstance(); for (int i = 0; i < unknown.length; i++) { m.element[i] = element[i] + monomial.element[i]; } m.degree = degree + monomial.degree; return m; } public boolean multiple(Monomial monomial) { return multiple(monomial, false); } public boolean multiple(Monomial monomial, boolean strict) { boolean equal = true; for (int i = 0; i < unknown.length; i++) { if (element[i] < monomial.element[i]) return false; equal &= element[i] == monomial.element[i]; } return strict ? !equal : true; } public Monomial divide(Monomial monomial) throws ArithmeticException { Monomial m = newinstance(); for (int i = 0; i < unknown.length; i++) { int n = element[i] - monomial.element[i]; if (n < 0) throw new NotDivisibleException(); m.element[i] = n; } m.degree = degree - monomial.degree; return m; } public Monomial gcd(Monomial monomial) { Monomial m = newinstance(); for (int i = 0; i < unknown.length; i++) { int n = Math.min(element[i], monomial.element[i]); m.element[i] = n; m.degree += n; } return m; } public Monomial scm(Monomial monomial) { Monomial m = newinstance(); for (int i = 0; i < unknown.length; i++) { int n = Math.max(element[i], monomial.element[i]); m.element[i] = n; m.degree += n; } return m; } public int degree() { return degree; } public Monomial valueof(Monomial monomial) { Monomial m = newinstance(); System.arraycopy(monomial.element, 0, m.element, 0, m.element.length); m.degree = monomial.degree; return m; } public Monomial valueof(Literal literal) { Monomial m = newinstance(); m.init(literal); return m; } public Literal literalValue() { return Literal.valueOf(this); } public int element(int n) { return element[n]; } public Iterator iterator() { return iterator(newinstance()); } public Iterator iterator(Monomial beginning) { return new MonomialIterator(beginning, this); } public Iterator divisor() { return divisor(newinstance()); } public Iterator divisor(Monomial beginning) { return new MonomialDivisor(beginning, this); } public int compareTo(Monomial monomial) { return ordering.compare(this, monomial); } public int compareTo(Object o) { return compareTo((Monomial) o); } void init(Literal literal) { int s = literal.size(); for (int i = 0; i < s; i++) { Variable v = literal.getVariable(i); int c = literal.getPower(i); int n = variable(v, unknown); if (n < unknown.length) put(n, c); } } void put(int n, int integer) { element[n] += integer; degree += integer; } public String toString() { StringBuffer buffer = new StringBuffer(); if (degree == 0) buffer.append("1"); boolean b = false; for (int i = 0; i < unknown.length; i++) { int c = element(i); if (c > 0) { if (b) buffer.append("*"); else b = true; Variable v = unknown[i]; if (c == 1) buffer.append(v); else { if (v instanceof Fraction || v instanceof Pow) { buffer.append("(").append(v).append(")"); } else buffer.append(v); buffer.append("^").append(c); } } } return buffer.toString(); } public void toMathML(MathML element, Object data) { if (degree == 0) { MathML e1 = element.element("mn"); e1.appendChild(element.text("1")); element.appendChild(e1); } for (int i = 0; i < unknown.length; i++) { int c = element(i); if (c > 0) { unknown[i].toMathML(element, new Integer(c)); } } } protected Monomial newinstance() { return new Monomial(element.length, unknown, ordering); } } class MonomialIterator implements Iterator { static final Ordering ordering = Monomial.iteratorOrdering; Monomial monomial; Monomial current; boolean carry; MonomialIterator(Monomial beginning, Monomial monomial) { this.monomial = monomial; current = monomial.valueof(beginning); if (ordering.compare(current, monomial) > 0) carry = true; } public boolean hasNext() { return !carry; } public Object next() { Monomial m = monomial.valueof(current); if (ordering.compare(current, monomial) < 0) increment(); else carry = true; return m; } void increment() { int s = 0; int n = 0; while (n < current.element.length && current.element[n] == 0) n++; if (n < current.element.length) { s = current.element[n]; current.element[n] = 0; n++; } if (n < current.element.length) { current.element[n]++; fill(s - 1); } else { current.degree++; fill(s + 1); } } private void fill(int s) { current.element[0] = s; } public void remove() { throw new UnsupportedOperationException(); } } class MonomialDivisor extends MonomialIterator { MonomialDivisor(Monomial beginning, Monomial monomial) { super(beginning, monomial); if (hasNext()) seek(); } void seek() { int n = current.element.length; while (n > 0) { n--; if (current.element[n] > monomial.element[n]) break; } int p = n; while (n > 0) { n--; current.element[p] += current.element[n]; current.element[n] = 0; } if (p < current.element.length && current.element[p] > monomial.element[p]) increment(); } void increment() { int s = 0; int n = 0; while (n < current.element.length && current.element[n] == 0) n++; if (n < current.element.length) { s = current.element[n]; current.element[n] = 0; n++; } while (n < current.element.length && current.element[n] == monomial.element[n]) { s += current.element[n]; current.element[n] = 0; n++; } if (n < current.element.length) { current.element[n]++; fill(s - 1); } else { current.degree++; fill(s + 1); } } private void fill(int s) { for (int i = 0; i < current.element.length; i++) { int d = Math.min(monomial.element[i] - current.element[i], s); current.element[i] += d; s -= d; } } } class Lexicographic extends Ordering { public static final Ordering ordering = new Lexicographic(); Lexicographic() { } public int compare(Monomial m1, Monomial m2) { int c1[] = m1.element; int c2[] = m2.element; int n = c1.length; for (int i = n - 1; i >= 0; i--) { if (c1[i] < c2[i]) return -1; else if (c1[i] > c2[i]) return 1; } return 0; } } class TotalDegreeLexicographic extends Lexicographic implements DegreeOrdering { public static final Ordering ordering = new TotalDegreeLexicographic(); TotalDegreeLexicographic() { } public int compare(Monomial m1, Monomial m2) { if (m1.degree < m2.degree) return -1; else if (m1.degree > m2.degree) return 1; else return super.compare(m1, m2); } } class DegreeReverseLexicographic extends Ordering implements DegreeOrdering { public static final Ordering ordering = new DegreeReverseLexicographic(); DegreeReverseLexicographic() { } public int compare(Monomial m1, Monomial m2) { if (m1.degree < m2.degree) return -1; else if (m1.degree > m2.degree) return 1; else { int c1[] = m1.element; int c2[] = m2.element; int n = c1.length; for (int i = 0; i < n; i++) { if (c1[i] > c2[i]) return -1; else if (c1[i] < c2[i]) return 1; } return 0; } } } class KthElimination extends Ordering { final int k; KthElimination(int k, int direction) { this.k = k; } public int compare(Monomial m1, Monomial m2) { int c1[] = m1.element; int c2[] = m2.element; int n = c1.length; int k = n - this.k; for (int i = n - 1; i >= k; i--) { if (c1[i] < c2[i]) return -1; else if (c1[i] > c2[i]) return 1; } return DegreeReverseLexicographic.ordering.compare(m1, m2); } }