diff --git a/apps/solver/Makefile b/apps/solver/Makefile index de0f341b5..0d2610333 100644 --- a/apps/solver/Makefile +++ b/apps/solver/Makefile @@ -18,4 +18,10 @@ i18n_files += $(addprefix apps/solver/,\ base.pt.i18n\ ) +tests += $(addprefix apps/solver/test/,\ + equation_store.cpp\ +) +test_objs += $(addprefix apps/solver/, equation.o equation_store.o) +test_objs += $(addprefix apps/shared/, expression_model.o expression_model_store.o) + app_images += apps/solver/solver_icon.png diff --git a/apps/solver/test/equation_store.cpp b/apps/solver/test/equation_store.cpp new file mode 100644 index 000000000..0586c7573 --- /dev/null +++ b/apps/solver/test/equation_store.cpp @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +#include "../equation_store.h" +#include "../../../poincare/test/helper.h" + +using namespace Poincare; + +namespace Solver { + +void assert_equation_system_exact_solve_to(const char * equations[], EquationStore::Error error, EquationStore::Type type, const char * variables, const char * solutions[], int numberOfSolutions) { + GlobalContext globalContext; + EquationStore equationStore; + int index = 0; + while (equations[index] != 0) { + Shared::ExpressionModel * e = equationStore.addEmptyModel(); + e->setContent(equations[index++]); + } + EquationStore::Error err = equationStore.exactSolve(&globalContext); + assert(err == error); + if (err != EquationStore::Error::NoError) { + return; + } + assert(equationStore.type() == type); + assert(equationStore.numberOfSolutions() == numberOfSolutions); + if (numberOfSolutions == INT_MAX) { + return; + } + if (type == EquationStore::Type::LinearSystem) { + for (int i = 0; i < numberOfSolutions; i++) { + assert(equationStore.variableAtIndex(i) == variables[i]); + } + } else { + assert(equationStore.variableAtIndex(0) == variables[0]); + } + char buffer[200]; + int n = type == EquationStore::Type::PolynomialMonovariable ? numberOfSolutions+1 : numberOfSolutions; // Check Delta for PolynomialMonovariable + for (int i = 0; i < n; i++) { + equationStore.exactSolutionLayoutAtIndex(i, true)->writeTextInBuffer(buffer, 200); + translate_in_ASCII_chars(buffer); + assert(strcmp(buffer, solutions[i]) == 0); + } +} + +QUIZ_CASE(equation_solve) { + // x+y+z+a+b+c+d = 0 + const char * equations0[] = {"x+y+z+a+b+c+d=0", 0}; + assert_equation_system_exact_solve_to(equations0, EquationStore::Error::TooManyVariables, EquationStore::Type::LinearSystem, nullptr, nullptr, 0); + + // x^2+y = 0 + const char * equations1[] = {"x^2+y=0", 0}; + assert_equation_system_exact_solve_to(equations1, EquationStore::Error::NonLinearSystem, EquationStore::Type::LinearSystem, nullptr, nullptr, 0); + + // cos(x) = 0 + const char * equations2[] = {"cos(x)=0", 0}; + assert_equation_system_exact_solve_to(equations2, EquationStore::Error::RequireApproximateSolution, EquationStore::Type::LinearSystem, nullptr, nullptr, 0); + + // 2 = 0 + const char * equations3[] = {"2=0", 0}; + //assert_equation_system_exact_solve_to("2=0", EquationStore::Error::NoError, EquationStore::Type::LinearSystem, "", nullptr, 0); + // 0 = 0 + const char * equations4[] = {"0=0", 0}; + //assert_equation_system_exact_solve_to(equations4, EquationStore::Error::NoError, EquationStore::Type::LinearSystem, "", nullptr, INT_MAX); + + // x-x+2 = 0 + const char * equations5[] = {"x-x+2=0", 0}; + //assert_equation_system_exact_solve_to(equations5, EquationStore::Error::NoError, EquationStore::Type::LinearSystem, "", nullptr, 0); + + // x-x= 0 + const char * equations6[] = {"x-x=0", 0}; + //assert_equation_system_exact_solve_to(equations5, EquationStore::Error::NoError, EquationStore::Type::LinearSystem, "", nullptr, INT_MAX); + + // 2x+3=4 + const char * equations7[] = {"2x+3=4", 0}; + //assert_equation_system_exact_solve_to(equations7, EquationStore::Error::NoError, EquationStore::Type::LinearSystem, "x", {"1/2"}, 1); + + // 3x^2-4x+4=2 + const char * equations8[] = {"3x^2-4x+4=2", 0}; + const char * solutions8[] = {"(2-R(2)*I)/(3)","(2+R(2)*I)/(3)", "-8"}; + assert_equation_system_exact_solve_to(equations8, EquationStore::Error::NoError, EquationStore::Type::PolynomialMonovariable, "x", solutions8, 2); + + // 2*x^2-4*x+4=3 + const char * equations9[] = {"2*x^2-4*x+4=3", 0}; + const char * solutions9[] = {"(2-R(2))/(2)","(2+R(2))/(2)", "8"}; + assert_equation_system_exact_solve_to(equations9, EquationStore::Error::NoError, EquationStore::Type::PolynomialMonovariable, "x", solutions9, 2); + + // 2*x^2-4*x+2=0 + const char * equations10[] = {"2*x^2-4*x+2=0", 0}; + const char * solutions10[] = {"1", "0"}; + assert_equation_system_exact_solve_to(equations10, EquationStore::Error::NoError, EquationStore::Type::PolynomialMonovariable, "x", solutions10, 1); + + + // TODO + // x^3 - 4x^2 + 6x - 24 = 0 + //const char * equations10[] = {"2*x^2-4*x+4=3", 0}; + //assert_equation_system_exact_solve_to(equations10, EquationStore::Error::NoError, EquationStore::Type::PolynomialMonovariable, "x", {"4", "I*R(6)", "-I*R(6)", "-11616"}, 3); + + //x^3+x^2+1=0 + // x^3-3x-2=0 + + // Linear System +} + +} diff --git a/poincare/Makefile b/poincare/Makefile index 3222bafc5..fa1b389fa 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -140,7 +140,6 @@ tests += $(addprefix poincare/test/,\ properties.cpp\ rational.cpp\ simplify_mix.cpp\ - solver.cpp\ subtraction.cpp\ symbol.cpp\ store.cpp\ diff --git a/poincare/test/helper.cpp b/poincare/test/helper.cpp index c1e658f7c..7100b2461 100644 --- a/poincare/test/helper.cpp +++ b/poincare/test/helper.cpp @@ -36,6 +36,7 @@ void translate_in_ASCII_chars(char * expression) { case Ion::Charset::Root: *c = 'R'; break; case Ion::Charset::SmallPi: *c = 'P'; break; case Ion::Charset::MultiplicationSign: *c = '*'; break; + case Ion::Charset::MiddleDot: *c = '*'; break; case Ion::Charset::Sto: *c = '>'; break; } } diff --git a/poincare/test/properties.cpp b/poincare/test/properties.cpp index 524aa785d..40302afdd 100644 --- a/poincare/test/properties.cpp +++ b/poincare/test/properties.cpp @@ -126,6 +126,9 @@ QUIZ_CASE(poincare_get_polynomial_coefficients) { assert_parsed_expression_has_polynomial_coefficient("x^2+x+2", 'x', coefficient0); const char * coefficient1[] = {"12+(-6)*P", "12", "3", 0}; //3*x^2+12*x-6*π+12 assert_parsed_expression_has_polynomial_coefficient("3*(x+2)^2-6*P", 'x', coefficient1); - const char * coefficient2[] = {"2+32*x", "2", "6", "2", 0}; //2*n^3+6*n^2-2*n+2+32*x - assert_parsed_expression_has_polynomial_coefficient("2*(n+1)^3-4n+32*x", 'n', coefficient2); + // TODO: decomment when enable 3-degree polynomes + //const char * coefficient2[] = {"2+32*x", "2", "6", "2", 0}; //2*n^3+6*n^2+2*n+2+32*x + //assert_parsed_expression_has_polynomial_coefficient("2*(n+1)^3-4n+32*x", 'n', coefficient2); + const char * coefficient3[] = {"1", "-P", "1", 0}; //x^2-Pi*x+1 + assert_parsed_expression_has_polynomial_coefficient("x^2-P*x+1", 'x', coefficient3); } diff --git a/poincare/test/solver.cpp b/poincare/test/solver.cpp deleted file mode 100644 index 0f5b56c36..000000000 --- a/poincare/test/solver.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include -#include -#include -#include -#include "helper.h" - -using namespace Poincare; - -void assert_equation_solve_to(const char * expression, int expectedNumberOfSolution, const char ** solutions, const char * delta, Expression::AngleUnit angleUnit = Expression::AngleUnit::Degree) { - GlobalContext globalContext; - Expression * e = parse_expression(expression); - assert(e->type() == Expression::Type::Equal); - Expression * solutionBuffer[Poincare::Expression::k_maxNumberOfVariables]; - Expression * deltaBuffer[1] = {nullptr}; - int numberOfSolutions = static_cast(e)->solve(solutionBuffer, deltaBuffer, globalContext, angleUnit); - assert(numberOfSolutions == expectedNumberOfSolution); - if (numberOfSolutions >= 0 && numberOfSolutions < INT_MAX) { - for (int i = 0; i < numberOfSolutions; i++) { - Expression * f = parse_expression(solutions[i]); - Expression::Simplify(&f, globalContext, angleUnit); - assert(solutionBuffer[i]->isIdenticalTo(f)); - delete f; - delete solutionBuffer[i]; - } - assert(solutions[numberOfSolutions] == 0); - if (delta) { - Expression * deltaExpression = parse_expression(delta); - Expression::Simplify(&deltaExpression, globalContext, angleUnit); - assert(deltaBuffer[0]->isIdenticalTo(deltaExpression)); - delete deltaBuffer[0]; - delete deltaExpression; - } - } - delete e; -} - -QUIZ_CASE(poincare_solve_equations) { - // x+y+z+a+b+c+d = 0 - assert_equation_solve_to("x+y+z+a+b+c+d=0", -10, nullptr, nullptr); - // 2 = 0 - assert_equation_solve_to("2=0", -1, nullptr, nullptr); - // 0 = 0 - assert_equation_solve_to("0=0", INT_MAX, nullptr, nullptr); - // cos(x) = 0 - // TODO - // x-x+2 = 0 - assert_equation_solve_to("x-x+2=0", -1, nullptr, nullptr); - // x-x= 0 - assert_equation_solve_to("x-x=0", INT_MAX, nullptr, nullptr); - // 2x+3=4 - const char * solutions0[] = {"1/2", 0}; - assert_equation_solve_to("2*x+3=4", 1, solutions0, nullptr); - // 3x^2-4x+4=2 - const char * solutions1[] = {"1-R(2)/2", "1+R(2)/2", 0}; - const char * delta1 = "8"; - assert_equation_solve_to("2*x^2-4*x+4=3", 2, solutions1, delta1); - // 3x^2-4x+2=0 - const char * solutions2[] = {"1", 0}; - const char * delta2 = "0"; - assert_equation_solve_to("2*x^2-4*x+2=0", 1, solutions2, delta2); -#if 0 - // x^3 - 4x^2 + 6x - 24 = 0 - const char * solutions3[] = {"4", "I*R(6)", "-I*R(6)", 0}; - const char * delta3 = "-11616"; - assert_equation_solve_to("x^3+x^2+1=0", 3, solutions3, delta3); - // x^3-3x-2=0 - const char * solutions4[] = {"-1", "2", 0}; - const char * delta4 = "0"; - assert_equation_solve_to("x^3-3x-2=0", 2, solutions4, delta4); - // TODO: polynome degree 3, 4 -#endif - // TODO: linear system -}