[sequence] Changed sequences behavior

Sequences can now be defined using specific terms form other sequences :
Un = n
Vn = u(3)

Initial values can also depend on other sequences.
Should there be a circular dependency, the sequences concerned will
display "undef" as value

Change-Id: I6fe1f3ff7b500f35d480ddefb42de729c327432e
This commit is contained in:
Arthur Camouseigt
2020-07-03 17:15:38 +02:00
committed by Émilie Feral
parent 688394abce
commit 8434da60ef
11 changed files with 301 additions and 60 deletions

View File

@@ -1,5 +1,7 @@
#include "sequence_context.h"
#include "sequence_store.h"
#include "cache_context.h"
#include "../shared/poincare_helpers.h"
#include <cmath>
using namespace Poincare;
@@ -9,63 +11,104 @@ namespace Sequence {
template<typename T>
TemplatedSequenceContext<T>::TemplatedSequenceContext() :
m_rank(-1),
m_values{{NAN, NAN, NAN}, {NAN, NAN, NAN}, {NAN, NAN, NAN}}
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}}
{
}
template<typename T>
T TemplatedSequenceContext<T>::valueOfSequenceAtPreviousRank(int sequenceIndex, int rank) const {
return m_values[sequenceIndex][rank];
return m_commonRankValues[sequenceIndex][rank];
}
template<typename T>
void TemplatedSequenceContext<T>::resetCache() {
m_rank = -1;
/* 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
* and do not use them. */
m_commonRank = -1;
for (int i = 0; i < MaxNumberOfSequences; i ++) {
m_independantRanks[i] = -1;
}
}
template<typename T>
bool TemplatedSequenceContext<T>::iterateUntilRank(int n, SequenceStore * sequenceStore, SequenceContext * sqctx) {
if (m_rank > n) {
m_rank = -1;
if (m_commonRank > n) {
m_commonRank = -1;
}
if (n < 0 || n-m_rank > k_maxRecurrentRank) {
if (n < 0 || n-m_commonRank > k_maxRecurrentRank) {
return false;
}
while (m_rank++ < n) {
step(sequenceStore, sqctx);
while (m_commonRank < n) {
step(sqctx);
}
m_rank--;
return true;
}
template<typename T>
void TemplatedSequenceContext<T>::step(SequenceStore * sequenceStore, SequenceContext * sqctx) {
/* Shift values */
for (int i = 0; i < MaxNumberOfSequences; i++) {
void TemplatedSequenceContext<T>::step(SequenceContext * sqctx, int sequenceIndex) {
// First we increment the rank
bool stepMultipleSequences = sequenceIndex == -1;
if (stepMultipleSequences) {
m_commonRank++;
} else {
setIndependantSequenceRank(independantSequenceRank(sequenceIndex) + 1, sequenceIndex);
}
// Then we shift the values stored in the arrays
int start, stop, rank;
T * sequenceArray;
if (stepMultipleSequences) {
start = 0;
stop = MaxNumberOfSequences;
sequenceArray = reinterpret_cast<T*>(&m_commonRankValues);
rank = m_commonRank;
} else {
start = sequenceIndex;
stop = sequenceIndex + 1;
sequenceArray = reinterpret_cast<T*>(&m_independantRankValues);
rank = independantSequenceRank(sequenceIndex);
}
for (int i = start; i < stop; i++) {
T * rowPointer = sequenceArray + i * (MaxRecurrenceDepth + 1);
for (int j = MaxRecurrenceDepth; j > 0; j--) {
m_values[i][j] = m_values[i][j-1];
*(rowPointer + j) = *(rowPointer + j - 1);
}
m_values[i][0] = NAN;
*rowPointer= NAN;
}
/* Evaluate new u(n) and v(n) */
// sequences hold u, v, w in this order
// We create an array containing the sequences we want to update
Sequence * sequences[MaxNumberOfSequences] = {nullptr, nullptr, nullptr};
for (int i = 0; i < sequenceStore->numberOfModels(); i++) {
int usedSize = stepMultipleSequences ? MaxNumberOfSequences : 1;
SequenceStore * sequenceStore = sqctx->sequenceStore();
stop = stepMultipleSequences ? sequenceStore->numberOfModels() : start + 1;
for (int i = start; i < stop; i++) {
Sequence * u = sequenceStore->modelForRecord(sequenceStore->recordAtIndex(i));
sequences[SequenceStore::sequenceIndexForName(u->fullName()[0])] = u->isDefined() ? u : nullptr;
int index = stepMultipleSequences ? SequenceStore::sequenceIndexForName(u->fullName()[0]) : 0;
sequences[index] = u->isDefined() ? u : nullptr;
}
/* 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.
// We approximate the value of the next rank for each sequence we want to update
stop = stepMultipleSequences ? MaxNumberOfSequences : sequenceIndex + 1;
/* In case stop is MaxNumberOfSequences, we 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<T>(m_rank, sqctx) : NAN;
* and u can only be known at the third iteration.
* In case stop is 1, there is only one sequence we want to update. Moreover,
* the call to approximateToNextRank will handle potential dependencies. */
for (int k = 0; k < usedSize; k++) {
for (int i = start; i < stop; i++) {
T * pointerToUpdate = sequenceArray + i * (MaxRecurrenceDepth + 1);
if (std::isnan(*(pointerToUpdate))) {
int j = stepMultipleSequences ? i : 0;
*(pointerToUpdate) = sequences[j] ? sequences[j]->template approximateToNextRank<T>(rank, sqctx, sequenceIndex) : NAN;
}
}
}
@@ -73,5 +116,7 @@ void TemplatedSequenceContext<T>::step(SequenceStore * sequenceStore, SequenceCo
template class TemplatedSequenceContext<float>;
template class TemplatedSequenceContext<double>;
template void * SequenceContext::helper<float>();
template void * SequenceContext::helper<double>();
}