/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package jmathexpr.arithmetic.equation;
import java.util.ArrayList;
import java.util.List;
import jmathexpr.Expression;
import jmathexpr.Variable;
import jmathexpr.arithmetic.ANumber;
import jmathexpr.bool.TruthValue;
import jmathexpr.arithmetic.equation.rule.RuleMachine;
import jmathexpr.arithmetic.func.UnivariateNumberFunction;
import jmathexpr.arithmetic.op.Multiplication;
import jmathexpr.arithmetic.op.Negation;
import jmathexpr.arithmetic.op.Subtraction;
import jmathexpr.relation.Equality;
import jmathexpr.set.EmptySet;
import jmathexpr.set.FiniteSet;
import jmathexpr.set.Set;
import jmathexpr.util.context.ExpressionContext;
import jmathexpr.util.context.Statement;
import jmathexpr.util.context.Statement.Command;
/**
* Equation in one unknown. This class is immutable.
*
* @author Elemér Furka
*/
public abstract class Equation extends Equality {
/**
* The rule machine used to solve this equation.
*/
protected RuleMachine rules;
/**
* The variable this equation can be solved for.
*/
protected final Variable x;
/**
* Creates a new radical equation specifying the two sides of the equality.
*
* @param lhs left hand side of the equality
* @param rhs right hand side of the equality
* @param x the indeterminate in the equation
*/
protected Equation(Expression lhs, Expression rhs, Variable x) {
super(lhs, rhs);
this.x = x;
}
/**
* Creates a new equation instance using an existing equality.
*
* @param equality the equality to be transformed into an equation
* @param x the indeterminate in the equation
*/
protected Equation(Equality equality, Variable x) {
this(equality.lhs(), equality.rhs(), x);
}
/**
* Solves this equation step by step. The steps are stored internally.
*
* @return a set of zero or one or infinite number of elements: the solutions of this equation
* @throws EquationSolveException if the equation cannot be solved
*/
public abstract Set solve() throws EquationSolveException;
@Override
public Expression evaluate() {
Expression evaluated = super.evaluate();
if (evaluated instanceof TruthValue) {
return evaluated;
} else {
Expression reduced =
new Subtraction(((Equality) evaluated).lhs(), ((Equality) evaluated).rhs()).evaluate();
TruthValue isZero = isZero(reduced);
if (isZero != null) {
return isZero;
}
}
return evaluated;
}
private static TruthValue isZero(Expression expr) {
if (expr instanceof ANumber) {
return TruthValue.valueOf(((ANumber) expr).isZero());
} else if (expr instanceof Multiplication) {
TruthValue leftIsZero = isZero(((Multiplication) expr).lhs());
TruthValue rightIsZero = isZero(((Multiplication) expr).rhs());
if (leftIsZero == TruthValue.True) {
return TruthValue.True;
} else if (rightIsZero == TruthValue.True) {
return TruthValue.True;
} else if (leftIsZero == TruthValue.False && rightIsZero == TruthValue.False) {
return TruthValue.False;
}
} else if (expr instanceof Negation) {
return isZero(((Negation) expr).getChild());
} else if (expr instanceof UnivariateNumberFunction) {
return TruthValue.False;
}
return null;
}
/**
* Converts the equality into an appropriate equation.
*
* @param eq an equality
* @param x a variable
* @return the equality converted into an equation
*/
public static Equation convert(Equality eq, Variable x) {
if (AbsoluteValueEquation.isA(eq, x)) {
return new AbsoluteValueEquation(eq, x);
} else if (RadicalEquation.isA(eq, x)) {
return new RadicalEquation(eq, x);
} else if (QuadraticEquation.isConvertible(eq, x)) {
return new QuadraticEquation(eq, x);
} else {
return new LinearEquation(eq, x);
}
}
/**
* Returns the variable this equation is solved for.
*
* @return this equation's variable
*/
public Variable variable() {
return x;
}
@Override
public Set domain() {
return x.domain();
}
protected Set check(Set result) {
List<Expression> checked = new ArrayList();
if (result instanceof FiniteSet) {
for (Expression e : ((FiniteSet) result)) {
if (satisfies(e)) {
checked.add(e);
}
}
return new FiniteSet(checked);
} else if (result instanceof EmptySet) {
return result;
} else {
throw new IllegalStateException("Set type not yet supported: " + result);
}
}
private boolean satisfies(Expression expr) {
try {
x.setValue(expr);
Expression evaluated = evaluate();
if (evaluated instanceof TruthValue) {
boolean satisfied = ((TruthValue) evaluated).toBoolean();
System.out.printf(" check: %s at %s = %s: %s%n",
this, x.name(), expr, satisfied);
if (!satisfied) {
Equality eq = new Equality(lhs.evaluate(), rhs.evaluate());
ExpressionContext.getInstance().addStatement(
new Statement(Command.Expression, eq));
}
return satisfied;
} else {
Equality eq = (Equality) evaluated;
throw new IllegalStateException(String.format(
"Cannot check equality: %s = %s (%s %s), %s = %s ",
eq.lhs(), eq.rhs(), eq.lhs().getClass().getSimpleName(), eq.rhs().getClass().getSimpleName(), x.name(), expr));
}
} finally {
x.reset();
}
}
}