
jscl.math.Expression Maven / Gradle / Ivy
package jscl.math;
import jscl.JsclMathEngine;
import jscl.math.function.Constant;
import jscl.math.function.Fraction;
import jscl.math.function.Inverse;
import jscl.math.numeric.Real;
import jscl.math.polynomial.Polynomial;
import jscl.math.polynomial.UnivariatePolynomial;
import jscl.mathml.MathML;
import jscl.text.*;
import jscl.text.msg.Messages;
import jscl.util.ArrayUtils;
import org.solovyev.common.Converter;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
public class Expression extends Generic {
private Literal literals[];
private JsclInteger coefficients[];
int size;
Expression() {
}
Expression(int size) {
init(size);
}
public int size() {
return size;
}
public Literal literal(int n) {
return literals[n];
}
public JsclInteger coef(int n) {
return coefficients[n];
}
void init(int size) {
literals = new Literal[size];
coefficients = new JsclInteger[size];
this.size = size;
}
void resize(int size) {
int length = literals.length;
if (size < length) {
Literal literal[] = new Literal[size];
JsclInteger coef[] = new JsclInteger[size];
System.arraycopy(this.literals, length - size, literal, 0, size);
System.arraycopy(this.coefficients, length - size, coef, 0, size);
this.literals = literal;
this.coefficients = coef;
this.size = size;
}
}
public Expression add(@Nonnull Expression that) {
final Expression result = newInstance(size + that.size);
int i = result.size;
int thisI = this.size;
int thatI = that.size;
Literal thisLiteral = thisI > 0 ? this.literals[--thisI] : null;
Literal thatLiteral = thatI > 0 ? that.literals[--thatI] : null;
while (thisLiteral != null || thatLiteral != null) {
int c;
if (thisLiteral == null) {
c = 1;
} else if (thatLiteral == null) {
c = -1;
} else {
c = -thisLiteral.compareTo(thatLiteral);
}
if (c < 0) {
final JsclInteger thisCoefficient = this.coefficients[thisI];
--i;
result.literals[i] = thisLiteral;
result.coefficients[i] = thisCoefficient;
thisLiteral = thisI > 0 ? literals[--thisI] : null;
} else if (c > 0) {
JsclInteger en = that.coefficients[thatI];
--i;
result.literals[i] = thatLiteral;
result.coefficients[i] = en;
thatLiteral = thatI > 0 ? that.literals[--thatI] : null;
} else {
JsclInteger sum = coefficients[thisI].add(that.coefficients[thatI]);
if (sum.signum() != 0) {
--i;
result.literals[i] = thisLiteral;
result.coefficients[i] = sum;
}
thisLiteral = thisI > 0 ? literals[--thisI] : null;
thatLiteral = thatI > 0 ? that.literals[--thatI] : null;
}
}
result.resize(result.size - i);
return result;
}
@Nonnull
public Generic add(@Nonnull Generic that) {
if (that instanceof Expression) {
return add((Expression) that);
} else if (that instanceof JsclInteger || that instanceof Rational || that instanceof NumericWrapper) {
return add(valueOf(that));
} else {
return that.valueOf(this).add(that);
}
}
public Expression subtract(Expression expression) {
return multiplyAndAdd(Literal.newInstance(), JsclInteger.valueOf(-1), expression);
}
@Nonnull
public Generic subtract(@Nonnull Generic that) {
if (that instanceof Expression) {
return subtract((Expression) that);
} else if (that instanceof JsclInteger || that instanceof Rational || that instanceof NumericWrapper) {
return subtract(valueOf(that));
} else {
return that.valueOf(this).subtract(that);
}
}
Expression multiplyAndAdd(@Nonnull Literal literal, @Nonnull JsclInteger coefficient, @Nonnull Expression that) {
if (coefficient.signum() == 0) return this;
final Expression result = newInstance(size + that.size);
int i = result.size;
int thisI = this.size;
int thatI = that.size;
Literal thisLiteral = thisI > 0 ? literals[--thisI] : null;
Literal thatLiteral = thatI > 0 ? that.literals[--thatI].multiply(literal) : null;
while (thisLiteral != null || thatLiteral != null) {
int c = thisLiteral == null ? 1 : (thatLiteral == null ? -1 : -thisLiteral.compareTo(thatLiteral));
if (c < 0) {
JsclInteger en = coefficients[thisI];
--i;
result.literals[i] = thisLiteral;
result.coefficients[i] = en;
thisLiteral = thisI > 0 ? literals[--thisI] : null;
} else if (c > 0) {
JsclInteger en = that.coefficients[thatI].multiply(coefficient);
--i;
result.literals[i] = thatLiteral;
result.coefficients[i] = en;
thatLiteral = thatI > 0 ? that.literals[--thatI].multiply(literal) : null;
} else {
JsclInteger en = coefficients[thisI].add(that.coefficients[thatI].multiply(coefficient));
if (en.signum() != 0) {
--i;
result.literals[i] = thisLiteral;
result.coefficients[i] = en;
}
thisLiteral = thisI > 0 ? literals[--thisI] : null;
thatLiteral = thatI > 0 ? that.literals[--thatI].multiply(literal) : null;
}
}
result.resize(result.size - i);
return result;
}
public Expression multiply(Expression expression) {
Expression result = newInstance(0);
for (int i = 0; i < size; i++) {
result = result.multiplyAndAdd(literals[i], coefficients[i], expression);
}
return result;
}
@Nonnull
public Generic multiply(@Nonnull Generic that) {
if (that instanceof Expression) {
return multiply((Expression) that);
} else if (that instanceof JsclInteger || that instanceof Rational || that instanceof NumericWrapper) {
return multiply(valueOf(that));
} else {
return that.multiply(this);
}
}
@Nonnull
public Generic divide(@Nonnull Generic that) throws NotDivisibleException {
Generic a[] = divideAndRemainder(that);
if (a[1].signum() == 0) return a[0];
else throw new NotDivisibleException();
}
public Generic[] divideAndRemainder(Generic generic) throws ArithmeticException {
if (generic instanceof Expression) {
Expression ex = (Expression) generic;
Literal l1 = literalScm();
Literal l2 = ex.literalScm();
Literal l = l1.gcd(l2);
Variable va[] = l.variables();
if (va.length == 0) {
if (signum() == 0 && ex.signum() != 0) return new Generic[]{this, JsclInteger.valueOf(0)};
else try {
return divideAndRemainder(ex.integerValue());
} catch (NotIntegerException e) {
return new Generic[]{JsclInteger.valueOf(0), this};
}
} else {
Polynomial fact = Polynomial.factory(va[0]);
Polynomial p[] = fact.valueOf(this).divideAndRemainder(fact.valueOf(ex));
return new Generic[]{p[0].genericValue(), p[1].genericValue()};
}
} else if (generic instanceof JsclInteger) {
try {
Expression ex = newInstance(size);
for (int i = 0; i < size; i++) {
ex.literals[i] = literals[i];
ex.coefficients[i] = coefficients[i].divide((JsclInteger) generic);
}
return new Generic[]{ex, JsclInteger.valueOf(0)};
} catch (NotDivisibleException e) {
return new Generic[]{JsclInteger.valueOf(0), this};
}
} else if (generic instanceof Rational || generic instanceof NumericWrapper) {
return divideAndRemainder(valueOf(generic));
} else {
return generic.valueOf(this).divideAndRemainder(generic);
}
}
public Generic gcd(@Nonnull Generic generic) {
if (generic instanceof Expression) {
final Expression that = (Expression) generic;
final Literal thisL = this.literalScm();
final Literal thatL = that.literalScm();
final Literal gcdL = thisL.gcd(thatL);
final Variable vars[] = gcdL.variables();
if (vars.length == 0) {
if (signum() == 0) {
return that;
} else {
return this.gcd(that.gcd());
}
} else {
Polynomial p = Polynomial.factory(vars[0]);
return p.valueOf(this).gcd(p.valueOf(that)).genericValue();
}
} else if (generic instanceof JsclInteger) {
if (generic.signum() == 0) {
return this;
} else {
return this.gcd().gcd(generic);
}
} else if (generic instanceof Rational || generic instanceof NumericWrapper) {
return gcd(valueOf(generic));
} else {
return generic.valueOf(this).gcd(generic);
}
}
@Nonnull
public Generic gcd() {
JsclInteger result = JsclInteger.valueOf(0);
for (int i = size - 1; i >= 0; i--) {
result = result.gcd(coefficients[i]);
}
return result;
}
@Nonnull
public Literal literalScm() {
Literal result = Literal.newInstance();
for (int i = 0; i < size; i++) {
result = result.scm(literals[i]);
}
return result;
}
public Generic negate() {
return multiply(JsclInteger.valueOf(-1));
}
public int signum() {
return size == 0 ? 0 : coefficients[0].signum();
}
public int degree() {
return 0;
}
public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException {
if (isPolynomial(variable)) {
return ((UnivariatePolynomial) Polynomial.factory(variable).valueOf(this)).antiderivative().genericValue();
} else {
try {
Variable v = variableValue();
try {
return v.antiDerivative(variable);
} catch (NotIntegrableException e) {
if (v instanceof Fraction) {
Generic g[] = ((Fraction) v).getParameters();
if (g[1].isConstant(variable)) {
return new Inverse(g[1]).selfExpand().multiply(g[0].antiDerivative(variable));
}
}
}
} catch (NotVariableException e) {
Generic sumElements[] = sumValue();
if (sumElements.length > 1) {
Generic result = JsclInteger.valueOf(0);
for (Generic sumElement : sumElements) {
result = result.add(sumElement.antiDerivative(variable));
}
return result;
} else {
final Generic products[] = sumElements[0].productValue();
Generic constantProduct = JsclInteger.valueOf(1);
Generic notConstantProduct = JsclInteger.valueOf(1);
for (Generic product : products) {
if (product.isConstant(variable)) {
constantProduct = constantProduct.multiply(product);
} else {
notConstantProduct = notConstantProduct.multiply(product);
}
}
if (constantProduct.compareTo(JsclInteger.valueOf(1)) != 0) {
return constantProduct.multiply(notConstantProduct.antiDerivative(variable));
}
}
}
}
throw new NotIntegrableException(this);
}
public Generic derivative(@Nonnull Variable variable) {
Generic s = JsclInteger.valueOf(0);
Literal l = literalScm();
int n = l.size();
for (int i = 0; i < n; i++) {
Variable v = l.getVariable(i);
Generic a = ((UnivariatePolynomial) Polynomial.factory(v).valueOf(this)).derivative(variable).genericValue();
s = s.add(a);
}
return s;
}
public Generic substitute(@Nonnull final Variable variable, final Generic generic) {
final Map content = literalScm().content(new Converter() {
@Nonnull
@Override
public Generic convert(@Nonnull Variable v) {
return v.substitute(variable, generic);
}
});
return substitute(content);
}
@Nonnull
private Generic substitute(@Nonnull Map content) {
// sum = sumElement_0 + sumElement_1 + ... + sumElement_size
Generic sum = JsclInteger.ZERO;
for (int i = 0; i < size; i++) {
final Literal literal = literals[i];
// sumElement = variable_1 ^ power_1 * variable_2 ^ power_2 * ... * variable_size ^ power_size
Generic sumElement = coefficients[i];
for (int j = 0; j < literal.size(); j++) {
final Variable variable = literal.getVariable(j);
Generic b = content.get(variable).pow(literal.getPower(j));
if (Matrix.isMatrixProduct(sumElement, b)) {
throw new ArithmeticException("Should not be matrix!");
}
sumElement = sumElement.multiply(b);
}
sum = sum.add(sumElement);
}
return sum;
}
public Generic expand() {
return substitute(literalScm().content(EXPAND_CONVERTER));
}
public Generic factorize() {
return Factorization.compute(substitute(literalScm().content(FACTORIZE_CONVERTER)));
}
public Generic elementary() {
return substitute(literalScm().content(ELEMENTARY_CONVERTER));
}
public Generic simplify() {
return Simplification.compute(this);
}
public Generic numeric() {
try {
return integerValue().numeric();
} catch (NotIntegerException ex) {
final Literal literal = literalScm();
final Map content = literal.content(NUMERIC_CONVERTER);
return substitute(content);
}
}
@Nonnull
public Generic valueOf(@Nonnull Generic generic) {
final Expression result = newInstance(0);
result.init(generic);
return result;
}
@Nonnull
public Generic[] sumValue() {
final Generic result[] = new Generic[size];
for (int i = 0; i < result.length; i++) {
result[i] = valueOf(literals[i], coefficients[i]);
}
return result;
}
@Nonnull
public Generic[] productValue() throws NotProductException {
if (size == 0) {
return new Generic[]{JsclInteger.valueOf(0)};
} else if (size == 1) {
final Literal l = literals[0];
final JsclInteger k = coefficients[0];
Generic productElements[] = l.productValue();
if (k.compareTo(JsclInteger.valueOf(1)) == 0) {
return productElements;
} else {
final Generic result[] = new Generic[productElements.length + 1];
System.arraycopy(productElements, 0, result, 1, productElements.length);
result[0] = k;
return result;
}
} else {
throw new NotProductException();
}
}
public Power powerValue() throws NotPowerException {
if (size == 0) return new Power(JsclInteger.valueOf(0), 1);
else if (size == 1) {
Literal l = literals[0];
JsclInteger en = coefficients[0];
if (en.compareTo(JsclInteger.valueOf(1)) == 0) return l.powerValue();
else if (l.degree() == 0) return en.powerValue();
else throw new NotPowerException();
} else throw new NotPowerException();
}
public Expression expressionValue() throws NotExpressionException {
return this;
}
@Override
public boolean isInteger() {
try {
integerValue();
return true;
} catch (NotIntegerException e) {
return false;
}
}
public JsclInteger integerValue() throws NotIntegerException {
if (size == 0) {
return JsclInteger.valueOf(0);
} else if (size == 1) {
final Literal l = literals[0];
final JsclInteger c = coefficients[0];
if (l.degree() == 0) {
return c;
} else {
throw new NotIntegerException();
}
} else {
throw new NotIntegerException();
}
}
public Variable variableValue() throws NotVariableException {
if (size == 0) {
throw new NotVariableException();
} else if (size == 1) {
final Literal l = literals[0];
final JsclInteger c = coefficients[0];
if (c.compareTo(JsclInteger.valueOf(1)) == 0) {
return l.variableValue();
} else {
throw new NotVariableException();
}
} else {
throw new NotVariableException();
}
}
public Variable[] variables() {
return literalScm().variables();
}
public static Variable[] variables(Generic elements[]) {
final List result = new ArrayList();
for (Generic element : elements) {
for (Variable variable : element.variables()) {
if (!result.contains(variable)) {
result.add(variable);
}
}
}
return ArrayUtils.toArray(result, new Variable[result.size()]);
}
public boolean isPolynomial(@Nonnull Variable variable) {
boolean result = true;
final Literal l = literalScm();
for (int i = 0; i < l.size(); i++) {
final Variable v = l.getVariable(i);
if (!v.isConstant(variable) && !v.isIdentity(variable)) {
result = false;
break;
}
}
return result;
}
public boolean isConstant(@Nonnull Variable variable) {
Literal l = literalScm();
for (int i = 0; i < l.size(); i++) {
if (!l.getVariable(i).isConstant(variable)) {
return false;
}
}
return true;
}
public JsclVector grad(Variable variable[]) {
Generic v[] = new Generic[variable.length];
for (int i = 0; i < variable.length; i++) v[i] = derivative(variable[i]);
return new JsclVector(v);
}
public Generic laplacian(Variable variable[]) {
return grad(variable).divergence(variable);
}
public Generic dalembertian(Variable variable[]) {
Generic a = derivative(variable[0]).derivative(variable[0]);
for (int i = 1; i < 4; i++) a = a.subtract(derivative(variable[i]).derivative(variable[i]));
return a;
}
public int compareTo(Expression expression) {
int i1 = size;
int i2 = expression.size;
Literal l1 = i1 == 0 ? null : literals[--i1];
Literal l2 = i2 == 0 ? null : expression.literals[--i2];
while (l1 != null || l2 != null) {
int c = l1 == null ? -1 : (l2 == null ? 1 : l1.compareTo(l2));
if (c < 0) return -1;
else if (c > 0) return 1;
else {
c = coefficients[i1].compareTo(expression.coefficients[i2]);
if (c < 0) return -1;
else if (c > 0) return 1;
l1 = i1 == 0 ? null : literals[--i1];
l2 = i2 == 0 ? null : expression.literals[--i2];
}
}
return 0;
}
public int compareTo(@Nonnull Generic generic) {
if (generic instanceof Expression) {
return compareTo((Expression) generic);
} else if (generic instanceof JsclInteger || generic instanceof Rational || generic instanceof NumericWrapper) {
return compareTo(valueOf(generic));
} else {
return generic.valueOf(this).compareTo(generic);
}
}
@Nonnull
public static Expression valueOf(@Nonnull Variable variable) {
return valueOf(Literal.valueOf(variable));
}
@Nonnull
public static Expression valueOf(@Nonnull Literal literal) {
return valueOf(literal, JsclInteger.valueOf(1));
}
@Nonnull
public static Expression valueOf(@Nonnull JsclInteger integer) {
return valueOf(Literal.newInstance(), integer);
}
@Nonnull
public static Expression valueOf(@Nonnull Literal literal, @Nonnull JsclInteger integer) {
final Expression result = new Expression();
result.init(literal, integer);
return result;
}
void init(Literal lit, JsclInteger integer) {
if (integer.signum() != 0) {
init(1);
literals[0] = lit;
coefficients[0] = integer;
} else init(0);
}
public static Expression valueOf(Rational rational) {
Expression ex = new Expression();
ex.init(rational);
return ex;
}
public static Expression valueOf(@Nonnull Constant constant) {
final Expression expression = new Expression(1);
Literal literal = new Literal();
literal.init(constant, 1);
expression.init(literal, JsclInteger.ONE);
return expression;
}
public static Expression valueOf(@Nonnull Double value) {
final Expression expression = new Expression(1);
Literal literal = new Literal();
literal.init(new DoubleVariable(new NumericWrapper(Real.valueOf(value))), 1);
expression.init(literal, JsclInteger.ONE);
return expression;
}
public static Expression valueOf(@Nonnull String expression) throws ParseException {
final MutableInt position = new MutableInt(0);
final Parser.Parameters p = Parser.Parameters.newInstance(expression, position, JsclMathEngine.getInstance());
final Generic generic = ExpressionParser.parser.parse(p, null);
ParserUtils.skipWhitespaces(p);
int index = position.intValue();
if (index < expression.length()) {
throw new ParseException(Messages.msg_1, index, expression, index + 1);
}
return new Expression().init(generic);
}
public static Expression init(@Nonnull NumericWrapper numericWrapper) {
final Expression expression = new Expression(1);
Literal literal = new Literal();
literal.init(new ExpressionVariable(numericWrapper), 1);
expression.init(literal, JsclInteger.ONE);
return expression;
}
void init(Expression expression) {
init(expression.size);
System.arraycopy(expression.literals, 0, literals, 0, size);
System.arraycopy(expression.coefficients, 0, coefficients, 0, size);
}
void init(JsclInteger integer) {
init(Literal.newInstance(), integer);
}
void init(Rational rational) {
try {
init(Literal.newInstance(), rational.integerValue());
} catch (NotIntegerException e) {
init(Literal.valueOf(rational.variableValue()), JsclInteger.valueOf(1));
}
}
Expression init(@Nonnull Generic generic) {
if (generic instanceof Expression) {
init((Expression) generic);
} else if (generic instanceof JsclInteger) {
init((JsclInteger) generic);
} else if (generic instanceof NumericWrapper) {
init((NumericWrapper) generic);
} else if (generic instanceof Rational) {
init((Rational) generic);
} else throw new ArithmeticException("Could not initialize expression with " + generic.getClass());
return this;
}
public String toString() {
final StringBuilder result = new StringBuilder();
if (signum() == 0) {
result.append("0");
}
// result = coef[0] * literal[0] + coef[1] * literal[1] + ... +
for (int i = 0; i < size; i++) {
final Literal literal = literals[i];
final JsclInteger coefficient = coefficients[i];
if (coefficient.signum() > 0 && i > 0) {
result.append("+");
}
if (literal.degree() == 0) {
result.append(coefficient);
} else {
if (coefficient.abs().compareTo(JsclInteger.valueOf(1)) == 0) {
if (coefficient.signum() < 0) {
result.append("-");
}
} else {
result.append(coefficient).append("*");
}
result.append(literal);
}
}
return result.toString();
}
public String toJava() {
final StringBuilder result = new StringBuilder();
if (signum() == 0) {
result.append("JsclDouble.valueOf(0)");
}
for (int i = 0; i < size; i++) {
Literal l = literals[i];
JsclInteger en = coefficients[i];
if (i > 0) {
if (en.signum() < 0) {
result.append(".subtract(");
en = (JsclInteger) en.negate();
} else result.append(".add(");
}
if (l.degree() == 0) result.append(en.toJava());
else {
if (en.abs().compareTo(JsclInteger.valueOf(1)) == 0) {
if (en.signum() > 0) result.append(l.toJava());
else if (en.signum() < 0) result.append(l.toJava()).append(".negate()");
} else result.append(en.toJava()).append(".multiply(").append(l.toJava()).append(")");
}
if (i > 0) result.append(")");
}
return result.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);
}
for (int i = 0; i < size; i++) {
Literal l = literals[i];
JsclInteger en = coefficients[i];
if (en.signum() > 0 && i > 0) {
MathML e2 = element.element("mo");
e2.appendChild(element.text("+"));
e1.appendChild(e2);
}
if (l.degree() == 0) separateSign(e1, en);
else {
if (en.abs().compareTo(JsclInteger.valueOf(1)) == 0) {
if (en.signum() < 0) {
MathML e2 = element.element("mo");
e2.appendChild(element.text("-"));
e1.appendChild(e2);
}
} else separateSign(e1, en);
l.toMathML(e1, null);
}
}
element.appendChild(e1);
}
@Nonnull
@Override
public Set extends Constant> getConstants() {
final Set result = new HashSet();
for (Literal literal : literals) {
for (Variable variable : literal.variables()) {
result.addAll(variable.getConstants());
}
}
return result;
}
public static void separateSign(MathML element, Generic generic) {
if (generic.signum() < 0) {
MathML e1 = element.element("mo");
e1.appendChild(element.text("-"));
element.appendChild(e1);
generic.negate().toMathML(element, null);
} else {
generic.toMathML(element, null);
}
}
@Nonnull
private Expression newInstance(int n) {
return new Expression(n);
}
protected static final Converter FACTORIZE_CONVERTER = new Converter() {
@Nonnull
@Override
public Generic convert(@Nonnull Variable variable) {
return variable.factorize();
}
};
protected static final Converter ELEMENTARY_CONVERTER = new Converter() {
@Nonnull
@Override
public Generic convert(@Nonnull Variable variable) {
return variable.elementary();
}
};
protected static final Converter EXPAND_CONVERTER = new Converter() {
@Nonnull
@Override
public Generic convert(@Nonnull Variable variable) {
return variable.expand();
}
};
protected static final Converter NUMERIC_CONVERTER = new Converter() {
@Nonnull
@Override
public Generic convert(@Nonnull Variable variable) {
return variable.numeric();
}
};
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy