mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-28 01:59:59 +01:00
[poincare] ParameteredExpression: overrides getVariables to avoid
considering parameter as a variable
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user