mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
127 lines
4.5 KiB
C++
127 lines
4.5 KiB
C++
#include "sequence_context.h"
|
|
#include "sequence_store.h"
|
|
#include "sequence_cache_context.h"
|
|
#include "../shared/poincare_helpers.h"
|
|
#include <cmath>
|
|
|
|
using namespace Poincare;
|
|
|
|
namespace Shared {
|
|
|
|
template<typename T>
|
|
TemplatedSequenceContext<T>::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<typename T>
|
|
T TemplatedSequenceContext<T>::valueOfCommonRankSequenceAtPreviousRank(int sequenceIndex, int rank) const {
|
|
return m_commonRankValues[sequenceIndex][rank];
|
|
}
|
|
|
|
template<typename T>
|
|
void TemplatedSequenceContext<T>::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<typename T>
|
|
bool TemplatedSequenceContext<T>::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<typename T>
|
|
void TemplatedSequenceContext<T>::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<T*>(&m_commonRankValues);
|
|
rank = m_commonRank;
|
|
} else {
|
|
start = sequenceIndex;
|
|
stop = sequenceIndex + 1;
|
|
sequenceArray = reinterpret_cast<T*>(&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++) {
|
|
Ion::Storage::Record record = sequenceStore->recordAtIndex(i);
|
|
if (!record.isNull()) {
|
|
Sequence * u = sequenceStore->modelForRecord(record);
|
|
int index = stepMultipleSequences ? SequenceStore::sequenceIndexForName(u->fullName()[0]) : 0;
|
|
sequences[index] = u->isDefined() ? u : nullptr;
|
|
} else {
|
|
sequences[i] = 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<T>(rank, sqctx, sequenceIndex) : NAN;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template class TemplatedSequenceContext<float>;
|
|
template class TemplatedSequenceContext<double>;
|
|
template void * SequenceContext::helper<float>();
|
|
template void * SequenceContext::helper<double>();
|
|
|
|
}
|