mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
[apps] Sequence: enable to defined dependent sequences
This commit is contained in:
committed by
EmilieNumworks
parent
81e0148325
commit
032cafdb04
@@ -17,8 +17,9 @@ app_objs += $(addprefix apps/sequence/,\
|
||||
list/type_parameter_controller.o\
|
||||
values/interval_parameter_controller.o\
|
||||
values/values_controller.o\
|
||||
local_context.o\
|
||||
cache_context.o\
|
||||
sequence.o\
|
||||
sequence_context.o\
|
||||
sequence_store.o\
|
||||
sequence_title_cell.o\
|
||||
)
|
||||
|
||||
@@ -55,7 +55,7 @@ void App::Snapshot::tidy() {
|
||||
|
||||
App::App(Container * container, Snapshot * snapshot) :
|
||||
FunctionApp(container, snapshot, &m_inputViewController),
|
||||
m_nContext(((AppsContainer *)container)->globalContext()),
|
||||
m_sequenceContext(((AppsContainer *)container)->globalContext(), snapshot->sequenceStore()),
|
||||
m_listController(&m_listFooter, snapshot->sequenceStore(), &m_listHeader, &m_listFooter),
|
||||
m_listFooter(&m_listHeader, &m_listController, &m_listController, ButtonRowController::Position::Bottom, ButtonRowController::Style::EmbossedGrey),
|
||||
m_listHeader(nullptr, &m_listFooter, &m_listController),
|
||||
@@ -78,10 +78,7 @@ InputViewController * App::inputViewController() {
|
||||
}
|
||||
|
||||
Context * App::localContext() {
|
||||
if (m_tabViewController.activeTab() == 0) {
|
||||
return &m_nContext;
|
||||
}
|
||||
return TextFieldDelegateApp::localContext();
|
||||
return &m_sequenceContext;
|
||||
}
|
||||
|
||||
const char * App::XNT() {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <escher.h>
|
||||
#include <poincare.h>
|
||||
#include "local_context.h"
|
||||
#include "sequence_context.h"
|
||||
#include "sequence_store.h"
|
||||
#include "graph/graph_controller.h"
|
||||
#include "graph/curve_view_range.h"
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
const char * XNT() override;
|
||||
private:
|
||||
App(Container * container, Snapshot * snapshot);
|
||||
LocalContext<float> m_nContext;
|
||||
SequenceContext m_sequenceContext;
|
||||
ListController m_listController;
|
||||
ButtonRowController m_listFooter;
|
||||
ButtonRowController m_listHeader;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "local_context.h"
|
||||
#include "cache_context.h"
|
||||
#include <cmath>
|
||||
|
||||
using namespace Poincare;
|
||||
@@ -6,7 +6,7 @@ using namespace Poincare;
|
||||
namespace Sequence {
|
||||
|
||||
template<typename T>
|
||||
LocalContext<T>::LocalContext(Context * parentContext) :
|
||||
CacheContext<T>::CacheContext(Context * parentContext) :
|
||||
VariableContext<T>('n', parentContext),
|
||||
m_values{{Complex<T>::Float(NAN), Complex<T>::Float(NAN)},
|
||||
{Complex<T>::Float(NAN), Complex<T>::Float(NAN)}}
|
||||
@@ -14,7 +14,7 @@ LocalContext<T>::LocalContext(Context * parentContext) :
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const Expression * LocalContext<T>::expressionForSymbol(const Symbol * symbol) {
|
||||
const Expression * CacheContext<T>::expressionForSymbol(const Symbol * symbol) {
|
||||
if (symbol->name() == Symbol::SpecialSymbols::un || symbol->name() == Symbol::SpecialSymbols::un1 ||
|
||||
symbol->name() == Symbol::SpecialSymbols::vn || symbol->name() == Symbol::SpecialSymbols::vn1) {
|
||||
return &m_values[nameIndexForSymbol(symbol)][rankIndexForSymbol(symbol)];
|
||||
@@ -23,16 +23,12 @@ const Expression * LocalContext<T>::expressionForSymbol(const Symbol * symbol) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void LocalContext<T>::setValueForSequenceRank(T value, const char * sequenceName, int rank) {
|
||||
for (int i = 0; i < SequenceStore::k_maxNumberOfSequences; i++) {
|
||||
if (strcmp(sequenceName, SequenceStore::k_sequenceNames[i]) == 0) {
|
||||
m_values[i][rank] = Complex<T>::Float(value);
|
||||
}
|
||||
}
|
||||
void CacheContext<T>::setValueForSymbol(T value, const Poincare::Symbol * symbol) {
|
||||
m_values[nameIndexForSymbol(symbol)][rankIndexForSymbol(symbol)] = Complex<T>::Float(value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
int LocalContext<T>::nameIndexForSymbol(const Poincare::Symbol * symbol) {
|
||||
int CacheContext<T>::nameIndexForSymbol(const Poincare::Symbol * symbol) {
|
||||
switch (symbol->name()) {
|
||||
case Symbol::SpecialSymbols::un:
|
||||
return 0;
|
||||
@@ -48,7 +44,7 @@ int LocalContext<T>::nameIndexForSymbol(const Poincare::Symbol * symbol) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
int LocalContext<T>::rankIndexForSymbol(const Poincare::Symbol * symbol) {
|
||||
int CacheContext<T>::rankIndexForSymbol(const Poincare::Symbol * symbol) {
|
||||
switch (symbol->name()) {
|
||||
case Symbol::SpecialSymbols::un:
|
||||
return 0;
|
||||
@@ -63,7 +59,7 @@ int LocalContext<T>::rankIndexForSymbol(const Poincare::Symbol * symbol) {
|
||||
}
|
||||
}
|
||||
|
||||
template class LocalContext<float>;
|
||||
template class LocalContext<double>;
|
||||
template class CacheContext<float>;
|
||||
template class CacheContext<double>;
|
||||
|
||||
}
|
||||
23
apps/sequence/cache_context.h
Normal file
23
apps/sequence/cache_context.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef SEQUENCE_CACHE_CONTEXT_H
|
||||
#define SEQUENCE_CACHE_CONTEXT_H
|
||||
|
||||
#include <poincare.h>
|
||||
#include "sequence_context.h"
|
||||
|
||||
namespace Sequence {
|
||||
|
||||
template<typename T>
|
||||
class CacheContext : public Poincare::VariableContext<T> {
|
||||
public:
|
||||
CacheContext(Poincare::Context * parentContext);
|
||||
const Poincare::Expression * expressionForSymbol(const Poincare::Symbol * symbol) override;
|
||||
void setValueForSymbol(T value, const Poincare::Symbol * symbol);
|
||||
private:
|
||||
int nameIndexForSymbol(const Poincare::Symbol * symbol);
|
||||
int rankIndexForSymbol(const Poincare::Symbol * symbol);
|
||||
Poincare::Complex<T> m_values[MaxNumberOfSequences][MaxRecurrenceDepth];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -41,7 +41,7 @@ private:
|
||||
View * loadView() override;
|
||||
void unloadView(View * view) override;
|
||||
static constexpr KDCoordinate k_emptySubRowHeight = 30;
|
||||
constexpr static int k_maxNumberOfRows = 3*SequenceStore::k_maxNumberOfSequences;
|
||||
constexpr static int k_maxNumberOfRows = 3*MaxNumberOfSequences;
|
||||
SequenceStore * m_sequenceStore;
|
||||
SequenceTitleCell * m_sequenceTitleCells[k_maxNumberOfRows];
|
||||
Shared::FunctionExpressionCell * m_expressionCells[k_maxNumberOfRows];
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
#ifndef SEQUENCE_LOCAL_CONTEXT_H
|
||||
#define SEQUENCE_LOCAL_CONTEXT_H
|
||||
|
||||
#include <poincare.h>
|
||||
#include "sequence_store.h"
|
||||
|
||||
namespace Sequence {
|
||||
|
||||
template<typename T>
|
||||
class LocalContext : public Poincare::VariableContext<T> {
|
||||
public:
|
||||
LocalContext(Poincare::Context * parentContext);
|
||||
const Poincare::Expression * expressionForSymbol(const Poincare::Symbol * symbol) override;
|
||||
void setValueForSequenceRank(T value, const char * sequenceName, int rank);
|
||||
private:
|
||||
constexpr static int k_depth = 2;
|
||||
int nameIndexForSymbol(const Poincare::Symbol * symbol);
|
||||
int rankIndexForSymbol(const Poincare::Symbol * symbol);
|
||||
Poincare::Complex<T> m_values[SequenceStore::k_maxNumberOfSequences][k_depth];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "sequence.h"
|
||||
#include "local_context.h"
|
||||
#include "sequence_store.h"
|
||||
#include "cache_context.h"
|
||||
#include "../../poincare/src/layout/string_layout.h"
|
||||
#include "../../poincare/src/layout/baseline_relative_layout.h"
|
||||
#include <string.h>
|
||||
@@ -22,11 +23,7 @@ Sequence::Sequence(const char * text, KDColor color) :
|
||||
m_nameLayout(nullptr),
|
||||
m_definitionName(nullptr),
|
||||
m_firstInitialConditionName(nullptr),
|
||||
m_secondInitialConditionName(nullptr),
|
||||
m_indexBufferFloat{-1, -1},
|
||||
m_indexBufferDouble{-1, -1},
|
||||
m_bufferFloat{NAN, NAN},
|
||||
m_bufferDouble{NAN, NAN}
|
||||
m_secondInitialConditionName(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -77,7 +74,6 @@ Sequence& Sequence::operator=(const Sequence& other) {
|
||||
setContent(contentText);
|
||||
setFirstInitialConditionContent(firstInitialText);
|
||||
setSecondInitialConditionContent(secondInitialText);
|
||||
resetBuffer();
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -130,7 +126,7 @@ void Sequence::setType(Type type) {
|
||||
}
|
||||
setFirstInitialConditionContent("");
|
||||
setSecondInitialConditionContent("");
|
||||
resetBuffer();
|
||||
//sqctx->resetCache();
|
||||
}
|
||||
|
||||
Poincare::Expression * Sequence::firstInitialConditionExpression(Context * context) const {
|
||||
@@ -177,7 +173,7 @@ Poincare::ExpressionLayout * Sequence::secondInitialConditionLayout() {
|
||||
|
||||
void Sequence::setContent(const char * c) {
|
||||
Function::setContent(c);
|
||||
resetBuffer();
|
||||
//sqctx->resetCache();
|
||||
}
|
||||
|
||||
void Sequence::setFirstInitialConditionContent(const char * c) {
|
||||
@@ -190,7 +186,7 @@ void Sequence::setFirstInitialConditionContent(const char * c) {
|
||||
delete m_firstInitialConditionLayout;
|
||||
m_firstInitialConditionLayout = nullptr;
|
||||
}
|
||||
resetBuffer();
|
||||
//sqctx->resetCache();
|
||||
}
|
||||
|
||||
void Sequence::setSecondInitialConditionContent(const char * c) {
|
||||
@@ -203,7 +199,7 @@ void Sequence::setSecondInitialConditionContent(const char * c) {
|
||||
delete m_secondInitialConditionLayout;
|
||||
m_secondInitialConditionLayout = nullptr;
|
||||
}
|
||||
resetBuffer();
|
||||
//sqctx->resetCache();
|
||||
}
|
||||
|
||||
char Sequence::symbol() const {
|
||||
@@ -281,71 +277,66 @@ bool Sequence::isEmpty() {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T Sequence::templatedApproximateAtAbscissa(T x, Poincare::Context * context) const {
|
||||
T Sequence::templatedApproximateAtAbscissa(T x, SequenceContext * sqctx) const {
|
||||
T n = std::round(x);
|
||||
int sequenceIndex = name() == SequenceStore::k_sequenceNames[0] ? 0 : 1;
|
||||
if (sqctx->iterateUntilRank<T>(n)) {
|
||||
return sqctx->valueOfSequenceAtPreviousRank<T>(sequenceIndex, 0);
|
||||
}
|
||||
return NAN;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T Sequence::approximateToNextRank(int n, SequenceContext * sqctx) const {
|
||||
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 nSymbol(symbol());
|
||||
Poincare::Symbol vnSymbol(Symbol::SpecialSymbols::vn);
|
||||
Poincare::Symbol vn1Symbol(Symbol::SpecialSymbols::vn1);
|
||||
Poincare::Symbol unSymbol(Symbol::SpecialSymbols::un);
|
||||
Poincare::Symbol un1Symbol(Symbol::SpecialSymbols::un1);
|
||||
switch (m_type) {
|
||||
case Type::Explicite:
|
||||
if (n < 0) {
|
||||
return NAN;
|
||||
}
|
||||
return Shared::Function::evaluateAtAbscissa(n, context);
|
||||
{
|
||||
ctx.setValueForSymbol(un, &unSymbol);
|
||||
ctx.setValueForSymbol(vn, &vnSymbol);
|
||||
Poincare::Complex<T> e = Poincare::Complex<T>::Float(n);
|
||||
ctx.setExpressionForSymbolName(&e, &nSymbol, *sqctx);
|
||||
return expression(sqctx)->template approximateToScalar<T>(ctx);
|
||||
}
|
||||
case Type::SingleRecurrence:
|
||||
{
|
||||
if (n < 0 || n > k_maxRecurrentRank) {
|
||||
return NAN;
|
||||
}
|
||||
if (n == 0) {
|
||||
setBufferIndexValue<T>(0,0);
|
||||
setBufferValue(firstInitialConditionExpression(context)->approximateToScalar<T>(*context), 0);
|
||||
return bufferValue<T>(0);
|
||||
return firstInitialConditionExpression(sqctx)->template approximateToScalar<T>(*sqctx);
|
||||
}
|
||||
LocalContext<T> subContext = LocalContext<T>(context);
|
||||
Poincare::Symbol nSymbol(symbol());
|
||||
int start = indexBuffer<T>(0) < 0 || indexBuffer<T>(0) > n ? 0 : indexBuffer<T>(0);
|
||||
T un = indexBuffer<T>(0) < 0 || indexBuffer<T>(0) > n ? firstInitialConditionExpression(context)->approximateToScalar<T>(*context) : bufferValue<T>(0);
|
||||
for (int i = start; i < n; i++) {
|
||||
subContext.setValueForSequenceRank(un, name(), 0);
|
||||
Poincare::Complex<T> e = Poincare::Complex<T>::Float(i);
|
||||
subContext.setExpressionForSymbolName(&e, &nSymbol, subContext);
|
||||
un = expression(&subContext)-> template approximateToScalar<T>(subContext);
|
||||
}
|
||||
setBufferValue(un, 0);
|
||||
setBufferIndexValue<T>(n, 0);
|
||||
return un;
|
||||
ctx.setValueForSymbol(un, &un1Symbol);
|
||||
ctx.setValueForSymbol(unm1, &unSymbol);
|
||||
ctx.setValueForSymbol(vn, &vn1Symbol);
|
||||
ctx.setValueForSymbol(vnm1, &vnSymbol);
|
||||
Poincare::Complex<T> e = Poincare::Complex<T>::Float(n-1);
|
||||
ctx.setExpressionForSymbolName(&e, &nSymbol, *sqctx);
|
||||
return expression(sqctx)->template approximateToScalar<T>(ctx);
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (n < 0 || n > k_maxRecurrentRank) {
|
||||
return NAN;
|
||||
}
|
||||
if (n == 0) {
|
||||
return firstInitialConditionExpression(context)->approximateToScalar<T>(*context);
|
||||
return firstInitialConditionExpression(sqctx)->template approximateToScalar<T>(*sqctx);
|
||||
}
|
||||
if (n == 1) {
|
||||
setBufferIndexValue<T>(0, 0);
|
||||
setBufferValue(firstInitialConditionExpression(context)->approximateToScalar<T>(*context), 0);
|
||||
setBufferIndexValue<T>(1, 1);
|
||||
setBufferValue(secondInitialConditionExpression(context)->approximateToScalar<T>(*context), 1);
|
||||
return bufferValue<T>(1);
|
||||
return secondInitialConditionExpression(sqctx)->template approximateToScalar<T>(*sqctx);
|
||||
}
|
||||
LocalContext<T> subContext = LocalContext<T>(context);
|
||||
Poincare::Symbol nSymbol(symbol());
|
||||
int start = indexBuffer<T>(0) >= 0 && indexBuffer<T>(0) < n && indexBuffer<T>(1) > 0 && indexBuffer<T>(1) <= n && indexBuffer<T>(0) + 1 == indexBuffer<T>(1) ? indexBuffer<T>(0) : 0;
|
||||
T un = indexBuffer<T>(0) >= 0 && indexBuffer<T>(0) < n && indexBuffer<T>(1) > 0 && indexBuffer<T>(1) <= n && indexBuffer<T>(0) + 1 == indexBuffer<T>(1) ? bufferValue<T>(0) : firstInitialConditionExpression(context)->approximateToScalar<T>(*context);
|
||||
T un1 = indexBuffer<T>(0) >= 0 && indexBuffer<T>(0) < n && indexBuffer<T>(1) > 0 && indexBuffer<T>(1) <= n && indexBuffer<T>(0) + 1 == indexBuffer<T>(1) ? bufferValue<T>(1) : secondInitialConditionExpression(context)->approximateToScalar<T>(*context);
|
||||
for (int i = start; i < n-1; i++) {
|
||||
subContext.setValueForSequenceRank(un, name(), 0);
|
||||
subContext.setValueForSequenceRank(un1, name(), 1);
|
||||
Poincare::Complex<T> e = Poincare::Complex<T>::Float(i);
|
||||
subContext.setExpressionForSymbolName(&e, &nSymbol, subContext);
|
||||
un = un1;
|
||||
un1 = expression(&subContext)->template approximateToScalar<T>(subContext);
|
||||
}
|
||||
setBufferValue(un, 0);
|
||||
setBufferIndexValue<T>(n-1, 0);
|
||||
setBufferValue(un1, 1);
|
||||
setBufferIndexValue<T>(n, 1);
|
||||
return un1;
|
||||
ctx.setValueForSymbol(unm1, &un1Symbol);
|
||||
ctx.setValueForSymbol(unm2, &unSymbol);
|
||||
ctx.setValueForSymbol(vnm1, &vn1Symbol);
|
||||
ctx.setValueForSymbol(vnm2, &vnSymbol);
|
||||
Poincare::Complex<T> e = Poincare::Complex<T>::Float(n-2);
|
||||
ctx.setExpressionForSymbolName(&e, &nSymbol, *sqctx);
|
||||
return expression(sqctx)->template approximateToScalar<T>(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -402,11 +393,6 @@ void Sequence::tidy() {
|
||||
}
|
||||
}
|
||||
|
||||
void Sequence::resetBuffer() const {
|
||||
m_indexBufferFloat[0] = -1;
|
||||
m_indexBufferFloat[1] = -1;
|
||||
m_indexBufferDouble[0] = -1;
|
||||
m_indexBufferDouble[1] = -1;
|
||||
}
|
||||
|
||||
template double Sequence::approximateToNextRank<double>(int, SequenceContext*) const;
|
||||
template float Sequence::approximateToNextRank<float>(int, SequenceContext*) const;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define SEQUENCE_SEQUENCE_H
|
||||
|
||||
#include "../shared/function.h"
|
||||
#include "sequence_context.h"
|
||||
#include <assert.h>
|
||||
|
||||
namespace Sequence {
|
||||
@@ -39,20 +40,21 @@ public:
|
||||
bool isDefined() override;
|
||||
bool isEmpty() override;
|
||||
float evaluateAtAbscissa(float x, Poincare::Context * context) const override {
|
||||
return templatedApproximateAtAbscissa(x, context);
|
||||
return templatedApproximateAtAbscissa(x, static_cast<SequenceContext *>(context));
|
||||
}
|
||||
double evaluateAtAbscissa(double x, Poincare::Context * context) const override {
|
||||
return templatedApproximateAtAbscissa(x, context);
|
||||
return templatedApproximateAtAbscissa(x, static_cast<SequenceContext *>(context));
|
||||
}
|
||||
template<typename T> T approximateToNextRank(int n, SequenceContext * sqctx) const;
|
||||
double sumOfTermsBetweenAbscissa(double start, double end, Poincare::Context * context);
|
||||
void tidy() override;
|
||||
|
||||
private:
|
||||
constexpr static int k_maxRecurrentRank = 10000;
|
||||
constexpr static double k_maxNumberOfTermsInSum = 100000.0;
|
||||
constexpr static size_t k_dataLengthInBytes = (3*TextField::maxBufferSize()+3)*sizeof(char)+1;
|
||||
static_assert((k_dataLengthInBytes & 0x3) == 0, "The sequence data size is not a multiple of 4 bytes (cannot compute crc)"); // Assert that dataLengthInBytes is a multiple of 4
|
||||
char symbol() const override;
|
||||
template<typename T> T templatedApproximateAtAbscissa(T x, Poincare::Context * context) const;
|
||||
template<typename T> T templatedApproximateAtAbscissa(T x, SequenceContext * sqctx) const;
|
||||
Type m_type;
|
||||
char m_firstInitialConditionText[TextField::maxBufferSize()];
|
||||
char m_secondInitialConditionText[TextField::maxBufferSize()];
|
||||
@@ -64,49 +66,6 @@ private:
|
||||
Poincare::ExpressionLayout * m_definitionName;
|
||||
Poincare::ExpressionLayout * m_firstInitialConditionName;
|
||||
Poincare::ExpressionLayout * m_secondInitialConditionName;
|
||||
/* In order to accelerate the computation of values of recurrent sequences,
|
||||
* we memoize the last computed values of the sequence and their associated
|
||||
* ranks (n and n+1 for instance). Thereby, when another evaluation at a
|
||||
* superior rank k > n+1 is called, we avoid iterating from 0 but can start
|
||||
* from n. */
|
||||
constexpr static int k_maxRecurrenceDepth = 2;
|
||||
mutable int m_indexBufferFloat[k_maxRecurrenceDepth];
|
||||
mutable int m_indexBufferDouble[k_maxRecurrenceDepth];
|
||||
mutable float m_bufferFloat[k_maxRecurrenceDepth];
|
||||
mutable double m_bufferDouble[k_maxRecurrenceDepth];
|
||||
void resetBuffer() const;
|
||||
template<typename T> void setBufferValue(T value, int i) const {
|
||||
assert(i >= 0 && i < k_maxRecurrentRank);
|
||||
if (sizeof(T) == sizeof(float)) {
|
||||
m_bufferFloat[i] = value;
|
||||
} else {
|
||||
m_bufferDouble[i] = value;
|
||||
}
|
||||
}
|
||||
template<typename T> void setBufferIndexValue(int index, int i) const {
|
||||
assert(i >= 0 && i < k_maxRecurrentRank);
|
||||
if (sizeof(T) == sizeof(float)) {
|
||||
m_indexBufferFloat[i] = index;
|
||||
} else {
|
||||
m_indexBufferDouble[i] = index;
|
||||
}
|
||||
}
|
||||
template<typename T> T bufferValue(int i) const {
|
||||
assert(i >= 0 && i < k_maxRecurrentRank);
|
||||
if (sizeof(T) == sizeof(float)) {
|
||||
return m_bufferFloat[i];
|
||||
} else {
|
||||
return m_bufferDouble[i];
|
||||
}
|
||||
}
|
||||
template<typename T> int indexBuffer(int i) const {
|
||||
assert(i >= 0 && i < k_maxRecurrentRank);
|
||||
if (sizeof(T) == sizeof(float)) {
|
||||
return m_indexBufferFloat[i];
|
||||
} else {
|
||||
return m_indexBufferDouble[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
66
apps/sequence/sequence_context.cpp
Normal file
66
apps/sequence/sequence_context.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#include "sequence_context.h"
|
||||
#include "sequence_store.h"
|
||||
#include <cmath>
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Sequence {
|
||||
|
||||
template<typename T>
|
||||
TemplatedSequenceContext<T>::TemplatedSequenceContext() :
|
||||
m_rank(-1),
|
||||
m_values{{NAN, NAN, NAN},{NAN, NAN, NAN}}
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T TemplatedSequenceContext<T>::valueOfSequenceAtPreviousRank(int sequenceIndex, int rank) const {
|
||||
return m_values[sequenceIndex][rank];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void TemplatedSequenceContext<T>::resetCache() {
|
||||
m_rank = -1;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool TemplatedSequenceContext<T>::iterateUntilRank(int n, SequenceStore * sequenceStore, SequenceContext * sqctx) {
|
||||
if (m_rank > n) {
|
||||
m_rank = -1;
|
||||
}
|
||||
if (n < 0 || n-m_rank > k_maxRecurrentRank) {
|
||||
return false;
|
||||
}
|
||||
while (m_rank++ < n) {
|
||||
step(sequenceStore, 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++) {
|
||||
for (int j = MaxRecurrenceDepth; j > 0; j--) {
|
||||
m_values[i][j] = m_values[i][j-1];
|
||||
}
|
||||
m_values[i][0] = NAN;
|
||||
}
|
||||
|
||||
/* Evaluate new u(n) and v(n) */
|
||||
Sequence * u = sequenceStore->numberOfFunctions() > 0 ? sequenceStore->functionAtIndex(0) : nullptr;
|
||||
u = u && u->isDefined() ? u : nullptr;
|
||||
Sequence * v = sequenceStore->numberOfFunctions() > 1 ? sequenceStore->functionAtIndex(1) : nullptr;
|
||||
v = v && v->isDefined() ? v : nullptr;
|
||||
|
||||
/* TODO: explain */
|
||||
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;
|
||||
}
|
||||
|
||||
template class TemplatedSequenceContext<float>;
|
||||
template class TemplatedSequenceContext<double>;
|
||||
|
||||
}
|
||||
77
apps/sequence/sequence_context.h
Normal file
77
apps/sequence/sequence_context.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#ifndef SEQUENCE_SEQUENCE_CONTEXT_H
|
||||
#define SEQUENCE_SEQUENCE_CONTEXT_H
|
||||
|
||||
#include <poincare.h>
|
||||
|
||||
namespace Sequence {
|
||||
|
||||
constexpr static int MaxRecurrenceDepth = 2;
|
||||
static constexpr int MaxNumberOfSequences = 2;
|
||||
|
||||
class SequenceStore;
|
||||
class SequenceContext;
|
||||
|
||||
template<typename T>
|
||||
class TemplatedSequenceContext {
|
||||
public:
|
||||
TemplatedSequenceContext();
|
||||
T valueOfSequenceAtPreviousRank(int sequenceIndex, int rank) const;
|
||||
void resetCache();
|
||||
bool iterateUntilRank(int n, SequenceStore * sequenceStore, SequenceContext * sqctx);
|
||||
private:
|
||||
constexpr static int k_maxRecurrentRank = 10000;
|
||||
/* Cache:
|
||||
* In order to accelerate the computation of values of recurrent sequences,
|
||||
* we memoize the last computed values of the sequence and their associated
|
||||
* ranks (n and n+1 for instance). Thereby, when another evaluation at a
|
||||
* superior rank k > n+1 is called, we avoid iterating from 0 but can start
|
||||
* from n. */
|
||||
void step(SequenceStore * sequenceStore, SequenceContext * sqctx);
|
||||
int m_rank;
|
||||
T m_values[MaxNumberOfSequences][MaxRecurrenceDepth+1];
|
||||
};
|
||||
|
||||
class SequenceContext : public Poincare::Context {
|
||||
public:
|
||||
SequenceContext(Poincare::Context * parentContext, SequenceStore * sequenceStore) :
|
||||
Context(),
|
||||
m_floatSequenceContext(),
|
||||
m_doubleSequenceContext(),
|
||||
m_sequenceStore(sequenceStore),
|
||||
m_parentContext(parentContext) {}
|
||||
/* expressionForSymbol & setExpressionForSymbolName directly call the parent
|
||||
* context respective methods. Indeed, special chars like n, u(n), u(n+1),
|
||||
* v(n), v(n+1) are taken into accound only when evaluating sequences which
|
||||
* is done in another context. */
|
||||
const Poincare::Expression * expressionForSymbol(const Poincare::Symbol * symbol) override {
|
||||
return m_parentContext->expressionForSymbol(symbol);
|
||||
}
|
||||
void setExpressionForSymbolName(const Poincare::Expression * expression, const Poincare::Symbol * symbol, Poincare::Context & context) override {
|
||||
m_parentContext->setExpressionForSymbolName(expression, symbol, context);
|
||||
}
|
||||
template<typename T> T valueOfSequenceAtPreviousRank(int sequenceIndex, int rank) const {
|
||||
if (sizeof(T) == sizeof(float)) {
|
||||
return m_floatSequenceContext.valueOfSequenceAtPreviousRank(sequenceIndex, rank);
|
||||
}
|
||||
return m_doubleSequenceContext.valueOfSequenceAtPreviousRank(sequenceIndex, rank);
|
||||
}
|
||||
void resetCache() {
|
||||
m_floatSequenceContext.resetCache();
|
||||
m_doubleSequenceContext.resetCache();
|
||||
}
|
||||
template<typename T> bool iterateUntilRank(int n) {
|
||||
if (sizeof(T) == sizeof(float)) {
|
||||
return m_floatSequenceContext.iterateUntilRank(n, m_sequenceStore, this);
|
||||
}
|
||||
return m_doubleSequenceContext.iterateUntilRank(n, m_sequenceStore, this);
|
||||
}
|
||||
private:
|
||||
TemplatedSequenceContext<float> m_floatSequenceContext;
|
||||
TemplatedSequenceContext<double> m_doubleSequenceContext;
|
||||
SequenceStore * m_sequenceStore;
|
||||
Poincare::Context * m_parentContext;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -7,14 +7,14 @@ extern "C" {
|
||||
|
||||
namespace Sequence {
|
||||
|
||||
constexpr KDColor SequenceStore::k_defaultColors[k_maxNumberOfSequences];
|
||||
constexpr const char * SequenceStore::k_sequenceNames[k_maxNumberOfSequences];
|
||||
constexpr KDColor SequenceStore::k_defaultColors[MaxNumberOfSequences];
|
||||
constexpr const char * SequenceStore::k_sequenceNames[MaxNumberOfSequences];
|
||||
|
||||
uint32_t SequenceStore::storeChecksum() {
|
||||
size_t dataLengthInBytes = k_maxNumberOfSequences*sizeof(uint32_t);
|
||||
size_t dataLengthInBytes = MaxNumberOfSequences*sizeof(uint32_t);
|
||||
assert((dataLengthInBytes & 0x3) == 0); // Assert that dataLengthInBytes is a multiple of 4
|
||||
uint32_t checksums[k_maxNumberOfSequences];
|
||||
for (int i = 0; i < k_maxNumberOfSequences; i++) {
|
||||
uint32_t checksums[MaxNumberOfSequences];
|
||||
for (int i = 0; i < MaxNumberOfSequences; i++) {
|
||||
checksums[i] = m_sequences[i].checksum();
|
||||
}
|
||||
return Ion::crc32((uint32_t *)checksums, dataLengthInBytes/sizeof(uint32_t));
|
||||
@@ -34,7 +34,7 @@ Sequence * SequenceStore::definedFunctionAtIndex(int i) {
|
||||
}
|
||||
|
||||
Sequence * SequenceStore::addEmptyFunction() {
|
||||
assert(m_numberOfFunctions < k_maxNumberOfSequences);
|
||||
assert(m_numberOfFunctions < MaxNumberOfSequences);
|
||||
const char * name = firstAvailableName();
|
||||
KDColor color = firstAvailableColor();
|
||||
Sequence addedSequence(name, color);
|
||||
@@ -56,10 +56,11 @@ void SequenceStore::removeFunction(Shared::Function * f) {
|
||||
}
|
||||
Sequence emptySequence("", KDColorBlack);
|
||||
m_sequences[m_numberOfFunctions] = emptySequence;
|
||||
//sqctx->resetCache();
|
||||
}
|
||||
|
||||
int SequenceStore::maxNumberOfFunctions() {
|
||||
return k_maxNumberOfSequences;
|
||||
return MaxNumberOfSequences;
|
||||
}
|
||||
|
||||
char SequenceStore::symbol() const {
|
||||
@@ -67,7 +68,7 @@ char SequenceStore::symbol() const {
|
||||
}
|
||||
|
||||
const char * SequenceStore::firstAvailableName() {
|
||||
for (int k = 0; k < k_maxNumberOfSequences; k++) {
|
||||
for (int k = 0; k < MaxNumberOfSequences; k++) {
|
||||
int j = 0;
|
||||
while (j < m_numberOfFunctions) {
|
||||
if (m_sequences[j].name() == k_sequenceNames[k]) {
|
||||
@@ -83,7 +84,7 @@ const char * SequenceStore::firstAvailableName() {
|
||||
}
|
||||
|
||||
const KDColor SequenceStore::firstAvailableColor() {
|
||||
for (int k = 0; k < k_maxNumberOfSequences; k++) {
|
||||
for (int k = 0; k < MaxNumberOfSequences; k++) {
|
||||
int j = 0;
|
||||
while (j < m_numberOfFunctions) {
|
||||
if (m_sequences[j].color() == k_defaultColors[k]) {
|
||||
@@ -104,6 +105,7 @@ void SequenceStore::removeAll() {
|
||||
m_sequences[i] = emptySequence;
|
||||
}
|
||||
m_numberOfFunctions = 0;
|
||||
//sqctx->resetCache();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#ifndef SEQUENCE_SEQUENCE_STORE_H
|
||||
#define SEQUENCE_SEQUENCE_STORE_H
|
||||
|
||||
#include "sequence.h"
|
||||
#include "../shared/function_store.h"
|
||||
#include "sequence.h"
|
||||
#include <stdint.h>
|
||||
#include <escher.h>
|
||||
|
||||
@@ -21,16 +21,15 @@ public:
|
||||
const char * firstAvailableName() override;
|
||||
char symbol() const override;
|
||||
void removeAll() override;
|
||||
static constexpr int k_maxNumberOfSequences = 2;
|
||||
static constexpr const char * k_sequenceNames[k_maxNumberOfSequences] = {
|
||||
static constexpr const char * k_sequenceNames[MaxNumberOfSequences] = {
|
||||
"u", "v"//, "w"
|
||||
};
|
||||
private:
|
||||
const KDColor firstAvailableColor() override;
|
||||
static constexpr KDColor k_defaultColors[k_maxNumberOfSequences] = {
|
||||
static constexpr KDColor k_defaultColors[MaxNumberOfSequences] = {
|
||||
Palette::Red, Palette::Blue//, Palette::YellowDark
|
||||
};
|
||||
Sequence m_sequences[k_maxNumberOfSequences];
|
||||
Sequence m_sequences[MaxNumberOfSequences];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user