From 032cafdb04170538ba87e1c217ee4eac244c40ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 13 Dec 2017 17:06:08 +0100 Subject: [PATCH] [apps] Sequence: enable to defined dependent sequences --- apps/sequence/Makefile | 3 +- apps/sequence/app.cpp | 7 +- apps/sequence/app.h | 4 +- .../{local_context.cpp => cache_context.cpp} | 22 ++-- apps/sequence/cache_context.h | 23 ++++ apps/sequence/list/list_controller.h | 2 +- apps/sequence/local_context.h | 24 ---- apps/sequence/sequence.cpp | 124 ++++++++---------- apps/sequence/sequence.h | 53 +------- apps/sequence/sequence_context.cpp | 66 ++++++++++ apps/sequence/sequence_context.h | 77 +++++++++++ apps/sequence/sequence_store.cpp | 20 +-- apps/sequence/sequence_store.h | 9 +- 13 files changed, 258 insertions(+), 176 deletions(-) rename apps/sequence/{local_context.cpp => cache_context.cpp} (66%) create mode 100644 apps/sequence/cache_context.h delete mode 100644 apps/sequence/local_context.h create mode 100644 apps/sequence/sequence_context.cpp create mode 100644 apps/sequence/sequence_context.h diff --git a/apps/sequence/Makefile b/apps/sequence/Makefile index 6ab4de6e1..dca498c03 100644 --- a/apps/sequence/Makefile +++ b/apps/sequence/Makefile @@ -17,8 +17,9 @@ app_objs += $(addprefix apps/sequence/,\ list/type_parameter_controller.o\ values/interval_parameter_controller.o\ values/values_controller.o\ - local_context.o\ + cache_context.o\ sequence.o\ + sequence_context.o\ sequence_store.o\ sequence_title_cell.o\ ) diff --git a/apps/sequence/app.cpp b/apps/sequence/app.cpp index d257927c2..a446d29e8 100644 --- a/apps/sequence/app.cpp +++ b/apps/sequence/app.cpp @@ -55,7 +55,7 @@ void App::Snapshot::tidy() { App::App(Container * container, Snapshot * snapshot) : FunctionApp(container, snapshot, &m_inputViewController), - m_nContext(((AppsContainer *)container)->globalContext()), + m_sequenceContext(((AppsContainer *)container)->globalContext(), snapshot->sequenceStore()), m_listController(&m_listFooter, snapshot->sequenceStore(), &m_listHeader, &m_listFooter), m_listFooter(&m_listHeader, &m_listController, &m_listController, ButtonRowController::Position::Bottom, ButtonRowController::Style::EmbossedGrey), m_listHeader(nullptr, &m_listFooter, &m_listController), @@ -78,10 +78,7 @@ InputViewController * App::inputViewController() { } Context * App::localContext() { - if (m_tabViewController.activeTab() == 0) { - return &m_nContext; - } - return TextFieldDelegateApp::localContext(); + return &m_sequenceContext; } const char * App::XNT() { diff --git a/apps/sequence/app.h b/apps/sequence/app.h index 920572dff..3f9d83bb5 100644 --- a/apps/sequence/app.h +++ b/apps/sequence/app.h @@ -3,7 +3,7 @@ #include #include -#include "local_context.h" +#include "sequence_context.h" #include "sequence_store.h" #include "graph/graph_controller.h" #include "graph/curve_view_range.h" @@ -39,7 +39,7 @@ public: const char * XNT() override; private: App(Container * container, Snapshot * snapshot); - LocalContext m_nContext; + SequenceContext m_sequenceContext; ListController m_listController; ButtonRowController m_listFooter; ButtonRowController m_listHeader; diff --git a/apps/sequence/local_context.cpp b/apps/sequence/cache_context.cpp similarity index 66% rename from apps/sequence/local_context.cpp rename to apps/sequence/cache_context.cpp index ca1357454..f3683b5a9 100644 --- a/apps/sequence/local_context.cpp +++ b/apps/sequence/cache_context.cpp @@ -1,4 +1,4 @@ -#include "local_context.h" +#include "cache_context.h" #include using namespace Poincare; @@ -6,7 +6,7 @@ using namespace Poincare; namespace Sequence { template -LocalContext::LocalContext(Context * parentContext) : +CacheContext::CacheContext(Context * parentContext) : VariableContext('n', parentContext), m_values{{Complex::Float(NAN), Complex::Float(NAN)}, {Complex::Float(NAN), Complex::Float(NAN)}} @@ -14,7 +14,7 @@ LocalContext::LocalContext(Context * parentContext) : } template -const Expression * LocalContext::expressionForSymbol(const Symbol * symbol) { +const Expression * CacheContext::expressionForSymbol(const Symbol * symbol) { if (symbol->name() == Symbol::SpecialSymbols::un || symbol->name() == Symbol::SpecialSymbols::un1 || symbol->name() == Symbol::SpecialSymbols::vn || symbol->name() == Symbol::SpecialSymbols::vn1) { return &m_values[nameIndexForSymbol(symbol)][rankIndexForSymbol(symbol)]; @@ -23,16 +23,12 @@ const Expression * LocalContext::expressionForSymbol(const Symbol * symbol) { } template -void LocalContext::setValueForSequenceRank(T value, const char * sequenceName, int rank) { - for (int i = 0; i < SequenceStore::k_maxNumberOfSequences; i++) { - if (strcmp(sequenceName, SequenceStore::k_sequenceNames[i]) == 0) { - m_values[i][rank] = Complex::Float(value); - } - } +void CacheContext::setValueForSymbol(T value, const Poincare::Symbol * symbol) { + m_values[nameIndexForSymbol(symbol)][rankIndexForSymbol(symbol)] = Complex::Float(value); } template -int LocalContext::nameIndexForSymbol(const Poincare::Symbol * symbol) { +int CacheContext::nameIndexForSymbol(const Poincare::Symbol * symbol) { switch (symbol->name()) { case Symbol::SpecialSymbols::un: return 0; @@ -48,7 +44,7 @@ int LocalContext::nameIndexForSymbol(const Poincare::Symbol * symbol) { } template -int LocalContext::rankIndexForSymbol(const Poincare::Symbol * symbol) { +int CacheContext::rankIndexForSymbol(const Poincare::Symbol * symbol) { switch (symbol->name()) { case Symbol::SpecialSymbols::un: return 0; @@ -63,7 +59,7 @@ int LocalContext::rankIndexForSymbol(const Poincare::Symbol * symbol) { } } -template class LocalContext; -template class LocalContext; +template class CacheContext; +template class CacheContext; } diff --git a/apps/sequence/cache_context.h b/apps/sequence/cache_context.h new file mode 100644 index 000000000..c1c5536e0 --- /dev/null +++ b/apps/sequence/cache_context.h @@ -0,0 +1,23 @@ +#ifndef SEQUENCE_CACHE_CONTEXT_H +#define SEQUENCE_CACHE_CONTEXT_H + +#include +#include "sequence_context.h" + +namespace Sequence { + +template +class CacheContext : public Poincare::VariableContext { +public: + CacheContext(Poincare::Context * parentContext); + const Poincare::Expression * expressionForSymbol(const Poincare::Symbol * symbol) override; + void setValueForSymbol(T value, const Poincare::Symbol * symbol); +private: + int nameIndexForSymbol(const Poincare::Symbol * symbol); + int rankIndexForSymbol(const Poincare::Symbol * symbol); + Poincare::Complex m_values[MaxNumberOfSequences][MaxRecurrenceDepth]; +}; + +} + +#endif diff --git a/apps/sequence/list/list_controller.h b/apps/sequence/list/list_controller.h index 23455776a..2db46d6bd 100644 --- a/apps/sequence/list/list_controller.h +++ b/apps/sequence/list/list_controller.h @@ -41,7 +41,7 @@ private: View * loadView() override; void unloadView(View * view) override; static constexpr KDCoordinate k_emptySubRowHeight = 30; - constexpr static int k_maxNumberOfRows = 3*SequenceStore::k_maxNumberOfSequences; + constexpr static int k_maxNumberOfRows = 3*MaxNumberOfSequences; SequenceStore * m_sequenceStore; SequenceTitleCell * m_sequenceTitleCells[k_maxNumberOfRows]; Shared::FunctionExpressionCell * m_expressionCells[k_maxNumberOfRows]; diff --git a/apps/sequence/local_context.h b/apps/sequence/local_context.h deleted file mode 100644 index 6b1e69ea3..000000000 --- a/apps/sequence/local_context.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef SEQUENCE_LOCAL_CONTEXT_H -#define SEQUENCE_LOCAL_CONTEXT_H - -#include -#include "sequence_store.h" - -namespace Sequence { - -template -class LocalContext : public Poincare::VariableContext { -public: - LocalContext(Poincare::Context * parentContext); - const Poincare::Expression * expressionForSymbol(const Poincare::Symbol * symbol) override; - void setValueForSequenceRank(T value, const char * sequenceName, int rank); -private: - constexpr static int k_depth = 2; - int nameIndexForSymbol(const Poincare::Symbol * symbol); - int rankIndexForSymbol(const Poincare::Symbol * symbol); - Poincare::Complex m_values[SequenceStore::k_maxNumberOfSequences][k_depth]; -}; - -} - -#endif diff --git a/apps/sequence/sequence.cpp b/apps/sequence/sequence.cpp index ec79b0ecd..960ef65a1 100644 --- a/apps/sequence/sequence.cpp +++ b/apps/sequence/sequence.cpp @@ -1,5 +1,6 @@ #include "sequence.h" -#include "local_context.h" +#include "sequence_store.h" +#include "cache_context.h" #include "../../poincare/src/layout/string_layout.h" #include "../../poincare/src/layout/baseline_relative_layout.h" #include @@ -22,11 +23,7 @@ Sequence::Sequence(const char * text, KDColor color) : m_nameLayout(nullptr), m_definitionName(nullptr), m_firstInitialConditionName(nullptr), - m_secondInitialConditionName(nullptr), - m_indexBufferFloat{-1, -1}, - m_indexBufferDouble{-1, -1}, - m_bufferFloat{NAN, NAN}, - m_bufferDouble{NAN, NAN} + m_secondInitialConditionName(nullptr) { } @@ -77,7 +74,6 @@ Sequence& Sequence::operator=(const Sequence& other) { setContent(contentText); setFirstInitialConditionContent(firstInitialText); setSecondInitialConditionContent(secondInitialText); - resetBuffer(); return *this; } @@ -130,7 +126,7 @@ void Sequence::setType(Type type) { } setFirstInitialConditionContent(""); setSecondInitialConditionContent(""); - resetBuffer(); + //sqctx->resetCache(); } Poincare::Expression * Sequence::firstInitialConditionExpression(Context * context) const { @@ -177,7 +173,7 @@ Poincare::ExpressionLayout * Sequence::secondInitialConditionLayout() { void Sequence::setContent(const char * c) { Function::setContent(c); - resetBuffer(); + //sqctx->resetCache(); } void Sequence::setFirstInitialConditionContent(const char * c) { @@ -190,7 +186,7 @@ void Sequence::setFirstInitialConditionContent(const char * c) { delete m_firstInitialConditionLayout; m_firstInitialConditionLayout = nullptr; } - resetBuffer(); + //sqctx->resetCache(); } void Sequence::setSecondInitialConditionContent(const char * c) { @@ -203,7 +199,7 @@ void Sequence::setSecondInitialConditionContent(const char * c) { delete m_secondInitialConditionLayout; m_secondInitialConditionLayout = nullptr; } - resetBuffer(); + //sqctx->resetCache(); } char Sequence::symbol() const { @@ -281,71 +277,66 @@ bool Sequence::isEmpty() { } template -T Sequence::templatedApproximateAtAbscissa(T x, Poincare::Context * context) const { +T Sequence::templatedApproximateAtAbscissa(T x, SequenceContext * sqctx) const { T n = std::round(x); + int sequenceIndex = name() == SequenceStore::k_sequenceNames[0] ? 0 : 1; + if (sqctx->iterateUntilRank(n)) { + return sqctx->valueOfSequenceAtPreviousRank(sequenceIndex, 0); + } + return NAN; +} + +template +T Sequence::approximateToNextRank(int n, SequenceContext * sqctx) const { + CacheContext ctx = CacheContext(sqctx); + T un = sqctx->valueOfSequenceAtPreviousRank(0, 0); + T unm1 = sqctx->valueOfSequenceAtPreviousRank(0, 1); + T unm2 = sqctx->valueOfSequenceAtPreviousRank(0, 2); + T vn = sqctx->valueOfSequenceAtPreviousRank(1, 0); + T vnm1 = sqctx->valueOfSequenceAtPreviousRank(1, 1); + T vnm2 = sqctx->valueOfSequenceAtPreviousRank(1, 2); + Poincare::Symbol nSymbol(symbol()); + Poincare::Symbol vnSymbol(Symbol::SpecialSymbols::vn); + Poincare::Symbol vn1Symbol(Symbol::SpecialSymbols::vn1); + Poincare::Symbol unSymbol(Symbol::SpecialSymbols::un); + Poincare::Symbol un1Symbol(Symbol::SpecialSymbols::un1); switch (m_type) { case Type::Explicite: - if (n < 0) { - return NAN; - } - return Shared::Function::evaluateAtAbscissa(n, context); + { + ctx.setValueForSymbol(un, &unSymbol); + ctx.setValueForSymbol(vn, &vnSymbol); + Poincare::Complex e = Poincare::Complex::Float(n); + ctx.setExpressionForSymbolName(&e, &nSymbol, *sqctx); + return expression(sqctx)->template approximateToScalar(ctx); + } case Type::SingleRecurrence: { - if (n < 0 || n > k_maxRecurrentRank) { - return NAN; - } if (n == 0) { - setBufferIndexValue(0,0); - setBufferValue(firstInitialConditionExpression(context)->approximateToScalar(*context), 0); - return bufferValue(0); + return firstInitialConditionExpression(sqctx)->template approximateToScalar(*sqctx); } - LocalContext subContext = LocalContext(context); - Poincare::Symbol nSymbol(symbol()); - int start = indexBuffer(0) < 0 || indexBuffer(0) > n ? 0 : indexBuffer(0); - T un = indexBuffer(0) < 0 || indexBuffer(0) > n ? firstInitialConditionExpression(context)->approximateToScalar(*context) : bufferValue(0); - for (int i = start; i < n; i++) { - subContext.setValueForSequenceRank(un, name(), 0); - Poincare::Complex e = Poincare::Complex::Float(i); - subContext.setExpressionForSymbolName(&e, &nSymbol, subContext); - un = expression(&subContext)-> template approximateToScalar(subContext); - } - setBufferValue(un, 0); - setBufferIndexValue(n, 0); - return un; + ctx.setValueForSymbol(un, &un1Symbol); + ctx.setValueForSymbol(unm1, &unSymbol); + ctx.setValueForSymbol(vn, &vn1Symbol); + ctx.setValueForSymbol(vnm1, &vnSymbol); + Poincare::Complex e = Poincare::Complex::Float(n-1); + ctx.setExpressionForSymbolName(&e, &nSymbol, *sqctx); + return expression(sqctx)->template approximateToScalar(ctx); } default: { - if (n < 0 || n > k_maxRecurrentRank) { - return NAN; - } if (n == 0) { - return firstInitialConditionExpression(context)->approximateToScalar(*context); + return firstInitialConditionExpression(sqctx)->template approximateToScalar(*sqctx); } if (n == 1) { - setBufferIndexValue(0, 0); - setBufferValue(firstInitialConditionExpression(context)->approximateToScalar(*context), 0); - setBufferIndexValue(1, 1); - setBufferValue(secondInitialConditionExpression(context)->approximateToScalar(*context), 1); - return bufferValue(1); + return secondInitialConditionExpression(sqctx)->template approximateToScalar(*sqctx); } - LocalContext subContext = LocalContext(context); - Poincare::Symbol nSymbol(symbol()); - int start = indexBuffer(0) >= 0 && indexBuffer(0) < n && indexBuffer(1) > 0 && indexBuffer(1) <= n && indexBuffer(0) + 1 == indexBuffer(1) ? indexBuffer(0) : 0; - T un = indexBuffer(0) >= 0 && indexBuffer(0) < n && indexBuffer(1) > 0 && indexBuffer(1) <= n && indexBuffer(0) + 1 == indexBuffer(1) ? bufferValue(0) : firstInitialConditionExpression(context)->approximateToScalar(*context); - T un1 = indexBuffer(0) >= 0 && indexBuffer(0) < n && indexBuffer(1) > 0 && indexBuffer(1) <= n && indexBuffer(0) + 1 == indexBuffer(1) ? bufferValue(1) : secondInitialConditionExpression(context)->approximateToScalar(*context); - for (int i = start; i < n-1; i++) { - subContext.setValueForSequenceRank(un, name(), 0); - subContext.setValueForSequenceRank(un1, name(), 1); - Poincare::Complex e = Poincare::Complex::Float(i); - subContext.setExpressionForSymbolName(&e, &nSymbol, subContext); - un = un1; - un1 = expression(&subContext)->template approximateToScalar(subContext); - } - setBufferValue(un, 0); - setBufferIndexValue(n-1, 0); - setBufferValue(un1, 1); - setBufferIndexValue(n, 1); - return un1; + ctx.setValueForSymbol(unm1, &un1Symbol); + ctx.setValueForSymbol(unm2, &unSymbol); + ctx.setValueForSymbol(vnm1, &vn1Symbol); + ctx.setValueForSymbol(vnm2, &vnSymbol); + Poincare::Complex e = Poincare::Complex::Float(n-2); + ctx.setExpressionForSymbolName(&e, &nSymbol, *sqctx); + return expression(sqctx)->template approximateToScalar(ctx); } } } @@ -402,11 +393,6 @@ void Sequence::tidy() { } } -void Sequence::resetBuffer() const { - m_indexBufferFloat[0] = -1; - m_indexBufferFloat[1] = -1; - m_indexBufferDouble[0] = -1; - m_indexBufferDouble[1] = -1; -} - +template double Sequence::approximateToNextRank(int, SequenceContext*) const; +template float Sequence::approximateToNextRank(int, SequenceContext*) const; } diff --git a/apps/sequence/sequence.h b/apps/sequence/sequence.h index 8cdebacbb..a9ac84360 100644 --- a/apps/sequence/sequence.h +++ b/apps/sequence/sequence.h @@ -2,6 +2,7 @@ #define SEQUENCE_SEQUENCE_H #include "../shared/function.h" +#include "sequence_context.h" #include namespace Sequence { @@ -39,20 +40,21 @@ public: bool isDefined() override; bool isEmpty() override; float evaluateAtAbscissa(float x, Poincare::Context * context) const override { - return templatedApproximateAtAbscissa(x, context); + return templatedApproximateAtAbscissa(x, static_cast(context)); } double evaluateAtAbscissa(double x, Poincare::Context * context) const override { - return templatedApproximateAtAbscissa(x, context); + return templatedApproximateAtAbscissa(x, static_cast(context)); } + template T approximateToNextRank(int n, SequenceContext * sqctx) const; double sumOfTermsBetweenAbscissa(double start, double end, Poincare::Context * context); void tidy() override; + private: - constexpr static int k_maxRecurrentRank = 10000; constexpr static double k_maxNumberOfTermsInSum = 100000.0; constexpr static size_t k_dataLengthInBytes = (3*TextField::maxBufferSize()+3)*sizeof(char)+1; static_assert((k_dataLengthInBytes & 0x3) == 0, "The sequence data size is not a multiple of 4 bytes (cannot compute crc)"); // Assert that dataLengthInBytes is a multiple of 4 char symbol() const override; - template T templatedApproximateAtAbscissa(T x, Poincare::Context * context) const; + template T templatedApproximateAtAbscissa(T x, SequenceContext * sqctx) const; Type m_type; char m_firstInitialConditionText[TextField::maxBufferSize()]; char m_secondInitialConditionText[TextField::maxBufferSize()]; @@ -64,49 +66,6 @@ private: Poincare::ExpressionLayout * m_definitionName; Poincare::ExpressionLayout * m_firstInitialConditionName; Poincare::ExpressionLayout * m_secondInitialConditionName; - /* In order to accelerate the computation of values of recurrent sequences, - * we memoize the last computed values of the sequence and their associated - * ranks (n and n+1 for instance). Thereby, when another evaluation at a - * superior rank k > n+1 is called, we avoid iterating from 0 but can start - * from n. */ - constexpr static int k_maxRecurrenceDepth = 2; - mutable int m_indexBufferFloat[k_maxRecurrenceDepth]; - mutable int m_indexBufferDouble[k_maxRecurrenceDepth]; - mutable float m_bufferFloat[k_maxRecurrenceDepth]; - mutable double m_bufferDouble[k_maxRecurrenceDepth]; - void resetBuffer() const; - template void setBufferValue(T value, int i) const { - assert(i >= 0 && i < k_maxRecurrentRank); - if (sizeof(T) == sizeof(float)) { - m_bufferFloat[i] = value; - } else { - m_bufferDouble[i] = value; - } - } - template void setBufferIndexValue(int index, int i) const { - assert(i >= 0 && i < k_maxRecurrentRank); - if (sizeof(T) == sizeof(float)) { - m_indexBufferFloat[i] = index; - } else { - m_indexBufferDouble[i] = index; - } - } - template T bufferValue(int i) const { - assert(i >= 0 && i < k_maxRecurrentRank); - if (sizeof(T) == sizeof(float)) { - return m_bufferFloat[i]; - } else { - return m_bufferDouble[i]; - } - } - template int indexBuffer(int i) const { - assert(i >= 0 && i < k_maxRecurrentRank); - if (sizeof(T) == sizeof(float)) { - return m_indexBufferFloat[i]; - } else { - return m_indexBufferDouble[i]; - } - } }; } diff --git a/apps/sequence/sequence_context.cpp b/apps/sequence/sequence_context.cpp new file mode 100644 index 000000000..7e1c73995 --- /dev/null +++ b/apps/sequence/sequence_context.cpp @@ -0,0 +1,66 @@ +#include "sequence_context.h" +#include "sequence_store.h" +#include + +using namespace Poincare; + +namespace Sequence { + +template +TemplatedSequenceContext::TemplatedSequenceContext() : + m_rank(-1), + m_values{{NAN, NAN, NAN},{NAN, NAN, NAN}} +{ +} + +template +T TemplatedSequenceContext::valueOfSequenceAtPreviousRank(int sequenceIndex, int rank) const { + return m_values[sequenceIndex][rank]; +} + +template +void TemplatedSequenceContext::resetCache() { + m_rank = -1; +} + +template +bool TemplatedSequenceContext::iterateUntilRank(int n, SequenceStore * sequenceStore, SequenceContext * sqctx) { + if (m_rank > n) { + m_rank = -1; + } + if (n < 0 || n-m_rank > k_maxRecurrentRank) { + return false; + } + while (m_rank++ < n) { + step(sequenceStore, sqctx); + } + m_rank--; + return true; +} + +template +void TemplatedSequenceContext::step(SequenceStore * sequenceStore, SequenceContext * sqctx) { + /* Shift values */ + for (int i = 0; i < MaxNumberOfSequences; i++) { + for (int j = MaxRecurrenceDepth; j > 0; j--) { + m_values[i][j] = m_values[i][j-1]; + } + m_values[i][0] = NAN; + } + + /* Evaluate new u(n) and v(n) */ + Sequence * u = sequenceStore->numberOfFunctions() > 0 ? sequenceStore->functionAtIndex(0) : nullptr; + u = u && u->isDefined() ? u : nullptr; + Sequence * v = sequenceStore->numberOfFunctions() > 1 ? sequenceStore->functionAtIndex(1) : nullptr; + v = v && v->isDefined() ? v : nullptr; + + /* TODO: explain */ + m_values[0][0] = u ? u->approximateToNextRank(m_rank, sqctx) : NAN; + m_values[1][0] = v ? v->approximateToNextRank(m_rank, sqctx) : NAN; + m_values[0][0] = u ? u->approximateToNextRank(m_rank, sqctx) : NAN; +} + +template class TemplatedSequenceContext; +template class TemplatedSequenceContext; + +} diff --git a/apps/sequence/sequence_context.h b/apps/sequence/sequence_context.h new file mode 100644 index 000000000..c1fefdc3c --- /dev/null +++ b/apps/sequence/sequence_context.h @@ -0,0 +1,77 @@ +#ifndef SEQUENCE_SEQUENCE_CONTEXT_H +#define SEQUENCE_SEQUENCE_CONTEXT_H + +#include + +namespace Sequence { + +constexpr static int MaxRecurrenceDepth = 2; +static constexpr int MaxNumberOfSequences = 2; + +class SequenceStore; +class SequenceContext; + +template +class TemplatedSequenceContext { +public: + TemplatedSequenceContext(); + T valueOfSequenceAtPreviousRank(int sequenceIndex, int rank) const; + void resetCache(); + bool iterateUntilRank(int n, SequenceStore * sequenceStore, SequenceContext * sqctx); +private: + constexpr static int k_maxRecurrentRank = 10000; + /* Cache: + * In order to accelerate the computation of values of recurrent sequences, + * we memoize the last computed values of the sequence and their associated + * ranks (n and n+1 for instance). Thereby, when another evaluation at a + * superior rank k > n+1 is called, we avoid iterating from 0 but can start + * from n. */ + void step(SequenceStore * sequenceStore, SequenceContext * sqctx); + int m_rank; + T m_values[MaxNumberOfSequences][MaxRecurrenceDepth+1]; +}; + +class SequenceContext : public Poincare::Context { +public: + SequenceContext(Poincare::Context * parentContext, SequenceStore * sequenceStore) : + Context(), + m_floatSequenceContext(), + m_doubleSequenceContext(), + m_sequenceStore(sequenceStore), + m_parentContext(parentContext) {} + /* expressionForSymbol & setExpressionForSymbolName directly call the parent + * 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. */ + const Poincare::Expression * expressionForSymbol(const Poincare::Symbol * symbol) override { + return m_parentContext->expressionForSymbol(symbol); + } + void setExpressionForSymbolName(const Poincare::Expression * expression, const Poincare::Symbol * symbol, Poincare::Context & context) override { + m_parentContext->setExpressionForSymbolName(expression, symbol, context); + } + template T valueOfSequenceAtPreviousRank(int sequenceIndex, int rank) const { + if (sizeof(T) == sizeof(float)) { + return m_floatSequenceContext.valueOfSequenceAtPreviousRank(sequenceIndex, rank); + } + return m_doubleSequenceContext.valueOfSequenceAtPreviousRank(sequenceIndex, rank); + } + void resetCache() { + m_floatSequenceContext.resetCache(); + m_doubleSequenceContext.resetCache(); + } + template bool iterateUntilRank(int n) { + if (sizeof(T) == sizeof(float)) { + return m_floatSequenceContext.iterateUntilRank(n, m_sequenceStore, this); + } + return m_doubleSequenceContext.iterateUntilRank(n, m_sequenceStore, this); + } +private: + TemplatedSequenceContext m_floatSequenceContext; + TemplatedSequenceContext m_doubleSequenceContext; + SequenceStore * m_sequenceStore; + Poincare::Context * m_parentContext; +}; + +} + +#endif diff --git a/apps/sequence/sequence_store.cpp b/apps/sequence/sequence_store.cpp index 044d36c20..b0ef9ddbb 100644 --- a/apps/sequence/sequence_store.cpp +++ b/apps/sequence/sequence_store.cpp @@ -7,14 +7,14 @@ extern "C" { namespace Sequence { -constexpr KDColor SequenceStore::k_defaultColors[k_maxNumberOfSequences]; -constexpr const char * SequenceStore::k_sequenceNames[k_maxNumberOfSequences]; +constexpr KDColor SequenceStore::k_defaultColors[MaxNumberOfSequences]; +constexpr const char * SequenceStore::k_sequenceNames[MaxNumberOfSequences]; uint32_t SequenceStore::storeChecksum() { - size_t dataLengthInBytes = k_maxNumberOfSequences*sizeof(uint32_t); + size_t dataLengthInBytes = MaxNumberOfSequences*sizeof(uint32_t); assert((dataLengthInBytes & 0x3) == 0); // Assert that dataLengthInBytes is a multiple of 4 - uint32_t checksums[k_maxNumberOfSequences]; - for (int i = 0; i < k_maxNumberOfSequences; i++) { + uint32_t checksums[MaxNumberOfSequences]; + for (int i = 0; i < MaxNumberOfSequences; i++) { checksums[i] = m_sequences[i].checksum(); } return Ion::crc32((uint32_t *)checksums, dataLengthInBytes/sizeof(uint32_t)); @@ -34,7 +34,7 @@ Sequence * SequenceStore::definedFunctionAtIndex(int i) { } Sequence * SequenceStore::addEmptyFunction() { - assert(m_numberOfFunctions < k_maxNumberOfSequences); + assert(m_numberOfFunctions < MaxNumberOfSequences); const char * name = firstAvailableName(); KDColor color = firstAvailableColor(); Sequence addedSequence(name, color); @@ -56,10 +56,11 @@ void SequenceStore::removeFunction(Shared::Function * f) { } Sequence emptySequence("", KDColorBlack); m_sequences[m_numberOfFunctions] = emptySequence; + //sqctx->resetCache(); } int SequenceStore::maxNumberOfFunctions() { - return k_maxNumberOfSequences; + return MaxNumberOfSequences; } char SequenceStore::symbol() const { @@ -67,7 +68,7 @@ char SequenceStore::symbol() const { } const char * SequenceStore::firstAvailableName() { - for (int k = 0; k < k_maxNumberOfSequences; k++) { + for (int k = 0; k < MaxNumberOfSequences; k++) { int j = 0; while (j < m_numberOfFunctions) { if (m_sequences[j].name() == k_sequenceNames[k]) { @@ -83,7 +84,7 @@ const char * SequenceStore::firstAvailableName() { } const KDColor SequenceStore::firstAvailableColor() { - for (int k = 0; k < k_maxNumberOfSequences; k++) { + for (int k = 0; k < MaxNumberOfSequences; k++) { int j = 0; while (j < m_numberOfFunctions) { if (m_sequences[j].color() == k_defaultColors[k]) { @@ -104,6 +105,7 @@ void SequenceStore::removeAll() { m_sequences[i] = emptySequence; } m_numberOfFunctions = 0; + //sqctx->resetCache(); } } diff --git a/apps/sequence/sequence_store.h b/apps/sequence/sequence_store.h index 9d9c7d18c..e46b44b8e 100644 --- a/apps/sequence/sequence_store.h +++ b/apps/sequence/sequence_store.h @@ -1,8 +1,8 @@ #ifndef SEQUENCE_SEQUENCE_STORE_H #define SEQUENCE_SEQUENCE_STORE_H -#include "sequence.h" #include "../shared/function_store.h" +#include "sequence.h" #include #include @@ -21,16 +21,15 @@ public: const char * firstAvailableName() override; char symbol() const override; void removeAll() override; - static constexpr int k_maxNumberOfSequences = 2; - static constexpr const char * k_sequenceNames[k_maxNumberOfSequences] = { + static constexpr const char * k_sequenceNames[MaxNumberOfSequences] = { "u", "v"//, "w" }; private: const KDColor firstAvailableColor() override; - static constexpr KDColor k_defaultColors[k_maxNumberOfSequences] = { + static constexpr KDColor k_defaultColors[MaxNumberOfSequences] = { Palette::Red, Palette::Blue//, Palette::YellowDark }; - Sequence m_sequences[k_maxNumberOfSequences]; + Sequence m_sequences[MaxNumberOfSequences]; }; }