Skip to content

Commit

Permalink
WIP #856 improve FullSimplify
Browse files Browse the repository at this point in the history
>> FullSimplify( (2 *Sqrt(6) - Sqrt(3)) / (Sqrt(2) - 4) )
-Sqrt(3/2)
  • Loading branch information
axkr committed Nov 13, 2023
1 parent 5dabc58 commit 741be58
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ public static String getVersion() {
// don't use a Logger in Config startup methods. Print the message to console instead:
System.out.println("Config.getVersion() failed: " + e.getMessage());
}
return "0.0.0";
return "3.0.1-SNAPSHOT";
}

/** A trie builder for mapping int[] sequences to IExpr. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,10 @@ public SimplifyVisitor(Function<IExpr, Long> complexityFunction, boolean fullSim
fFullSimplify = fullSimplify;
}

private IExpr eval(IExpr a) {
return fEngine.evaluate(a);
}

private IExpr tryExpandTransformation(IAST plusAST, IExpr test) {
IExpr result = F.NIL;
long minCounter = fComplexityFunction.apply(plusAST);
Expand Down Expand Up @@ -318,7 +322,7 @@ private IExpr tryTransformations(IExpr expr) {
IExpr[] commonFactors =
Algebra.InternalFindCommonFactorPlus.findCommonFactors((IAST) expr, true);
if (commonFactors != null) {
temp = fEngine.evaluate(F.Times(commonFactors[0], commonFactors[1]));
temp = eval(F.Times(commonFactors[0], commonFactors[1]));
simplifiedResult.checkLessEqual(temp);
}

Expand All @@ -328,7 +332,7 @@ private IExpr tryTransformations(IExpr expr) {
temp = tryPlusLog((IAST) expr);
}
if (temp.isPresent()) {
temp = fEngine.evaluate(temp);
temp = eval(temp);
simplifiedResult.checkLessEqual(temp);
}
// } else if (expr.isExp() && expr.second().isTimes()) {
Expand Down Expand Up @@ -372,17 +376,17 @@ private IExpr tryTransformations(IExpr expr) {
if (((IAST) expr).hasTrigonometricFunction()) {

try {
temp = F.eval(F.TrigExpand(expr));
temp = eval(F.TrigExpand(expr));
simplifiedResult.checkLess(temp);
} catch (ValidateException ve) {
//
}

try {
temp = F.eval(F.TrigToExp(expr));
temp = eval(F.TrigToExp(expr));
if (!simplifiedResult.checkLess(temp)) {
if (fFullSimplify) {
temp = F.eval(F.Factor(temp));
temp = eval(F.Factor(temp));
simplifiedResult.checkLess(temp);
}
}
Expand All @@ -391,15 +395,15 @@ private IExpr tryTransformations(IExpr expr) {
}

try {
temp = F.eval(F.TrigReduce(expr));
temp = eval(F.TrigReduce(expr));
simplifiedResult.checkLess(temp);
} catch (ValidateException ve) {
//
}
}

try {
temp = F.eval(F.ExpToTrig(expr));
temp = eval(F.ExpToTrig(expr));
simplifiedResult.checkLess(temp);
} catch (ValidateException ve) {
//
Expand All @@ -408,14 +412,13 @@ private IExpr tryTransformations(IExpr expr) {
try {
IExpr together = expr;
if (simplifiedResult.minCounter < Config.MAX_SIMPLIFY_TOGETHER_LEAFCOUNT) {
together = F.eval(F.Together(expr));
together = eval(F.Together(expr));
simplifiedResult.checkLess(together);
}

if (fFullSimplify) {
if (together.isTimes()) {
IExpr[] parts =
Algebra.numeratorDenominator((IAST) together, true, EvalEngine.get());
IExpr[] parts = Algebra.numeratorDenominator((IAST) together, true, EvalEngine.get());
IExpr numerator = parts[0];
IExpr denominator = parts[1];
// common factors in numerator, denominator may be canceled here, so check if we have
Expand All @@ -439,21 +442,21 @@ private IExpr tryTransformations(IExpr expr) {
// Maybe restricting factoring to smaller expressions is necessary here
temp = F.NIL;
if (fFullSimplify && expandAllCounter < 50) { // Config.MAX_SIMPLIFY_FACTOR_LEAFCOUNT) {
temp = F.eval(F.Factor(expr));
temp = eval(F.Factor(expr));
simplifiedResult.checkLess(temp);
}
// if (fFullSimplify
// && (minCounter >= Config.MAX_SIMPLIFY_FACTOR_LEAFCOUNT || !temp.equals(expr))) {
// if (expandAllCounter < (Config.MAX_SIMPLIFY_FACTOR_LEAFCOUNT / 2) && !fFullSimplify) {
// temp = F.eval(F.Factor(expr));
// temp = eval(F.Factor(expr));
// count = fComplexityFunction.apply(temp);
// if (count < minCounter) {
// minCounter = count;
// result = temp;
// }
// } else
if (expandAllCounter < Config.MAX_SIMPLIFY_FACTOR_LEAFCOUNT) {
temp = F.eval(F.FactorSquareFree(expr));
temp = eval(F.FactorSquareFree(expr));
simplifiedResult.checkLess(temp);
}

Expand All @@ -463,7 +466,7 @@ private IExpr tryTransformations(IExpr expr) {

try {
if (simplifiedResult.minCounter < Config.MAX_SIMPLIFY_APART_LEAFCOUNT) {
temp = F.eval(F.Apart(expr));
temp = eval(F.Apart(expr));
simplifiedResult.checkLess(temp);
}
} catch (ValidateException ve) {
Expand Down Expand Up @@ -522,7 +525,7 @@ public IExpr visit(IASTMutable ast) {

IExpr temp = visitAST(ast);
if (temp.isPresent()) {
temp = fEngine.evaluate(temp);
temp = eval(temp);
if (sResult.checkLessEqual(temp)) {
if (temp.isAST()) {
ast = (IASTMutable) temp;
Expand Down Expand Up @@ -582,7 +585,7 @@ private IExpr visitPower(IASTMutable powerAST, SimplifiedResult sResult) {
IAST plus1 = (IAST) powerAST.base();
IAST plus2 = plus1.setAtCopy(2, plus1.arg2().negate());
// example (5+Sqrt(17)) * (5-Sqrt(17))
IExpr expr = F.eval(F.Expand(F.Times(plus1, plus2)));
IExpr expr = eval(F.Expand(F.Times(plus1, plus2)));
if (expr.isNumber() && !expr.isZero()) {
IExpr powerSimplified = S.Times.of(expr.inverse(), plus2);
if (sResult.checkLess(powerSimplified)) {
Expand Down Expand Up @@ -626,18 +629,18 @@ private IExpr visitPower(IASTMutable powerAST, SimplifiedResult sResult) {

if (plusResult.isPresent()) {
logFactor.append(F.Power(S.E, plusResult));
IExpr temp = fEngine.evaluate(logFactor);
IExpr temp = eval(logFactor);
sResult.checkLessEqual(temp);
}
}
return F.NIL;
}

private IExpr visitTimes(IASTMutable timesAST, SimplifiedResult sResult) {
final IExpr denominator = S.Denominator.of(timesAST);
final IExpr denominator = eval(F.Denominator(timesAST));
if (!denominator.isNumber()) {
final IExpr numerator = F.Numerator(timesAST);
if (numerator.isTimes() || denominator.isTimes()) {
final IExpr numerator = eval(F.Numerator(timesAST));
if (fFullSimplify || numerator.isTimes() || denominator.isTimes()) {
IExpr numer = F.evalExpandAll(numerator);
IExpr denom = F.evalExpandAll(denominator);
if (S.PossibleZeroQ.ofQ(F.Subtract(numer, denom))) {
Expand All @@ -657,21 +660,22 @@ private IExpr visitTimes(IASTMutable timesAST, SimplifiedResult sResult) {
int i = 1;
// for (int i = 1; i < ast.size(); i++) {
int lastIndex = -1;
INumber numberFactors = F.C1;
while (i < timesAST.size()) {
IExpr timesArg = timesAST.get(i);
if (timesArg.isPowerReciprocal() && timesArg.base().isPlus()
&& timesArg.base().size() == 3) {
// example 1/(5+Sqrt(17)) => 1/8*(5-Sqrt(17))
if (timesArg.isPowerReciprocal() && timesArg.base().isPlus2()) {
// try multiplying the conjugate
// example 1/(5+Sqrt(17)) => 1/(5-Sqrt(17))
IAST plus1 = (IAST) timesArg.base();
IAST plus2 = plus1.setAtCopy(2, plus1.arg2().negate());
// example (5+Sqrt(17)) * (5-Sqrt(17))
IExpr expr = F.eval(F.Expand(F.Times(plus1, plus2)));
if (expr.isNumber() && !expr.isZero()) {
IASTMutable powerSimplified = F.Times(expr.inverse(), plus2);
IExpr expand1 = eval(F.Expand(F.Times(plus1, plus2)));
if (expand1.isNumber() && !expand1.isZero()) {
numberFactors = numberFactors.times(((INumber) expand1).inverse());
if (newTimes.isPresent()) {
newTimes.set(i, powerSimplified);
newTimes.set(i, plus2);
} else {
newTimes = timesAST.setAtClone(i, powerSimplified);
newTimes = timesAST.setAtClone(i, plus2);
}
i++;
continue; // while
Expand Down Expand Up @@ -704,7 +708,7 @@ private IExpr visitTimes(IASTMutable timesAST, SimplifiedResult sResult) {
} else {
IExpr lhsRest = timesArg.base().rest();
IExpr rhsRest = rhs.base().rest();
IExpr zeroCandidate = fEngine.evaluate(F.Plus(lhsRest, rhsRest));
IExpr zeroCandidate = eval(F.Plus(lhsRest, rhsRest));
if (zeroCandidate.isZero()) {
// found something like: (2-rest)^(z) * (2+rest)^(z) ==> (4-rest^2)^(z)
IAST powerSimplified = F
Expand Down Expand Up @@ -748,27 +752,34 @@ private IExpr visitTimes(IASTMutable timesAST, SimplifiedResult sResult) {
if (newTimes.isPresent()) {
sResult.result = timesAST;
try {
temp = F.eval(newTimes);
if (sResult.checkLessEqual(temp)) {
if (temp.isAtom()) {
return temp;
temp = eval(newTimes);
IExpr temp2 = numberFactors.times(temp);
if (sResult.checkLessEqual(temp2)) {
if (temp2.isAtom()) {
return temp2;
}
}
temp = F.eval(F.Expand(temp));
temp = eval(F.Expand(temp));
temp = numberFactors.times(temp);
if (sResult.checkLess(temp)) {
if (temp.isAtom()) {
return temp;
}
}
if (temp.isTimes()) {
temp = eval(F.Expand(temp));
if (sResult.checkLess(temp)) {
if (temp.isAtom()) {
return temp;
}
}
}

} catch (RuntimeException rex) {
Errors.printMessage(S.Simplify, rex, EvalEngine.get());
Errors.printMessage(fFullSimplify ? S.FullSimplify : S.Simplify, rex, EvalEngine.get());
}
}

// temp = tryTransformations(result);
// return temp.orElse(result);

temp = tryTransformations(sResult.result.orElse(timesAST));
if (temp.isPresent()) {
sResult.result = temp;
Expand Down Expand Up @@ -802,7 +813,7 @@ private IExpr visitPlus(IASTMutable plusAST, SimplifiedResult sResult) {
temp = tryTransformations(basicPlus.oneIdentity0());
if (temp.isPresent()) {
if (!restPlus.isAST0()) {
temp = fEngine.evaluate(F.Plus(temp, restPlus));
temp = eval(F.Plus(temp, restPlus));
}
if (!temp.isPlus()) {
return temp;
Expand Down Expand Up @@ -834,7 +845,7 @@ private IExpr visitPlus(IASTMutable plusAST, SimplifiedResult sResult) {
plusAST.setEvalFlags(plusAST.getEvalFlags() ^ IAST.IS_HASH_EVALED);
temp = hashRuleMap.evaluateRepeated(plusAST, fEngine);
if (temp.isPresent()) {
return fEngine.evaluate(temp);
return eval(temp);
}
}
functionExpand(plusAST, sResult);
Expand Down Expand Up @@ -1124,7 +1135,7 @@ private void functionExpand(IExpr expr, SimplifiedResult sResult) { // long minC
// result) {
if (expr.isBooleanFunction()) {
try {
expr = F.eval(F.BooleanMinimize(expr));
expr = eval(F.BooleanMinimize(expr));
sResult.checkLess(expr);
return;
} catch (RuntimeException rex) {
Expand Down Expand Up @@ -1154,7 +1165,7 @@ private void functionExpand(IExpr expr, SimplifiedResult sResult) { // long minC
}
}
try {
expr = F.eval(F.FunctionExpand(expr));
expr = eval(F.FunctionExpand(expr));
sResult.checkLess(expr);
} catch (RuntimeException rex) {
//
Expand All @@ -1163,7 +1174,7 @@ private void functionExpand(IExpr expr, SimplifiedResult sResult) { // long minC
if (expr.isLog() //
|| (expr.isPower() && expr.first().isAbs())) {
try {
expr = F.eval(F.FunctionExpand(expr));
expr = eval(F.FunctionExpand(expr));
sResult.checkLessEqual(expr);
} catch (RuntimeException rex) {
//
Expand All @@ -1187,14 +1198,13 @@ private IExpr reduceNumberFactor(IASTMutable timesAST) {
long minCounter = fComplexityFunction.apply(arg1);
IExpr imPart = AbstractFunctionEvaluator.getComplexExpr(arg1.first(), F.CI);
if (imPart.isPresent()) {
IExpr negativeAST = fEngine.evaluate(F.Distribute(F.Times(F.CI, arg1)));
IExpr negativeAST = eval(F.Distribute(F.Times(F.CI, arg1)));
long count = fComplexityFunction.apply(negativeAST);
if (count <= minCounter) {
return fEngine
.evaluate(F.Times(negativeAST, F.Distribute(F.Times(F.CNI, timesAST.rest()))));
return eval(F.Times(negativeAST, F.Distribute(F.Times(F.CNI, timesAST.rest()))));
}
} else {
IExpr negativeAST = fEngine.evaluate(F.Distribute(F.Times(F.CN1, arg1)));
IExpr negativeAST = eval(F.Distribute(F.Times(F.CN1, arg1)));
long count = fComplexityFunction.apply(negativeAST);
if (count <= minCounter) {
IASTAppendable result = F.TimesAlloc(timesAST.size());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9984,6 +9984,15 @@ public void testFullSimplify() {
"E^x");
}

public void testFullSimplifyIssue856() {
// github issue #856
check("FullSimplify( (2 *Sqrt(6) - Sqrt(3)) * (Sqrt(2) + 4))", //
"7*Sqrt(6)");
check("FullSimplify( (2 *Sqrt(6) - Sqrt(3)) * (-Sqrt(2) - 4) )", //
"-7*Sqrt(6)");
check("FullSimplify( (2 *Sqrt(6) - Sqrt(3)) / (Sqrt(2) - 4) )", //
"-Sqrt(3/2)");
}
public void testFunction() {
EvalEngine.resetModuleCounter4JUnit();
// check("(p + #) & /. p -> q", //
Expand Down

0 comments on commit 741be58

Please sign in to comment.