diff --git a/apps/solver/equation_store.h b/apps/solver/equation_store.h index ab190c131..98da959d9 100644 --- a/apps/solver/equation_store.h +++ b/apps/solver/equation_store.h @@ -21,7 +21,7 @@ private: return emptyModel(); } void setModelAtIndex(Shared::ExpressionModel * f, int i) override; - static constexpr int k_maxNumberOfEquations = 6; + static constexpr int k_maxNumberOfEquations = Poincare::Expression::k_maxNumberOfVariables; // Enable the same number of equations as the number of unknown variables Equation m_equations[k_maxNumberOfEquations];; }; diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 93eb0fa75..44d845bb0 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -215,6 +215,17 @@ public: * - (-1) if the expression is not a polynome * - the degree of the polynome otherwise */ virtual int polynomialDegree(char symbolName) const; + /* 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 = ['x', 'y', 'w'] and would return 3. If the final number of + * variables would overflow the maxNumberOfVariables, getVariables return -1 */ + static constexpr int k_maxNumberOfVariables = 6; + virtual int getVariables(char * variables) const; + /* getPolynomialCoefficients fill the table coefficients with the expressions + * of the first 4 polynomial coefficients. coefficients is null-terminated + * and has up to 4 entries. */ + //virtual void getPolynomialCoefficients(char symbolName, Expression ** coefficients) const; /* Comparison */ /* isIdenticalTo is the "easy" equality, it returns true if both trees have diff --git a/poincare/include/poincare/symbol.h b/poincare/include/poincare/symbol.h index db70d832e..9b33fbdb4 100644 --- a/poincare/include/poincare/symbol.h +++ b/poincare/include/poincare/symbol.h @@ -36,6 +36,7 @@ public: Type type() const override; Expression * clone() const override; int polynomialDegree(char symbolName) const override; + int getVariables(char * variables) const override; Sign sign() const override; bool isMatrixSymbol() const; bool isScalarSymbol() const; diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 61ba5af80..7b3153362 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -207,6 +207,18 @@ int Expression::polynomialDegree(char symbolName) const { return 0; } +int Expression::getVariables(char * variables) const { + int numberOfVariables = 0; + for (int i = 0; i < numberOfOperands(); i++) { + int n = operand(i)->getVariables(variables); + if (n < 0) { + return -1; + } + numberOfVariables = n > numberOfVariables ? n : numberOfVariables; + } + return numberOfVariables; +} + bool Expression::isOfType(Type * types, int length) const { for (int i = 0; i < length; i++) { if (type() == types[i]) { diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index abcb886f2..c4e6aaa26 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -113,6 +113,26 @@ int Symbol::polynomialDegree(char symbol) const { return 0; } +int Symbol::getVariables(char * variables) const { + size_t variablesLength = strlen(variables); + if (m_name >= 'a' && m_name <= 'z') { + char * currentChar = variables; + while (*currentChar != 0) { + if (*currentChar == m_name) { + return variablesLength; + } + currentChar++; + } + if (variablesLength < k_maxNumberOfVariables) { + variables[variablesLength] = m_name; + variables[variablesLength+1] = 0; + return variablesLength+1; + } + return -1; + } + return variablesLength; +} + Expression * Symbol::replaceSymbolWithExpression(char symbol, Expression * expression) { if (m_name == symbol) { Expression * value = expression->clone(); diff --git a/poincare/test/properties.cpp b/poincare/test/properties.cpp index 460fc908f..cd9eb0d19 100644 --- a/poincare/test/properties.cpp +++ b/poincare/test/properties.cpp @@ -77,3 +77,28 @@ QUIZ_CASE(poincare_characteristic_range) { assert_parsed_expression_has_characteristic_range("log(cos(40*x))", 9.0f); assert_parsed_expression_has_characteristic_range("cos(cos(x))", 360.0f); } + +void assert_parsed_expression_has_variables(const char * expression, const char * variables) { + Expression * e = parse_expression(expression); + char variableBuffer[Expression::k_maxNumberOfVariables+1] = {0}; + int numberOfVariables = e->getVariables(variableBuffer); + if (variables == nullptr) { + assert(numberOfVariables == -1); + } else { + assert(numberOfVariables == strlen(variables)); + char * currentChar = variableBuffer; + while (*variables != 0) { + assert(*currentChar++ == *variables++); + } + } + delete e; +} + +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"); +}