package org.matheclipse.core.reflection.system;
import org.matheclipse.core.builtin.function.LeafCount;
import org.matheclipse.core.eval.exception.Validate;
import org.matheclipse.core.eval.exception.WrongArgumentType;
import org.matheclipse.core.eval.interfaces.AbstractFunctionEvaluator;
import org.matheclipse.core.expression.F;
import org.matheclipse.core.interfaces.IAST;
import org.matheclipse.core.interfaces.IComplex;
import org.matheclipse.core.interfaces.IComplexNum;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.IFraction;
import org.matheclipse.core.interfaces.IInteger;
import org.matheclipse.core.interfaces.INum;
import org.matheclipse.core.interfaces.INumber;
import org.matheclipse.core.interfaces.ISymbol;
import org.matheclipse.core.visit.AbstractVisitorBoolean;
import org.matheclipse.core.visit.VisitorExpr;
/**
* Try to simplify a given expression
*/
public class Simplify extends AbstractFunctionEvaluator {
public static class IsBasicExpressionVisitor extends AbstractVisitorBoolean {
public IsBasicExpressionVisitor() {
super();
}
@Override
public boolean visit(IAST ast) {
if (ast.isTimes() || ast.isPlus()) {
// check the arguments
for (int i = 1; i < ast.size(); i++) {
if (!ast.get(i).accept(this)) {
return false;
}
}
return true;
}
if (ast.isPower() && (ast.get(2).isInteger())) {
// check the arguments
return ast.arg1().accept(this);
}
return false;
}
@Override
public boolean visit(IComplex element) {
return true;
}
@Override
public boolean visit(IComplexNum element) {
return true;
}
@Override
public boolean visit(IFraction element) {
return true;
}
@Override
public boolean visit(IInteger element) {
return true;
}
@Override
public boolean visit(INum element) {
return true;
}
@Override
public boolean visit(ISymbol symbol) {
return true;
}
}
class SimplifyVisitor extends VisitorExpr {
final IsBasicExpressionVisitor isBasicAST = new IsBasicExpressionVisitor();
public SimplifyVisitor() {
super();
}
private IExpr tryTransformations(IAST plusAST, IExpr test) {
IExpr result = null;
int minCounter = LeafCount.leafCount(plusAST);
IExpr temp;
int count;
try {
temp = F.evalExpandAll(test);
count = LeafCount.leafCount(temp);
if (count < minCounter) {
minCounter = count;
result = temp;
}
} catch (WrongArgumentType wat) {
//
}
return result;
}
private IExpr tryTransformations(IExpr expr) {
IExpr result = null;
if (expr.isAST()) {
// try ExpandAll, Together, Apart, Factor to reduce the expression
int minCounter = LeafCount.leafCount(expr);
IExpr temp;
int count;
try {
temp = F.evalExpandAll(expr);
count = LeafCount.leafCount(temp);
if (count < minCounter) {
minCounter = count;
result = temp;
}
} catch (WrongArgumentType wat) {
//
}
try {
temp = F.eval(F.Together(expr));
count = LeafCount.leafCount(temp);
if (count < minCounter) {
minCounter = count;
result = temp;
}
} catch (WrongArgumentType wat) {
//
}
try {
temp = F.eval(F.Factor(expr));
count = LeafCount.leafCount(temp);
if (count < minCounter) {
minCounter = count;
result = temp;
}
} catch (WrongArgumentType wat) {
//
}
try {
temp = F.eval(F.Apart(expr));
count = LeafCount.leafCount(temp);
if (count < minCounter) {
minCounter = count;
result = temp;
}
} catch (WrongArgumentType wat) {
//
}
}
return result;
}
@Override
public IExpr visit(IAST ast) {
IExpr temp;
temp = visitAST(ast);
if (temp != null) {
return temp;
}
if (ast.isPlus()) {
IAST basicPlus = F.Plus();
IAST restPlus = F.Plus();
for (int i = 1; i < ast.size(); i++) {
temp = ast.get(i);
if (temp.accept(isBasicAST)) {
basicPlus.add(temp);
} else {
restPlus.add(temp);
}
}
if (basicPlus.size() > 1) {
temp = tryTransformations(basicPlus.getOneIdentity(F.C0));
if (temp != null) {
if (restPlus.size() == 1) {
return temp;
}
return F.Plus(temp, restPlus);
}
}
} else if (ast.isTimes()) {
IAST basicTimes = F.Times();
IAST restTimes = F.Times();
INumber number = null;
if (ast.arg1().isNumber()) {
number = (INumber) ast.arg1();
}
IExpr reduced;
for (int i = 1; i < ast.size(); i++) {
temp = ast.get(i);
if (temp.accept(isBasicAST)) {
if (i != 1 && number != null) {
if (temp.isPlus()) {
// * Plus[.....]
reduced = tryToReduceNumericFactor(ast, temp, number, i);
if (reduced != null) {
return reduced;
}
} else if (temp.isPower() && ((IAST) temp).arg1().isPlus() && ((IAST) temp).get(2).isMinusOne()) {
// * Power[Plus[...], -1 ]
reduced = tryToReduceNumericFactor(ast, ((IAST) temp).arg1(), number.inverse(), i);
if (reduced != null) {
return F.Power(reduced, F.CN1);
}
}
}
basicTimes.add(temp);
} else {
restTimes.add(temp);
}
}
if (basicTimes.size() > 1) {
temp = tryTransformations(basicTimes.getOneIdentity(F.C0));
if (temp != null) {
if (restTimes.size() == 1) {
return temp;
}
return F.Times(temp, restTimes);
}
}
}
temp = F.evalExpandAll(ast);
int minCounter = LeafCount.leafCount(ast);
int count = LeafCount.leafCount(temp);
if (count < minCounter) {
return temp;
}
return null;
}
private IExpr tryToReduceNumericFactor(IAST ast, IExpr temp, IExpr arg1, int i) {
IExpr expandedAst = tryTransformations((IAST) temp, F.Times(arg1, temp));
if (expandedAst != null) {
IAST result = F.Times();
ast.range(2, ast.size()).toList(result);
result.set(i - 1, expandedAst);
return result;
}
return null;
}
}
public Simplify() {
}
@Override
public IExpr evaluate(final IAST ast) {
Validate.checkSize(ast, 2);
IExpr expr = ast.arg1();
int minCounter = LeafCount.leafCount(expr);
IExpr result = expr;
int count = 0;
IExpr temp = expr.accept(new SimplifyVisitor());
while (temp != null) {
count = LeafCount.leafCount(temp);
if (count < minCounter) {
minCounter = count;
result = temp;
temp = result.accept(new SimplifyVisitor());
} else {
return result;
}
}
return result;
}
}
Ads help maintain this website.