[solver] Make EquationStore inherits from StorageExpressionModelStore

This commit is contained in:
Émilie Feral
2019-02-22 10:05:22 +01:00
parent 53ee0607a1
commit 0f37ee25f7
5 changed files with 71 additions and 47 deletions

View File

@@ -16,12 +16,12 @@ Ion::Storage::Record::ErrorStatus StorageCartesianFunctionStore::addEmptyModel()
}
void StorageCartesianFunctionStore::setMemoizedModelAtIndex(int cacheIndex, Ion::Storage::Record record) const {
assert(cacheIndex >= 0 && cacheIndex < k_maxNumberOfMemoizedModels);
assert(cacheIndex >= 0 && cacheIndex < maxNumberOfMemoizedModels());
m_functions[cacheIndex] = StorageCartesianFunction(record);
}
ExpressionModelHandle * StorageCartesianFunctionStore::memoizedModelAtIndex(int cacheIndex) const {
assert(cacheIndex >= 0 && cacheIndex < k_maxNumberOfMemoizedModels);
assert(cacheIndex >= 0 && cacheIndex < maxNumberOfMemoizedModels());
return &m_functions[cacheIndex];
}

View File

@@ -16,14 +16,14 @@ Ion::Storage::Record StorageExpressionModelStore::recordAtIndex(int i) const {
}
ExpressionModelHandle * StorageExpressionModelStore::privateModelForRecord(Ion::Storage::Record record) const {
for (int i = 0; i < k_maxNumberOfMemoizedModels; i++) {
for (int i = 0; i < maxNumberOfMemoizedModels(); i++) {
if (!memoizedModelAtIndex(i)->isNull() && *memoizedModelAtIndex(i) == record) {
return memoizedModelAtIndex(i);
}
}
setMemoizedModelAtIndex(m_oldestMemoizedIndex, record);
ExpressionModelHandle * result = memoizedModelAtIndex(m_oldestMemoizedIndex);
m_oldestMemoizedIndex = (m_oldestMemoizedIndex+1) % k_maxNumberOfMemoizedModels;
m_oldestMemoizedIndex = (m_oldestMemoizedIndex+1) % maxNumberOfMemoizedModels();
return result;
}
@@ -77,7 +77,7 @@ Ion::Storage::Record StorageExpressionModelStore::recordStatifyingTestAtIndex(in
void StorageExpressionModelStore::resetMemoizedModelsExceptRecord(const Ion::Storage::Record record) const {
Ion::Storage::Record emptyRecord;
for (int i = 0; i < k_maxNumberOfMemoizedModels; i++) {
for (int i = 0; i < maxNumberOfMemoizedModels(); i++) {
if (*memoizedModelAtIndex(i) != record) {
setMemoizedModelAtIndex(i, emptyRecord);
}

View File

@@ -16,6 +16,8 @@ public:
StorageExpressionModelStore();
// Getters
// By default, the number of models is not bounded
virtual int maxNumberOfModels() const { return -1; }
int numberOfModels() const;
int numberOfDefinedModels() const { return numberOfModelsSatisfyingTest([](ExpressionModelHandle * m) { return m->isDefined(); }); }
Ion::Storage::Record recordAtIndex(int i) const;
@@ -28,10 +30,11 @@ public:
void removeModel(Ion::Storage::Record record);
// Other
void tidy();
virtual void tidy();
void storageDidChangeForRecord(const Ion::Storage::Record record) const { resetMemoizedModelsExceptRecord(record); }
protected:
constexpr static int k_maxNumberOfMemoizedModels = 10;
int maxNumberOfMemoizedModels() const { return maxNumberOfModels() < 0 ? k_maxNumberOfMemoizedModels : maxNumberOfModels(); }
typedef bool (*ModelTest)(ExpressionModelHandle * model);
int numberOfModelsSatisfyingTest(ModelTest test) const;
Ion::Storage::Record recordStatifyingTestAtIndex(int i, ModelTest test) const;

View File

@@ -1,4 +1,5 @@
#include "equation_store.h"
#include "../constant.h"
#include "../shared/poincare_helpers.h"
#include <limits.h>
@@ -21,6 +22,7 @@ using namespace Shared;
namespace Solver {
EquationStore::EquationStore() :
StorageExpressionModelStore(),
m_type(Type::LinearSystem),
m_numberOfSolutions(0),
m_exactSolutionExactLayouts{},
@@ -28,17 +30,32 @@ EquationStore::EquationStore() :
{
}
Equation * EquationStore::emptyModel() {
static Equation e;
return &e;
Ion::Storage::Record::ErrorStatus EquationStore::addEmptyModel() {
char name[3] = {'e', '?', 0}; // name is going to be e0 or e1 or ... e5
int currentNumber = 0;
while (currentNumber < k_maxNumberOfEquations) {
name[1] = '0'+currentNumber;
if (Ion::Storage::sharedStorage()->recordBaseNamedWithExtension(name, Equation::extension).isNull()) {
break;
}
currentNumber++;
}
assert(currentNumber < k_maxNumberOfEquations);
return Ion::Storage::sharedStorage()->createRecordWithExtension(name, Equation::extension, nullptr, 0);
}
void EquationStore::setModelAtIndex(Shared::ExpressionModel * e, int i) {
m_equations[i] = *(static_cast<Equation *>(e));;
void EquationStore::setMemoizedModelAtIndex(int cacheIndex, Ion::Storage::Record record) const {
assert(cacheIndex >= 0 && cacheIndex < maxNumberOfMemoizedModels());
m_equations[cacheIndex] = Equation(record);
}
ExpressionModelHandle * EquationStore::memoizedModelAtIndex(int cacheIndex) const {
assert(cacheIndex >= 0 && cacheIndex < maxNumberOfMemoizedModels());
return &m_equations[cacheIndex];
}
void EquationStore::tidy() {
ExpressionModelStore::tidy();
StorageExpressionModelStore::tidy();
tidySolution();
}
@@ -78,7 +95,7 @@ bool EquationStore::haveMoreApproximationSolutions(Context * context) {
return false;
}
double step = (m_intervalApproximateSolutions[1]-m_intervalApproximateSolutions[0])*k_precision;
return !std::isnan(PoincareHelpers::NextRoot(definedModelAtIndex(0)->standardForm(context), m_variables[0], m_approximateSolutions[m_numberOfSolutions-1], step, m_intervalApproximateSolutions[1], *context));
return !std::isnan(PoincareHelpers::NextRoot(modelForRecord(definedRecordAtIndex(0))->standardForm(context), m_variables[0], m_approximateSolutions[m_numberOfSolutions-1], step, m_intervalApproximateSolutions[1], *context));
}
void EquationStore::approximateSolve(Poincare::Context * context) {
@@ -88,7 +105,7 @@ void EquationStore::approximateSolve(Poincare::Context * context) {
double start = m_intervalApproximateSolutions[0];
double step = (m_intervalApproximateSolutions[1]-m_intervalApproximateSolutions[0])*k_precision;
for (int i = 0; i < k_maxNumberOfApproximateSolutions; i++) {
m_approximateSolutions[i] = PoincareHelpers::NextRoot(definedModelAtIndex(0)->standardForm(context), m_variables[0], start, step, m_intervalApproximateSolutions[1], *context);
m_approximateSolutions[i] = PoincareHelpers::NextRoot(modelForRecord(definedRecordAtIndex(0))->standardForm(context), m_variables[0], start, step, m_intervalApproximateSolutions[1], *context);
if (std::isnan(m_approximateSolutions[i])) {
break;
} else {
@@ -105,7 +122,7 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context) {
m_variables[0][0] = 0;
int numberOfVariables = 0;
for (int i = 0; i < numberOfDefinedModels(); i++) {
const Expression e = definedModelAtIndex(i)->standardForm(context);
const Expression e = modelForRecord(definedRecordAtIndex(i))->standardForm(context);
if (e.isUninitialized() || e.type() == ExpressionNode::Type::Undefined) {
return Error::EquationUndefined;
}
@@ -130,7 +147,7 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context) {
bool isLinear = true; // Invalid the linear system if one equation is non-linear
Preferences * preferences = Preferences::sharedPreferences();
for (int i = 0; i < numberOfDefinedModels(); i++) {
isLinear = isLinear && definedModelAtIndex(i)->standardForm(context).getLinearCoefficients((char *)m_variables, Poincare::SymbolAbstract::k_maxNameSize, coefficients[i], &constants[i], *context, updatedComplexFormat(), preferences->angleUnit());
isLinear = isLinear && modelForRecord(definedRecordAtIndex(i))->standardForm(context).getLinearCoefficients((char *)m_variables, Poincare::SymbolAbstract::k_maxNameSize, coefficients[i], &constants[i], *context, updatedComplexFormat(context), preferences->angleUnit());
if (!isLinear) {
// TODO: should we clean pool allocated memory if the system is not linear
#if 0
@@ -161,7 +178,7 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context) {
// Step 2. Polynomial & Monovariable?
assert(numberOfVariables == 1 && numberOfDefinedModels() == 1);
Expression polynomialCoefficients[Expression::k_maxNumberOfPolynomialCoefficients];
int degree = definedModelAtIndex(0)->standardForm(context).getPolynomialReducedCoefficients(m_variables[0], polynomialCoefficients, *context, updatedComplexFormat(), preferences->angleUnit());
int degree = modelForRecord(definedRecordAtIndex(0))->standardForm(context).getPolynomialReducedCoefficients(m_variables[0], polynomialCoefficients, *context, updatedComplexFormat(context), preferences->angleUnit());
if (degree == 2) {
// Polynomial degree <= 2
m_type = Type::PolynomialMonovariable;
@@ -189,14 +206,14 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context) {
m_exactSolutionExactLayouts[solutionIndex] = PoincareHelpers::CreateLayout(exactSolutions[i]);
m_exactSolutionApproximateLayouts[solutionIndex] = PoincareHelpers::CreateLayout(exactSolutionsApproximations[i]);
// Check for identity between exact and approximate layouts
char exactBuffer[Shared::ExpressionModel::k_expressionBufferSize];
char approximateBuffer[Shared::ExpressionModel::k_expressionBufferSize];
m_exactSolutionExactLayouts[solutionIndex].serializeForParsing(exactBuffer, Shared::ExpressionModel::k_expressionBufferSize);
m_exactSolutionApproximateLayouts[solutionIndex].serializeForParsing(approximateBuffer, Shared::ExpressionModel::k_expressionBufferSize);
char exactBuffer[::Constant::MaxSerializedExpressionSize];
char approximateBuffer[::Constant::MaxSerializedExpressionSize];
m_exactSolutionExactLayouts[solutionIndex].serializeForParsing(exactBuffer, ::Constant::MaxSerializedExpressionSize);
m_exactSolutionApproximateLayouts[solutionIndex].serializeForParsing(approximateBuffer, ::Constant::MaxSerializedExpressionSize);
m_exactSolutionIdentity[solutionIndex] = strcmp(exactBuffer, approximateBuffer) == 0;
if (!m_exactSolutionIdentity[solutionIndex]) {
char buffer[Shared::ExpressionModel::k_expressionBufferSize];
m_exactSolutionEquality[solutionIndex] = exactSolutions[i].isEqualToItsApproximationLayout(exactSolutionsApproximations[i], buffer, Shared::ExpressionModel::k_expressionBufferSize, preferences->complexFormat(), preferences->angleUnit(), preferences->displayMode(), preferences->numberOfSignificantDigits(), *context);
char buffer[::Constant::MaxSerializedExpressionSize];
m_exactSolutionEquality[solutionIndex] = exactSolutions[i].isEqualToItsApproximationLayout(exactSolutionsApproximations[i], buffer, ::Constant::MaxSerializedExpressionSize, preferences->complexFormat(), preferences->angleUnit(), preferences->displayMode(), preferences->numberOfSignificantDigits(), *context);
}
solutionIndex++;
}
@@ -221,7 +238,7 @@ EquationStore::Error EquationStore::resolveLinearSystem(Expression exactSolution
Ab.setDimensions(m, n+1);
// Compute the rank of (A | b)
int rankAb = Ab.rank(*context, updatedComplexFormat(), angleUnit, true);
int rankAb = Ab.rank(*context, updatedComplexFormat(context), angleUnit, true);
// Initialize the number of solutions
m_numberOfSolutions = INT_MAX;
@@ -246,7 +263,7 @@ EquationStore::Error EquationStore::resolveLinearSystem(Expression exactSolution
m_numberOfSolutions = n;
for (int i = 0; i < m_numberOfSolutions; i++) {
exactSolutions[i] = Ab.matrixChild(i,n);
exactSolutions[i].simplifyAndApproximate(&exactSolutions[i], &exactSolutionsApproximations[i], *context, updatedComplexFormat(), Poincare::Preferences::sharedPreferences()->angleUnit());
exactSolutions[i].simplifyAndApproximate(&exactSolutions[i], &exactSolutionsApproximations[i], *context, updatedComplexFormat(context), Poincare::Preferences::sharedPreferences()->angleUnit());
}
}
}
@@ -258,7 +275,7 @@ EquationStore::Error EquationStore::oneDimensialPolynomialSolve(Expression exact
assert(degree == 2);
// Compute delta = b*b-4ac
Expression delta = Subtraction::Builder(Power::Builder(coefficients[1].clone(), Rational::Builder(2)), Multiplication::Builder(Rational::Builder(4), coefficients[0].clone(), coefficients[2].clone()));
delta = delta.simplify(*context, updatedComplexFormat(), Poincare::Preferences::sharedPreferences()->angleUnit());
delta = delta.simplify(*context, updatedComplexFormat(context), Poincare::Preferences::sharedPreferences()->angleUnit());
if (delta.isUninitialized()) {
delta = Poincare::Undefined::Builder();
}
@@ -275,7 +292,7 @@ EquationStore::Error EquationStore::oneDimensialPolynomialSolve(Expression exact
}
exactSolutions[m_numberOfSolutions-1] = delta;
for (int i = 0; i < m_numberOfSolutions; i++) {
exactSolutions[i].simplifyAndApproximate(&exactSolutions[i], &exactSolutionsApproximations[i], *context, updatedComplexFormat(), Poincare::Preferences::sharedPreferences()->angleUnit());
exactSolutions[i].simplifyAndApproximate(&exactSolutions[i], &exactSolutionsApproximations[i], *context, updatedComplexFormat(context), Poincare::Preferences::sharedPreferences()->angleUnit());
}
return Error::NoError;
#if 0
@@ -351,17 +368,17 @@ void EquationStore::tidySolution() {
}
}
Preferences::ComplexFormat EquationStore::updatedComplexFormat() {
Preferences::ComplexFormat EquationStore::updatedComplexFormat(Context * context) {
Preferences::ComplexFormat complexFormat = Preferences::sharedPreferences()->complexFormat();
if (complexFormat == Preferences::ComplexFormat::Real && isExplictlyComplex()) {
if (complexFormat == Preferences::ComplexFormat::Real && isExplictlyComplex(context)) {
return Preferences::ComplexFormat::Cartesian;
}
return complexFormat;
}
bool EquationStore::isExplictlyComplex() {
bool EquationStore::isExplictlyComplex(Context * context) {
for (int i = 0; i < numberOfDefinedModels(); i++) {
if (definedModelAtIndex(i)->containsIComplex()) {
if (modelForRecord(definedRecordAtIndex(i))->containsIComplex(context)) {
return true;
}
}

View File

@@ -2,13 +2,13 @@
#define SOLVER_EQUATION_STORE_H
#include "equation.h"
#include "../shared/expression_model_store.h"
#include "../shared/storage_expression_model_store.h"
#include <poincare/symbol_abstract.h>
#include <stdint.h>
namespace Solver {
class EquationStore : public Shared::ExpressionModelStore {
class EquationStore : public Shared::StorageExpressionModelStore {
public:
enum class Type {
LinearSystem,
@@ -23,14 +23,14 @@ public:
NonLinearSystem = -4,
RequireApproximateSolution = -5,
};
/* EquationStore */
EquationStore();
Equation * modelAtIndex(int i) override {
assert(i>=0 && i<m_numberOfModels);
return &m_equations[i];
}
Equation * definedModelAtIndex(int i) override { return static_cast<Equation *>(Shared::ExpressionModelStore::definedModelAtIndex(i)); }
/* StorageExpressionModelStore */
int maxNumberOfModels() const override { return k_maxNumberOfEquations; }
Shared::ExpiringPointer<Equation> modelForRecord(Ion::Storage::Record record) const { return Shared::ExpiringPointer<Equation>(static_cast<Equation *>(privateModelForRecord(record))); }
Ion::Storage::Record::ErrorStatus addEmptyModel() override;
/* EquationStore */
Type type() const {
return m_type;
}
@@ -69,24 +69,28 @@ public:
bool haveMoreApproximationSolutions(Poincare::Context * context);
void tidy() override;
static constexpr int k_maxNumberOfExactSolutions = Poincare::Expression::k_maxNumberOfVariables > Poincare::Expression::k_maxPolynomialDegree + 1? Poincare::Expression::k_maxNumberOfVariables : Poincare::Expression::k_maxPolynomialDegree + 1;
static constexpr int k_maxNumberOfApproximateSolutions = 10;
static constexpr int k_maxNumberOfSolutions = k_maxNumberOfExactSolutions > k_maxNumberOfApproximateSolutions ? k_maxNumberOfExactSolutions : k_maxNumberOfApproximateSolutions;
private:
static constexpr double k_precision = 0.01;
static constexpr int k_maxNumberOfEquations = Poincare::Expression::k_maxNumberOfVariables; // Enable the same number of equations as the number of unknown variables
Equation * emptyModel() override;
Equation * nullModel() override {
return emptyModel();
}
void setModelAtIndex(Shared::ExpressionModel * f, int i) override;
// StorageExpressionModelStore
const char * modelExtension() const override { return Equation::extension; }
/* We don't really use model memoization as the number of Equation is limited
* and we keep enough Equations to store them all. */
void setMemoizedModelAtIndex(int cacheIndex, Ion::Storage::Record record) const override;
Shared::ExpressionModelHandle * memoizedModelAtIndex(int cacheIndex) const override;
Error resolveLinearSystem(Poincare::Expression solutions[k_maxNumberOfExactSolutions], Poincare::Expression solutionApproximations[k_maxNumberOfExactSolutions], Poincare::Expression coefficients[k_maxNumberOfEquations][Poincare::Expression::k_maxNumberOfVariables], Poincare::Expression constants[k_maxNumberOfEquations], Poincare::Context * context);
Error oneDimensialPolynomialSolve(Poincare::Expression solutions[k_maxNumberOfExactSolutions], Poincare::Expression solutionApproximations[k_maxNumberOfExactSolutions], Poincare::Expression polynomialCoefficients[Poincare::Expression::k_maxNumberOfPolynomialCoefficients], int degree, Poincare::Context * context);
void tidySolution();
bool isExplictlyComplex();
Poincare::Preferences::ComplexFormat updatedComplexFormat();
bool isExplictlyComplex(Poincare::Context * context);
Poincare::Preferences::ComplexFormat updatedComplexFormat(Poincare::Context * context);
Equation m_equations[k_maxNumberOfEquations];
mutable Equation m_equations[k_maxNumberOfEquations];
Type m_type;
char m_variables[Poincare::Expression::k_maxNumberOfVariables][Poincare::SymbolAbstract::k_maxNameSize];
int m_numberOfSolutions;