mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
[poincare] Fix replaceReplaceableSymbols for parametered expressions
Scenario: ans*int(0,x,0,0)->x then cos(x) crashed because replaceReplaceableSymbols would not care if it was replacing parameters in a parametered expression
This commit is contained in:
committed by
EmilieNumworks
parent
764cf1087a
commit
94fb5815f9
@@ -76,6 +76,7 @@ class Expression : public TreeHandle {
|
||||
friend class NthRoot;
|
||||
friend class Number;
|
||||
friend class Opposite;
|
||||
friend class ParameteredExpression;
|
||||
friend class Parenthesis;
|
||||
friend class PermuteCoefficient;
|
||||
friend class Power;
|
||||
@@ -347,8 +348,8 @@ protected:
|
||||
Expression defaultReplaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression expression);
|
||||
/* 'deepReplaceReplaceableSymbols' returns an uninitialized expression if it
|
||||
* is circularly defined. Same convention as for 'ExpressionWithoutSymbols'.*/
|
||||
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly) { return node()->deepReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly); }
|
||||
Expression defaultReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly);
|
||||
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) { return node()->deepReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly, parameteredAncestorsCount); }
|
||||
Expression defaultReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount);
|
||||
|
||||
/* Simplification */
|
||||
void beautifyAndApproximateScalar(Expression * simplifiedExpression, Expression * approximateExpression, ExpressionNode::ReductionContext userReductionContext, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit);
|
||||
|
||||
@@ -172,7 +172,7 @@ public:
|
||||
/*!*/ virtual Expression setSign(Sign s, ReductionContext reductionContext);
|
||||
virtual int polynomialDegree(Context * context, const char * symbolName) const;
|
||||
/*!*/ virtual int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const;
|
||||
/*!*/ virtual Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly);
|
||||
/*!*/ virtual Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount);
|
||||
typedef bool (*isVariableTest)(const char * c, Poincare::Context * context);
|
||||
virtual int getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable, int nextVariableIndex) const;
|
||||
virtual float characteristicXRange(Context * context, Preferences::AngleUnit angleUnit) const;
|
||||
|
||||
@@ -41,7 +41,7 @@ private:
|
||||
int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||
// Simplification
|
||||
Expression shallowReduce(ReductionContext reductionContext) override;
|
||||
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly) override;
|
||||
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) override;
|
||||
LayoutShape leftLayoutShape() const override { return strlen(m_name) > 1 ? LayoutShape::MoreLetters : LayoutShape::OneLetter; };
|
||||
LayoutShape rightLayoutShape() const override { return LayoutShape::BoundaryPunctuation; }
|
||||
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
// Simplification
|
||||
Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression);
|
||||
Expression shallowReduce(ExpressionNode::ReductionContext reductionContext);
|
||||
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly);
|
||||
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ public:
|
||||
// Expression
|
||||
bool isParameteredExpression() const override { return true; }
|
||||
Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) override;
|
||||
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) override;
|
||||
|
||||
// Expression properties
|
||||
int getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable, int nextVariableIndex) const override;
|
||||
};
|
||||
@@ -36,6 +38,8 @@ public:
|
||||
* f(X)=diff(cos(x),x,X), X being an unknown. ReplaceUnknownInExpression does
|
||||
* that. */
|
||||
Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression);
|
||||
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount);
|
||||
Symbol parameter();
|
||||
protected:
|
||||
ParameteredExpression(const ParameteredExpressionNode * node) : Expression(node) {}
|
||||
};
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
|
||||
/* Simplification */
|
||||
Expression shallowReduce(ReductionContext reductionContext) override;
|
||||
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly) override;
|
||||
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) override;
|
||||
LayoutShape leftLayoutShape() const override;
|
||||
|
||||
/* Approximation */
|
||||
@@ -62,6 +62,7 @@ public:
|
||||
|
||||
// Symbol properties
|
||||
bool isSystemSymbol() const { return node()->isUnknown(); }
|
||||
bool hasSameNameAs(Symbol & other) const;
|
||||
const char * name() const { return node()->name(); }
|
||||
// IsVariable tests
|
||||
static bool isSeriesSymbol(const char * c, Poincare::Context * context);
|
||||
@@ -71,7 +72,7 @@ public:
|
||||
Expression shallowReduce(ExpressionNode::ReductionContext reductionContext);
|
||||
Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression);
|
||||
int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const;
|
||||
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly);
|
||||
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount);
|
||||
private:
|
||||
SymbolNode * node() const { return static_cast<SymbolNode *>(Expression::node()); }
|
||||
};
|
||||
|
||||
@@ -394,10 +394,10 @@ void Expression::defaultSetChildrenInPlace(Expression other) {
|
||||
}
|
||||
}
|
||||
|
||||
Expression Expression::defaultReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly) {
|
||||
Expression Expression::defaultReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) {
|
||||
int nbChildren = numberOfChildren();
|
||||
for (int i = 0; i < nbChildren; i++) {
|
||||
Expression c = childAtIndex(i).deepReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly);
|
||||
Expression c = childAtIndex(i).deepReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly, parameteredAncestorsCount);
|
||||
if (c.isUninitialized()) { // the expression is circularly defined, escape
|
||||
return Expression();
|
||||
}
|
||||
@@ -746,7 +746,7 @@ Expression Expression::ExpressionWithoutSymbols(Expression e, Context * context,
|
||||
break;
|
||||
}
|
||||
didReplace = false;
|
||||
e = e.deepReplaceReplaceableSymbols(context, &didReplace, replaceFunctionsOnly);
|
||||
e = e.deepReplaceReplaceableSymbols(context, &didReplace, replaceFunctionsOnly, 0);
|
||||
if (e.isUninitialized()) { // the expression is circularly defined, escape
|
||||
replacementCount = k_maxSymbolReplacementsCount;
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ int ExpressionNode::getPolynomialCoefficients(Context * context, const char * sy
|
||||
return Expression(this).defaultGetPolynomialCoefficients(context, symbolName, coefficients);
|
||||
}
|
||||
|
||||
Expression ExpressionNode::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly) {
|
||||
return Expression(this).defaultReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly);
|
||||
Expression ExpressionNode::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) {
|
||||
return Expression(this).defaultReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly, parameteredAncestorsCount);
|
||||
}
|
||||
|
||||
int ExpressionNode::getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable, int nextVariableIndex) const {
|
||||
|
||||
@@ -65,8 +65,8 @@ Expression FunctionNode::shallowReduce(ReductionContext reductionContext) {
|
||||
return Function(this).shallowReduce(reductionContext); // This uses Symbol::shallowReduce
|
||||
}
|
||||
|
||||
Expression FunctionNode::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly) {
|
||||
return Function(this).deepReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly);
|
||||
Expression FunctionNode::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) {
|
||||
return Function(this).deepReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly, parameteredAncestorsCount);
|
||||
}
|
||||
|
||||
Evaluation<float> FunctionNode::approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const {
|
||||
@@ -133,13 +133,15 @@ Expression Function::shallowReduce(ExpressionNode::ReductionContext reductionCon
|
||||
return result.deepReduce(reductionContext);
|
||||
}
|
||||
|
||||
Expression Function::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly) {
|
||||
// Replace replaceable symbols in child
|
||||
Expression self = defaultReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly);
|
||||
if (self.isUninitialized()) { // if the child is circularly defined, escape
|
||||
return self;
|
||||
Expression Function::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) {
|
||||
{
|
||||
// Replace replaceable symbols in child
|
||||
Expression self = defaultReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly ,parameteredAncestorsCount);
|
||||
if (self.isUninitialized()) { // if the child is circularly defined, escape
|
||||
return self;
|
||||
}
|
||||
assert(*this == self);
|
||||
}
|
||||
assert(*this == self);
|
||||
Expression e = context->expressionForSymbolAbstract(*this, false);
|
||||
if (e.isUninitialized()) {
|
||||
return *this;
|
||||
|
||||
@@ -9,6 +9,10 @@ Expression ParameteredExpressionNode::replaceSymbolWithExpression(const SymbolAb
|
||||
return ParameteredExpression(this).replaceSymbolWithExpression(symbol, expression);
|
||||
}
|
||||
|
||||
Expression ParameteredExpressionNode::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) {
|
||||
return ParameteredExpression(this).deepReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly, parameteredAncestorsCount);
|
||||
}
|
||||
|
||||
int ParameteredExpressionNode::getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable, int nextVariableIndex) const {
|
||||
int numberOfVariables = childAtIndex(ParameteredExpression::ParameteredChildIndex())->getVariables(context, isVariable, variables, maxSizeVariable, nextVariableIndex);
|
||||
// Handle exception
|
||||
@@ -62,4 +66,31 @@ Expression ParameteredExpression::replaceSymbolWithExpression(const SymbolAbstra
|
||||
return *this;
|
||||
}
|
||||
|
||||
Expression ParameteredExpression::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) {
|
||||
/* All children replaceable symbols should be replaced apart from symbols that
|
||||
* are parameters in parametered expressions.*/
|
||||
int childrenCount = numberOfChildren();
|
||||
for (int i = 0; i < childrenCount; i++) {
|
||||
if (i == ParameterChildIndex()) {
|
||||
// Do not replace symbols in the parameter child
|
||||
continue;
|
||||
}
|
||||
/* In the parametered child, increase the parametered ancestors count so
|
||||
* that when replacing symbols, the expressions check that the symbols are
|
||||
* not the parametered symbols. */
|
||||
bool shouldIncreaseParameteredAncestorsCount = i == ParameteredChildIndex();
|
||||
Expression c = childAtIndex(i).deepReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly, parameteredAncestorsCount + (shouldIncreaseParameteredAncestorsCount ? 1 : 0));
|
||||
if (c.isUninitialized()) { // the expression is circularly defined, escape
|
||||
return Expression();
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Symbol ParameteredExpression::parameter() {
|
||||
Expression e = childAtIndex(ParameteredExpression::ParameterChildIndex());
|
||||
assert(e.type() == ExpressionNode::Type::Symbol);
|
||||
return static_cast<Symbol&>(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -94,8 +94,8 @@ Expression SymbolNode::shallowReduce(ReductionContext reductionContext) {
|
||||
return Symbol(this).shallowReduce(reductionContext);
|
||||
}
|
||||
|
||||
Expression SymbolNode::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly) {
|
||||
return Symbol(this).deepReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly);
|
||||
Expression SymbolNode::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) {
|
||||
return Symbol(this).deepReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly, parameteredAncestorsCount);
|
||||
}
|
||||
|
||||
ExpressionNode::LayoutShape SymbolNode::leftLayoutShape() const {
|
||||
@@ -134,6 +134,10 @@ Symbol Symbol::Builder(CodePoint name) {
|
||||
return Symbol::Builder(buffer, codePointLength);
|
||||
}
|
||||
|
||||
bool Symbol::hasSameNameAs(Symbol & other) const {
|
||||
return (strcmp(other.name(), name()) == 0);
|
||||
}
|
||||
|
||||
bool Symbol::isSeriesSymbol(const char * c, Poincare::Context * context) {
|
||||
// [NV][1-3]
|
||||
if (c[2] == 0 && (c[0] == 'N' || c[0] == 'V') && c[1] >= '1' && c[1] <= '3') {
|
||||
@@ -218,10 +222,25 @@ int Symbol::getPolynomialCoefficients(Context * context, const char * symbolName
|
||||
return 0;
|
||||
}
|
||||
|
||||
Expression Symbol::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly) {
|
||||
Expression Symbol::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) {
|
||||
if (replaceFunctionsOnly || isSystemSymbol()) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Check that this is not a parameter in a parametered expression
|
||||
Expression ancestor = *this;
|
||||
while (parameteredAncestorsCount > 0) {
|
||||
ancestor = ancestor.parent();
|
||||
assert(!ancestor.isUninitialized());
|
||||
if (ancestor.isParameteredExpression()) {
|
||||
parameteredAncestorsCount--;
|
||||
Symbol ancestorParameter = static_cast<ParameteredExpression&>(ancestor).parameter();
|
||||
if (hasSameNameAs(ancestorParameter)) {
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Expression e = context->expressionForSymbolAbstract(*this, true);
|
||||
if (e.isUninitialized()) {
|
||||
return *this;
|
||||
|
||||
Reference in New Issue
Block a user