[poincare] Replace symbols with their expressions iteratively

... not recursively.
This commit is contained in:
Léa Saviot
2018-11-08 16:47:32 +01:00
committed by Émilie Feral
parent 5bba2e9528
commit ada8f5f3c4
6 changed files with 86 additions and 16 deletions

View File

@@ -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);

View File

@@ -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;

View File

@@ -31,6 +31,7 @@ public:
/* Simplification */
Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit, bool replaceSymbols = true) override;
Expression replaceSymbols(Context & context) override;
/* Approximation */
Evaluation<float> approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<float>(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<SymbolNode *>(Expression::node()); }
};

View File

@@ -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<typename U>
Evaluation<U> 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);
}

View File

@@ -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()) {

View File

@@ -5,6 +5,7 @@
#include <poincare/layout_helper.h>
#include <poincare/parenthesis.h>
#include <poincare/rational.h>
#include <poincare/undefined.h>
#include <poincare/vertical_offset_layout.h>
#include <ion.h>
#include <cmath>
@@ -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<typename T>
Evaluation<T> 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<T>::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<T>::Undefined();
}
e = e.replaceSymbols(context);
}
return e.approximateToEvaluation<T>(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;
}
}