From 3dca515441de001b2ded6f2e8f3ab71eae5d4349 Mon Sep 17 00:00:00 2001 From: Arthur Camouseigt Date: Fri, 4 Sep 2020 16:20:33 +0200 Subject: [PATCH] [VariableBox] Added sequences to the variable box It is now possible to call the value of a defined sequence anywhere. Change-Id: I1990e93c50f9add175b7ea274e07004ba63289e5 --- apps/Makefile | 5 +- apps/calculation/app.h | 3 +- apps/calculation/calculation.cpp | 3 +- apps/code/app.h | 3 +- apps/hardware_test/app.h | 3 +- apps/home/app.h | 3 +- apps/math_variable_box_controller.cpp | 26 ++++++++-- apps/math_variable_box_controller.h | 5 +- apps/math_variable_box_empty_controller.cpp | 6 +++ apps/math_variable_box_empty_controller.h | 3 +- apps/on_boarding/app.h | 3 +- apps/probability/app.h | 3 +- apps/regression/app.h | 3 +- apps/sequence/app.cpp | 5 +- apps/sequence/app.h | 7 +-- apps/settings/app.h | 3 +- apps/shared/Makefile | 5 +- apps/shared/cache_context.cpp | 35 ++++++------- apps/shared/cache_context.h | 2 + apps/shared/function.h | 2 +- apps/shared/function_app.h | 3 +- apps/shared/global_context.cpp | 52 ++++++++++++++++---- apps/shared/global_context.h | 11 +++-- apps/shared/sequence.cpp | 54 +++++++++++++++------ apps/shared/sequence.h | 5 +- apps/shared/sequence_context.cpp | 18 +++---- apps/shared/sequence_context.h | 42 ++++++++-------- apps/shared/sequence_store.h | 5 +- apps/shared/sequence_title_cell.h | 4 +- apps/shared/shared_app.cpp | 10 ++++ apps/shared/shared_app.h | 14 ++++++ apps/solver/app.h | 3 +- apps/statistics/app.h | 3 +- apps/usb/app.h | 3 +- apps/variables.de.i18n | 2 + apps/variables.en.i18n | 2 + apps/variables.es.i18n | 2 + apps/variables.fr.i18n | 2 + apps/variables.it.i18n | 2 + apps/variables.nl.i18n | 2 + apps/variables.pt.i18n | 2 + escher/include/escher/app.h | 2 +- poincare/include/poincare/expression.h | 1 + poincare/include/poincare/sequence.h | 1 + poincare/include/poincare/symbol_abstract.h | 1 + poincare/src/parsing/parser.cpp | 8 +-- poincare/src/sequence.cpp | 49 ++++++++++--------- poincare/src/sum_and_product.cpp | 12 ++++- poincare/src/symbol_abstract.cpp | 5 -- poincare/src/variable_context.cpp | 1 - 50 files changed, 297 insertions(+), 152 deletions(-) create mode 100644 apps/shared/shared_app.cpp create mode 100644 apps/shared/shared_app.h diff --git a/apps/Makefile b/apps/Makefile index eb07e5ceb..0fc824793 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -41,7 +41,10 @@ apps_src += $(addprefix apps/,\ title_bar_view.cpp \ ) -tests_src += apps/exam_mode_configuration_official.cpp +tests_src += $(addprefix apps/,\ + exam_mode_configuration_official.cpp \ +) + snapshots_declaration = $(foreach i,$(apps),$(i)::Snapshot m_snapshot$(subst :,,$(i))Snapshot;) apps_declaration = $(foreach i,$(apps),$(i) m_$(subst :,,$(i));) diff --git a/apps/calculation/app.h b/apps/calculation/app.h index 0c188181e..56cb21854 100644 --- a/apps/calculation/app.h +++ b/apps/calculation/app.h @@ -6,6 +6,7 @@ #include "history_controller.h" #include "../shared/text_field_delegate_app.h" #include +#include "../shared/shared_app.h" namespace Calculation { @@ -17,7 +18,7 @@ public: I18n::Message upperName() override; const Image * icon() override; }; - class Snapshot : public ::App::Snapshot { + class Snapshot : public ::SharedApp::Snapshot { public: Snapshot(); App * unpack(Container * container) override; diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index 2ed67a817..b4c898b91 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -169,7 +169,8 @@ Calculation::DisplayOutput Calculation::displayOutput(Context * context) { ExpressionNode::Type::Sum, ExpressionNode::Type::Derivative, ExpressionNode::Type::ConfidenceInterval, - ExpressionNode::Type::PredictionInterval + ExpressionNode::Type::PredictionInterval, + ExpressionNode::Type::Sequence }; return e.isOfType(approximateOnlyTypes, sizeof(approximateOnlyTypes)/sizeof(ExpressionNode::Type)); }, context) diff --git a/apps/code/app.h b/apps/code/app.h index 57ee6181a..a9babedce 100644 --- a/apps/code/app.h +++ b/apps/code/app.h @@ -9,6 +9,7 @@ #include "script_store.h" #include "python_toolbox.h" #include "variable_box_controller.h" +#include "../shared/shared_app.h" namespace Code { @@ -20,7 +21,7 @@ public: I18n::Message upperName() override; const Image * icon() override; }; - class Snapshot : public ::App::Snapshot { + class Snapshot : public SharedApp::Snapshot { public: Snapshot(); App * unpack(Container * container) override; diff --git a/apps/hardware_test/app.h b/apps/hardware_test/app.h index 98b6827a6..5579381ca 100644 --- a/apps/hardware_test/app.h +++ b/apps/hardware_test/app.h @@ -11,12 +11,13 @@ #include "led_test_controller.h" #include "serial_number_controller.h" #include "vblank_test_controller.h" +#include "../shared/shared_app.h" namespace HardwareTest { class App : public ::App { public: - class Snapshot : public ::App::Snapshot { + class Snapshot : public ::SharedApp::Snapshot { public: App * unpack(Container * container) override; Descriptor * descriptor() override; diff --git a/apps/home/app.h b/apps/home/app.h index 59325a440..4d92c5564 100644 --- a/apps/home/app.h +++ b/apps/home/app.h @@ -3,6 +3,7 @@ #include #include "controller.h" +#include "../shared/shared_app.h" namespace Home { @@ -13,7 +14,7 @@ public: I18n::Message name() override; I18n::Message upperName() override; }; - class Snapshot : public ::App::Snapshot, public SelectableTableViewDataSource { + class Snapshot : public ::SharedApp::Snapshot, public SelectableTableViewDataSource { public: App * unpack(Container * container) override; Descriptor * descriptor() override; diff --git a/apps/math_variable_box_controller.cpp b/apps/math_variable_box_controller.cpp index 1d6c968ce..060d44f2e 100644 --- a/apps/math_variable_box_controller.cpp +++ b/apps/math_variable_box_controller.cpp @@ -9,6 +9,7 @@ #include #include #include +#include using namespace Poincare; using namespace Shared; @@ -76,6 +77,8 @@ int MathVariableBoxController::numberOfRows() const { return Storage::sharedStorage()->numberOfRecordsWithExtension(Ion::Storage::expExtension); case Page::Function: return Storage::sharedStorage()->numberOfRecordsWithExtension(Ion::Storage::funcExtension); + case Page::Sequence: + return Storage::sharedStorage()->numberOfRecordsWithExtension(Ion::Storage::seqExtension); default: return 0; } @@ -104,13 +107,19 @@ void MathVariableBoxController::willDisplayCellForIndex(HighlightCell * cell, in if (m_currentPage == Page::Expression) { static_assert(Shared::Function::k_maxNameWithArgumentSize > Poincare::SymbolAbstract::k_maxNameSize, "Forgot argument's size?"); symbolLength = SymbolAbstract::TruncateExtension(symbolName, record.fullName(), SymbolAbstract::k_maxNameSize); - } else { - assert(m_currentPage == Page::Function); + } else if (m_currentPage == Page::Function) { ContinuousFunction f(record); symbolLength = f.nameWithArgument( symbolName, Shared::Function::k_maxNameWithArgumentSize ); + } else { + assert(m_currentPage == Page::Sequence); + Shared::Sequence u(record); + symbolLength = u.nameWithArgument( + symbolName, + Shared::Sequence::k_maxNameWithArgumentSize + ); } Layout symbolLayout = LayoutHelper::String(symbolName, symbolLength); myCell->setLayout(symbolLayout); @@ -147,7 +156,7 @@ MessageTableCellWithChevron * MathVariableBoxController::nodeCellAtIndex(int ind } MathVariableBoxController::Page MathVariableBoxController::pageAtIndex(int index) { - Page pages[2] = {Page::Expression, Page::Function}; + Page pages[k_numberOfMenuRows] = {Page::Expression, Page::Function, Page::Sequence}; return pages[index]; } @@ -212,7 +221,7 @@ bool MathVariableBoxController::selectLeaf(int selectedRow) { I18n::Message MathVariableBoxController::nodeLabelAtIndex(int index) { assert(m_currentPage == Page::RootMenu); - I18n::Message labels[2] = {I18n::Message::Expressions, I18n::Message::Functions}; + I18n::Message labels[k_numberOfMenuRows] = {I18n::Message::Expressions, I18n::Message::Functions, I18n::Message::Sequences}; return labels[index]; } @@ -248,7 +257,14 @@ Layout MathVariableBoxController::expressionLayoutForRecord(Storage::Record reco const char * MathVariableBoxController::extension() const { assert(m_currentPage != Page::RootMenu); - return m_currentPage == Page::Function ? Ion::Storage::funcExtension : Ion::Storage::expExtension; + if (m_currentPage == Page::Function) { + return Ion::Storage::funcExtension; + } else if (m_currentPage == Page::Expression) { + return Ion::Storage::expExtension; + } else { + assert(m_currentPage == Page::Sequence); + return Ion::Storage::seqExtension; + } } Storage::Record MathVariableBoxController::recordAtIndex(int rowIndex) { diff --git a/apps/math_variable_box_controller.h b/apps/math_variable_box_controller.h index 8e6052a11..86f968303 100644 --- a/apps/math_variable_box_controller.h +++ b/apps/math_variable_box_controller.h @@ -27,13 +27,14 @@ public: enum class Page { RootMenu = 0, Expression = 1, - Function = 2 + Function = 2, + Sequence = 3 }; void lockDeleteEvent(Page page) { m_lockPageDelete = page; } private: constexpr static int k_maxNumberOfDisplayedRows = (Ion::Display::Height - Metric::TitleBarHeight - Metric::PopUpTopMargin - Metric::StackTitleHeight) / Metric::ToolboxRowHeight + 2; // (240 - 18 - 50 - 20) / 40 = 3.8; the 0.8 cell can be above and below so we add +2 to get 5 - constexpr static int k_numberOfMenuRows = 2; + constexpr static int k_numberOfMenuRows = 3; constexpr static KDCoordinate k_leafMargin = 20; ExpressionTableCellWithExpression * leafCellAtIndex(int index) override; MessageTableCellWithChevron * nodeCellAtIndex(int index) override; diff --git a/apps/math_variable_box_empty_controller.cpp b/apps/math_variable_box_empty_controller.cpp index f5ad187f7..d025851ec 100644 --- a/apps/math_variable_box_empty_controller.cpp +++ b/apps/math_variable_box_empty_controller.cpp @@ -45,6 +45,12 @@ void MathVariableBoxEmptyController::setType(Type type) { layout = Poincare::LayoutHelper::String(storeFunction, strlen(storeFunction), MathVariableBoxEmptyView::k_font); break; } + case Type::Sequence: + { + messages[0] = I18n::Message::EmptySequenceBox0; + messages[3] = I18n::Message::Default; + break; + } default: assert(false); } diff --git a/apps/math_variable_box_empty_controller.h b/apps/math_variable_box_empty_controller.h index 120ff42b6..c50665303 100644 --- a/apps/math_variable_box_empty_controller.h +++ b/apps/math_variable_box_empty_controller.h @@ -13,7 +13,8 @@ public: enum class Type { None = 0, Expressions = 1, - Functions = 2 + Functions = 2, + Sequence = 3 }; void setType(Type type); // View Controller diff --git a/apps/on_boarding/app.h b/apps/on_boarding/app.h index d58a0b1ad..d9dbe43a4 100644 --- a/apps/on_boarding/app.h +++ b/apps/on_boarding/app.h @@ -4,12 +4,13 @@ #include #include "logo_controller.h" #include "localization_controller.h" +#include "../shared/shared_app.h" namespace OnBoarding { class App : public ::App { public: - class Snapshot : public ::App::Snapshot { + class Snapshot : public ::SharedApp::Snapshot { public: App * unpack(Container * container) override; Descriptor * descriptor() override; diff --git a/apps/probability/app.h b/apps/probability/app.h index afb9075a7..323087042 100644 --- a/apps/probability/app.h +++ b/apps/probability/app.h @@ -14,6 +14,7 @@ #include "calculation/left_integral_calculation.h" #include "calculation/right_integral_calculation.h" #include "calculation/finite_integral_calculation.h" +#include "../shared/shared_app.h" constexpr static size_t max(const int * data, int seed = 0) { return (*data == 0 ? seed : max(data+1, *data > seed ? *data : seed)); @@ -29,7 +30,7 @@ public: I18n::Message upperName() override; const Image * icon() override; }; - class Snapshot : public ::App::Snapshot { + class Snapshot : public ::SharedApp::Snapshot { public: enum class Page { Distribution, diff --git a/apps/regression/app.h b/apps/regression/app.h index 2c529af77..5ebb06f1b 100644 --- a/apps/regression/app.h +++ b/apps/regression/app.h @@ -8,6 +8,7 @@ #include "regression_controller.h" #include "store.h" #include "store_controller.h" +#include "../shared/shared_app.h" namespace Regression { @@ -19,7 +20,7 @@ public: I18n::Message upperName() override; const Image * icon() override; }; - class Snapshot : public ::App::Snapshot, public TabViewDataSource { + class Snapshot : public ::SharedApp::Snapshot, public TabViewDataSource { public: Snapshot(); App * unpack(Container * container) override; diff --git a/apps/sequence/app.cpp b/apps/sequence/app.cpp index 6023049ac..b5ef4253e 100644 --- a/apps/sequence/app.cpp +++ b/apps/sequence/app.cpp @@ -1,6 +1,7 @@ #include "app.h" #include "../apps_container.h" #include "sequence_icon.h" +#include "../shared/global_context.h" using namespace Poincare; @@ -20,7 +21,6 @@ const Image * App::Descriptor::icon() { App::Snapshot::Snapshot() : Shared::FunctionApp::Snapshot::Snapshot(), - m_sequenceStore(), m_graphRange() { } @@ -40,13 +40,12 @@ App::Descriptor * App::Snapshot::descriptor() { } void App::Snapshot::tidy() { - m_sequenceStore.tidy(); m_graphRange.setDelegate(nullptr); } App::App(Snapshot * snapshot) : FunctionApp(snapshot, &m_inputViewController), - m_sequenceContext(AppsContainer::sharedAppsContainer()->globalContext(), snapshot->functionStore()), + m_sequenceContext(AppsContainer::sharedAppsContainer()->globalContext(), static_cast(AppsContainer::sharedAppsContainer()->globalContext())->sequenceStore()), m_listController(&m_listFooter, this, &m_listHeader, &m_listFooter), m_listFooter(&m_listHeader, &m_listController, &m_listController, ButtonRowController::Position::Bottom, ButtonRowController::Style::EmbossedGray), m_listHeader(nullptr, &m_listFooter, &m_listController), diff --git a/apps/sequence/app.h b/apps/sequence/app.h index 349f3afe5..834c8d3ce 100644 --- a/apps/sequence/app.h +++ b/apps/sequence/app.h @@ -10,6 +10,8 @@ #include "values/values_controller.h" #include "../shared/function_app.h" #include "../shared/interval.h" +#include "../shared/global_context.h" +#include "../apps_container.h" namespace Sequence { @@ -27,12 +29,11 @@ public: App * unpack(Container * container) override; void reset() override; Descriptor * descriptor() override; - Shared::SequenceStore * functionStore() override { return &m_sequenceStore; } + Shared::SequenceStore * functionStore() override { return static_cast(AppsContainer::sharedAppsContainer()->globalContext())->sequenceStore(); } CurveViewRange * graphRange() { return &m_graphRange; } Shared::Interval * interval() { return &m_interval; } private: void tidy() override; - Shared::SequenceStore m_sequenceStore; CurveViewRange m_graphRange; Shared::Interval m_interval; }; @@ -47,7 +48,7 @@ public: // NestedMenuController * variableBoxForInputEventHandler(InputEventHandler * textInput) override; CodePoint XNT() override { return 'n'; } Shared::SequenceContext * localContext() override; - Shared::SequenceStore * functionStore() override { return snapshot()->functionStore(); } + Shared::SequenceStore * functionStore() override { return static_cast(AppsContainer::sharedAppsContainer()->globalContext())->sequenceStore(); } Shared::Interval * interval() { return snapshot()->interval(); } ValuesController * valuesController() override { return &m_valuesController; diff --git a/apps/settings/app.h b/apps/settings/app.h index f395958b5..72967b40b 100644 --- a/apps/settings/app.h +++ b/apps/settings/app.h @@ -3,6 +3,7 @@ #include "main_controller.h" #include "../shared/text_field_delegate_app.h" +#include "../shared/shared_app.h" namespace Settings { @@ -14,7 +15,7 @@ public: I18n::Message upperName() override; const Image * icon() override; }; - class Snapshot : public ::App::Snapshot { + class Snapshot : public ::SharedApp::Snapshot { public: App * unpack(Container * container) override; Descriptor * descriptor() override; diff --git a/apps/shared/Makefile b/apps/shared/Makefile index 9a4ed1975..e12384f37 100644 --- a/apps/shared/Makefile +++ b/apps/shared/Makefile @@ -64,14 +64,15 @@ app_shared_src = $(addprefix apps/shared/,\ range_parameter_controller.cpp \ regular_table_view_data_source.cpp \ round_cursor_view.cpp \ + scrollable_multiple_expressions_view.cpp \ + scrollable_two_expressions_cell.cpp \ sequence.cpp\ sequence_context.cpp\ sequence_store.cpp\ sequence_title_cell.cpp \ - scrollable_multiple_expressions_view.cpp \ - scrollable_two_expressions_cell.cpp \ separable.cpp \ separator_even_odd_buffer_text_cell.cpp \ + shared_app.cpp \ simple_interactive_curve_view_controller.cpp \ store_cell.cpp \ store_controller.cpp \ diff --git a/apps/shared/cache_context.cpp b/apps/shared/cache_context.cpp index 760c1531a..41425558f 100644 --- a/apps/shared/cache_context.cpp +++ b/apps/shared/cache_context.cpp @@ -1,8 +1,10 @@ #include "cache_context.h" #include "sequence.h" #include "sequence_store.h" -#include "../shared/poincare_helpers.h" +#include "poincare_helpers.h" #include +#include +#include #include using namespace Poincare; @@ -20,23 +22,22 @@ template const Expression CacheContext::expressionForSymbolAbstract(const SymbolAbstract & symbol, bool clone) { // [u|v|w](n(+1)?) if (symbol.type() == ExpressionNode::Type::Sequence) { - Symbol s = const_cast(static_cast(symbol)); - if (s.childAtIndex(0).type() == ExpressionNode::Type::Symbol) { - return Float::Builder(m_values[nameIndexForSymbol(s)][0]); - } else if (s.childAtIndex(0).type() == ExpressionNode::Type::Addition) { - return Float::Builder(m_values[nameIndexForSymbol(s)][1]); + int index = nameIndexForSymbol(const_cast(static_cast(symbol))); + Expression rank = symbol.childAtIndex(0).clone(); + if (rank.isIdenticalTo(Symbol::Builder(UCodePointUnknown))) { + return Float::Builder(m_values[index][0]); + } if (rank.isIdenticalTo(Addition::Builder(Symbol::Builder(UCodePointUnknown), Rational::Builder(1)))) { + return Float::Builder(m_values[index][1]); + } + Ion::Storage::Record record = m_sequenceContext->sequenceStore()->recordAtIndex(index); + Sequence * seq = m_sequenceContext->sequenceStore()->modelForRecord(record); + rank.replaceSymbolWithExpression(Symbol::Builder(UCodePointUnknown), Float::Builder(m_nValue)); + T n = PoincareHelpers::ApproximateToScalar(rank, this); + // In case the rank is not int or sequence referenced is not defined, return NAN + if (std::floor(n) == n && seq->fullName() != nullptr) { + return Float::Builder(seq->valueAtRank(n, m_sequenceContext)); } else { - Sequence seq = m_sequenceContext->sequenceStore()->sequenceAtIndex(nameIndexForSymbol(s)); - // In case the sequence referenced is not defined, return NAN - if (seq.fullName() == nullptr) { - return Float::Builder(NAN); - } - Expression rank = symbol.childAtIndex(0); - if (rank.isNumber()) { - return Float::Builder(seq.valueAtRank(rank.approximateToScalar(this, Poincare::Preferences::ComplexFormat::Cartesian, Poincare::Preferences::AngleUnit::Radian), m_sequenceContext)); - } else { - return Float::Builder(NAN); - } + return Float::Builder(NAN); } } return ContextWithParent::expressionForSymbolAbstract(symbol, clone); diff --git a/apps/shared/cache_context.h b/apps/shared/cache_context.h index 7c54c1f02..7f10a99f9 100644 --- a/apps/shared/cache_context.h +++ b/apps/shared/cache_context.h @@ -14,11 +14,13 @@ public: CacheContext(Poincare::Context * parentContext); const Poincare::Expression expressionForSymbolAbstract(const Poincare::SymbolAbstract & symbol, bool clone) override; void setValueForSymbol(T value, const Poincare::Symbol & symbol); + void setNValue(int n) { m_nValue = n; } void setSequenceContext(SequenceContext * sequenceContext) { m_sequenceContext = sequenceContext;} private: int nameIndexForSymbol(const Poincare::Symbol & symbol); int rankIndexForSymbol(const Poincare::Symbol & symbol); T m_values[MaxNumberOfSequences][MaxRecurrenceDepth]; + int m_nValue; SequenceContext * m_sequenceContext; }; diff --git a/apps/shared/function.h b/apps/shared/function.h index c755a0675..453940025 100644 --- a/apps/shared/function.h +++ b/apps/shared/function.h @@ -45,7 +45,7 @@ public: // Name int name(char * buffer, size_t bufferSize); - int nameWithArgument(char * buffer, size_t bufferSize); + virtual int nameWithArgument(char * buffer, size_t bufferSize); virtual int printValue(double cursorT, double cursorX, double cursorY, char * buffer, int bufferSize, int precision, Poincare::Context * context); virtual I18n::Message parameterMessageName() const = 0; diff --git a/apps/shared/function_app.h b/apps/shared/function_app.h index d15e4c5e8..4763906b5 100644 --- a/apps/shared/function_app.h +++ b/apps/shared/function_app.h @@ -6,12 +6,13 @@ #include "function_store.h" #include "curve_view_cursor.h" #include "values_controller.h" +#include "shared_app.h" namespace Shared { class FunctionApp : public ExpressionFieldDelegateApp { public: - class Snapshot : public ::App::Snapshot, public TabViewDataSource { + class Snapshot : public ::SharedApp::Snapshot, public TabViewDataSource { public: Snapshot(); CurveViewCursor * cursor() { return &m_cursor; } diff --git a/apps/shared/global_context.cpp b/apps/shared/global_context.cpp index 8109f9468..43817af5b 100644 --- a/apps/shared/global_context.cpp +++ b/apps/shared/global_context.cpp @@ -1,5 +1,6 @@ #include "global_context.h" #include "continuous_function.h" +#include "sequence.h" #include "poincare_helpers.h" #include #include @@ -10,6 +11,13 @@ namespace Shared { constexpr const char * GlobalContext::k_extensions[]; +SequenceStore * GlobalContext::sequenceStore() { + static SequenceStore sequenceStore; + return &sequenceStore; +} + + + bool GlobalContext::SymbolAbstractNameIsFree(const char * baseName) { return SymbolAbstractRecordWithBaseName(baseName).isNull(); } @@ -18,9 +26,11 @@ const Layout GlobalContext::LayoutForRecord(Ion::Storage::Record record) { assert(!record.isNull()); if (Ion::Storage::FullNameHasExtension(record.fullName(), Ion::Storage::expExtension, strlen(Ion::Storage::expExtension))) { return PoincareHelpers::CreateLayout(ExpressionForActualSymbol(record)); - } else { - assert(Ion::Storage::FullNameHasExtension(record.fullName(), Ion::Storage::funcExtension, strlen(Ion::Storage::funcExtension))); + } else if (Ion::Storage::FullNameHasExtension(record.fullName(), Ion::Storage::funcExtension, strlen(Ion::Storage::funcExtension))) { return ContinuousFunction(record).layout(); + } else { + assert(Ion::Storage::FullNameHasExtension(record.fullName(), Ion::Storage::seqExtension, strlen(Ion::Storage::seqExtension))); + return Sequence(record).layout(); } } @@ -36,22 +46,26 @@ Context::SymbolAbstractType GlobalContext::expressionTypeForIdentifier(const cha const char * extension = Ion::Storage::sharedStorage()->extensionOfRecordBaseNamedWithExtensions(identifier, length, k_extensions, k_numberOfExtensions); if (extension == nullptr) { return Context::SymbolAbstractType::None; + } else if (extension == Ion::Storage::expExtension) { + return Context::SymbolAbstractType::Symbol; + } else if (extension == Ion::Storage::funcExtension) { + return Context::SymbolAbstractType::Function; + } else { + assert(extension == Ion::Storage::seqExtension); + return Context::SymbolAbstractType::Sequence; } - assert(k_numberOfExtensions == 2); - assert(extension == Ion::Storage::expExtension || extension == Ion::Storage::funcExtension); - return extension == Ion::Storage::expExtension ? Context::SymbolAbstractType::Symbol : Context::SymbolAbstractType::Function; } const Expression GlobalContext::expressionForSymbolAbstract(const SymbolAbstract & symbol, bool clone) { Ion::Storage::Record r = SymbolAbstractRecordWithBaseName(symbol.name()); - return ExpressionForSymbolAndRecord(symbol, r); + return ExpressionForSymbolAndRecord(symbol, r, this); } void GlobalContext::setExpressionForSymbolAbstract(const Expression & expression, const SymbolAbstract & symbol) { /* If the new expression contains the symbol, replace it because it will be * destroyed afterwards (to be able to do A+2->A) */ Ion::Storage::Record record = SymbolAbstractRecordWithBaseName(symbol.name()); - Expression e = ExpressionForSymbolAndRecord(symbol, record); + Expression e = ExpressionForSymbolAndRecord(symbol, record, this); if (e.isUninitialized()) { e = Undefined::Builder(); } @@ -69,12 +83,14 @@ void GlobalContext::setExpressionForSymbolAbstract(const Expression & expression } } -const Expression GlobalContext::ExpressionForSymbolAndRecord(const SymbolAbstract & symbol, Ion::Storage::Record r) { +const Expression GlobalContext::ExpressionForSymbolAndRecord(const SymbolAbstract & symbol, Ion::Storage::Record r, Context * ctx) { if (symbol.type() == ExpressionNode::Type::Symbol) { return ExpressionForActualSymbol(r); + } else if (symbol.type() == ExpressionNode::Type::Function) { + return ExpressionForFunction(symbol, r); } - assert(symbol.type() == ExpressionNode::Type::Function); - return ExpressionForFunction(symbol, r); + assert(symbol.type() == ExpressionNode::Type::Sequence); + return ExpressionForSequence(symbol, r, ctx); } const Expression GlobalContext::ExpressionForActualSymbol(Ion::Storage::Record r) { @@ -99,6 +115,22 @@ const Expression GlobalContext::ExpressionForFunction(const SymbolAbstract & sym return e; } +const Expression GlobalContext::ExpressionForSequence(const SymbolAbstract & symbol, Ion::Storage::Record r, Context * ctx) { + if (!Ion::Storage::FullNameHasExtension(r.fullName(), Ion::Storage::seqExtension, strlen(Ion::Storage::seqExtension))) { + return Expression(); + } + /* An function record value has metadata before the expression. To get the + * expression, use the function record handle. */ + Sequence seq(r); + double rank = PoincareHelpers::ApproximateToScalar(symbol.childAtIndex(0), ctx); + if (std::floor(rank) == rank) { + SequenceContext sqctx(ctx, sequenceStore()); + return Float::Builder(seq.evaluateXYAtParameter(rank, &sqctx).x2()); + } else { + return Float::Builder(NAN); + } +} + Ion::Storage::Record::ErrorStatus GlobalContext::SetExpressionForActualSymbol(const Expression & expression, const SymbolAbstract & symbol, Ion::Storage::Record previousRecord) { if (!previousRecord.isNull() && Ion::Storage::FullNameHasExtension(previousRecord.fullName(), Ion::Storage::funcExtension, strlen(Ion::Storage::funcExtension))) { /* A function can overwrite a variable, but a variable cannot be created if diff --git a/apps/shared/global_context.h b/apps/shared/global_context.h index eff54b0f9..f17aa44fd 100644 --- a/apps/shared/global_context.h +++ b/apps/shared/global_context.h @@ -8,13 +8,14 @@ #include #include #include +#include "sequence_store.h" namespace Shared { class GlobalContext final : public Poincare::Context { public: - static constexpr int k_numberOfExtensions = 2; - static constexpr const char * k_extensions[] = {Ion::Storage::expExtension, Ion::Storage::funcExtension}; + static constexpr int k_numberOfExtensions = 3; + static constexpr const char * k_extensions[] = {Ion::Storage::expExtension, Ion::Storage::funcExtension, Ion::Storage::seqExtension}; // Storage information static bool SymbolAbstractNameIsFree(const char * baseName); @@ -30,19 +31,19 @@ public: SymbolAbstractType expressionTypeForIdentifier(const char * identifier, int length) override; const Poincare::Expression expressionForSymbolAbstract(const Poincare::SymbolAbstract & symbol, bool clone) override; void setExpressionForSymbolAbstract(const Poincare::Expression & expression, const Poincare::SymbolAbstract & symbol) override; - + static SequenceStore * sequenceStore(); private: // Expression getters - static const Poincare::Expression ExpressionForSymbolAndRecord(const Poincare::SymbolAbstract & symbol, Ion::Storage::Record r); + static const Poincare::Expression ExpressionForSymbolAndRecord(const Poincare::SymbolAbstract & symbol, Ion::Storage::Record r, Context * ctx); static const Poincare::Expression ExpressionForActualSymbol(Ion::Storage::Record r); static const Poincare::Expression ExpressionForFunction(const Poincare::SymbolAbstract & symbol, Ion::Storage::Record r); + static const Poincare::Expression ExpressionForSequence(const Poincare::SymbolAbstract & symbol, Ion::Storage::Record r, Context * ctx); // Expression setters static Ion::Storage::Record::ErrorStatus SetExpressionForActualSymbol(const Poincare::Expression & expression, const Poincare::SymbolAbstract & symbol, Ion::Storage::Record previousRecord); static Ion::Storage::Record::ErrorStatus SetExpressionForFunction(const Poincare::Expression & expression, const Poincare::SymbolAbstract & symbol, Ion::Storage::Record previousRecord); // Record getter static Ion::Storage::Record SymbolAbstractRecordWithBaseName(const char * name); - }; } diff --git a/apps/shared/sequence.cpp b/apps/shared/sequence.cpp index 93042ea32..e6302274f 100644 --- a/apps/shared/sequence.cpp +++ b/apps/shared/sequence.cpp @@ -20,6 +20,31 @@ I18n::Message Sequence::parameterMessageName() const { return I18n::Message::N; } +int Sequence::nameWithArgument(char * buffer, size_t bufferSize) { + int seqNameSize = name(buffer, bufferSize); + assert(seqNameSize > 0); + size_t result = seqNameSize; + assert(result <= bufferSize); + buffer[result++] = '('; + assert(result <= bufferSize); + assert(UTF8Decoder::CharSizeOfCodePoint(symbol()) <= 2); + result += UTF8Decoder::CodePointToChars(symbol(), buffer+result, bufferSize-result); + assert(result <= bufferSize); + switch (type()) + { + case Type::Explicit: + result += strlcpy(buffer+result, ")", bufferSize-result); + break; + case Type::SingleRecurrence: + result += strlcpy(buffer+result, "+1)", bufferSize-result); + break; + default: + result += strlcpy(buffer+result, "+2)", bufferSize-result); + break; + } + return result; +} + void Sequence::tidy() { m_definition.tidyName(); Function::tidy(); // m_definitionName.tidy() @@ -111,7 +136,7 @@ T Sequence::templatedApproximateAtAbscissa(T x, SequenceContext * sqctx) const { T n = std::round(x); int sequenceIndex = SequenceStore::sequenceIndexForName(fullName()[0]); if (sqctx->iterateUntilRank(n)) { - return sqctx->valueOfSequenceAtPreviousRank(sequenceIndex, 0); + return sqctx->valueOfCommonRankSequenceAtPreviousRank(sequenceIndex, 0); } return NAN; } @@ -122,20 +147,19 @@ T Sequence::valueAtRank(int n, SequenceContext *sqctx) { return NAN; } int sequenceIndex = SequenceStore::sequenceIndexForName(fullName()[0]); - if (sqctx->independantSequenceRank(sequenceIndex) > n || sqctx->independantSequenceRank(sequenceIndex) < 0) { + if (sqctx->independentSequenceRank(sequenceIndex) > n || sqctx->independentSequenceRank(sequenceIndex) < 0) { // Reset cache indexes and cache values - sqctx->setIndependantSequenceRank(-1, sequenceIndex); + sqctx->setIndependentSequenceRank(-1, sequenceIndex); for (int i = 0 ; i < MaxRecurrenceDepth+1; i++) { - sqctx->setIndependantSequenceValue(NAN, sequenceIndex, i); + sqctx->setIndependentSequenceValue(NAN, sequenceIndex, i); } } - - while(sqctx->independantSequenceRank(sequenceIndex) < n) { + while(sqctx->independentSequenceRank(sequenceIndex) < n) { sqctx->stepSequenceAtIndex(sequenceIndex); } - /* In case we have sqctx->independantSequenceRank(sequenceIndex) = n, we can return the + /* In case we have sqctx->independentSequenceRank(sequenceIndex) = n, we can return the * value */ - T value = sqctx->independantSequenceValue(sequenceIndex, 0); + T value = sqctx->independentSequenceValue(sequenceIndex, 0); return value; } @@ -156,22 +180,22 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx, int sequenceIn /* In case we step only one sequence to the next step, the data stored in * values is not necessarily u(n), u(n-1).... Indeed, since the indexes are - * independant, if the index for u is 3 but the one for v is 5, value will + * independent, if the index for u is 3 but the one for v is 5, value will * hold u(3), u(2), u(1) | v(5), v(4), v(3). Therefore, the calculation will * be wrong if they relay on a symbol such as u(n). To prevent this, we align * all the values around the index of the sequence we are stepping. */ - int independantRank = sqctx->independantSequenceRank(sequenceIndex); + int independentRank = sqctx->independentSequenceRank(sequenceIndex); for (int i = 0; i < MaxNumberOfSequences; i++) { - if (sequenceIndex != -1 && sqctx->independantSequenceRank(i) != independantRank) { - int offset = independantRank - sqctx->independantSequenceRank(i); + if (sequenceIndex != -1 && sqctx->independentSequenceRank(i) != independentRank) { + int offset = independentRank - sqctx->independentSequenceRank(i); if (offset != 0) { for (int j = MaxRecurrenceDepth; j >= 0; j--) { - values[i][j] = j-offset < 0 ? NAN : sqctx->independantSequenceValue(i, j-offset); + values[i][j] = j-offset < 0 ? NAN : sqctx->independentSequenceValue(i, j-offset); } } } else { for (int j = 0; j < MaxRecurrenceDepth+1; j++) { - values[i][j] = sequenceIndex != -1 ? sqctx->independantSequenceValue(i, j) : sqctx->valueOfSequenceAtPreviousRank(i, j); + values[i][j] = sequenceIndex != -1 ? sqctx->independentSequenceValue(i, j) : sqctx->valueOfCommonRankSequenceAtPreviousRank(i, j); } } } @@ -184,7 +208,7 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx, int sequenceIn symbols[i][j] = Symbol::Builder(name[j], strlen(name[j])); } } - + ctx.setNValue(n); switch (type()) { case Type::Explicit: { diff --git a/apps/shared/sequence.h b/apps/shared/sequence.h index d1ded7d87..016d12e23 100644 --- a/apps/shared/sequence.h +++ b/apps/shared/sequence.h @@ -1,5 +1,5 @@ -#ifndef SEQUENCE_SEQUENCE_H -#define SEQUENCE_SEQUENCE_H +#ifndef APPS_SHARED_SEQUENCE_H +#define APPS_SHARED_SEQUENCE_H #include "../shared/function.h" #include "sequence_context.h" @@ -29,6 +29,7 @@ public: } I18n::Message parameterMessageName() const override; CodePoint symbol() const override { return 'n'; } + int nameWithArgument(char * buffer, size_t bufferSize) override; void tidy() override; // MetaData getters Type type() const; diff --git a/apps/shared/sequence_context.cpp b/apps/shared/sequence_context.cpp index 05600441b..fc1f48738 100644 --- a/apps/shared/sequence_context.cpp +++ b/apps/shared/sequence_context.cpp @@ -12,13 +12,13 @@ template TemplatedSequenceContext::TemplatedSequenceContext() : m_commonRank(-1), m_commonRankValues{{NAN, NAN, NAN}, {NAN, NAN, NAN}, {NAN, NAN, NAN}}, - m_independantRanks{-1, -1, -1}, - m_independantRankValues{{NAN, NAN, NAN}, {NAN, NAN, NAN}, {NAN, NAN, NAN}} + m_independentRanks{-1, -1, -1}, + m_independentRankValues{{NAN, NAN, NAN}, {NAN, NAN, NAN}, {NAN, NAN, NAN}} { } template -T TemplatedSequenceContext::valueOfSequenceAtPreviousRank(int sequenceIndex, int rank) const { +T TemplatedSequenceContext::valueOfCommonRankSequenceAtPreviousRank(int sequenceIndex, int rank) const { return m_commonRankValues[sequenceIndex][rank]; } @@ -26,11 +26,11 @@ template void TemplatedSequenceContext::resetCache() { /* We only need to reset the ranks. Indeed, when we compute the values of the * sequences, we use ranks as memoization indexes. Therefore, we know that the - * values stored in m_commomValues and m_independantRankValues are dirty + * values stored in m_commomValues and m_independentRankValues are dirty * and do not use them. */ m_commonRank = -1; for (int i = 0; i < MaxNumberOfSequences; i ++) { - m_independantRanks[i] = -1; + m_independentRanks[i] = -1; } } @@ -55,7 +55,7 @@ void TemplatedSequenceContext::step(SequenceContext * sqctx, int sequenceInde if (stepMultipleSequences) { m_commonRank++; } else { - setIndependantSequenceRank(independantSequenceRank(sequenceIndex) + 1, sequenceIndex); + setIndependentSequenceRank(independentSequenceRank(sequenceIndex) + 1, sequenceIndex); } // Then we shift the values stored in the arrays @@ -69,8 +69,8 @@ void TemplatedSequenceContext::step(SequenceContext * sqctx, int sequenceInde } else { start = sequenceIndex; stop = sequenceIndex + 1; - sequenceArray = reinterpret_cast(&m_independantRankValues); - rank = independantSequenceRank(sequenceIndex); + sequenceArray = reinterpret_cast(&m_independentRankValues); + rank = independentSequenceRank(sequenceIndex); } for (int i = start; i < stop; i++) { @@ -107,7 +107,7 @@ void TemplatedSequenceContext::step(SequenceContext * sqctx, int sequenceInde T * pointerToUpdate = sequenceArray + i * (MaxRecurrenceDepth + 1); if (std::isnan(*(pointerToUpdate))) { int j = stepMultipleSequences ? i : 0; - *(pointerToUpdate) = sequences[j] ? sequences[j]->template approximateToNextRank(rank, sqctx, sequenceIndex) : NAN; + *pointerToUpdate = sequences[j] ? sequences[j]->template approximateToNextRank(rank, sqctx, sequenceIndex) : NAN; } } } diff --git a/apps/shared/sequence_context.h b/apps/shared/sequence_context.h index b0adbed67..83c8d8e9f 100644 --- a/apps/shared/sequence_context.h +++ b/apps/shared/sequence_context.h @@ -1,5 +1,5 @@ -#ifndef SEQUENCE_SEQUENCE_CONTEXT_H -#define SEQUENCE_SEQUENCE_CONTEXT_H +#ifndef APPS_SHARED_SEQUENCE_CONTEXT_H +#define APPS_SHARED_SEQUENCE_CONTEXT_H #include #include @@ -17,14 +17,14 @@ template class TemplatedSequenceContext { public: TemplatedSequenceContext(); - T valueOfSequenceAtPreviousRank(int sequenceIndex, int rank) const; + T valueOfCommonRankSequenceAtPreviousRank(int sequenceIndex, int rank) const; void resetCache(); bool iterateUntilRank(int n, SequenceStore * sequenceStore, SequenceContext * sqctx); - int independantSequenceRank(int sequenceIndex) { return m_independantRanks[sequenceIndex]; } - void setIndependantSequenceRank(int rank, int sequenceIndex) { m_independantRanks[sequenceIndex] = rank; } - T independantSequenceValue(int sequenceIndex, int depth) { return m_independantRankValues[sequenceIndex][depth]; } - void setIndependantSequenceValue(T value, int sequenceIndex, int depth) { m_independantRankValues[sequenceIndex][depth] = value; } + int independentSequenceRank(int sequenceIndex) { return m_independentRanks[sequenceIndex]; } + void setIndependentSequenceRank(int rank, int sequenceIndex) { m_independentRanks[sequenceIndex] = rank; } + T independentSequenceValue(int sequenceIndex, int depth) { return m_independentRankValues[sequenceIndex][depth]; } + void setIndependentSequenceValue(T value, int sequenceIndex, int depth) { m_independentRankValues[sequenceIndex][depth] = value; } void step(SequenceContext * sqctx, int sequenceIndex = -1); private: constexpr static int k_maxRecurrentRank = 10000; @@ -41,16 +41,16 @@ private: * sequence is defined using a fixed term of another, u(3) for instance, we * compute its value through the second type of cache. This way, we do not * erase the data stored in the first type of cache and we can compute the - * values of each sequence at independant rank. This means that + * values of each sequence at independent rank. This means that * (u(3), v(5), w(10)) can be computed at the same time. - * This cache is therefore used for independant steps of sequences + * This cache is therefore used for independent steps of sequences */ int m_commonRank; T m_commonRankValues[MaxNumberOfSequences][MaxRecurrenceDepth+1]; // Used for fixed computations - int m_independantRanks[MaxNumberOfSequences]; - T m_independantRankValues[MaxNumberOfSequences][MaxRecurrenceDepth+1]; + int m_independentRanks[MaxNumberOfSequences]; + T m_independentRankValues[MaxNumberOfSequences][MaxRecurrenceDepth+1]; }; class SequenceContext : public Poincare::ContextWithParent { @@ -64,8 +64,8 @@ public: * context respective methods. Indeed, special chars like n, u(n), u(n+1), * v(n), v(n+1) are taken into accound only when evaluating sequences which * is done in another context. */ - template T valueOfSequenceAtPreviousRank(int sequenceIndex, int rank) { - return static_cast*>(helper())->valueOfSequenceAtPreviousRank(sequenceIndex, rank); + template T valueOfCommonRankSequenceAtPreviousRank(int sequenceIndex, int rank) { + return static_cast*>(helper())->valueOfCommonRankSequenceAtPreviousRank(sequenceIndex, rank); } void resetCache() { @@ -77,20 +77,20 @@ public: return static_cast*>(helper())->iterateUntilRank(n, m_sequenceStore, this); } - template int independantSequenceRank(int sequenceIndex) { - return static_cast*>(helper())->independantSequenceRank(sequenceIndex); + template int independentSequenceRank(int sequenceIndex) { + return static_cast*>(helper())->independentSequenceRank(sequenceIndex); } - template void setIndependantSequenceRank(int rank, int sequenceIndex) { - static_cast*>(helper())->setIndependantSequenceRank(rank, sequenceIndex); + template void setIndependentSequenceRank(int rank, int sequenceIndex) { + static_cast*>(helper())->setIndependentSequenceRank(rank, sequenceIndex); } - template T independantSequenceValue(int sequenceIndex, int depth) { - return static_cast*>(helper())->independantSequenceValue(sequenceIndex, depth); + template T independentSequenceValue(int sequenceIndex, int depth) { + return static_cast*>(helper())->independentSequenceValue(sequenceIndex, depth); } - template void setIndependantSequenceValue(T value, int sequenceIndex, int depth) { - static_cast*>(helper())->setIndependantSequenceValue(value, sequenceIndex, depth); + template void setIndependentSequenceValue(T value, int sequenceIndex, int depth) { + static_cast*>(helper())->setIndependentSequenceValue(value, sequenceIndex, depth); } template void stepSequenceAtIndex(int sequenceIndex) { diff --git a/apps/shared/sequence_store.h b/apps/shared/sequence_store.h index f30cc25e3..6e0a48184 100644 --- a/apps/shared/sequence_store.h +++ b/apps/shared/sequence_store.h @@ -1,8 +1,7 @@ -#ifndef SEQUENCE_SEQUENCE_STORE_H -#define SEQUENCE_SEQUENCE_STORE_H +#ifndef APPS_SHARED_SEQUENCE_STORE_H +#define APPS_SHARED_SEQUENCE_STORE_H #include "../shared/function_store.h" -#include "../shared/global_context.h" #include "sequence.h" #include #include diff --git a/apps/shared/sequence_title_cell.h b/apps/shared/sequence_title_cell.h index 353a2060a..fe7473db7 100644 --- a/apps/shared/sequence_title_cell.h +++ b/apps/shared/sequence_title_cell.h @@ -1,5 +1,5 @@ -#ifndef SEQUENCE_SEQUENCE_TITLE_CELL_H -#define SEQUENCE_SEQUENCE_TITLE_CELL_H +#ifndef APPS_SHARED_SEQUENCE_TITLE_CELL_H +#define APPS_SHARED_SEQUENCE_TITLE_CELL_H #include "../shared/function_title_cell.h" #include diff --git a/apps/shared/shared_app.cpp b/apps/shared/shared_app.cpp new file mode 100644 index 000000000..24c341392 --- /dev/null +++ b/apps/shared/shared_app.cpp @@ -0,0 +1,10 @@ +#include "shared_app.h" +#include "global_context.h" +#include + +void SharedApp::Snapshot::pack(App * app) { + /* Since the sequence store is now accessible from every app, when exiting + * any application, we need to tidy it.*/ + static_cast(AppsContainer::sharedAppsContainer()->globalContext())->sequenceStore()->tidy(); + App::Snapshot::pack(app); +} \ No newline at end of file diff --git a/apps/shared/shared_app.h b/apps/shared/shared_app.h new file mode 100644 index 000000000..ebe0a9003 --- /dev/null +++ b/apps/shared/shared_app.h @@ -0,0 +1,14 @@ +#ifndef SHARED_APP_H +#define SHARED_APP_H + +#include + +class SharedApp : public App { + public: + class Snapshot : public App::Snapshot { + public: + void pack(App * app) override; + }; +}; + +#endif \ No newline at end of file diff --git a/apps/solver/app.h b/apps/solver/app.h index 54c2aa71e..c0deb34ff 100644 --- a/apps/solver/app.h +++ b/apps/solver/app.h @@ -7,6 +7,7 @@ #include "equation_store.h" #include "interval_controller.h" #include "solutions_controller.h" +#include "../shared/shared_app.h" namespace Solver { @@ -18,7 +19,7 @@ public: I18n::Message upperName() override; const Image * icon() override; }; - class Snapshot : public ::App::Snapshot { + class Snapshot : public ::SharedApp::Snapshot { public: Snapshot(); App * unpack(Container * container) override; diff --git a/apps/statistics/app.h b/apps/statistics/app.h index 587eb2b9c..ef5b4cfa8 100644 --- a/apps/statistics/app.h +++ b/apps/statistics/app.h @@ -8,6 +8,7 @@ #include "store.h" #include "store_controller.h" #include "../shared/text_field_delegate_app.h" +#include "../shared/shared_app.h" namespace Statistics { @@ -19,7 +20,7 @@ public: I18n::Message upperName() override; const Image * icon() override; }; - class Snapshot : public ::App::Snapshot, public TabViewDataSource { + class Snapshot : public ::SharedApp::Snapshot, public TabViewDataSource { public: Snapshot(); App * unpack(Container * container) override; diff --git a/apps/usb/app.h b/apps/usb/app.h index 356cf36f1..f928e08cc 100644 --- a/apps/usb/app.h +++ b/apps/usb/app.h @@ -3,6 +3,7 @@ #include "escher/include/escher/app.h" #include "usb_connected_controller.h" +#include "../shared/shared_app.h" namespace USB { @@ -13,7 +14,7 @@ public: I18n::Message name() override; I18n::Message upperName() override; }; - class Snapshot : public ::App::Snapshot { + class Snapshot : public ::SharedApp::Snapshot { public: App * unpack(Container * container) override; Descriptor * descriptor() override; diff --git a/apps/variables.de.i18n b/apps/variables.de.i18n index 220ab3680..777ba78b7 100644 --- a/apps/variables.de.i18n +++ b/apps/variables.de.i18n @@ -1,8 +1,10 @@ Variables = "Variablen" Expressions = "Ausdrücke" Functions = "Funktionen" +Sequences = "Folgen" EmptyExpressionBox0 = "Sie haben keine Variable definiert." EmptyFunctionBox0 = "Sie haben keine Funktion definiert." +EmptySequenceBox0 = "Sie haben keine Folge definiert." EmptyExpressionBox1 = "Um eine Variable zu definieren:" EmptyFunctionBox1 = "Um eine Funktion zu definieren:" EmptyExpressionBox2 = "Erlaubte Zeichen im Namen:" diff --git a/apps/variables.en.i18n b/apps/variables.en.i18n index 5c8aa8ef6..c4dbff499 100644 --- a/apps/variables.en.i18n +++ b/apps/variables.en.i18n @@ -1,8 +1,10 @@ Variables = "Variables" Expressions = "Expressions" Functions = "Functions" +Sequences = "Sequences" EmptyExpressionBox0 = "You have not defined any variables." EmptyFunctionBox0 = "You have not defined any functions." +EmptySequenceBox0 = "You have not defined any sequences." EmptyExpressionBox1 = "To define a variable, type:" EmptyFunctionBox1 = "To define a function, type:" EmptyExpressionBox2 = "The variable name can contain:" diff --git a/apps/variables.es.i18n b/apps/variables.es.i18n index 86124ebe3..7d1f1ec4d 100644 --- a/apps/variables.es.i18n +++ b/apps/variables.es.i18n @@ -1,8 +1,10 @@ Variables = "Variables" Expressions = "Expresiones" Functions = "Funciones" +Sequences = "Sucesiones" EmptyExpressionBox0 = "Ninguna variable definida." EmptyFunctionBox0 = "Ninguna función definida." +EmptySequenceBox0 = "Ninguna sucesión definida." EmptyExpressionBox1 = "Para definir una, teclear :" EmptyFunctionBox1 = "Para definir una, teclear :" EmptyExpressionBox2 = "El nombre de variable debe" diff --git a/apps/variables.fr.i18n b/apps/variables.fr.i18n index da626f514..243c1d205 100644 --- a/apps/variables.fr.i18n +++ b/apps/variables.fr.i18n @@ -1,8 +1,10 @@ Variables = "Variables" Expressions = "Expressions" Functions = "Fonctions" +Sequences = "Suites" EmptyExpressionBox0 = "Vous n'avez défini aucune variable." EmptyFunctionBox0 = "Vous n'avez défini aucune fonction." +EmptySequenceBox0 = "Vous n'avez défini aucune suite." EmptyExpressionBox1 = "Pour définir une variable, tapez :" EmptyFunctionBox1 = "Pour définir une fonction, tapez :" EmptyExpressionBox2 = "Le nom de la variable peut" diff --git a/apps/variables.it.i18n b/apps/variables.it.i18n index 8871d3e51..e32ba5af0 100644 --- a/apps/variables.it.i18n +++ b/apps/variables.it.i18n @@ -1,8 +1,10 @@ Variables = "Variabili" Expressions = "Espressioni" Functions = "Funzioni" +Sequences = "Successioni" EmptyExpressionBox0 = "Non avete definito nessuna variabile." EmptyFunctionBox0 = "Non avete definito nessuna funzione." +EmptySequenceBox0 = "Non avete definito nessuna successione." EmptyExpressionBox1 = "Per definire una variabile, digitare :" EmptyFunctionBox1 = "Per definire una funzione, digitare :" EmptyExpressionBox2 = "Il nome della variabile può" diff --git a/apps/variables.nl.i18n b/apps/variables.nl.i18n index 06305f239..3f80a107b 100644 --- a/apps/variables.nl.i18n +++ b/apps/variables.nl.i18n @@ -1,8 +1,10 @@ Variables = "Variabelen" Expressions = "Uitdrukkingen" Functions = "Functies" +Sequences = "Rijen" EmptyExpressionBox0 = "Je hebt geen variabelen gedefinieerd." EmptyFunctionBox0 = "Je hebt geen functies gedefinieerd." +EmptySequenceBox0 = "Je hebt geen rij gedefinieerd." EmptyExpressionBox1 = "Om een variabele to definiëren, typ:" EmptyFunctionBox1 = "Om een functie to definiëren, typ:" EmptyExpressionBox2 = "De naam van de variabele kan bevatten:" diff --git a/apps/variables.pt.i18n b/apps/variables.pt.i18n index 493e43f01..5f080d0f9 100644 --- a/apps/variables.pt.i18n +++ b/apps/variables.pt.i18n @@ -1,8 +1,10 @@ Variables = "Variáveis" Expressions = "Expressões" Functions = "Funções" +Sequences = "Sequências" EmptyExpressionBox0 = "Nenhuma variável definida." EmptyFunctionBox0 = "Nenhuma função definida." +EmptySequenceBox0 = "Nenhuma sequência definida." EmptyExpressionBox1 = "Para definir uma, digite :" EmptyFunctionBox1 = "Para definir uma, digite :" EmptyExpressionBox2 = "O nome da variável pode conter:" diff --git a/escher/include/escher/app.h b/escher/include/escher/app.h index 7a5a79d5e..b39868845 100644 --- a/escher/include/escher/app.h +++ b/escher/include/escher/app.h @@ -34,7 +34,7 @@ public: class Snapshot { public: virtual App * unpack(Container * container) = 0; - void pack(App * app); + virtual void pack(App * app); /* reset all instances to their initial values */ virtual void reset() {} virtual void storageDidChangeForRecord(Ion::Storage::Record) {} diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 20a5dee45..f94cf79a6 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -98,6 +98,7 @@ class Expression : public TreeHandle { friend class SubtractionNode; friend class Sum; friend class SumAndProduct; + friend class SumAndProductNode; friend class Symbol; friend class SymbolAbstractNode; friend class Tangent; diff --git a/poincare/include/poincare/sequence.h b/poincare/include/poincare/sequence.h index 7d15d2662..043d71f4c 100644 --- a/poincare/include/poincare/sequence.h +++ b/poincare/include/poincare/sequence.h @@ -19,6 +19,7 @@ public: Type type() const override { return Type::Sequence; } Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) override; + int simplificationOrderSameType(const ExpressionNode * e, bool ascending, bool canBeInterrupted, bool ignoreParentheses) const override; private: char m_name[0]; diff --git a/poincare/include/poincare/symbol_abstract.h b/poincare/include/poincare/symbol_abstract.h index 633ecad08..e31ba27b4 100644 --- a/poincare/include/poincare/symbol_abstract.h +++ b/poincare/include/poincare/symbol_abstract.h @@ -66,6 +66,7 @@ class SymbolAbstract : public Expression { friend class Symbol; friend class SymbolNode; friend class SymbolAbstractNode; + friend class SumAndProductNode; public: const char * name() const { return node()->name(); } bool hasSameNameAs(const SymbolAbstract & other) const; diff --git a/poincare/src/parsing/parser.cpp b/poincare/src/parsing/parser.cpp index dfd85c16b..eb206b1f6 100644 --- a/poincare/src/parsing/parser.cpp +++ b/poincare/src/parsing/parser.cpp @@ -416,13 +416,9 @@ void Parser::parseSequence(Expression & leftHandSide, const char name, Token::Ty Expression rank = parseUntil(rightDelimiter); if (m_status != Status::Progress) { } else if (!popTokenIfType(rightDelimiter)) { - m_status = Status::Error; // Right delimiter missing. - } else if (rank.type() == ExpressionNode::Type::BasedInteger - || rank.isIdenticalTo(Symbol::Builder('n')) - || rank.isIdenticalTo(Addition::Builder(Symbol::Builder('n'), BasedInteger::Builder("1")))) { - leftHandSide = Sequence::Builder(&name, 1, rank); + m_status = Status::Error; // Right delimiter missing } else { - m_status = Status::Error; // Unexpected parameter. + leftHandSide = Sequence::Builder(&name, 1, rank); } } } diff --git a/poincare/src/sequence.cpp b/poincare/src/sequence.cpp index 869afa9eb..83957a050 100644 --- a/poincare/src/sequence.cpp +++ b/poincare/src/sequence.cpp @@ -20,28 +20,29 @@ Expression SequenceNode::replaceSymbolWithExpression(const SymbolAbstract & symb return Sequence(this).replaceSymbolWithExpression(symbol, expression); } +int SequenceNode::simplificationOrderSameType(const ExpressionNode * e, bool ascending, bool canBeInterrupted, bool ignoreParentheses) const { + /* This function ensures that terms like u(n) and u(n+1), u(n) and v(n), + * u(a) and u(b) do not factorize. + * We never want to factorize. The only cases where it could be useful are + * like the following : u(n)+u(n). But thanks to the cache system, no + * computation is needed for the second term.*/ + assert(type() == e->type()); + assert(numberOfChildren() == 1); + assert(e->numberOfChildren() == 1); + ExpressionNode * seq = const_cast(e); + int delta = strcmp(name(), reinterpret_cast(seq)->name()); + if (delta == 0) { + return SimplificationOrder(childAtIndex(0), e->childAtIndex(0), ascending, canBeInterrupted, ignoreParentheses); + } + return delta; +} + Layout SequenceNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { assert(name()[0] >= 'u' && name()[0] <= 'w'); - Layout rank; - for (char sequenceName = 'u'; sequenceName <= 'w'; sequenceName++) { - if (name()[0] == sequenceName) { - // Checking for the sequence children - if (childAtIndex(0)->type() == Type::Symbol) { - // u(n) - rank = LayoutHelper::String("n", strlen("n")); - } else if (childAtIndex(0)->type() == Type::Addition) { - rank = LayoutHelper::String("n+1", strlen("n+1")); - } else { - assert(childAtIndex(0)->type() == Type::BasedInteger); - rank = static_cast(*childAtIndex(0)).integer().createLayout(); - } - return HorizontalLayout::Builder( - CodePointLayout::Builder(sequenceName), - VerticalOffsetLayout::Builder(rank, VerticalOffsetLayoutNode::Position::Subscript)); - } - } - assert(false); - return LayoutHelper::String(name(), strlen(name())); + Layout rank = childAtIndex(0)->createLayout(floatDisplayMode, numberOfSignificantDigits); + return HorizontalLayout::Builder( + CodePointLayout::Builder(name()[0]), + VerticalOffsetLayout::Builder(rank, VerticalOffsetLayoutNode::Position::Subscript)); } int SequenceNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { @@ -49,7 +50,7 @@ int SequenceNode::serialize(char * buffer, int bufferSize, Preferences::PrintFlo } Expression SequenceNode::shallowReduce(ReductionContext reductionContext) { - return Sequence(this).shallowReduce(reductionContext); // This uses Symbol::shallowReduce + return Sequence(this).shallowReduce(reductionContext); } Evaluation SequenceNode::approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { @@ -95,8 +96,12 @@ Expression Sequence::replaceSymbolWithExpression(const SymbolAbstract & symbol, return *this; } -// Those two functions will be updated in a comming commit Expression Sequence::shallowReduce(ExpressionNode::ReductionContext reductionContext) { + if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined + || childAtIndex(0).isUndefined()) + { + return replaceWithUndefinedInPlace(); + } return *this; } diff --git a/poincare/src/sum_and_product.cpp b/poincare/src/sum_and_product.cpp index 8816dc958..c5f6cd5b3 100644 --- a/poincare/src/sum_and_product.cpp +++ b/poincare/src/sum_and_product.cpp @@ -32,14 +32,22 @@ Evaluation SumAndProductNode::templatedApproximate(Context * context, Prefere if (std::isnan(start) || std::isnan(end) || start != (int)start || end != (int)end || end - start > k_maxNumberOfSteps) { return Complex::Undefined(); } - VariableContext nContext = VariableContext(static_cast(childAtIndex(1))->name(), context); + SymbolNode * symbol = static_cast(childAtIndex(1)); + VariableContext nContext = VariableContext(symbol->name(), context); Evaluation result = Complex::Builder((T)emptySumAndProductValue()); for (int i = (int)start; i <= (int)end; i++) { if (Expression::ShouldStopProcessing()) { return Complex::Undefined(); } nContext.setApproximationForVariable((T)i); - result = evaluateWithNextTerm(T(), result, childAtIndex(0)->approximate(T(), &nContext, complexFormat, angleUnit), complexFormat); + Expression child = Expression(childAtIndex(0)).clone(); + if (child.type() == ExpressionNode::Type::Sequence) { + /* Since we cannot get the expression of a sequence term like we would for + * a function, we replace its potential abstract rank by the value it should + * have. We can then evaluate its value */ + child.childAtIndex(0).replaceSymbolWithExpression(symbol, Float::Builder(i)); + } + result = evaluateWithNextTerm(T(), result, child.node()->approximate(T(), &nContext, complexFormat, angleUnit), complexFormat); if (result.isUndefined()) { return Complex::Undefined(); } diff --git a/poincare/src/symbol_abstract.cpp b/poincare/src/symbol_abstract.cpp index 541b1ee3f..09b87aff0 100644 --- a/poincare/src/symbol_abstract.cpp +++ b/poincare/src/symbol_abstract.cpp @@ -37,11 +37,6 @@ Expression SymbolAbstractNode::setSign(ExpressionNode::Sign s, ReductionContext int SymbolAbstractNode::simplificationOrderSameType(const ExpressionNode * e, bool ascending, bool canBeInterrupted, bool ignoreParentheses) const { assert(type() == e->type()); - /* We do not want the sequences to be factorized. Otherwise, u(n) will be - * factorized with u(n+1). */ - if (type() == Type::Sequence) { - return -1; - } return strcmp(name(), static_cast(e)->name()); } diff --git a/poincare/src/variable_context.cpp b/poincare/src/variable_context.cpp index b7899cefe..75812fab7 100644 --- a/poincare/src/variable_context.cpp +++ b/poincare/src/variable_context.cpp @@ -2,7 +2,6 @@ #include #include #include - #include namespace Poincare {