/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package jmathexpr.arithmetic.op;
import java.util.ArrayList;
import java.util.List;
import jmathexpr.Expression;
import jmathexpr.Precedence;
import jmathexpr.Variable;
import jmathexpr.arithmetic.ANumber;
import jmathexpr.arithmetic.Polynomial;
import jmathexpr.arithmetic.natural.Naturals;
import jmathexpr.arithmetic.real.Reals;
import jmathexpr.op.BinaryOperation;
import jmathexpr.op.Operation;
import jmathexpr.op.Sign;
import jmathexpr.set.Set;
import jmathexpr.set.op.CartesianProduct;
/**
* The binary operation subtraction (minus).
*
* @author Elemér Furka
*/
public final class Subtraction extends BinaryOperation {
public Subtraction(Expression lhs, Expression rhs) {
super (lhs, rhs, Sign.Subtraction);
}
/**
* Creates a new Subtraction or Sum instance based on the input arguments.
*
* @param lhs the left hand side expression (minuend)
* @param rhs the right hand side expression (subtrahend)
*
* @return either a new Subtraction or Sum instance
*/
public static Operation subtract(Expression lhs, Expression rhs) {
if (rhs instanceof Operation && rhs.getPrecedence() == Precedence.Addition) {
return Sum.subtract(lhs, rhs);
} else if (lhs instanceof Operation && lhs.getPrecedence() == Precedence.Addition) {
return Sum.subtract(lhs, rhs);
} else {
return new Subtraction(lhs, rhs);
}
}
@Override
public Expression evaluate() {
Expression simplified = simplify();
if (!(simplified instanceof Subtraction)) return simplified;
Expression l = ((Subtraction) simplified).lhs;
Expression r = ((Subtraction) simplified).rhs;
if (l instanceof ANumber && r instanceof ANumber) {
return ((ANumber) l).subtract((ANumber) r);
} else if (l instanceof Polynomial) {
return ((Polynomial) l).subtract(r);
}
return new Subtraction(l, r);
}
private Expression simplify() {
Expression l = lhs.evaluate();
Expression r = rhs.evaluate();
if (l.equals(r)) { // a - a = 0
return Naturals.zero();
} else if (l instanceof Addition && ((Addition) l).rhs().equals(r)) { // (a + b) - b = a
return ((Addition) l).lhs();
// contradicts to
// } else if (l instanceof Negation) { // -a - b = -(a + b)
// return new Negation(new Addition(((Negation) l).getChild(), r)).evaluate();
} else if (r instanceof ANumber && ((ANumber) r).isNegative()) { // a - (-b) = a + b
return new Addition(l, ((ANumber) r).negate()).evaluate();
} else if (r instanceof Negation) { // a - (-b) = a + b
return new Addition(l, ((Negation) r).getChild()).evaluate();
} else if (l instanceof Operation && l.getPrecedence() == Precedence.Addition) {
return new Sum(l, new Negation(r)).evaluate();
} else if (r instanceof Operation && r.getPrecedence() == Precedence.Addition) {
return new Sum(l, new Negation(r)).evaluate();
}
return new Subtraction(l, r);
}
@Override
public Precedence getPrecedence() {
return Precedence.Addition;
}
@Override
public Set domain() {
return new CartesianProduct(Reals.getInstance(), Reals.getInstance());
}
@Override
public Set codomain() {
return Reals.getInstance();
}
@Override
protected Operation create(Expression lhs, Expression rhs) {
return subtract(lhs, rhs);
}
/**
* Converts this difference into a polynomial.
*
* @param x the indeterminate
* @return a newly created polynomial instance
*/
public Polynomial toPolynomial(Variable x) {
List<Expression> terms = new ArrayList();
terms.add(lhs);
terms.add(new Negation(rhs));
return new Polynomial(terms, x);
}
@Override
public boolean matches(Expression expr) {
boolean matches = super.matches(expr);
if (!matches) {
if (expr instanceof Sum) {
return ((Sum) expr).matches(this);
}
}
return matches;
}
/**
* Multiplies both terms of this subtraction by the given expression from left.
*
* @param expr an arbitrary expression
* @return a new Subtraction instance having its both terms multiplied by the
* specified expression
*/
public Subtraction multiply(Expression expr) {
return new Subtraction(new Multiplication(expr, lhs), new Multiplication(expr, rhs));
}
@Override
public boolean isCommutative() {
return false;
}
@Override
public String toString() {
if (rhs instanceof Negation) {
return String.format("%s %s (%s)", lhs, sign, rhs);
} else {
return super.toString();
}
}
}