From 6ce912069f8af636e66eaddc6799d09eaca0d189 Mon Sep 17 00:00:00 2001 From: axexlck Date: Tue, 11 Jun 2024 05:37:28 +0200 Subject: [PATCH] WIP #1001 --- .../core/builtin/SeriesFunctions.java | 49 ++++++++++++++++++- .../core/builtin/SimplifyFunctions.java | 14 ++++++ .../core/system/LowercaseTestCase.java | 32 ++++++++++++ 3 files changed, 94 insertions(+), 1 deletion(-) diff --git a/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/SeriesFunctions.java b/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/SeriesFunctions.java index 776b440a0d..9d984a3df6 100644 --- a/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/SeriesFunctions.java +++ b/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/SeriesFunctions.java @@ -315,7 +315,7 @@ private static IExpr evalLimit(final IExpr expr, LimitData data, EvalEngine engi return limitValue; } - if (limitValue.isNumericFunction(true)) { + if (limitValue.isNumericFunction(true) && expression.isFree(x -> x == S.Piecewise, true)) { IExpr temp = evalReplaceAll(expression, data, engine); if (temp.isPresent()) { return temp; @@ -354,6 +354,8 @@ private static IExpr evalLimit(final IExpr expr, LimitData data, EvalEngine engi return timesLimit(ast, data, engine); } else if (ast.isPower() && !ast.base().isPositive() && !ast.exponent().isPositive()) { return powerLimit(ast, data, engine); + } else if (ast.isAST(S.Piecewise)) { + return piecewiseLimit(ast, data, engine); } else if (ast.argSize() > 0 && ast.topHead().isNumericFunctionAttribute()) { IASTMutable copy = ast.copy(); IExpr temp = F.NIL; @@ -603,6 +605,7 @@ private static IExpr lHospitalesRule(IExpr numerator, IExpr denominator, LimitDa expr = engine.evalQuiet(F.Simplify(expr)); } if (expr.isFree(v -> v.equals(S.D) || v.equals(S.Derivative), true)) { + engine.incRecursionCounter(); return evalLimit(expr, data, engine); } } catch (RecursionLimitExceeded rle) { @@ -782,6 +785,43 @@ private static IExpr numeratorDenominatorLimit(IExpr numerator, IExpr denominato // return F.Times(data.limit(numerator), F.Power(data.limit(denominator), F.CN1)); } + private static IExpr piecewiseLimit(final IAST piecwiseAST, LimitData data, EvalEngine engine) { + IExpr limit = data.limitValue(); + IExpr variable = data.variable(); + if (limit.isReal()) { + int[] piecewiseDimension = piecwiseAST.isPiecewise(); + if (piecewiseDimension != null && piecewiseDimension[0] > 0) { + IAST matrixNx2 = (IAST) piecwiseAST.first(); + for (int i = 0; i < piecewiseDimension[0]; i++) { + IAST row2 = matrixNx2.getAST(i + 1); + IExpr result = row2.first(); + IExpr comparison = row2.second(); + + if (data.direction == Direction.FROM_BELOW) { + if (comparison.isAST(S.Less, 3) && comparison.first().equals(variable) + && comparison.second().equals(limit)) { + comparison = ((IAST) comparison).setAtCopy(0, S.LessEqual); + } + } else if (data.direction == Direction.FROM_ABOVE) { + if (comparison.isAST(S.Greater, 3) && comparison.first().equals(variable) + && comparison.second().equals(limit)) { + comparison = ((IAST) comparison).setAtCopy(0, S.GreaterEqual); + } + } + IExpr temp = engine.evaluate(F.subs(comparison, variable, limit)); + if (temp.isTrue()) { + return engine.evaluate(F.subs(result, variable, limit)); + } else if (!temp.isFalse()) { + return F.NIL; + } + + } + return piecwiseAST.second(); + } + } + return F.NIL; + } + private static IExpr plusLimit(final IAST plusAST, LimitData data, EvalEngine engine) { // Limit[a_+b_+c_,sym->lim] -> // Limit[a,sym->lim]+Limit[b,sym->lim]+Limit[c,sym->lim] @@ -1226,6 +1266,7 @@ public void setUp(final ISymbol newSymbol) { } } + /** * * @@ -1405,6 +1446,7 @@ public int[] expectedArgSize(IAST ast) { } } + /** * * @@ -1459,6 +1501,7 @@ public IExpr evaluate(final IAST ast, EvalEngine engine) { } } + /** * * @@ -1495,6 +1538,7 @@ public IExpr evaluate(final IAST ast, EvalEngine engine) { } } + /** * * @@ -1549,6 +1593,7 @@ public IExpr evaluate(final IAST ast, EvalEngine engine) { } + /** * * @@ -1815,6 +1860,7 @@ public static IExpr polynomialSeriesCoefficient(IExpr univariatePolynomial, IExp } } + /** * * @@ -1875,6 +1921,7 @@ public IExpr evaluate(final IAST ast, EvalEngine engine) { } return F.NIL; } + } diff --git a/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/SimplifyFunctions.java b/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/SimplifyFunctions.java index b60aa81ce2..188b252d50 100644 --- a/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/SimplifyFunctions.java +++ b/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/SimplifyFunctions.java @@ -29,6 +29,7 @@ import org.matheclipse.core.interfaces.IInteger; import org.matheclipse.core.interfaces.INum; import org.matheclipse.core.interfaces.INumber; +import org.matheclipse.core.interfaces.IRational; import org.matheclipse.core.interfaces.ISymbol; import org.matheclipse.core.patternmatching.hash.HashedOrderlessMatcher; import org.matheclipse.core.patternmatching.hash.HashedOrderlessMatcherPlus; @@ -654,6 +655,19 @@ private IExpr visitTimes(IASTMutable timesAST, SimplifiedResult sResult) { final IExpr denominator = eval(F.Denominator(timesAST)); if (!denominator.isNumber()) { final IExpr numerator = eval(F.Numerator(timesAST)); + if (numerator.isAST(S.RealAbs, 2) && numerator.first().equals(denominator) + && denominator.isPlus() && denominator.first().isRational()) { + IRational n = (IRational) denominator.first(); + IExpr rest = denominator.rest().oneIdentity0(); + // Piecewise({{-1,rest<(-n)}},1) + return F.Piecewise(F.list(F.list(F.CN1, F.Less(rest, n.negate()))), F.C1); + } else if (denominator.isAST(S.RealAbs, 2) && denominator.first().equals(numerator) + && numerator.isPlus() && numerator.first().isRational()) { + IRational n = (IRational) numerator.first(); + IExpr rest = numerator.rest().oneIdentity0(); + // Piecewise({{-1,rest<(-n)}},1) + return F.Piecewise(F.list(F.list(F.CN1, F.Less(rest, n.negate()))), F.C1); + } if (fFullSimplify || numerator.isTimes() || denominator.isTimes()) { IExpr numer = F.evalExpandAll(numerator); IExpr denom = F.evalExpandAll(denominator); diff --git a/symja_android_library/matheclipse-core/src/test/java/org/matheclipse/core/system/LowercaseTestCase.java b/symja_android_library/matheclipse-core/src/test/java/org/matheclipse/core/system/LowercaseTestCase.java index f5e081de39..866d48699b 100644 --- a/symja_android_library/matheclipse-core/src/test/java/org/matheclipse/core/system/LowercaseTestCase.java +++ b/symja_android_library/matheclipse-core/src/test/java/org/matheclipse/core/system/LowercaseTestCase.java @@ -12762,6 +12762,23 @@ public void testLimit() { "0"); } + @Test + public void testLimitIssue1001() { + // github issue #1001 + check("Simplify(RealAbs(x + 2)/(x+2))", // + "Piecewise({{-1,x<-2}},1)"); + check("Simplify(RealAbs(x - 2)/(x-2))", // + "Piecewise({{-1,x<2}},1)"); + check("Limit(RealAbs(x + 2), x -> -2, Direction -> -1)", // + "0"); + check("Limit(x + 2, x -> -2, Direction -> -1)", // + "0"); + check("Limit(RealAbs(x + 2)/(x+2), x -> -2, Direction -> -1)", // + "1"); + check("Limit(RealAbs(x + 2)/(x+2), x -> -2, Direction -> 1)", // + "-1"); + } + @Test public void testLimitIssue536() { // avoid endless recursion: @@ -24161,6 +24178,20 @@ public void testToString() { @Test public void testTotal() { + // TODO only add up elements inside List, Association, SparseArray,... + // check("t = Array(Subscript(a, ##) &, {2, 3, 4})", // + // "{{{Subscript(a,1,1,1),Subscript(a,1,1,2),Subscript(a,1,1,3),Subscript(a,1,1,4)},{Subscript(a,\n" + // // + // + "1,2,1),Subscript(a,1,2,2),Subscript(a,1,2,3),Subscript(a,1,2,4)},{Subscript(a,1,\n" // + // + "3,1),Subscript(a,1,3,2),Subscript(a,1,3,3),Subscript(a,1,3,4)}},{{Subscript(a,2,\n" // + // + "1,1),Subscript(a,2,1,2),Subscript(a,2,1,3),Subscript(a,2,1,4)},{Subscript(a,2,2,\n" // + // + + // "1),Subscript(a,2,2,2),Subscript(a,2,2,3),Subscript(a,2,2,4)},{Subscript(a,2,3,1),Subscript(a,\n" + // // + // + "2,3,2),Subscript(a,2,3,3),Subscript(a,2,3,4)}}}"); + // check("Total(t, {-1})", // + // ""); + check("Total({x^2, 3*x^3, 1})", // "1+x^2+3*x^3"); @@ -24198,6 +24229,7 @@ public void testTotal() { "{6,15,24}"); check("Total({{1,2,3},{4,5,6},{7,8,9}},2)", // "45"); + } @Test