/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package jmathexpr.arithmetic.op;
import jmathexpr.Expression;
import jmathexpr.Precedence;
import jmathexpr.Variable;
import jmathexpr.arithmetic.ANumber;
import jmathexpr.arithmetic.Polynomial;
import jmathexpr.arithmetic.func.Lcm;
import jmathexpr.arithmetic.integer.IntegerNumber;
import jmathexpr.arithmetic.natural.Naturals;
import jmathexpr.arithmetic.real.Reals;
import jmathexpr.op.BinaryOperation;
import jmathexpr.op.Sign;
import jmathexpr.set.Set;
import jmathexpr.set.op.CartesianProduct;
import jmathexpr.util.logging.Logger;
/**
*
* @author Elemér Furka
*/
public class Addition extends BinaryOperation {
public Addition(Expression lhs, Expression rhs) {
super (lhs, rhs, Sign.Addition);
}
@Override
public Expression evaluate() {
Expression simplified = simplify();
if (!(simplified instanceof Addition)) return simplified;
Expression l = ((Addition) simplified).lhs;
Expression r = ((Addition) simplified).rhs;
if (l instanceof ANumber && r instanceof ANumber) {
return ((ANumber) l).add((ANumber) r);
}
return new Addition(l, r);
}
private Expression simplify() {
Expression l = lhs.evaluate();
Expression r = rhs.evaluate();
if (l.equals(r)) {
return new Multiplication(Naturals.getInstance().create(2), l);
} else if (l instanceof Division && r instanceof Division) {
Division dl = (Division) l;
Division dr = (Division) r;
if (dl.rhs().equals(dr.rhs())) { // common denominator
return new Division(new Addition(dl.lhs(), dr.lhs()), dl.rhs()).evaluate();
}
} else if (l instanceof Division) { // a/b + c = (a + bc) / b
Division div = (Division) l;
return new Division(new Addition(
div.lhs(), new Multiplication(div.rhs(), r)), div.rhs()).evaluate();
} else if (l instanceof Negation) { // -a + b = b - a
if (r instanceof Negation) { // -a - b = -(a + b)
return new Negation(new Addition(((Negation) l).getChild(), ((Negation) r).getChild()));
} else { // -a + b = b - a
return new Subtraction(r, ((Negation) l).getChild()).evaluate();
}
} else if (l.getPrecedence() == Precedence.Addition || r.getPrecedence() == Precedence.Addition) {
return new Sum(l, r).evaluate();
} else if (r instanceof Negation) { // a + (-b) = a - b
return new Subtraction(l, ((Negation) r).getChild()).evaluate();
}
return new Addition(l, r);
}
/**
* Factorize this sum (if possible).
*
* @return either the factorized form of this sum or this
*/
public Expression factorize() {
IntegerNumber l = null, r = null;
Expression lrest = null, rrest = null;
if (lhs instanceof IntegerNumber) {
l = (IntegerNumber) lhs;
lrest = Naturals.one();
} else if (lhs instanceof Multiplication
&& ((Multiplication) lhs).lhs() instanceof IntegerNumber) {
l = (IntegerNumber) ((Multiplication) lhs).lhs();
lrest = ((Multiplication) lhs).rhs();
} else if (lhs instanceof Division
&& ((Division) lhs).lhs() instanceof IntegerNumber) {
l = (IntegerNumber) ((Division) lhs).lhs();
lrest = new Division(Naturals.one(), ((Division) lhs).rhs());
}
if (rhs instanceof IntegerNumber) {
r = (IntegerNumber) rhs;
rrest = Naturals.one();
} else if (rhs instanceof Multiplication
&& ((Multiplication) rhs).lhs() instanceof IntegerNumber) {
r = (IntegerNumber) ((Multiplication) rhs).lhs();
rrest = ((Multiplication) rhs).rhs();
} else if (rhs instanceof Division
&& ((Division) rhs).lhs() instanceof IntegerNumber) {
r = (IntegerNumber) ((Division) rhs).lhs();
rrest = new Division(Naturals.one(), ((Division) rhs).rhs());
}
if (l != null && r != null) {
IntegerNumber lcm = (IntegerNumber) new Lcm(l, r).evaluate();
IntegerNumber gcd = (IntegerNumber) l.multiply(r).divide(lcm);
if (!gcd.isOne()) {
return new Multiplication(gcd, new Addition(
new Multiplication(l.divide(gcd), lrest),
new Multiplication(r.divide(gcd), rrest)).evaluate());
}
}
return this;
}
@Override
public Precedence getPrecedence() {
return Precedence.Addition;
}
@Override
public CartesianProduct domain() {
return new CartesianProduct(Reals.getInstance(), Reals.getInstance());
}
@Override
public Set codomain() {
return Reals.getInstance();
}
@Override
protected BinaryOperation create(Expression lhs, Expression rhs) {
return new Addition(lhs, rhs);
}
/**
* Converts this sum into a polynomial.
*
* @param x the indeterminate
* @return a newly created polynomial instance
*/
public Polynomial toPolynomial(Variable x) {
return new Sum(lhs, rhs).toPolynomial(x); // it also works if lhs or rhs is an addition/subtraction/sum
}
@Override
public boolean matches(Expression expr) {
boolean matches = super.matches(expr);
if (!matches) {
if (expr instanceof Sum) {
return ((Sum) expr).matches(this);
} else if (expr instanceof Polynomial) {
return ((Polynomial) expr).matches(this);
}
}
return matches;
}
/**
* Multiplies both terms of this addition by the given expression from left.
*
* @param expr an arbitrary expression
* @return a new Addition instance having its both terms multiplied by the
* specified expression
*/
public Addition multiply(Expression expr) {
return new Addition(new Multiplication(expr, lhs), new Multiplication(expr, rhs));
}
@Override
public boolean isCommutative() {
return true;
}
}