#include "sequence_context.h" #include "sequence_store.h" #include "cache_context.h" #include "../shared/poincare_helpers.h" #include using namespace Poincare; namespace Shared { template TemplatedSequenceContext::TemplatedSequenceContext() : m_commonRank(-1), m_commonRankValues{{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::valueOfCommonRankSequenceAtPreviousRank(int sequenceIndex, int rank) const { return m_commonRankValues[sequenceIndex][rank]; } 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_independentRankValues are dirty * and do not use them. */ m_commonRank = -1; for (int i = 0; i < MaxNumberOfSequences; i ++) { m_independentRanks[i] = -1; } } template bool TemplatedSequenceContext::iterateUntilRank(int n, SequenceStore * sequenceStore, SequenceContext * sqctx) { if (m_commonRank > n) { m_commonRank = -1; } if (n < 0 || n-m_commonRank > k_maxRecurrentRank) { return false; } while (m_commonRank < n) { step(sqctx); } return true; } template void TemplatedSequenceContext::step(SequenceContext * sqctx, int sequenceIndex) { // First we increment the rank bool stepMultipleSequences = sequenceIndex == -1; if (stepMultipleSequences) { m_commonRank++; } else { setIndependentSequenceRank(independentSequenceRank(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(&m_commonRankValues); rank = m_commonRank; } else { start = sequenceIndex; stop = sequenceIndex + 1; sequenceArray = reinterpret_cast(&m_independentRankValues); rank = independentSequenceRank(sequenceIndex); } for (int i = start; i < stop; i++) { T * rowPointer = sequenceArray + i * (MaxRecurrenceDepth + 1); for (int j = MaxRecurrenceDepth; j > 0; j--) { *(rowPointer + j) = *(rowPointer + j - 1); } *rowPointer= NAN; } // We create an array containing the sequences we want to update Sequence * sequences[MaxNumberOfSequences] = {nullptr, nullptr, nullptr}; 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)); int index = stepMultipleSequences ? SequenceStore::sequenceIndexForName(u->fullName()[0]) : 0; sequences[index] = u->isDefined() ? u : nullptr; } // 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. * 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(rank, sqctx, sequenceIndex) : NAN; } } } } template class TemplatedSequenceContext; template class TemplatedSequenceContext; template void * SequenceContext::helper(); template void * SequenceContext::helper(); }