From ada8f5f3c424bd051b5c1c163b9d73a7d276042f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 8 Nov 2018 16:47:32 +0100 Subject: [PATCH] [poincare] Replace symbols with their expressions iteratively ... not recursively. --- poincare/include/poincare/expression.h | 8 +++- poincare/include/poincare/expression_node.h | 1 + poincare/include/poincare/symbol.h | 2 + poincare/src/expression.cpp | 47 +++++++++++++++------ poincare/src/expression_node.cpp | 4 ++ poincare/src/symbol.cpp | 40 +++++++++++++++++- 6 files changed, 86 insertions(+), 16 deletions(-) diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index c4c2f2575..207c494bd 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -247,8 +247,14 @@ protected: /* Properties */ int getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const { return node()->getPolynomialCoefficients(context, symbolName, coefficients); } + bool hasSymbols(Context & context) const; + Expression replaceSymbols(Context & context) { return node()->replaceSymbols(context); } + Expression defaultReplaceSymbols(Context & context); /* Simplification */ + static void IncrementRecursionCount(); + static bool RecursionMaximalDepthExceeded(); + static bool RecursionCountResetisLocked(); Expression denominator(Context & context, Preferences::AngleUnit angleUnit) const { return node()->denominator(context, angleUnit); } Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit, bool replaceSymbols = true) { return node()->shallowReduce(context, angleUnit, replaceSymbols); } Expression shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) { return node()->shallowBeautify(context, angleUnit); } @@ -260,8 +266,6 @@ private: static constexpr int sRecursionLimit = 2000; //TODO value? static bool ResetRecursionCountAndLockReset(); static void UnlockRecursionCountReset(); - static void IncrementRecursionCount(); - static bool RecursionMaximalDepthExceeded(); Expression deepReduce(Context & context, Preferences::AngleUnit angleUnit, bool replaceSymbols = true); void deepReduceChildren(Context & context, Preferences::AngleUnit angleUnit, bool replaceSymbols) { return node()->deepReduceChildren(context, angleUnit, replaceSymbols); diff --git a/poincare/include/poincare/expression_node.h b/poincare/include/poincare/expression_node.h index 93ae1be7a..e41efb86e 100644 --- a/poincare/include/poincare/expression_node.h +++ b/poincare/include/poincare/expression_node.h @@ -106,6 +106,7 @@ public: /*!*/ virtual Expression setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit); virtual int polynomialDegree(Context & context, const char * symbolName) const; /*!*/ virtual int getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const; + /*!*/ virtual Expression replaceSymbols(Context & context); typedef bool (*isVariableTest)(const char * c); virtual int getVariables(Context & context, isVariableTest isVariable, char * variables, int maxSizeVariable) const; virtual float characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const; diff --git a/poincare/include/poincare/symbol.h b/poincare/include/poincare/symbol.h index 77b1eff52..c41f8e202 100644 --- a/poincare/include/poincare/symbol.h +++ b/poincare/include/poincare/symbol.h @@ -31,6 +31,7 @@ public: /* Simplification */ Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit, bool replaceSymbols = true) override; + Expression replaceSymbols(Context & context) override; /* Approximation */ Evaluation approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } @@ -75,6 +76,7 @@ public: Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit, bool replaceSymbols = true); Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression); int getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const; + Expression replaceSymbols(Context & context); private: SymbolNode * node() const { return static_cast(Expression::node()); } }; diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index f2ce0cb8a..0d613cb9d 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -14,7 +14,7 @@ namespace Poincare { static int sRecursionCount = 0; -static bool sRecursionCountReinitializationIsLocked = false; +static bool sRecursionCountResetIsLocked = false; /* Constructor & Destructor */ @@ -120,6 +120,11 @@ bool Expression::isApproximate(Context & context) const { } bool Expression::IsMatrix(const Expression e, Context & context) { + assert(RecursionCountResetisLocked()); + IncrementRecursionCount(); + if (RecursionMaximalDepthExceeded()) { + return false; + } return e.type() == ExpressionNode::Type::Matrix || e.type() == ExpressionNode::Type::ConfidenceInterval || e.type() == ExpressionNode::Type::MatrixDimension @@ -241,6 +246,20 @@ void Expression::defaultSetChildrenInPlace(Expression other) { } } +bool Expression::hasSymbols(Context & context) const { + return recursivelyMatches([](const Expression e, Context & context) { + return e.type() == ExpressionNode::Type::Symbol || e.type() == ExpressionNode::Type::Function; + }, context); +} + +Expression Expression::defaultReplaceSymbols(Context & context) { + int nbChildren = numberOfChildren(); + for (int i = 0; i < nbChildren; i++) { + childAtIndex(i).replaceSymbols(context); + } + return *this; +} + template Evaluation Expression::approximateToEvaluation(Context& context, Preferences::AngleUnit angleUnit) const { bool willHaveToUnlock = ResetRecursionCountAndLockReset(); @@ -356,24 +375,16 @@ Expression Expression::reduce(Context & context, Preferences::AngleUnit angleUni } bool Expression::ResetRecursionCountAndLockReset() { - if (!sRecursionCountReinitializationIsLocked) { + if (!sRecursionCountResetIsLocked) { sRecursionCount = 0; - sRecursionCountReinitializationIsLocked = true; + sRecursionCountResetIsLocked = true; return true; } return false; } void Expression::UnlockRecursionCountReset() { - sRecursionCountReinitializationIsLocked = false; -} - -void Expression::IncrementRecursionCount() { - sRecursionCount++; -} - -bool Expression::RecursionMaximalDepthExceeded() { - return sRecursionCount >= Expression::sRecursionLimit; + sRecursionCountResetIsLocked = false; } Expression Expression::deepReduce(Context & context, Preferences::AngleUnit angleUnit, bool replaceSymbols) { @@ -404,6 +415,18 @@ Expression Expression::deepBeautify(Context & context, Preferences::AngleUnit an return e; } +void Expression::IncrementRecursionCount() { + sRecursionCount++; +} + +bool Expression::RecursionMaximalDepthExceeded() { + return sRecursionCount >= Expression::sRecursionLimit; +} + +bool Expression::RecursionCountResetisLocked() { + return sRecursionCountResetIsLocked; +} + Expression Expression::setSign(ExpressionNode::Sign s, Context & context, Preferences::AngleUnit angleUnit) { return node()->setSign(s, context, angleUnit); } diff --git a/poincare/src/expression_node.cpp b/poincare/src/expression_node.cpp index d5d06a8c0..574da2145 100644 --- a/poincare/src/expression_node.cpp +++ b/poincare/src/expression_node.cpp @@ -27,6 +27,10 @@ int ExpressionNode::getPolynomialCoefficients(Context & context, const char * sy return Expression(this).defaultGetPolynomialCoefficients(context, symbolName, coefficients); } +Expression ExpressionNode::replaceSymbols(Context & context) { + return Expression(this).defaultReplaceSymbols(context); +} + int ExpressionNode::getVariables(Context & context, isVariableTest isVariable, char * variables, int maxSizeVariable) const { int numberOfVariables = 0; for (ExpressionNode * c : children()) { diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index da737ac54..1b0412605 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -119,12 +120,27 @@ Expression SymbolNode::shallowReduce(Context & context, Preferences::AngleUnit a return Symbol(this).shallowReduce(context, angleUnit, replaceSymbols); } +Expression SymbolNode::replaceSymbols(Context & context) { + return Symbol(this).replaceSymbols(context); +} + template Evaluation SymbolNode::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { - const Expression e = context.expressionForSymbol(Symbol(this)); + Expression e = context.expressionForSymbol(Symbol(this)); if (e.isUninitialized()) { return Complex::Undefined(); } + + /* First, replace all the symbols iteratively. This prevents a memory + * failure symbols are defined circularly. */ + while (e.hasSymbols(context)) { + assert(Expression::RecursionCountResetisLocked()); + Expression::IncrementRecursionCount(); + if (Expression::RecursionMaximalDepthExceeded()) { + return Complex::Undefined(); + } + e = e.replaceSymbols(context); + } return e.approximateToEvaluation(context, angleUnit); } @@ -163,7 +179,18 @@ Expression Symbol::shallowReduce(Context & context, Preferences::AngleUnit angle const Expression e = context.expressionForSymbol(*this); if (!e.isUninitialized()) { // The stored expression is beautified, so we need to call reduce - Expression result = e.clone(); + Expression result = e; + /* First, replace all the symbols iteratively. This prevents a memory + * failure symbols are defined circularly. */ + while (result.hasSymbols(context)) { + assert(RecursionCountResetisLocked()); + IncrementRecursionCount(); + if (RecursionMaximalDepthExceeded()) { + replaceWithInPlace(e); + return e; + } + result = result.replaceSymbols(context); + } replaceWithInPlace(result); return result.deepReduce(context, angleUnit); } @@ -193,4 +220,13 @@ int Symbol::getPolynomialCoefficients(Context & context, const char * symbolName return 0; } +Expression Symbol::replaceSymbols(Context & context) { + Expression e = context.expressionForSymbol(*this); + if (e.isUninitialized()) { + e = Undefined(); + } + replaceWithInPlace(e); + return e; +} + }