From 2e7fb601c8fd78f8dca24fe5cfbb735378d6592e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 16 Jul 2019 18:10:46 +0200 Subject: [PATCH] [app/sequence] Add a third sequence --- apps/sequence/cache_context.cpp | 18 +++++----- apps/sequence/sequence.cpp | 53 ++++++++++++++++++------------ apps/sequence/sequence_context.cpp | 33 ++++++++++--------- apps/sequence/sequence_context.h | 2 +- apps/sequence/sequence_store.cpp | 10 ++++++ apps/sequence/sequence_store.h | 3 +- 6 files changed, 71 insertions(+), 48 deletions(-) diff --git a/apps/sequence/cache_context.cpp b/apps/sequence/cache_context.cpp index d932455f4..f838d0610 100644 --- a/apps/sequence/cache_context.cpp +++ b/apps/sequence/cache_context.cpp @@ -8,17 +8,17 @@ namespace Sequence { template CacheContext::CacheContext(Context * parentContext) : - m_values{{NAN, NAN}, - {NAN, NAN}}, + m_values{{NAN, NAN},{NAN, NAN},{NAN,NAN}}, m_parentContext(parentContext) { } template const Expression CacheContext::expressionForSymbol(const SymbolAbstract & symbol, bool clone) { - // [u|v](n(+1)?) + // [u|v|w](n(+1)?) if (symbol.type() == ExpressionNode::Type::Symbol - && (symbol.name()[0] == SequenceStore::k_sequenceNames[0][0] || symbol.name()[0] == SequenceStore::k_sequenceNames[1][0]) + && symbol.name()[0] >= SequenceStore::k_sequenceNames[0][0] + && symbol.name()[0] <= SequenceStore::k_sequenceNames[MaxNumberOfSequences-1][0] && (strcmp(symbol.name()+1, "(n)") == 0 || strcmp(symbol.name()+1, "(n+1)") == 0)) { Symbol s = const_cast(static_cast(symbol)); @@ -39,12 +39,10 @@ void CacheContext::setValueForSymbol(T value, const Poincare::Symbol & symbol template int CacheContext::nameIndexForSymbol(const Poincare::Symbol & symbol) { - assert(strlen(symbol.name()) == 4 || strlen(symbol.name()) == 6); // [u|v](n(+1)?) - if (symbol.name()[0] == SequenceStore::k_sequenceNames[0][0]) { // u - return 0; - } - // v - return 1; + assert(strlen(symbol.name()) == 4 || strlen(symbol.name()) == 6); // [u|v|w](n(+1)?) + char name = symbol.name()[0]; + assert(name >= SequenceStore::k_sequenceNames[0][0] && name <= SequenceStore::k_sequenceNames[MaxNumberOfSequences-1][0]); // u, v or w + return name - 'u'; } template diff --git a/apps/sequence/sequence.cpp b/apps/sequence/sequence.cpp index ce8a16327..09ef07975 100644 --- a/apps/sequence/sequence.cpp +++ b/apps/sequence/sequence.cpp @@ -111,7 +111,7 @@ bool Sequence::isEmpty() { template T Sequence::templatedApproximateAtAbscissa(T x, SequenceContext * sqctx) const { T n = std::round(x); - int sequenceIndex = fullName()[0] == SequenceStore::k_sequenceNames[0][0] ? 0 : 1; + int sequenceIndex = SequenceStore::sequenceIndexForName(fullName()[0]); if (sqctx->iterateUntilRank(n)) { return sqctx->valueOfSequenceAtPreviousRank(sequenceIndex, 0); } @@ -129,21 +129,30 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx) const { Poincare::SerializationHelper::CodePoint(unknownN, bufferSize, UCodePointUnknownN); 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 vnSymbol = Symbol::Builder("v(n)", 4); - Poincare::Symbol vn1Symbol = Symbol::Builder("v(n+1)", 6); - Poincare::Symbol unSymbol = Symbol::Builder("u(n)", 4); - Poincare::Symbol un1Symbol = Symbol::Builder("u(n+1)", 6); + // Hold values u(n), u(n-1), u(n-2), v(n), v(n-1), v(n-2)... + T values[MaxNumberOfSequences][MaxRecurrenceDepth+1]; + for (int i = 0; i < MaxNumberOfSequences; i++) { + for (int j = 0; j < MaxRecurrenceDepth+1; j++) { + values[i][j] = sqctx->valueOfSequenceAtPreviousRank(i, j); + } + } + // Hold symbols u(n), u(n+1), v(n), v(n+1), w(n), w(n+1) + Poincare::Symbol symbols[MaxNumberOfSequences][MaxRecurrenceDepth]; + char name[MaxRecurrenceDepth][7] = {"0(n)","0(n+1)"}; + for (int i = 0; i < MaxNumberOfSequences; i++) { + for (int j = 0; j < MaxRecurrenceDepth; j++) { + name[j][0] = SequenceStore::k_sequenceNames[i][0]; + symbols[i][j] = Symbol::Builder(name[j], strlen(name[j])); + } + } + switch (type()) { case Type::Explicit: { - ctx.setValueForSymbol(un, unSymbol); - ctx.setValueForSymbol(vn, vnSymbol); + for (int i = 0; i < MaxNumberOfSequences; i++) { + // Set in context u(n) = u(n) for all sequences + ctx.setValueForSymbol(values[i][0], symbols[i][0]); + } return PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(sqctx), unknownN, (T)n, &ctx); } case Type::SingleRecurrence: @@ -151,10 +160,11 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx) const { if (n == initialRank()) { return PoincareHelpers::ApproximateToScalar(firstInitialConditionExpressionReduced(sqctx), sqctx); } - ctx.setValueForSymbol(un, un1Symbol); - ctx.setValueForSymbol(unm1, unSymbol); - ctx.setValueForSymbol(vn, vn1Symbol); - ctx.setValueForSymbol(vnm1, vnSymbol); + for (int i = 0; i < MaxNumberOfSequences; i++) { + // Set in context u(n) = u(n-1) and u(n+1) = u(n) for all sequences + ctx.setValueForSymbol(values[i][0], symbols[i][1]); + ctx.setValueForSymbol(values[i][1], symbols[i][0]); + } return PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(sqctx), unknownN, (T)(n-1), &ctx); } default: @@ -165,10 +175,11 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx) const { if (n == initialRank()+1) { return PoincareHelpers::ApproximateToScalar(secondInitialConditionExpressionReduced(sqctx), sqctx); } - ctx.setValueForSymbol(unm1, un1Symbol); - ctx.setValueForSymbol(unm2, unSymbol); - ctx.setValueForSymbol(vnm1, vn1Symbol); - ctx.setValueForSymbol(vnm2, vnSymbol); + for (int i = 0; i < MaxNumberOfSequences; i++) { + // Set in context u(n) = u(n-2) and u(n+1) = u(n-1) for all sequences + ctx.setValueForSymbol(values[i][1], symbols[i][1]); + ctx.setValueForSymbol(values[i][2], symbols[i][0]); + } return PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(sqctx), unknownN, (T)(n-2), &ctx); } } diff --git a/apps/sequence/sequence_context.cpp b/apps/sequence/sequence_context.cpp index d6f6cac92..fbb485f14 100644 --- a/apps/sequence/sequence_context.cpp +++ b/apps/sequence/sequence_context.cpp @@ -10,7 +10,7 @@ namespace Sequence { template TemplatedSequenceContext::TemplatedSequenceContext() : m_rank(-1), - m_values{{NAN, NAN, NAN},{NAN, NAN, NAN}} + m_values{{NAN, NAN, NAN}, {NAN, NAN, NAN}, {NAN, NAN, NAN}} { } @@ -50,22 +50,25 @@ void TemplatedSequenceContext::step(SequenceStore * sequenceStore, SequenceCo } /* Evaluate new u(n) and v(n) */ - Sequence * u = sequenceStore->numberOfModels() > 0 ? sequenceStore->modelForRecord(sequenceStore->recordAtIndex(0)) : nullptr; - u = u && u->isDefined() ? u : nullptr; - Sequence * v = sequenceStore->numberOfModels() > 1 ? sequenceStore->modelForRecord(sequenceStore->recordAtIndex(1)) : nullptr; - v = v && v->isDefined() ? v : nullptr; - /* Switch u & v if the name of u is v */ - if (u && u->fullName()[0] == SequenceStore::k_sequenceNames[1][0]) { - Sequence * temp = u; - u = v; - v = temp; + // sequences hold u, v, w in this order + Sequence * sequences[MaxNumberOfSequences] = {nullptr, nullptr, nullptr}; + for (int i = 0; i < sequenceStore->numberOfModels(); i++) { + Sequence * u = sequenceStore->modelForRecord(sequenceStore->recordAtIndex(i)); + sequences[SequenceStore::sequenceIndexForName(u->fullName()[0])] = u->isDefined() ? u : nullptr; } - /* Approximate u & v at the new rank. We evaluate u twice in case its - * expression depends on v. */ - 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; + /* Approximate u, v and w at the new rank. We have to evaluate all sequences + * MaxNumberOfSequences times in case the evaluations depend on each other. + * For example, if u expression depends on v and v depends on w. At the first + * iteration, we can only evaluate w, at the second iteration we evaluate v + * and u can only be known at the third iteration . */ + for (int k = 0; k < MaxNumberOfSequences; k++) { + for (int i = 0; i < MaxNumberOfSequences; i++) { + if (std::isnan(m_values[i][0])) { + m_values[i][0] = sequences[i] ? sequences[i]->approximateToNextRank(m_rank, sqctx) : NAN; + } + } + } } template class TemplatedSequenceContext; diff --git a/apps/sequence/sequence_context.h b/apps/sequence/sequence_context.h index 5908028db..86088840f 100644 --- a/apps/sequence/sequence_context.h +++ b/apps/sequence/sequence_context.h @@ -8,7 +8,7 @@ namespace Sequence { constexpr static int MaxRecurrenceDepth = 2; -static constexpr int MaxNumberOfSequences = 2; +static constexpr int MaxNumberOfSequences = 3; class SequenceStore; class SequenceContext; diff --git a/apps/sequence/sequence_store.cpp b/apps/sequence/sequence_store.cpp index 7752c1ecc..6f9ca7dfa 100644 --- a/apps/sequence/sequence_store.cpp +++ b/apps/sequence/sequence_store.cpp @@ -37,6 +37,16 @@ Ion::Storage::Record::ErrorStatus SequenceStore::addEmptyModel() { return Ion::Storage::sharedStorage()->createRecordWithExtension(name, modelExtension(), &data, sizeof(data)); } +int SequenceStore::sequenceIndexForName(char name) { + for (int i = 0; i < MaxNumberOfSequences; i++) { + if (k_sequenceNames[i][0] == name) { + return i; + } + } + assert(false); + return 0; +} + void SequenceStore::setMemoizedModelAtIndex(int cacheIndex, Ion::Storage::Record record) const { assert(cacheIndex >= 0 && cacheIndex < maxNumberOfMemoizedModels()); m_sequences[cacheIndex] = Sequence(record); diff --git a/apps/sequence/sequence_store.h b/apps/sequence/sequence_store.h index 3bfb94e9f..9528fd419 100644 --- a/apps/sequence/sequence_store.h +++ b/apps/sequence/sequence_store.h @@ -24,9 +24,10 @@ public: * changed */ int maxNumberOfModels() const override { return MaxNumberOfSequences; } + static int sequenceIndexForName(char name); static const char * firstAvailableName(int * nameIndex = nullptr); static constexpr const char * k_sequenceNames[MaxNumberOfSequences] = { - "u", "v"//, "w" + "u", "v", "w" }; private: