mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
[poincare] Change Expression::getVariables to get symbols with variable
sizes
This commit is contained in:
@@ -264,14 +264,16 @@ int StoreController::maxNumberOfElements() const {
|
||||
bool StoreController::privateFillColumnWithFormula(Expression formula, ExpressionNode::isVariableTest isVariable) {
|
||||
int currentColumn = selectedColumn();
|
||||
// Fetch the series used in the formula to compute the size of the filled in series
|
||||
char variables[Expression::k_maxNumberOfVariables];
|
||||
variables[0] = 0;
|
||||
constexpr static int k_maxSizeOfStoreSymbols = 3; // "V1", "N1", "X1", "Y1"
|
||||
char variables[Expression::k_maxNumberOfVariables][k_maxSizeOfStoreSymbols];
|
||||
variables[0][0] = 0;
|
||||
AppsContainer * appsContainer = ((TextFieldDelegateApp *)app())->container();
|
||||
formula.getVariables(*(appsContainer->globalContext()), isVariable, variables);
|
||||
int nbOfVariables = formula.getVariables(*(appsContainer->globalContext()), isVariable, variables, k_maxSizeOfStoreSymbols);
|
||||
assert(nbOfVariables >= 0);
|
||||
int numberOfValuesToCompute = -1;
|
||||
int index = 0;
|
||||
while (variables[index] != 0) {
|
||||
const char * seriesName = Symbol::textForSpecialSymbols(variables[index]);
|
||||
while (variables[index][0] != 0) {
|
||||
const char * seriesName = variables[index];
|
||||
assert(strlen(seriesName) == 2);
|
||||
int series = (int)(seriesName[1] - '0') - 1;
|
||||
assert(series >= 0 && series < DoublePairStore::k_numberOfSeries);
|
||||
|
||||
@@ -14,6 +14,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
Poincare::Expression standardForm(Poincare::Context * context) const;
|
||||
constexpr static int k_maxVariableSize = 10;
|
||||
private:
|
||||
void tidyStandardForm();
|
||||
mutable Poincare::Expression m_standardForm;
|
||||
|
||||
@@ -80,7 +80,7 @@ bool EquationStore::haveMoreApproximationSolutions(Context * context) {
|
||||
}
|
||||
|
||||
void EquationStore::approximateSolve(Poincare::Context * context) {
|
||||
assert(m_variables[0] != 0 && m_variables[1] == 0);
|
||||
assert(m_variables[0][0] != 0 && m_variables[1][0] == 0);
|
||||
assert(m_type == Type::Monovariable);
|
||||
m_numberOfSolutions = 0;
|
||||
double start = m_intervalApproximateSolutions[0];
|
||||
@@ -100,17 +100,20 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context) {
|
||||
tidySolution();
|
||||
|
||||
/* 0- Get unknown variables */
|
||||
m_variables[0] = 0;
|
||||
m_variables[0][0] = 0;
|
||||
int numberOfVariables = 0;
|
||||
for (int i = 0; i < numberOfDefinedModels(); i++) {
|
||||
const Expression e = definedModelAtIndex(i)->standardForm(context);
|
||||
if (e.isUninitialized() || e.type() == ExpressionNode::Type::Undefined) {
|
||||
return Error::EquationUndefined;
|
||||
}
|
||||
numberOfVariables = definedModelAtIndex(i)->standardForm(context).getVariables(*context, Symbol::isVariableSymbol, m_variables);
|
||||
if (numberOfVariables < 0) {
|
||||
numberOfVariables = definedModelAtIndex(i)->standardForm(context).getVariables(*context, Symbol::isVariableSymbol, m_variables, Equation::k_maxVariableSize);
|
||||
if (numberOfVariables == -1) {
|
||||
return Error::TooManyVariables;
|
||||
}
|
||||
/*if (numberOfVariables == -2) {
|
||||
return Error::VariableNameTooLong;
|
||||
}*/
|
||||
}
|
||||
|
||||
/* 1- Linear System? */
|
||||
@@ -150,9 +153,8 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context) {
|
||||
} else {
|
||||
/* 2- Polynomial & Monovariable? */
|
||||
assert(numberOfVariables == 1 && numberOfDefinedModels() == 1);
|
||||
const char x[] = {m_variables[0], 0};
|
||||
Expression polynomialCoefficients[Expression::k_maxNumberOfPolynomialCoefficients];
|
||||
int degree = definedModelAtIndex(0)->standardForm(context).getPolynomialReducedCoefficients(x, polynomialCoefficients, *context, preferences->angleUnit());
|
||||
int degree = definedModelAtIndex(0)->standardForm(context).getPolynomialReducedCoefficients(m_variables[0], polynomialCoefficients, *context, preferences->angleUnit());
|
||||
if (degree == 2) {
|
||||
/* Polynomial degree <= 2*/
|
||||
m_type = Type::PolynomialMonovariable;
|
||||
@@ -189,7 +191,9 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context) {
|
||||
|
||||
EquationStore::Error EquationStore::resolveLinearSystem(Expression exactSolutions[k_maxNumberOfExactSolutions], Expression coefficients[k_maxNumberOfEquations][Expression::k_maxNumberOfVariables], Expression constants[k_maxNumberOfEquations], Context * context) {
|
||||
Preferences::AngleUnit angleUnit = Preferences::sharedPreferences()->angleUnit();
|
||||
int n = strlen(m_variables); // n unknown variables
|
||||
// n unknown variables
|
||||
int n = 0;
|
||||
while (m_variables[n++][0] != 0) {}
|
||||
int m = numberOfDefinedModels(); // m equations
|
||||
/* Create the matrix (A | b) for the equation Ax=b */
|
||||
Matrix Ab;
|
||||
|
||||
@@ -84,7 +84,7 @@ private:
|
||||
|
||||
Equation m_equations[k_maxNumberOfEquations];
|
||||
Type m_type;
|
||||
char m_variables[Poincare::Expression::k_maxNumberOfVariables+1];
|
||||
char m_variables[Poincare::Expression::k_maxNumberOfVariables+1][Equation::k_maxVariableSize];
|
||||
int m_numberOfSolutions;
|
||||
Poincare::Layout m_exactSolutionExactLayouts[k_maxNumberOfApproximateSolutions];
|
||||
Poincare::Layout m_exactSolutionApproximateLayouts[k_maxNumberOfExactSolutions];
|
||||
|
||||
@@ -124,14 +124,16 @@ public:
|
||||
* - (-1) if the expression is not a polynome
|
||||
* - the degree of the polynome otherwise */
|
||||
int polynomialDegree(Context & context, const char * symbolName) const { return this->node()->polynomialDegree(context, symbolName); }
|
||||
/* getVariables fills the table variables with the variable present in the
|
||||
* expression and returns the number of entries in filled in variables.
|
||||
* For instance getVariables('x+y+2*w/cos(4)') would result in
|
||||
* variables = « xyw » and would return 3. If the final number of
|
||||
* variables would overflow the maxNumberOfVariables, getVariables return -1 */
|
||||
/* getVariables fills the matrix variables with the symbols present in the
|
||||
* expression that passes the test isVariable. It returns the number of
|
||||
* entries filled in variables. For instance, getVariables of
|
||||
* 'x+y+2*w/cos(4)' would result in variables = {"x", "y", "w"} and would
|
||||
* return 3. If the final numberof variables would overflow the
|
||||
* maxNumberOfVariables, getVariables return -1. If one of the variable
|
||||
* lengths overflow the maxVariableLength; getVariables return -2. */
|
||||
static constexpr int k_maxNumberOfVariables = 6;
|
||||
int getVariables(Context & context, ExpressionNode::isVariableTest isVariable, char * variables) const { return node()->getVariables(context, isVariable, variables); }
|
||||
/* getLinearCoefficients return false if the expression is not linear with
|
||||
int getVariables(Context & context, ExpressionNode::isVariableTest isVariable, char * variables, int maxVariableLength) const { return node()->getVariables(context, isVariable, variables, maxVariableLength); }
|
||||
0 /* 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
|
||||
* order) and 'constant' with the constant of the expression. */
|
||||
|
||||
@@ -104,7 +104,7 @@ public:
|
||||
virtual int polynomialDegree(Context & context, const char * symbolName) const;
|
||||
/*!*/ virtual int getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const;
|
||||
typedef bool (*isVariableTest)(const char * c);
|
||||
virtual int getVariables(Context & context, isVariableTest isVariable, char * variables) const;
|
||||
virtual int getVariables(Context & context, isVariableTest isVariable, char * variables, int maxSizeVariable) const;
|
||||
virtual float characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const;
|
||||
bool isOfType(Type * types, int length) const;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
Type type() const override { return Type::Function; }
|
||||
int polynomialDegree(Context & context, const char * symbolName) const override;
|
||||
int getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const override;
|
||||
int getVariables(Context & context, isVariableTest isVariable, char * variables) const override;
|
||||
int getVariables(Context & context, isVariableTest isVariable, char * variables, int maxSizeVariable) const override;
|
||||
float characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
Expression replaceSymbolWithExpression(const char * symbol, Expression & expression) override;
|
||||
int polynomialDegree(Context & context, const char * symbolName) const override;
|
||||
int getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const override;
|
||||
int getVariables(Context & context, isVariableTest isVariable, char * variables) const override;
|
||||
int getVariables(Context & context, isVariableTest isVariable, char * variables, int maxSizeVariable) const override;
|
||||
float characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const override;
|
||||
|
||||
/* Comparison */
|
||||
|
||||
@@ -26,12 +26,12 @@ int ExpressionNode::getPolynomialCoefficients(Context & context, const char * sy
|
||||
return Expression(this).defaultGetPolynomialCoefficients(context, symbolName, coefficients);
|
||||
}
|
||||
|
||||
int ExpressionNode::getVariables(Context & context, isVariableTest isVariable, char * variables) const {
|
||||
int ExpressionNode::getVariables(Context & context, isVariableTest isVariable, char * variables, int maxSizeVariable) const {
|
||||
int numberOfVariables = 0;
|
||||
for (ExpressionNode * c : children()) {
|
||||
int n = c->getVariables(context, isVariable, variables);
|
||||
int n = c->getVariables(context, isVariable, variables, maxSizeVariable);
|
||||
if (n < 0) {
|
||||
return -1;
|
||||
return n;
|
||||
}
|
||||
numberOfVariables = n > numberOfVariables ? n : numberOfVariables;
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@ int FunctionNode::getPolynomialCoefficients(Context & context, const char * symb
|
||||
return e.getPolynomialCoefficients(context, symbolName, coefficients);
|
||||
}
|
||||
|
||||
int FunctionNode::getVariables(Context & context, isVariableTest isVariable, char * variables) const {
|
||||
int FunctionNode::getVariables(Context & context, isVariableTest isVariable, char * variables, int maxSizeVariable) const {
|
||||
Expression e = context.expressionForSymbol(Function(this));
|
||||
return e.getVariables(context, isVariable, variables);
|
||||
return e.getVariables(context, isVariable, variables, maxSizeVariable);
|
||||
}
|
||||
|
||||
float FunctionNode::characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const {
|
||||
|
||||
@@ -45,20 +45,23 @@ int SymbolNode::getPolynomialCoefficients(Context & context, const char * symbol
|
||||
return Symbol(this).getPolynomialCoefficients(context, symbolName, coefficients);
|
||||
}
|
||||
|
||||
int SymbolNode::getVariables(Context & context, isVariableTest isVariable, char * variables) const {
|
||||
size_t variablesLength = strlen(variables);
|
||||
int SymbolNode::getVariables(Context & context, isVariableTest isVariable, char * variables, int maxSizeVariable) const {
|
||||
size_t variablesLength = 0;
|
||||
while(variables[variablesLength++][0] != 0) {}
|
||||
if (isVariable(m_name)) {
|
||||
assert(m_name[1] == 0);
|
||||
char * currentChar = variables;
|
||||
while (*currentChar != 0) {
|
||||
if (*currentChar == m_name[0]) {
|
||||
int index = 0;
|
||||
while (variables[index][0] != 0) {
|
||||
if (strcmp(variables[index], m_name) == 0) {
|
||||
return variablesLength;
|
||||
}
|
||||
currentChar++;
|
||||
index++;
|
||||
}
|
||||
if (variablesLength < Expression::k_maxNumberOfVariables) {
|
||||
variables[variablesLength] = m_name[0];
|
||||
variables[variablesLength+1] = 0;
|
||||
if (strlen(m_name) + 1 > maxSizeVariable) {
|
||||
return -2;
|
||||
}
|
||||
strlcpy(variables[variablesLength], m_name, maxSizeVariable);
|
||||
variables[variablesLength+1][0] = 0;
|
||||
return variablesLength+1;
|
||||
}
|
||||
return -1;
|
||||
|
||||
@@ -79,29 +79,31 @@ QUIZ_CASE(poincare_characteristic_range) {
|
||||
assert_parsed_expression_has_characteristic_range("cos(cos(x))", 360.0f);
|
||||
}
|
||||
|
||||
void assert_parsed_expression_has_variables(const char * expression, const char * variables) {
|
||||
void assert_parsed_expression_has_variables(const char * expression, const char variables[][]) {
|
||||
Expression e = parse_expression(expression);
|
||||
quiz_assert(!e.isUninitialized());
|
||||
char variableBuffer[Expression::k_maxNumberOfVariables+1] = {0};
|
||||
int numberOfVariables = e.getVariables(Poincare::Symbol::isVariableSymbol, variableBuffer);
|
||||
if (variables == nullptr) {
|
||||
constexpr static int k_maxVariableSize = 10;
|
||||
char variableBuffer[Expression::k_maxNumberOfVariables+1][k_maxVariableSize] = {{0}};
|
||||
int numberOfVariables = e.getVariables(Poincare::Symbol::isVariableSymbol, variableBuffer, k_maxVariableSize);
|
||||
if (variables[0][0] == 0) {
|
||||
quiz_assert(numberOfVariables == -1);
|
||||
} else {
|
||||
quiz_assert(numberOfVariables == strlen(variables));
|
||||
char * currentChar = variableBuffer;
|
||||
while (*variables != 0) {
|
||||
quiz_assert(*currentChar++ == *variables++);
|
||||
quiz_assert(numberOfVariables == sizeof(variables));
|
||||
int index = 0;
|
||||
const char * currentChar = variableBuffer[];
|
||||
while (variableBuffer[index][0] != 0) {
|
||||
quiz_assert(strcmp(variableBuffer[index], variables[index]) == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QUIZ_CASE(poincare_get_variables) {
|
||||
assert_parsed_expression_has_variables("x+y", "xy");
|
||||
assert_parsed_expression_has_variables("x+y+z+2*t", "xyzt");
|
||||
assert_parsed_expression_has_variables("abcdef", "abcdef");
|
||||
assert_parsed_expression_has_variables("abcdefg", nullptr);
|
||||
assert_parsed_expression_has_variables("abcde", "abcde");
|
||||
assert_parsed_expression_has_variables("x^2+2*y+k!*A+w", "xykw");
|
||||
assert_parsed_expression_has_variables("x+y", {"x","y", ""});
|
||||
assert_parsed_expression_has_variables("x+y+z+2*t", {"x","y","z","t",""});
|
||||
assert_parsed_expression_has_variables("abcdef", {"a","b","c","d","e","f",""});
|
||||
assert_parsed_expression_has_variables("abcdefg", {""});
|
||||
assert_parsed_expression_has_variables("abcde", {"a","b","c","d","e",""});
|
||||
assert_parsed_expression_has_variables("x^2+2*y+k!*A+w", {"x","y","k","w",""});
|
||||
}
|
||||
|
||||
void assert_parsed_expression_has_polynomial_coefficient(const char * expression, const char * symbolName, const char ** coefficients, Preferences::AngleUnit angleUnit = Preferences::AngleUnit::Degree) {
|
||||
|
||||
Reference in New Issue
Block a user