/*
* 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.arithmetic.equation.rule.EquationRule;
import jmathexpr.arithmetic.equation.rule.RuleMachine;
import jmathexpr.arithmetic.func.Sqrt;
import jmathexpr.arithmetic.natural.Naturals;
import jmathexpr.arithmetic.op.Addition;
import jmathexpr.arithmetic.op.Exponentiation;
import jmathexpr.arithmetic.op.Subtraction;
import jmathexpr.arithmetic.op.Sum;
import jmathexpr.arithmetic.rule.DistributiveLaw;
import jmathexpr.relation.Equality;
import jmathexpr.set.Set;
import jmathexpr.util.logging.Logger;
import jmathexpr.util.pattern.AnyPattern;
import jmathexpr.util.pattern.ExpressionPattern;
import jmathexpr.util.pattern.FunctionPattern;
import jmathexpr.util.pattern.NotPattern;
import jmathexpr.util.pattern.TerminationPattern;
import jmathexpr.util.rule.CompositeRule;
import jmathexpr.util.rule.SimpleRule;
import jmathexpr.util.rule.SubRule;
/**
* Radical equation in one unknown. This class is immutable.
*
* @author Elemér Furka
*/
public class RadicalEquation extends Equation {
/**
* 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
*/
public RadicalEquation(Expression lhs, Expression rhs, Variable x) {
super(lhs, rhs, x);
}
/**
* Creates a new radical equation instance using an existing equality.
*
* @param equality the equality to be transformed into an equation
*/
public RadicalEquation(Equality equality, Variable x) {
this(equality.lhs(), equality.rhs(), x);
}
@Override
protected RadicalEquation create(Expression lhs, Expression rhs) {
return new RadicalEquation(lhs, rhs, x);
}
/**
* Tests if the given equality is a radical equation.
*
* @param equality the equality to test
* @param x the unknown in the equation
* @return true if the equality is a radical equation
*/
public static boolean isA(Equality equality, Variable x) {
return equality.contains(new Sqrt(new FunctionPattern(x)));
}
/**
* Solves this radical equation equality by equality. The steps are stored internally.
*
* @return a set of zero or one or infinite number of elements: the solution of this radical equation
*/
@Override
public Set solve() throws EquationSolveException {
rules = new RuleMachine(this);
rules.addRule(new SeparateRadicals());
rules.addRule(new Square());
rules.addRule(new DistributiveLaw());
rules.addRule(new ToLinearEquation());
rules.addRule(new ToQuadraticEquation());
Set result = rules.execute();
result = check(result);
return result;
}
/**
* Separates radical expressions.
*/
private class SeparateRadicals extends CompositeRule {
private final TerminationPattern a = new AnyPattern();
private final ExpressionPattern b = new NotPattern(new Sqrt(new FunctionPattern(x)));
private final ExpressionPattern s = new FunctionPattern(
new Sqrt(new FunctionPattern(x)));
private SeparateRadicals() {
super(false);
}
@Override
public boolean matches(Expression expr) {
target = expr;
// the order of these two subrules is important (the second one may match the first one)
if ((rule = new SqrtSubtract()).matches(expr)) return true;
if ((rule = new SqrtAdd()).matches(expr)) return true;
return false;
}
/**
* sqrt(f(x)) + a = b -> sqrt(f(x)) = b - a
*/
private class SqrtAdd extends SubRule {
@Override
public boolean matches(Expression expr) {
ExpressionPattern sum = new Sum(s, a);
return new Equality(sum, b).matches(expr);
}
@Override
public Expression apply() {
Equality eq = (Equality) target;
Expression lhs = Sum.subtract(eq.lhs(), a.hit());
Expression rhs = Sum.subtract(eq.rhs(), a.hit());
return new Equality(lhs, rhs);
}
}
/**
* sqrt(f(x)) - a = b -> sqrt(f(x)) = b + a
*/
private class SqrtSubtract extends SubRule {
@Override
public boolean matches(Expression expr) {
ExpressionPattern diff = new Subtraction(s, a);
return new Equality(diff, b).matches(expr);
}
@Override
public Expression apply() {
Equality eq = (Equality) target;
Expression lhs = Sum.add(eq.lhs(), a.hit());
Expression rhs = Sum.add(eq.rhs(), a.hit());
return new Equality(lhs, rhs);
}
}
}
/**
* Rule used to raise to square both sides of the equation.
*/
private class Square extends SimpleRule {
@Override
public boolean matches(Expression expr) {
target = expr;
return expr.contains(new Sqrt(new FunctionPattern(x)));
}
@Override
public Expression apply() {
ANumber two = Naturals.getInstance().create(2);
Equality eq = (Equality) target;
return new Equality(new Exponentiation(eq.lhs(), two),
new Exponentiation(eq.rhs(), two));
}
}
/**
* This rule transforms the current equation into a linear equation.
*/
private class ToLinearEquation extends SimpleRule implements EquationRule {
@Override
public boolean matches(Expression expr) {
target = expr;
return LinearEquation.isConvertible((Equality) expr, x);
}
@Override
public Expression apply() {
throw new UnsupportedOperationException("Call convertedEquations() instead!");
}
@Override
public List<Equation> convertedEquations() {
List<Equation> equations = new ArrayList();
Equality eq = (Equality) target;
equations.add(new LinearEquation(eq, x));
return equations;
}
}
/**
* This rule transforms the current equation into a quadratic equation.
*/
private class ToQuadraticEquation extends SimpleRule implements EquationRule {
@Override
public boolean matches(Expression expr) {
target = expr;
return QuadraticEquation.isConvertible(expr, x);
}
@Override
public Expression apply() {
throw new UnsupportedOperationException("Call convertedEquations() instead!");
}
@Override
public List<Equation> convertedEquations() {
List<Equation> equations = new ArrayList();
Equality eq = (Equality) target;
equations.add(new QuadraticEquation(eq, x));
return equations;
}
}
}