package org.matheclipse.core.reflection.system;
import org.matheclipse.core.basic.Config;
import org.matheclipse.core.convert.ExprVariables;
import org.matheclipse.core.convert.JASConvert;
import org.matheclipse.core.eval.EvalEngine;
import org.matheclipse.core.eval.exception.JASConversionException;
import org.matheclipse.core.eval.exception.Validate;
import org.matheclipse.core.eval.interfaces.AbstractFunctionEvaluator;
import org.matheclipse.core.expression.ASTRange;
import org.matheclipse.core.expression.F;
import org.matheclipse.core.generic.Functors;
import org.matheclipse.core.interfaces.IAST;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.IInteger;
import org.matheclipse.core.interfaces.ISymbol;
import org.matheclipse.parser.client.SyntaxError;
import com.google.common.base.Predicate;
import edu.jas.arith.BigInteger;
import edu.jas.arith.BigRational;
import edu.jas.poly.GenPolynomial;
import edu.jas.ufd.GCDFactory;
import edu.jas.ufd.GreatestCommonDivisor;
/**
* Cancel(expr) - cancels out common factors in numerators and denominators.
*/
public class Cancel extends AbstractFunctionEvaluator {
/**
* This predicate identifies polynomial expressions. It requires that the given expression is already expanded for
* Plus,Power and Times operations.
*
*/
private final static class PolynomialPredicate implements Predicate {
public boolean apply(IExpr expr) {
if (expr.isRational()) {
return true;
}
if (expr.isSymbol()) {
return true;
}
if (expr.isTimes() || expr.isPlus()) {
IAST ast = (IAST) expr;
for (int i = 1; i < ast.size(); i++) {
if (!apply(ast.get(i))) {
return false;
}
}
return true;
}
if (expr.isPower() && ((IAST) expr).arg1().isSymbol() && ((IAST) expr).arg2().isInteger()) {
try {
int in = ((IInteger) ((IAST) expr).arg2()).toInt();
if (in > 0) {
return true;
}
} catch (ArithmeticException ae) {
}
return false;
}
return false;
}
}
public Cancel() {
}
@Override
public IExpr evaluate(final IAST ast) {
Validate.checkRange(ast, 2, 3);
IExpr arg = F.evalExpandAll(ast.arg1());
try {
if (arg.isPlus()) {
IAST result = ((IAST) arg).map(Functors.evalArg(F.Cancel(F.Slot1), 1, EvalEngine.get()));
if (result == null) {
return arg;
}
return result;
} else if (arg.isTimes() || arg.isPower()) {
return cancelPowerTimes(arg);
}
} catch (JASConversionException jce) {
if (Config.DEBUG) {
jce.printStackTrace();
}
}
return arg;
}
/**
*
* @param powerTimesAST
* an Times[...] or Power[...] AST, where common factors should be canceled out.
* @return
* @throws JASConversionException
*/
public static IExpr cancelPowerTimes(IExpr powerTimesAST) throws JASConversionException {
IExpr[] parts = Apart.getFractionalParts(powerTimesAST);
if (parts != null) {
if (parts[0].isPlus() && parts[1].isPlus()) {
IAST[] numParts = ((IAST) parts[0]).split(new PolynomialPredicate());
IAST[] denParts = ((IAST) parts[1]).split(new PolynomialPredicate());
IExpr denParts0 = F.eval(denParts[0]);
if (!denParts0.equals(F.C1)) {
IExpr[] result = Cancel.cancelGCD(numParts[0], denParts0);
if (result != null) {
return F.Times(result[0], result[1], numParts[1], F.Power(F.Times(result[2], denParts[1]), F.CN1));
}
}
}
}
return powerTimesAST;
}
/**
* Calculate the 3 element result array
* [ commonFactor, poly1.divide(gcd(poly1, poly2)), poly2.divide(gcd(poly1, poly2)) ] for the given expressions
* poly1 and poly2.
*
*
* @param poly1
* a BigRational polynomial which could be converted to JAS polynomial
* @param poly2
* a BigRational polynomial which could be converted to JAS polynomial
* @return null if the expressions couldn't be converted to JAS polynomials
*/
public static IExpr[] cancelGCD(IExpr poly1, IExpr poly2) throws JASConversionException {
try {
ExprVariables eVar = new ExprVariables(poly1);
eVar.addVarList(poly2);
ASTRange r = new ASTRange(eVar.getVarList(), 1);
JASConvert jas = new JASConvert(r.toList(), BigRational.ZERO);
GenPolynomial p1 = jas.expr2JAS(poly1);
GenPolynomial p2 = jas.expr2JAS(poly2);
BigRational cofac = new BigRational();
GreatestCommonDivisor engine;
engine = GCDFactory.getImplementation(cofac);
GenPolynomial gcd = engine.gcd(p1, p2);
IExpr[] result = new IExpr[3];
if (gcd.isONE()) {
result[0] = jas.rationalPoly2Expr(gcd);
result[1] = jas.rationalPoly2Expr(p1);
result[2] = jas.rationalPoly2Expr(p2);
} else {
java.math.BigInteger commonNumerator, commonDenominator;
Object[] objects = jas.factorTerms(p1.divide(gcd));
commonNumerator = (java.math.BigInteger) objects[0];
result[1] = jas.integerPoly2Expr((GenPolynomial) objects[2]);
objects = jas.factorTerms(p2.divide(gcd));
commonDenominator = (java.math.BigInteger) objects[0];
result[2] = jas.integerPoly2Expr((GenPolynomial) objects[2]);
result[0] = F.fraction(commonNumerator, commonDenominator);
}
return result;
} catch (Exception e) {
if (Config.SHOW_STACKTRACE) {
e.printStackTrace();
}
}
return null;
}
@Override
public void setUp(final ISymbol symbol) throws SyntaxError {
symbol.setAttributes(ISymbol.LISTABLE);
super.setUp(symbol);
}
}
Ads help maintain this website.