mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-18 21:30:38 +01:00
[poincare] Replace symbols with their expressions iteratively
... not recursively.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()); }
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user