[app/sequence] Add a third sequence

This commit is contained in:
Émilie Feral
2019-07-16 18:10:46 +02:00
parent 7db5a10da9
commit 2e7fb601c8
6 changed files with 71 additions and 48 deletions

View File

@@ -8,17 +8,17 @@ namespace Sequence {
template<typename T>
CacheContext<T>::CacheContext(Context * parentContext) :
m_values{{NAN, NAN},
{NAN, NAN}},
m_values{{NAN, NAN},{NAN, NAN},{NAN,NAN}},
m_parentContext(parentContext)
{
}
template<typename T>
const Expression CacheContext<T>::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<Symbol &>(static_cast<const Symbol &>(symbol));
@@ -39,12 +39,10 @@ void CacheContext<T>::setValueForSymbol(T value, const Poincare::Symbol & symbol
template<typename T>
int CacheContext<T>::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<typename T>

View File

@@ -111,7 +111,7 @@ bool Sequence::isEmpty() {
template<typename T>
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<T>(n)) {
return sqctx->valueOfSequenceAtPreviousRank<T>(sequenceIndex, 0);
}
@@ -129,21 +129,30 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx) const {
Poincare::SerializationHelper::CodePoint(unknownN, bufferSize, UCodePointUnknownN);
CacheContext<T> ctx = CacheContext<T>(sqctx);
T un = sqctx->valueOfSequenceAtPreviousRank<T>(0, 0);
T unm1 = sqctx->valueOfSequenceAtPreviousRank<T>(0, 1);
T unm2 = sqctx->valueOfSequenceAtPreviousRank<T>(0, 2);
T vn = sqctx->valueOfSequenceAtPreviousRank<T>(1, 0);
T vnm1 = sqctx->valueOfSequenceAtPreviousRank<T>(1, 1);
T vnm2 = sqctx->valueOfSequenceAtPreviousRank<T>(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<T>(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<T>(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<T>(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);
}
}

View File

@@ -10,7 +10,7 @@ namespace Sequence {
template<typename T>
TemplatedSequenceContext<T>::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<T>::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<T>(m_rank, sqctx) : NAN;
m_values[1][0] = v ? v->approximateToNextRank<T>(m_rank, sqctx) : NAN;
m_values[0][0] = u ? u->approximateToNextRank<T>(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<T>(m_rank, sqctx) : NAN;
}
}
}
}
template class TemplatedSequenceContext<float>;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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: