From 8a272458ded94cafa83e3f77ebf3c22db74a135d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 13 Nov 2018 16:07:46 +0100 Subject: [PATCH] [poincare] recursivelyMatches takes replaceSymbols parameter This fixes: [7]->a 1+2->a The second operation would get interrupted because 'a' is a matrix if symbols are replaced --- apps/calculation/calculation_store.cpp | 6 ++--- apps/solver/equation.cpp | 2 +- poincare/include/poincare/expression.h | 6 ++--- poincare/src/determinant.cpp | 2 +- poincare/src/expression.cpp | 36 ++++++++++++++------------ poincare/src/symbol.cpp | 2 +- 6 files changed, 28 insertions(+), 26 deletions(-) diff --git a/apps/calculation/calculation_store.cpp b/apps/calculation/calculation_store.cpp index 85d06d15b..b3f747c9d 100644 --- a/apps/calculation/calculation_store.cpp +++ b/apps/calculation/calculation_store.cpp @@ -96,9 +96,9 @@ 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 in when any Store or Equal * expression appears.*/ - bool exactOuptutInvolvesStoreEqual = lastCalculation->exactOutput().recursivelyMatches([](const Expression e, Context & context) { - return e.type() == ExpressionNode::Type::Store || e.type() == ExpressionNode::Type::Equal; - }, *context); + bool exactOuptutInvolvesStoreEqual = lastCalculation->exactOutput().recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) { + return e.type() == ExpressionNode::Type::Store || e.type() == ExpressionNode::Type::Equal; + }, *context, false); if (lastCalculation->input().isApproximate(*context) || exactOuptutInvolvesStoreEqual) { return lastCalculation->approximateOutput(context); } diff --git a/apps/solver/equation.cpp b/apps/solver/equation.cpp index deb889ba4..3565c86c8 100644 --- a/apps/solver/equation.cpp +++ b/apps/solver/equation.cpp @@ -28,7 +28,7 @@ void Equation::tidy() { Expression Equation::standardForm(Context * context) const { if (m_standardForm.isUninitialized()) { const Expression e = expression(context); - if (e.recursivelyMatches([](const Expression e, Context & context) { return e.type() == ExpressionNode::Type::Undefined || e.type() == ExpressionNode::Type::Infinity || Expression::IsMatrix(e, context); }, *context)) { + 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)) { m_standardForm = Undefined(); return m_standardForm; } diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 3e32a1dd8..a7c872212 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -114,10 +114,10 @@ public: bool isNumber() const { return node()->isNumber(); } bool isRationalZero() const; bool isRationalOne() const; - typedef bool (*ExpressionTest)(const Expression e, Context & context); - bool recursivelyMatches(ExpressionTest test, Context & context) const; + typedef bool (*ExpressionTest)(const Expression e, Context & context, bool replaceSymbols); + bool recursivelyMatches(ExpressionTest test, Context & context, bool replaceSymbols) const; bool isApproximate(Context & context) const; - static bool IsMatrix(const Expression e, Context & context); + static bool IsMatrix(const Expression e, Context & context, bool replaceSymbols); /* '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/determinant.cpp b/poincare/src/determinant.cpp index efc3f0d6b..2a570c2b2 100644 --- a/poincare/src/determinant.cpp +++ b/poincare/src/determinant.cpp @@ -49,7 +49,7 @@ Expression Determinant::shallowReduce(Context & context, Preferences::AngleUnit #endif #endif // det(A) = A if A is not a matrix - if (!c0.recursivelyMatches(Expression::IsMatrix, context)) { + if (!c0.recursivelyMatches(Expression::IsMatrix, context, true)) { replaceWithInPlace(c0); return c0; } diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 4167400ca..82d86fc7e 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -74,12 +74,12 @@ bool Expression::isRationalOne() const { return type() == ExpressionNode::Type::Rational && convert().isOne(); } -bool Expression::recursivelyMatches(ExpressionTest test, Context & context) const { - if (test(*this, context)) { +bool Expression::recursivelyMatches(ExpressionTest test, Context & context, bool replaceSymbols) const { + if (test(*this, context, replaceSymbols)) { return true; } for (int i = 0; i < this->numberOfChildren(); i++) { - if (childAtIndex(i).recursivelyMatches(test, context)) { + if (childAtIndex(i).recursivelyMatches(test, context, replaceSymbols)) { return true; } } @@ -87,19 +87,20 @@ bool Expression::recursivelyMatches(ExpressionTest test, Context & context) cons } bool Expression::isApproximate(Context & context) const { - return recursivelyMatches([](const Expression e, Context & context) { + return recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) { return e.type() == ExpressionNode::Type::Decimal || e.type() == ExpressionNode::Type::Float - || IsMatrix(e, context) + || IsMatrix(e, context, replaceSymbols) || (e.type() == ExpressionNode::Type::Symbol + && replaceSymbols && static_cast(e).matches( - [](const Expression e, Context & context) { + [](const Expression e, Context & context, bool replaceSymbols) { return e.isApproximate(context); }, context)); - }, context); + }, context, true); } -bool Expression::IsMatrix(const Expression e, Context & context) { +bool Expression::IsMatrix(const Expression e, Context & context, bool replaceSymbols) { return e.type() == ExpressionNode::Type::Matrix || e.type() == ExpressionNode::Type::ConfidenceInterval || e.type() == ExpressionNode::Type::MatrixDimension @@ -107,12 +108,13 @@ bool Expression::IsMatrix(const Expression e, Context & context) { || e.type() == ExpressionNode::Type::MatrixInverse || e.type() == ExpressionNode::Type::MatrixTranspose || (e.type() == ExpressionNode::Type::Symbol + && replaceSymbols && static_cast(e).matches( - [](const Expression e, Context & context) { + [](const Expression e, Context & context, bool replaceSymbols) { return e.recursivelyMatches( - [](const Expression e, Context & context) { - return Expression::IsMatrix(e, context); }, - context); + [](const Expression e, Context & context, bool replaceSymbols) { + return Expression::IsMatrix(e, context, replaceSymbols); }, + context, replaceSymbols); }, context)); } @@ -135,7 +137,7 @@ bool containsVariables(const Expression e, char * variables, int maxVariableSize } bool Expression::getLinearCoefficients(char * variables, int maxVariableSize, Expression coefficients[], Expression constant[], Context & context, Preferences::AngleUnit angleUnit) const { - assert(!recursivelyMatches(IsMatrix, context)); + assert(!recursivelyMatches(IsMatrix, context, true)); // variables is in fact of type char[k_maxNumberOfVariables][maxVariableSize] int index = 0; while (variables[index*maxVariableSize] != 0) { @@ -161,7 +163,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) { return e.type() == ExpressionNode::Type::Undefined; }, context)); + assert(!recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) { return e.type() == ExpressionNode::Type::Undefined; }, context, true)); return false; } /* The equation is can be written: a_1*x+a_0 with a_1 and a_0 x-independent. @@ -222,12 +224,12 @@ void Expression::defaultSetChildrenInPlace(Expression other) { } bool Expression::hasReplaceableSymbols(Context & context) const { - return recursivelyMatches([](const Expression e, Context & context) { + return recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) { return (e.type() == ExpressionNode::Type::Symbol && !context.expressionForSymbol(static_cast(e)).isUninitialized()) || (e.type() == ExpressionNode::Type::Function && !context.expressionForSymbol(static_cast(e)).isUninitialized()); - }, context); + }, context, false); } Expression Expression::defaultReplaceReplaceableSymbols(Context & context) { @@ -360,7 +362,7 @@ Expression Expression::reduce(Context & context, Preferences::AngleUnit angleUni Expression Expression::deepReduce(Context & context, Preferences::AngleUnit angleUnit, bool replaceSymbols) { #if MATRIX_EXACT_REDUCING #else - if (IsMatrix(*this, context)) { + if (IsMatrix(*this, context, replaceSymbols)) { sSimplificationHasBeenInterrupted = true; return *this; } diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 294082fab..118c5d771 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -159,7 +159,7 @@ bool Symbol::isRegressionSymbol(const char * c) { bool Symbol::matches(ExpressionTest test, Context & context) const { Expression e = context.expressionForSymbol(*this); e = ExpressionWithoutSymbols(e, context); - return !e.isUninitialized() && test(e, context); + return !e.isUninitialized() && test(e, context, true); } Expression Symbol::shallowReduce(Context & context, Preferences::AngleUnit angleUnit, bool replaceSymbols) {