[poincare] ParameteredExpression: overrides getVariables to avoid

considering parameter as a variable
This commit is contained in:
Émilie Feral
2020-02-04 15:09:46 +01:00
committed by Léa Saviot
parent b8f65442db
commit 3df80ed780
11 changed files with 66 additions and 27 deletions

View File

@@ -146,7 +146,7 @@ EquationStore::Error EquationStore::privateExactSolve(Poincare::Context * contex
if (e.type() == ExpressionNode::Type::Unreal) {
return Error::EquationUnreal;
}
numberOfVariables = e.getVariables(context, [](const char * symbol, Poincare::Context * context) { return true; }, (char *)m_variables, Poincare::SymbolAbstract::k_maxNameSize);
numberOfVariables = e.getVariables(context, [](const char * symbol, Poincare::Context * context) { return true; }, (char *)m_variables, Poincare::SymbolAbstract::k_maxNameSize, numberOfVariables);
if (numberOfVariables == -1) {
return Error::TooManyVariables;
}
@@ -162,7 +162,7 @@ EquationStore::Error EquationStore::privateExactSolve(Poincare::Context * contex
for (int i = 0; i < numberOfDefinedModels(); i++) {
const Expression e = modelForRecord(definedRecordAtIndex(i))->standardForm(context, true);
assert(!e.isUninitialized() && e.type() != ExpressionNode::Type::Undefined && e.type() != ExpressionNode::Type::Unreal);
int varCount = e.getVariables(context, [](const char * symbol, Poincare::Context * context) { return context->expressionTypeForIdentifier(symbol, strlen(symbol)) == Poincare::Context::SymbolAbstractType::Symbol; }, (char *)m_userVariables, Poincare::SymbolAbstract::k_maxNameSize);
int varCount = e.getVariables(context, [](const char * symbol, Poincare::Context * context) { return context->expressionTypeForIdentifier(symbol, strlen(symbol)) == Poincare::Context::SymbolAbstractType::Symbol; }, (char *)m_userVariables, Poincare::SymbolAbstract::k_maxNameSize, m_numberOfUserVariables);
if (varCount < 0) {
m_numberOfUserVariables = Expression::k_maxNumberOfVariables;
break;

View File

@@ -183,7 +183,7 @@ public:
* If one of the variable lengths overflows maxVariableLength, getVariables
* returns -2. */
static constexpr int k_maxNumberOfVariables = 6;
int getVariables(Context * context, ExpressionNode::isVariableTest isVariable, char * variables, int maxVariableLength) const { return node()->getVariables(context, isVariable, variables, maxVariableLength); }
int getVariables(Context * context, ExpressionNode::isVariableTest isVariable, char * variables, int maxVariableLength, int nextVariableIndex = 0) const { return node()->getVariables(context, isVariable, variables, maxVariableLength, nextVariableIndex); }
/* getLinearCoefficients return false if the expression is not linear with
* the variables hold in 'variables'. Otherwise, it fills 'coefficients' with
* the coefficients of the variables hold in 'variables' (following the same

View File

@@ -173,7 +173,7 @@ public:
/*!*/ virtual int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const;
/*!*/ virtual Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly);
typedef bool (*isVariableTest)(const char * c, Poincare::Context * context);
virtual int getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable) const;
virtual int getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable, int nextVariableIndex) const;
virtual float characteristicXRange(Context * context, Preferences::AngleUnit angleUnit) const;
bool isOfType(Type * types, int length) const;
virtual bool beautifiedExpressionHasUnits() const { return false; } // This must be called on a beautified expression

View File

@@ -26,7 +26,7 @@ public:
Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) override;
int polynomialDegree(Context * context, const char * symbolName) const override;
int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const override;
int getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable) const override;
int getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable, int nextVariableIndex) const override;
float characteristicXRange(Context * context, Preferences::AngleUnit angleUnit) const override;
private:

View File

@@ -14,6 +14,8 @@ public:
// Expression
bool isParameteredExpression() const override { return true; }
Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) override;
// Expression properties
int getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable, int nextVariableIndex) const override;
};
class ParameteredExpression : public Expression {

View File

@@ -24,7 +24,7 @@ public:
Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) override;
int polynomialDegree(Context * context, const char * symbolName) const override;
int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const override;
int getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable) const override;
int getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable, int nextVariableIndex) const override;
float characteristicXRange(Context * context, Preferences::AngleUnit angleUnit) const override;
/* Layout */

View File

@@ -40,16 +40,15 @@ Expression ExpressionNode::deepReplaceReplaceableSymbols(Context * context, bool
return Expression(this).defaultReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly);
}
int ExpressionNode::getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable) const {
int numberOfVariables = 0;
int ExpressionNode::getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable, int nextVariableIndex) const {
for (ExpressionNode * c : children()) {
int n = c->getVariables(context, isVariable, variables, maxSizeVariable);
int n = c->getVariables(context, isVariable, variables, maxSizeVariable, nextVariableIndex);
if (n < 0) {
return n;
}
numberOfVariables = n > numberOfVariables ? n : numberOfVariables;
nextVariableIndex = n;
}
return numberOfVariables;
return nextVariableIndex;
}
float ExpressionNode::characteristicXRange(Context * context, Preferences::AngleUnit angleUnit) const {

View File

@@ -35,13 +35,13 @@ int FunctionNode::getPolynomialCoefficients(Context * context, const char * symb
return e.getPolynomialCoefficients(context, symbolName, coefficients, symbolicComputation);
}
int FunctionNode::getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable) const {
int FunctionNode::getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable, int nextVariableIndex) const {
Function f(this);
Expression e = SymbolAbstract::Expand(f, context, true);
if (e.isUninitialized()) {
return 0;
}
return e.getVariables(context, isVariable, variables, maxSizeVariable);
return e.node()->getVariables(context, isVariable, variables, maxSizeVariable, nextVariableIndex);
}
float FunctionNode::characteristicXRange(Context * context, Preferences::AngleUnit angleUnit) const {

View File

@@ -9,6 +9,38 @@ Expression ParameteredExpressionNode::replaceSymbolWithExpression(const SymbolAb
return ParameteredExpression(this).replaceSymbolWithExpression(symbol, expression);
}
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
if (numberOfVariables < 0) {
return numberOfVariables;
}
/* Remove the parameter symbol from the list of variable if it was added at
* the previous line */
// Get the parameter symbol
assert(childAtIndex(ParameteredExpression::ParameterChildIndex())->type() == ExpressionNode::Type::Symbol);
SymbolNode * parameterChild = static_cast<SymbolNode *>(childAtIndex(ParameteredExpression::ParameterChildIndex()));
for (int i = nextVariableIndex; i < numberOfVariables; i++) {
if (strcmp(parameterChild->name(), &variables[i]) == 0) {
variables[i] = 0;
numberOfVariables--;
break;
}
}
nextVariableIndex = numberOfVariables;
static_assert(ParameteredExpression::ParameteredChildIndex() == 0 && ParameteredExpression::ParameterChildIndex() == 1,
"ParameteredExpression::getVariables might not be valid");
for (int i = ParameteredExpression::ParameterChildIndex() + 1; i < numberOfChildren(); i++) {
int n = childAtIndex(i)->getVariables(context, isVariable, variables, maxSizeVariable, nextVariableIndex);
// Handle exception
if (n < 0) {
return n;
}
nextVariableIndex = n;
}
return nextVariableIndex;
}
Expression ParameteredExpression::replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) {
Expression c = childAtIndex(ParameterChildIndex());
assert(c.type() == ExpressionNode::Type::Symbol);

View File

@@ -37,31 +37,31 @@ int SymbolNode::getPolynomialCoefficients(Context * context, const char * symbol
return Symbol(this).getPolynomialCoefficients(context, symbolName, coefficients, symbolicComputation);
}
int SymbolNode::getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable) const {
int SymbolNode::getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable, int nextVariableIndex) const {
// variables is in fact of type char[k_maxNumberOfVariables][maxSizeVariable]
size_t variablesIndex = 0;
while(variables[variablesIndex] != 0) {
variablesIndex+= maxSizeVariable;
}
if (isVariable(m_name, context)) {
int index = 0;
while (variables[index] != 0) {
while (index < maxSizeVariable*Expression::k_maxNumberOfVariables && variables[index] != 0) {
if (strcmp(m_name, &variables[index]) == 0) {
return variablesIndex/maxSizeVariable;
return nextVariableIndex;
}
index+= maxSizeVariable;
}
if ((variablesIndex/maxSizeVariable) < Expression::k_maxNumberOfVariables) {
if (nextVariableIndex < Expression::k_maxNumberOfVariables) {
assert(variables[nextVariableIndex*maxSizeVariable] == 0);
if (strlen(m_name) + 1 > (size_t)maxSizeVariable) {
return -2;
}
strlcpy(&variables[variablesIndex], m_name, maxSizeVariable);
variables[variablesIndex+maxSizeVariable] = 0;
return variablesIndex/maxSizeVariable+1;
strlcpy(&variables[nextVariableIndex*maxSizeVariable], m_name, maxSizeVariable);
nextVariableIndex++;
if (nextVariableIndex < Expression::k_maxNumberOfVariables) {
variables[nextVariableIndex*maxSizeVariable] = 0;
}
return nextVariableIndex;
}
return -1;
}
return variablesIndex/maxSizeVariable;
return nextVariableIndex;
}
float SymbolNode::characteristicXRange(Context * context, Preferences::AngleUnit angleUnit) const {

View File

@@ -280,7 +280,7 @@ void assert_expression_has_variables(const char * expression, const char * varia
Shared::GlobalContext globalContext;
Expression e = parse_expression(expression, &globalContext, false);
constexpr static int k_maxVariableSize = Poincare::SymbolAbstract::k_maxNameSize;
char variableBuffer[Expression::k_maxNumberOfVariables+1][k_maxVariableSize] = {{0}};
char variableBuffer[Expression::k_maxNumberOfVariables][k_maxVariableSize] = {{0}};
int numberOfVariables = e.getVariables(&globalContext, [](const char * symbol, Poincare::Context * context) { return true; }, (char *)variableBuffer, k_maxVariableSize);
quiz_assert_print_if_failure(trueNumberOfVariables == numberOfVariables, expression);
if (numberOfVariables < 0) {
@@ -288,7 +288,7 @@ void assert_expression_has_variables(const char * expression, const char * varia
return;
}
int index = 0;
while (variableBuffer[index][0] != 0 || variables[index][0] != 0) {
while (index < Expression::k_maxNumberOfVariables && (variableBuffer[index][0] != 0 || variables[index][0] != 0)) {
quiz_assert_print_if_failure(strcmp(variableBuffer[index], variables[index]) == 0, expression);
index++;
}
@@ -307,11 +307,17 @@ QUIZ_CASE(poincare_properties_get_variables) {
assert_expression_has_variables("BBBBBB", variableBuffer5, 1);
const char * variableBuffer6[] = {""};
assert_expression_has_variables("a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q+r+s+t+aa+bb+cc+dd+ee+ff+gg+hh+ii+jj+kk+ll+mm+nn+oo", variableBuffer6, -1);
assert_expression_has_variables("a+b+c+d+e+f+g", variableBuffer6, -1);
// f: x→1+πx+x^2+toto
assert_simplify("1+π×x+x^2+toto→f(x)");
const char * variableBuffer7[] = {"tata","toto", ""};
assert_expression_has_variables("f(tata)", variableBuffer7, 2);
Ion::Storage::sharedStorage()->recordNamed("f.func").destroy();
const char * variableBuffer8[] = {"y", ""};
assert_expression_has_variables("diff(3x,x,0)y-2", variableBuffer8, 1);
const char * variableBuffer9[] = {"a", "b", "c", "d", "e", "f"};
assert_expression_has_variables("a+b+c+d+e+f", variableBuffer9, 6);
}
void assert_reduced_expression_has_polynomial_coefficient(const char * expression, const char * symbolName, const char ** coefficients, Preferences::ComplexFormat complexFormat = Cartesian, Preferences::AngleUnit angleUnit = Radian, ExpressionNode::SymbolicComputation symbolicComputation = ReplaceAllDefinedSymbolsWithDefinition) {