}
Expression two = Naturals.getInstance().create(2);
if (l instanceof ANumber) {
ANumber a = (ANumber) l;
if (a.negate().isOne()) {
return new Negation(r).evaluate();
} else if (r instanceof Division) {
Division d = (Division) r;
if (d.rhs() instanceof ANumber) { // a x/b = a/b x
l = a.divide((ANumber) d.rhs());
r = d.lhs();
}
} else if (r instanceof Multiplication) {
Multiplication m = (Multiplication) r;
if (m.lhs instanceof ANumber) { // a (bx) = (ab) x
l = a.multiply((ANumber) m.lhs);
r = m.rhs;
} else if (m.rhs instanceof ANumber) { // a (xb) = (ab) x
l = a.multiply((ANumber) m.rhs);
r = m.lhs;
}
} else if (r instanceof Negation) { // a (-x) = -ax
l = a.negate();
r = ((Negation) r).getChild();
return new Multiplication(l, r).evaluate();
} else if (a.isNegative()) { // -a x = -(ax)
return new Negation(new Multiplication(a.negate(), r)).evaluate();
}
} else if (l instanceof Negation) { // (-a)b = -(ab)
return new Negation(new Multiplication(((Negation) l).getChild(), r)).evaluate();
} else if (l instanceof Multiplication) { // (ab) c
Multiplication m = (Multiplication) l;
if (m.rhs instanceof Sqrt && r instanceof Sqrt) {
l = m.lhs;
r = new Multiplication(m.rhs, r).evaluate();
} else if (r instanceof ANumber) { // (ax) c = (ac) x
l = new Multiplication(m.lhs, r).evaluate();
r = m.rhs;
}
} else if (r instanceof Division) {
Division d = (Division) r;
if (l.equals(d.rhs())) { // a x/a = x
if (d.rhs() instanceof ANumber && ((ANumber) d.rhs()).isZero()) {
throw new ArithmeticException("Division by zero: " + this);
}
return d.lhs();
} else {
return new Division(new Multiplication(l, d.lhs()), d.rhs()).evaluate();
}
} else if (r instanceof Multiplication) { // a (b c)
Multiplication m = (Multiplication) r;
if (l.equals(m.lhs)) { // a (a c) = a^2 c
l = new Exponentiation(l, two).evaluate();
r = m.rhs;
} else if (l.equals(m.rhs)) { // a (b a) = a^2 b
l = new Exponentiation(l, two).evaluate();
r = m.lhs;
} else if (l instanceof Negation) {
if (m.lhs instanceof ANumber) { // -a (nx) = -n * ax
r = new Multiplication(l, m.rhs).evaluate();
l = ((ANumber) m.lhs).negate();
}
} else if (m.lhs instanceof ANumber) {
r = new Multiplication(l, m.rhs).evaluate();
l = m.lhs;
}
} else if (r instanceof ANumber) {
ANumber b = (ANumber) r;
if (l instanceof Multiplication) {
Multiplication m = (Multiplication) l;
if (m.rhs instanceof ANumber) { // (xa) b = x (ab)