diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index a9d718484..f2f794489 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -172,7 +172,7 @@ Calculation::DisplayOutput Calculation::displayOutput(Context * context) { } if (shouldOnlyDisplayExactOutput()) { m_displayOutput = DisplayOutput::ExactOnly; - } else if (exactOutput().recursivelyMatches([](const Expression e, Context & c, bool replaceSymbols) { + } else if (exactOutput().recursivelyMatches([](const Expression e, Context & c) { /* If the exact result contains one of the following types, do not * display it. */ ExpressionNode::Type t = e.type(); @@ -192,7 +192,7 @@ Calculation::DisplayOutput Calculation::displayOutput(Context * context) { } else if (strcmp(m_exactOutputText, Undefined::Name()) == 0 || strcmp(m_approximateOutputText, Unreal::Name()) == 0) { // If the approximate result is 'unreal' or the exact result is 'undef' m_displayOutput = DisplayOutput::ApproximateOnly; - } else if (input().isApproximate(*context) || exactOutput().isApproximate(*context)) { + } else if (input().recursivelyMatches(Expression::IsApproximate, *context) || exactOutput().recursivelyMatches(Expression::IsApproximate, *context)) { m_displayOutput = DisplayOutput::ExactAndApproximateToggle; } else { m_displayOutput = DisplayOutput::ExactAndApproximate; diff --git a/apps/calculation/calculation_store.cpp b/apps/calculation/calculation_store.cpp index d235445d1..618439860 100644 --- a/apps/calculation/calculation_store.cpp +++ b/apps/calculation/calculation_store.cpp @@ -96,10 +96,10 @@ Expression CalculationStore::ansExpression(Context * context) { * To avoid turning 'ans->A' in '2->A->A' or '2=A->A' (which cannot be * parsed), ans is replaced by the approximation output when any Store or * Equal expression appears. */ - bool exactOuptutInvolvesStoreEqual = lastCalculation->exactOutput().recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) { + bool exactOuptutInvolvesStoreEqual = lastCalculation->exactOutput().recursivelyMatches([](const Expression e, Context & context) { return e.type() == ExpressionNode::Type::Store || e.type() == ExpressionNode::Type::Equal; }, *context, false); - if (lastCalculation->input().isApproximate(*context) || exactOuptutInvolvesStoreEqual) { + if (lastCalculation->input().recursivelyMatches(Expression::IsApproximate, *context) || exactOuptutInvolvesStoreEqual) { return lastCalculation->approximateOutput(context); } return lastCalculation->exactOutput(); diff --git a/apps/solver/equation.cpp b/apps/solver/equation.cpp index 583deaf7f..e8586ae01 100644 --- a/apps/solver/equation.cpp +++ b/apps/solver/equation.cpp @@ -18,7 +18,7 @@ Equation::Equation(Ion::Storage::Record record) : } bool Equation::containsIComplex(Context * context) const { - return expressionClone().recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) { return e.type() == ExpressionNode::Type::Constant && static_cast(e).isIComplex(); }, *context, true); + return expressionClone().recursivelyMatches([](const Expression e, Context & context) { return e.type() == ExpressionNode::Type::Constant && static_cast(e).isIComplex(); }, *context, true); } Expression Equation::Model::standardForm(const Storage::Record * record, Context * context) const { @@ -28,7 +28,7 @@ Expression Equation::Model::standardForm(const Storage::Record * record, Context m_standardForm = Unreal::Builder(); return m_standardForm; } - if (e.recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) { return e.type() == ExpressionNode::Type::Undefined || e.type() == ExpressionNode::Type::Infinity || Expression::IsMatrix(e, context, replaceSymbols); }, *context, true)) { + if (e.recursivelyMatches([](const Expression e, Context & context) { return e.type() == ExpressionNode::Type::Undefined || e.type() == ExpressionNode::Type::Infinity || Expression::IsMatrix(e, context); }, *context, true)) { m_standardForm = Undefined::Builder(); return m_standardForm; } diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index f889f4cc7..2d3a09fe8 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -129,13 +129,14 @@ public: bool isRationalZero() const; bool isRationalOne() const; bool isRandom() const { return node()->isRandom(); } - static bool IsRandom(const Expression e, Context & context, bool replaceSymbols); - typedef bool (*ExpressionTest)(const Expression e, Context & context, bool replaceSymbols); - bool recursivelyMatches(ExpressionTest test, Context & context, bool replaceSymbols) const; - bool isApproximate(Context & context) const; - bool recursivelyMatchesInfinity(Context & context) { return recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) { return e.type() == ExpressionNode::Type::Infinity; }, context, true); } - static bool IsMatrix(const Expression e, Context & context, bool replaceSymbols); bool isParameteredExpression() const { return node()->isParameteredExpression(); } + typedef bool (*ExpressionTest)(const Expression e, Context & context); + bool recursivelyMatches(ExpressionTest test, Context & context, bool replaceSymbols = true) const; + // Set of ExpressionTest that can be used with recursivelyMatches + static bool IsApproximate(const Expression e, Context & context); + static bool IsRandom(const Expression e, Context & context); + static bool IsMatrix(const Expression e, Context & context); + static bool IsInfinity(const Expression e, Context & context); /* 'characteristicXRange' tries to assess the range on x where the expression * (considered as a function on x) has an interesting evolution. For example, * the period of the function on 'x' if it is periodic. If diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 2e40a4249..3a1b8ca17 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -83,9 +83,13 @@ bool Expression::isRationalOne() const { } bool Expression::recursivelyMatches(ExpressionTest test, Context & context, bool replaceSymbols) const { - if (test(*this, context, replaceSymbols)) { + if (test(*this, context)) { return true; } + ExpressionNode::Type t = type(); + if (replaceSymbols && (t == ExpressionNode::Type::Symbol || t == ExpressionNode::Type::Function)) { + return SymbolAbstract::matches(convert(), test, context); + } for (int i = 0; i < this->numberOfChildren(); i++) { if (childAtIndex(i).recursivelyMatches(test, context, replaceSymbols)) { return true; @@ -94,57 +98,26 @@ bool Expression::recursivelyMatches(ExpressionTest test, Context & context, bool return false; } -bool Expression::isApproximate(Context & context) const { - return recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) { - return e.type() == ExpressionNode::Type::Decimal - || e.type() == ExpressionNode::Type::Float - || ((e.type() == ExpressionNode::Type::Symbol || e.type() == ExpressionNode::Type::Function) - && replaceSymbols - && SymbolAbstract::matches( - static_cast(e), - [](const Expression e, Context & context, bool replaceSymbols) { - return e.isApproximate(context); - }, - context)); - }, context, true); +bool Expression::IsApproximate(const Expression e, Context & context) { + return e.type() == ExpressionNode::Type::Decimal || e.type() == ExpressionNode::Type::Float; } -bool Expression::IsRandom(const Expression e, Context & context, bool replaceSymbols) { - return e.isRandom() - || ((e.type() == ExpressionNode::Type::Symbol || e.type() == ExpressionNode::Type::Function) - && replaceSymbols - && SymbolAbstract::matches( - static_cast(e), - [](const Expression e, Context & context, bool replaceSymbols) { - return e.recursivelyMatches( - [](const Expression e, Context & context, bool replaceSymbols) { - return Expression::IsRandom(e, context, replaceSymbols); - }, - context, replaceSymbols); - }, - context)); +bool Expression::IsRandom(const Expression e, Context & context) { + return e.isRandom(); } -bool Expression::IsMatrix(const Expression e, Context & context, bool replaceSymbols) { +bool Expression::IsMatrix(const Expression e, Context & context) { return e.type() == ExpressionNode::Type::Matrix || e.type() == ExpressionNode::Type::ConfidenceInterval || e.type() == ExpressionNode::Type::MatrixDimension || e.type() == ExpressionNode::Type::PredictionInterval || e.type() == ExpressionNode::Type::MatrixInverse - || e.type() == ExpressionNode::Type::MatrixTranspose || e.type() == ExpressionNode::Type::MatrixIdentity - || ((e.type() == ExpressionNode::Type::Symbol || e.type() == ExpressionNode::Type::Function) - && replaceSymbols - && SymbolAbstract::matches( - static_cast(e), - [](const Expression e, Context & context, bool replaceSymbols) { - return e.recursivelyMatches( - [](const Expression e, Context & context, bool replaceSymbols) { - return Expression::IsMatrix(e, context, replaceSymbols); - }, - context, replaceSymbols); - }, - context)); + || e.type() == ExpressionNode::Type::MatrixTranspose; +} + +bool Expression::IsInfinity(const Expression e, Context & context) { + return e.type() == ExpressionNode::Type::Infinity; } bool containsVariables(const Expression e, char * variables, int maxVariableSize) { @@ -192,7 +165,7 @@ bool Expression::getLinearCoefficients(char * variables, int maxVariableSize, Ex /* degree is supposed to be 0 or 1. Otherwise, it means that equation * is 'undefined' due to the reduction of 0*inf for example. * (ie, x*y*inf = 0) */ - assert(!recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) { return e.isUndefined(); }, context, true)); + assert(!recursivelyMatches([](const Expression e, Context & context) { return e.isUndefined(); }, context, true)); return false; } /* The equation is can be written: a_1*x+a_0 with a_1 and a_0 x-independent. @@ -260,7 +233,7 @@ void Expression::defaultSetChildrenInPlace(Expression other) { } bool Expression::hasReplaceableSymbols(Context & context) const { - return recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) { + return recursivelyMatches([](const Expression e, Context & context) { return (e.type() == ExpressionNode::Type::Symbol && !static_cast(e).isSystemSymbol() && !context.expressionForSymbol(static_cast(e), false).isUninitialized()) @@ -366,7 +339,7 @@ Preferences::ComplexFormat Expression::UpdatedComplexFormatWithTextInput(Prefere } Preferences::ComplexFormat Expression::UpdatedComplexFormatWithExpressionInput(Preferences::ComplexFormat complexFormat, const Expression & exp, Context & context) { - if (complexFormat == Preferences::ComplexFormat::Real && exp.recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) { return e.type() == ExpressionNode::Type::Constant && static_cast(e).isIComplex(); }, context, true)) { + if (complexFormat == Preferences::ComplexFormat::Real && exp.recursivelyMatches([](const Expression e, Context & context) { return e.type() == ExpressionNode::Type::Constant && static_cast(e).isIComplex(); }, context, true)) { return Preferences::ComplexFormat::Cartesian; } return complexFormat; @@ -557,10 +530,12 @@ Expression Expression::reduce(Context & context, Preferences::ComplexFormat comp Expression Expression::deepReduce(Context & context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target, bool symbolicComputation) { #if MATRIX_EXACT_REDUCING #else - if (IsMatrix(*this, context, true)) { +#if 0 + if (IsMatrix(*this, context)) { sSimplificationHasBeenInterrupted = true; return *this; } +#endif #endif deepReduceChildren(context, complexFormat, angleUnit, target, symbolicComputation); diff --git a/poincare/src/logarithm.cpp b/poincare/src/logarithm.cpp index 95c80e5c7..ea281ebf8 100644 --- a/poincare/src/logarithm.cpp +++ b/poincare/src/logarithm.cpp @@ -223,7 +223,7 @@ Expression Logarithm::simpleShallowReduce(Context & context, Preferences::Comple replaceWithInPlace(result); return result; } - bool infiniteArg = c.recursivelyMatchesInfinity(context); + bool infiniteArg = c.recursivelyMatches(Expression::IsInfinity, context); // log(x,x)->1 with x != inf and log(inf,inf) = undef if (c.isIdenticalTo(b)) { Expression result = infiniteArg ? Undefined::Builder().convert() : Rational::Builder(1).convert(); @@ -241,7 +241,7 @@ Expression Logarithm::simpleShallowReduce(Context & context, Preferences::Comple const Rational r = static_cast(c); // log(0, x) = -inf if x > 1 && x != inf || inf x < 1 || undef if x < 0 if (r.isZero()) { - bool infiniteBase = b.recursivelyMatchesInfinity(context); + bool infiniteBase = b.recursivelyMatches(Expression::IsInfinity, context); // Special case: log(0,inf) -> undef if (infiniteBase) { Expression result = Undefined::Builder(); diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index b21f39e11..2728ae2c4 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -450,7 +450,7 @@ Expression Multiplication::privateShallowReduce(Context & context, Preferences:: // Check that other children don't match inf bool infiniteFactor = false; for (int i = 1; i < numberOfChildren(); i++) { - infiniteFactor = childAtIndex(i).recursivelyMatchesInfinity(context); + infiniteFactor = childAtIndex(i).recursivelyMatches(Expression::IsInfinity, context); if (infiniteFactor) { break; } diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index f17f5d676..298b6f677 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -384,7 +384,7 @@ Expression Power::shallowReduce(Context & context, Preferences::ComplexFormat co } } // 1^x = 1 if x != ±inf - if (a.isOne() && !childAtIndex(1).recursivelyMatchesInfinity(context)) { + if (a.isOne() && !childAtIndex(1).recursivelyMatches(Expression::IsInfinity, context)) { Expression result = Rational::Builder(1); replaceWithInPlace(result); return result; diff --git a/poincare/src/store.cpp b/poincare/src/store.cpp index 40b21c630..9d25f0a50 100644 --- a/poincare/src/store.cpp +++ b/poincare/src/store.cpp @@ -17,7 +17,7 @@ namespace Poincare { void StoreNode::deepReduceChildren(Context & context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target, bool symbolicComputation) { // Interrupt simplification if the expression stored contains a matrix - if (Expression(childAtIndex(0)).recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) { return Expression::IsMatrix(e, context, replaceSymbols); }, context, true)) { + if (Expression(childAtIndex(0)).recursivelyMatches([](const Expression e, Context & context) { return Expression::IsMatrix(e, context); }, context, true)) { Expression::SetInterruption(true); } } diff --git a/poincare/src/symbol_abstract.cpp b/poincare/src/symbol_abstract.cpp index 8ea0b00ed..83044b051 100644 --- a/poincare/src/symbol_abstract.cpp +++ b/poincare/src/symbol_abstract.cpp @@ -53,7 +53,7 @@ size_t SymbolAbstract::TruncateExtension(char * dst, const char * src, size_t le bool SymbolAbstract::matches(const SymbolAbstract & symbol, ExpressionTest test, Context & context) { Expression e = SymbolAbstract::Expand(symbol, context, false); - return !e.isUninitialized() && test(e, context, false); + return !e.isUninitialized() && e.recursivelyMatches(test, context, false); } Expression SymbolAbstract::Expand(const SymbolAbstract & symbol, Context & context, bool clone) {