From a2469c458f143c64dd54cb55637ec3d8357e44a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 4 Jun 2018 10:44:18 +0200 Subject: [PATCH] [solver] Add a interval parameter controller for approximate solutions --- apps/solver/Makefile | 1 + apps/solver/app.cpp | 1 + apps/solver/app.h | 3 + apps/solver/base.de.i18n | 2 + apps/solver/base.en.i18n | 2 + apps/solver/base.es.i18n | 2 + apps/solver/base.fr.i18n | 2 + apps/solver/base.pt.i18n | 2 + apps/solver/equation_store.cpp | 12 +++ apps/solver/equation_store.h | 3 + apps/solver/interval_controller.cpp | 133 ++++++++++++++++++++++++++++ apps/solver/interval_controller.h | 49 ++++++++++ apps/solver/list_controller.cpp | 5 ++ 13 files changed, 217 insertions(+) create mode 100644 apps/solver/interval_controller.cpp create mode 100644 apps/solver/interval_controller.h diff --git a/apps/solver/Makefile b/apps/solver/Makefile index 0d2610333..19ef5f0b6 100644 --- a/apps/solver/Makefile +++ b/apps/solver/Makefile @@ -6,6 +6,7 @@ app_objs += $(addprefix apps/solver/,\ equation_models_parameter_controller.o\ equation.o\ equation_store.o\ + interval_controller.o\ list_controller.o\ solutions_controller.o\ ) diff --git a/apps/solver/app.cpp b/apps/solver/app.cpp index 2e35f1e3f..81c47658e 100644 --- a/apps/solver/app.cpp +++ b/apps/solver/app.cpp @@ -45,6 +45,7 @@ void App::Snapshot::tidy() { App::App(Container * container, Snapshot * snapshot) : ExpressionFieldDelegateApp(container, snapshot, &m_inputViewController), m_solutionsController(&m_alternateEmptyViewController, snapshot->equationStore()), + m_intervalController(nullptr, snapshot->equationStore()), m_alternateEmptyViewController(nullptr, &m_solutionsController, &m_solutionsController), m_listController(&m_listFooter, snapshot->equationStore(), &m_listFooter), m_listFooter(&m_stackViewController, &m_listController, &m_listController, ButtonRowController::Position::Bottom, ButtonRowController::Style::EmbossedGrey), diff --git a/apps/solver/app.h b/apps/solver/app.h index 0235caf5e..a1cfc313d 100644 --- a/apps/solver/app.h +++ b/apps/solver/app.h @@ -5,6 +5,7 @@ #include "../shared/expression_field_delegate_app.h" #include "list_controller.h" #include "equation_store.h" +#include "interval_controller.h" #include "solutions_controller.h" namespace Solver { @@ -30,11 +31,13 @@ public: }; InputViewController * inputViewController() { return &m_inputViewController; } ViewController * solutionsControllerStack() { return &m_alternateEmptyViewController; } + ViewController * intervalController() { return &m_intervalController; } void willBecomeInactive() override; const char * XNT() override; private: App(Container * container, Snapshot * snapshot); SolutionsController m_solutionsController; + IntervalController m_intervalController; AlternateEmptyViewController m_alternateEmptyViewController; ListController m_listController; ButtonRowController m_listFooter; diff --git a/apps/solver/base.de.i18n b/apps/solver/base.de.i18n index 3ef78096e..d73ba7b29 100644 --- a/apps/solver/base.de.i18n +++ b/apps/solver/base.de.i18n @@ -10,3 +10,5 @@ Solution = "Solution" ApproximateSolution = "Solution approchée" NoSolution = "Le systeme n'admet aucune solution" InfiniteNumberOfSolutions = "Le systeme admet une infinite de solutions" +ApproximateSolutionIntervalInstruction0= "Entrez l'intervalle dans lequel" +ApproximateSolutionIntervalInstruction1= "rechercher une solution approchée." diff --git a/apps/solver/base.en.i18n b/apps/solver/base.en.i18n index 3ef78096e..d73ba7b29 100644 --- a/apps/solver/base.en.i18n +++ b/apps/solver/base.en.i18n @@ -10,3 +10,5 @@ Solution = "Solution" ApproximateSolution = "Solution approchée" NoSolution = "Le systeme n'admet aucune solution" InfiniteNumberOfSolutions = "Le systeme admet une infinite de solutions" +ApproximateSolutionIntervalInstruction0= "Entrez l'intervalle dans lequel" +ApproximateSolutionIntervalInstruction1= "rechercher une solution approchée." diff --git a/apps/solver/base.es.i18n b/apps/solver/base.es.i18n index 3ef78096e..d73ba7b29 100644 --- a/apps/solver/base.es.i18n +++ b/apps/solver/base.es.i18n @@ -10,3 +10,5 @@ Solution = "Solution" ApproximateSolution = "Solution approchée" NoSolution = "Le systeme n'admet aucune solution" InfiniteNumberOfSolutions = "Le systeme admet une infinite de solutions" +ApproximateSolutionIntervalInstruction0= "Entrez l'intervalle dans lequel" +ApproximateSolutionIntervalInstruction1= "rechercher une solution approchée." diff --git a/apps/solver/base.fr.i18n b/apps/solver/base.fr.i18n index 3ef78096e..d73ba7b29 100644 --- a/apps/solver/base.fr.i18n +++ b/apps/solver/base.fr.i18n @@ -10,3 +10,5 @@ Solution = "Solution" ApproximateSolution = "Solution approchée" NoSolution = "Le systeme n'admet aucune solution" InfiniteNumberOfSolutions = "Le systeme admet une infinite de solutions" +ApproximateSolutionIntervalInstruction0= "Entrez l'intervalle dans lequel" +ApproximateSolutionIntervalInstruction1= "rechercher une solution approchée." diff --git a/apps/solver/base.pt.i18n b/apps/solver/base.pt.i18n index 810032663..59ac7543b 100644 --- a/apps/solver/base.pt.i18n +++ b/apps/solver/base.pt.i18n @@ -10,3 +10,5 @@ Solution = "Solution" ApproximateSolution = "Solution approchée" NoSolution = "Le systeme n'admet aucune solution" InfiniteNumberOfSolutions = "Le systeme admet une infinite de solutions" +ApproximateSolutionIntervalInstruction0= "Entrez l'intervalle dans lequel" +ApproximateSolutionIntervalInstruction1= "rechercher une solution approchée." diff --git a/apps/solver/equation_store.cpp b/apps/solver/equation_store.cpp index 9902daa76..ebcf52674 100644 --- a/apps/solver/equation_store.cpp +++ b/apps/solver/equation_store.cpp @@ -40,6 +40,16 @@ Poincare::ExpressionLayout * EquationStore::exactSolutionLayoutAtIndex(int i, bo } } +double EquationStore::intervalBound(int index) const { + assert(m_type == Type::Monovariable && index >= 0 && index < 2); + return m_intervalApproximateSolutions[index]; +} + +void EquationStore::setIntervalBound(int index, double value) { + assert(m_type == Type::Monovariable && index >= 0 && index < 2); + m_intervalApproximateSolutions[index] = value; +} + double EquationStore::approximateSolutionAtIndex(int i) { assert(m_type == Type::Monovariable && i >= 0 && i < m_numberOfSolutions); return m_approximateSolutions[i]; @@ -101,6 +111,8 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context) { if (degree < 0) { /* 3- Monovariable non-polynomial */ m_type = Type::Monovariable; + m_intervalApproximateSolutions[0] = -10; + m_intervalApproximateSolutions[1] = 10; return Error::RequireApproximateSolution; } else { m_type = Type::PolynomialMonovariable; diff --git a/apps/solver/equation_store.h b/apps/solver/equation_store.h index 1f6dcd0ba..6e36d522b 100644 --- a/apps/solver/equation_store.h +++ b/apps/solver/equation_store.h @@ -38,6 +38,8 @@ public: return m_numberOfSolutions; } Poincare::ExpressionLayout * exactSolutionLayoutAtIndex(int i, bool exactLayout); + double intervalBound(int index) const; + void setIntervalBound(int index, double value); double approximateSolutionAtIndex(int i); void tidy() override; Error exactSolve(Poincare::Context * context); @@ -61,6 +63,7 @@ private: int m_numberOfSolutions; Poincare::ExpressionLayout * m_exactSolutionExactLayouts[k_maxNumberOfApproximateSolutions]; Poincare::ExpressionLayout * m_exactSolutionApproximateLayouts[k_maxNumberOfExactSolutions]; + double m_intervalApproximateSolutions[2]; double m_approximateSolutions[k_maxNumberOfApproximateSolutions]; }; diff --git a/apps/solver/interval_controller.cpp b/apps/solver/interval_controller.cpp new file mode 100644 index 000000000..98648b9e3 --- /dev/null +++ b/apps/solver/interval_controller.cpp @@ -0,0 +1,133 @@ +#include "interval_controller.h" +#include "app.h" +#include +#include + +namespace Solver { + +IntervalController::ContentView::ContentView(Responder * parentResponder, SelectableTableView * selectableTableView) : + m_instructions0(KDText::FontSize::Small, I18n::Message::ApproximateSolutionIntervalInstruction0, 0.5f, 0.5f, KDColorBlack, Palette::WallScreen), + m_instructions1(KDText::FontSize::Small, I18n::Message::ApproximateSolutionIntervalInstruction1, 0.5f, 0.5f, KDColorBlack, Palette::WallScreen), + m_selectableTableView(selectableTableView) +{ +} + +void IntervalController::ContentView::drawRect(KDContext * ctx, KDRect rect) const { + ctx->fillRect(KDRect(0, 0, bounds().width(), k_topMargin), Palette::WallScreen); +} + +int IntervalController::ContentView::numberOfSubviews() const { + return 3; +} + +View * IntervalController::ContentView::subviewAtIndex(int index) { + assert(index >= 0 && index < 5); + if (index == 0) { + return &m_instructions0; + } + if (index == 1) { + return &m_instructions1; + } + return m_selectableTableView; +} + +void IntervalController::ContentView::layoutSubviews() { + KDCoordinate textHeight = KDText::charSize(KDText::FontSize::Small).height(); + m_instructions0.setFrame(KDRect(0, k_topMargin/2-textHeight, bounds().width(), textHeight)); + m_instructions1.setFrame(KDRect(0, k_topMargin/2, bounds().width(), textHeight)); + m_selectableTableView->setFrame(KDRect(0, k_topMargin, bounds().width(), bounds().height()-k_topMargin)); +} + +/* IntervalController Controller */ + +IntervalController::IntervalController(Responder * parentResponder, EquationStore * equationStore) : + FloatParameterController(parentResponder), + m_selectableTableView(nullptr), + m_intervalCell{}, + m_equationStore(equationStore) +{ +} + +const char * IntervalController::title() { + return I18n::translate(I18n::Message::ApproximateSolution); +} + +int IntervalController::numberOfRows() { + return k_maxNumberOfCells+1; +} + +void IntervalController::willDisplayCellForIndex(HighlightCell * cell, int index) { + if (index == numberOfRows()-1) { + return; + } + I18n::Message labels[k_maxNumberOfCells] = {I18n::Message::XMin, I18n::Message::XMax}; + MessageTableCellWithEditableText * myCell = (MessageTableCellWithEditableText *) cell; + myCell->setMessage(labels[index]); + FloatParameterController::willDisplayCellForIndex(cell, index); +} + +HighlightCell * IntervalController::reusableParameterCell(int index, int type) { + assert(index >= 0); + assert(index < 2); + return m_intervalCell[index]; +} + +int IntervalController::reusableParameterCellCount(int type) { + return k_maxNumberOfCells; +} + +double IntervalController::parameterAtIndex(int index) { + return m_equationStore->intervalBound(index); +} + +bool IntervalController::setParameterAtIndex(int parameterIndex, double f) { + m_equationStore->setIntervalBound(parameterIndex, f); + return true; +} + +bool IntervalController::textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) { + if (FloatParameterController::textFieldDidFinishEditing(textField, text, event)) { + m_selectableTableView->reloadData(); + return true; + } + return false; +} + +void IntervalController::buttonAction() { + StackViewController * stack = stackController(); + App * solverApp = static_cast(app()); + stack->pop(); + stack->push(solverApp->solutionsControllerStack(), KDColorWhite, Palette::PurpleBright, Palette::PurpleBright); +} + +I18n::Message IntervalController::okButtonText() { + return I18n::Message::Resolve; +} + +View * IntervalController::loadView() { + m_selectableTableView = (SelectableTableView *)FloatParameterController::loadView(); + m_selectableTableView->setTopMargin(0); + for (int i = 0; i < k_maxNumberOfCells; i++) { + m_intervalCell[i] = new MessageTableCellWithEditableText(m_selectableTableView, this, m_draftTextBuffer); + } + ContentView * contentView = (ContentView *)new ContentView(this, m_selectableTableView); + return contentView; +} + +void IntervalController::unloadView(View * view) { + delete m_selectableTableView; + m_selectableTableView = nullptr; + for (int i = 0; i < k_maxNumberOfCells; i++) { + delete m_intervalCell[i]; + m_intervalCell[i] = nullptr; + } + FloatParameterController::unloadView(view); +} + +SelectableTableView * IntervalController::selectableTableView() { + return m_selectableTableView; +} + +} + + diff --git a/apps/solver/interval_controller.h b/apps/solver/interval_controller.h new file mode 100644 index 000000000..cb611f98d --- /dev/null +++ b/apps/solver/interval_controller.h @@ -0,0 +1,49 @@ +#ifndef SOLVER_INTERVAL_CONTROLLER_H +#define SOLVER_INTERVAL_CONTROLLER_H + +#include +#include "equation_store.h" +#include "../shared/float_parameter_controller.h" + +namespace Solver { + +class IntervalController : public Shared::FloatParameterController { +public: + IntervalController(Responder * parentResponder, EquationStore * equationStore); + const char * title() override; + int numberOfRows() override; + void willDisplayCellForIndex(HighlightCell * cell, int index) override; +private: + HighlightCell * reusableParameterCell(int index, int type) override; + int reusableParameterCellCount(int type) override; + void buttonAction() override; + double parameterAtIndex(int index) override; + bool setParameterAtIndex(int parameterIndex, double f) override; + bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override; + I18n::Message okButtonText() override; + View * loadView() override; + void unloadView(View * view) override; + class ContentView : public View { + public: + ContentView(Responder * parentResponder, SelectableTableView * selectableTableView); + void drawRect(KDContext * ctx, KDRect rect) const override; + private: + constexpr static KDCoordinate k_topMargin = 50; + int numberOfSubviews() const override; + View * subviewAtIndex(int index) override; + void layoutSubviews() override; + MessageTextView m_instructions0; + MessageTextView m_instructions1; + SelectableTableView * m_selectableTableView; + }; + SelectableTableView * selectableTableView() override; + SelectableTableView * m_selectableTableView; + constexpr static int k_maxNumberOfCells = 2; + char m_draftTextBuffer[MessageTableCellWithEditableText::k_bufferLength]; + MessageTableCellWithEditableText * m_intervalCell[k_maxNumberOfCells]; + EquationStore * m_equationStore; +}; + +} + +#endif diff --git a/apps/solver/list_controller.cpp b/apps/solver/list_controller.cpp index 17e4f8e0a..c2d800b44 100644 --- a/apps/solver/list_controller.cpp +++ b/apps/solver/list_controller.cpp @@ -150,7 +150,12 @@ void ListController::resolveEquations() { app()->displayWarning(I18n::Message::NonLinearSystem); return; case EquationStore::Error::RequireApproximateSolution: + { + StackViewController * stack = stackController(); + App * solverApp = static_cast(app()); + stack->push(solverApp->intervalController(), KDColorWhite, Palette::PurpleBright, Palette::PurpleBright); return; + } default: { assert(e == EquationStore::Error::NoError);