mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[VariableBox] Added sequences to the variable box
It is now possible to call the value of a defined sequence anywhere. Change-Id: I1990e93c50f9add175b7ea274e07004ba63289e5
This commit is contained in:
committed by
Émilie Feral
parent
c006ed7b10
commit
3dca515441
@@ -41,7 +41,10 @@ apps_src += $(addprefix apps/,\
|
||||
title_bar_view.cpp \
|
||||
)
|
||||
|
||||
tests_src += apps/exam_mode_configuration_official.cpp
|
||||
tests_src += $(addprefix apps/,\
|
||||
exam_mode_configuration_official.cpp \
|
||||
)
|
||||
|
||||
|
||||
snapshots_declaration = $(foreach i,$(apps),$(i)::Snapshot m_snapshot$(subst :,,$(i))Snapshot;)
|
||||
apps_declaration = $(foreach i,$(apps),$(i) m_$(subst :,,$(i));)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "history_controller.h"
|
||||
#include "../shared/text_field_delegate_app.h"
|
||||
#include <escher.h>
|
||||
#include "../shared/shared_app.h"
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
@@ -17,7 +18,7 @@ public:
|
||||
I18n::Message upperName() override;
|
||||
const Image * icon() override;
|
||||
};
|
||||
class Snapshot : public ::App::Snapshot {
|
||||
class Snapshot : public ::SharedApp::Snapshot {
|
||||
public:
|
||||
Snapshot();
|
||||
App * unpack(Container * container) override;
|
||||
|
||||
@@ -169,7 +169,8 @@ Calculation::DisplayOutput Calculation::displayOutput(Context * context) {
|
||||
ExpressionNode::Type::Sum,
|
||||
ExpressionNode::Type::Derivative,
|
||||
ExpressionNode::Type::ConfidenceInterval,
|
||||
ExpressionNode::Type::PredictionInterval
|
||||
ExpressionNode::Type::PredictionInterval,
|
||||
ExpressionNode::Type::Sequence
|
||||
};
|
||||
return e.isOfType(approximateOnlyTypes, sizeof(approximateOnlyTypes)/sizeof(ExpressionNode::Type));
|
||||
}, context)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "script_store.h"
|
||||
#include "python_toolbox.h"
|
||||
#include "variable_box_controller.h"
|
||||
#include "../shared/shared_app.h"
|
||||
|
||||
namespace Code {
|
||||
|
||||
@@ -20,7 +21,7 @@ public:
|
||||
I18n::Message upperName() override;
|
||||
const Image * icon() override;
|
||||
};
|
||||
class Snapshot : public ::App::Snapshot {
|
||||
class Snapshot : public SharedApp::Snapshot {
|
||||
public:
|
||||
Snapshot();
|
||||
App * unpack(Container * container) override;
|
||||
|
||||
@@ -11,12 +11,13 @@
|
||||
#include "led_test_controller.h"
|
||||
#include "serial_number_controller.h"
|
||||
#include "vblank_test_controller.h"
|
||||
#include "../shared/shared_app.h"
|
||||
|
||||
namespace HardwareTest {
|
||||
|
||||
class App : public ::App {
|
||||
public:
|
||||
class Snapshot : public ::App::Snapshot {
|
||||
class Snapshot : public ::SharedApp::Snapshot {
|
||||
public:
|
||||
App * unpack(Container * container) override;
|
||||
Descriptor * descriptor() override;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <escher.h>
|
||||
#include "controller.h"
|
||||
#include "../shared/shared_app.h"
|
||||
|
||||
namespace Home {
|
||||
|
||||
@@ -13,7 +14,7 @@ public:
|
||||
I18n::Message name() override;
|
||||
I18n::Message upperName() override;
|
||||
};
|
||||
class Snapshot : public ::App::Snapshot, public SelectableTableViewDataSource {
|
||||
class Snapshot : public ::SharedApp::Snapshot, public SelectableTableViewDataSource {
|
||||
public:
|
||||
App * unpack(Container * container) override;
|
||||
Descriptor * descriptor() override;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <poincare/preferences.h>
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
#include <apps/shared/sequence.h>
|
||||
|
||||
using namespace Poincare;
|
||||
using namespace Shared;
|
||||
@@ -76,6 +77,8 @@ int MathVariableBoxController::numberOfRows() const {
|
||||
return Storage::sharedStorage()->numberOfRecordsWithExtension(Ion::Storage::expExtension);
|
||||
case Page::Function:
|
||||
return Storage::sharedStorage()->numberOfRecordsWithExtension(Ion::Storage::funcExtension);
|
||||
case Page::Sequence:
|
||||
return Storage::sharedStorage()->numberOfRecordsWithExtension(Ion::Storage::seqExtension);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -104,13 +107,19 @@ void MathVariableBoxController::willDisplayCellForIndex(HighlightCell * cell, in
|
||||
if (m_currentPage == Page::Expression) {
|
||||
static_assert(Shared::Function::k_maxNameWithArgumentSize > Poincare::SymbolAbstract::k_maxNameSize, "Forgot argument's size?");
|
||||
symbolLength = SymbolAbstract::TruncateExtension(symbolName, record.fullName(), SymbolAbstract::k_maxNameSize);
|
||||
} else {
|
||||
assert(m_currentPage == Page::Function);
|
||||
} else if (m_currentPage == Page::Function) {
|
||||
ContinuousFunction f(record);
|
||||
symbolLength = f.nameWithArgument(
|
||||
symbolName,
|
||||
Shared::Function::k_maxNameWithArgumentSize
|
||||
);
|
||||
} else {
|
||||
assert(m_currentPage == Page::Sequence);
|
||||
Shared::Sequence u(record);
|
||||
symbolLength = u.nameWithArgument(
|
||||
symbolName,
|
||||
Shared::Sequence::k_maxNameWithArgumentSize
|
||||
);
|
||||
}
|
||||
Layout symbolLayout = LayoutHelper::String(symbolName, symbolLength);
|
||||
myCell->setLayout(symbolLayout);
|
||||
@@ -147,7 +156,7 @@ MessageTableCellWithChevron * MathVariableBoxController::nodeCellAtIndex(int ind
|
||||
}
|
||||
|
||||
MathVariableBoxController::Page MathVariableBoxController::pageAtIndex(int index) {
|
||||
Page pages[2] = {Page::Expression, Page::Function};
|
||||
Page pages[k_numberOfMenuRows] = {Page::Expression, Page::Function, Page::Sequence};
|
||||
return pages[index];
|
||||
}
|
||||
|
||||
@@ -212,7 +221,7 @@ bool MathVariableBoxController::selectLeaf(int selectedRow) {
|
||||
|
||||
I18n::Message MathVariableBoxController::nodeLabelAtIndex(int index) {
|
||||
assert(m_currentPage == Page::RootMenu);
|
||||
I18n::Message labels[2] = {I18n::Message::Expressions, I18n::Message::Functions};
|
||||
I18n::Message labels[k_numberOfMenuRows] = {I18n::Message::Expressions, I18n::Message::Functions, I18n::Message::Sequences};
|
||||
return labels[index];
|
||||
}
|
||||
|
||||
@@ -248,7 +257,14 @@ Layout MathVariableBoxController::expressionLayoutForRecord(Storage::Record reco
|
||||
|
||||
const char * MathVariableBoxController::extension() const {
|
||||
assert(m_currentPage != Page::RootMenu);
|
||||
return m_currentPage == Page::Function ? Ion::Storage::funcExtension : Ion::Storage::expExtension;
|
||||
if (m_currentPage == Page::Function) {
|
||||
return Ion::Storage::funcExtension;
|
||||
} else if (m_currentPage == Page::Expression) {
|
||||
return Ion::Storage::expExtension;
|
||||
} else {
|
||||
assert(m_currentPage == Page::Sequence);
|
||||
return Ion::Storage::seqExtension;
|
||||
}
|
||||
}
|
||||
|
||||
Storage::Record MathVariableBoxController::recordAtIndex(int rowIndex) {
|
||||
|
||||
@@ -27,13 +27,14 @@ public:
|
||||
enum class Page {
|
||||
RootMenu = 0,
|
||||
Expression = 1,
|
||||
Function = 2
|
||||
Function = 2,
|
||||
Sequence = 3
|
||||
};
|
||||
void lockDeleteEvent(Page page) { m_lockPageDelete = page; }
|
||||
|
||||
private:
|
||||
constexpr static int k_maxNumberOfDisplayedRows = (Ion::Display::Height - Metric::TitleBarHeight - Metric::PopUpTopMargin - Metric::StackTitleHeight) / Metric::ToolboxRowHeight + 2; // (240 - 18 - 50 - 20) / 40 = 3.8; the 0.8 cell can be above and below so we add +2 to get 5
|
||||
constexpr static int k_numberOfMenuRows = 2;
|
||||
constexpr static int k_numberOfMenuRows = 3;
|
||||
constexpr static KDCoordinate k_leafMargin = 20;
|
||||
ExpressionTableCellWithExpression * leafCellAtIndex(int index) override;
|
||||
MessageTableCellWithChevron * nodeCellAtIndex(int index) override;
|
||||
|
||||
@@ -45,6 +45,12 @@ void MathVariableBoxEmptyController::setType(Type type) {
|
||||
layout = Poincare::LayoutHelper::String(storeFunction, strlen(storeFunction), MathVariableBoxEmptyView::k_font);
|
||||
break;
|
||||
}
|
||||
case Type::Sequence:
|
||||
{
|
||||
messages[0] = I18n::Message::EmptySequenceBox0;
|
||||
messages[3] = I18n::Message::Default;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ public:
|
||||
enum class Type {
|
||||
None = 0,
|
||||
Expressions = 1,
|
||||
Functions = 2
|
||||
Functions = 2,
|
||||
Sequence = 3
|
||||
};
|
||||
void setType(Type type);
|
||||
// View Controller
|
||||
|
||||
@@ -4,12 +4,13 @@
|
||||
#include <escher.h>
|
||||
#include "logo_controller.h"
|
||||
#include "localization_controller.h"
|
||||
#include "../shared/shared_app.h"
|
||||
|
||||
namespace OnBoarding {
|
||||
|
||||
class App : public ::App {
|
||||
public:
|
||||
class Snapshot : public ::App::Snapshot {
|
||||
class Snapshot : public ::SharedApp::Snapshot {
|
||||
public:
|
||||
App * unpack(Container * container) override;
|
||||
Descriptor * descriptor() override;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "calculation/left_integral_calculation.h"
|
||||
#include "calculation/right_integral_calculation.h"
|
||||
#include "calculation/finite_integral_calculation.h"
|
||||
#include "../shared/shared_app.h"
|
||||
|
||||
constexpr static size_t max(const int * data, int seed = 0) {
|
||||
return (*data == 0 ? seed : max(data+1, *data > seed ? *data : seed));
|
||||
@@ -29,7 +30,7 @@ public:
|
||||
I18n::Message upperName() override;
|
||||
const Image * icon() override;
|
||||
};
|
||||
class Snapshot : public ::App::Snapshot {
|
||||
class Snapshot : public ::SharedApp::Snapshot {
|
||||
public:
|
||||
enum class Page {
|
||||
Distribution,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "regression_controller.h"
|
||||
#include "store.h"
|
||||
#include "store_controller.h"
|
||||
#include "../shared/shared_app.h"
|
||||
|
||||
namespace Regression {
|
||||
|
||||
@@ -19,7 +20,7 @@ public:
|
||||
I18n::Message upperName() override;
|
||||
const Image * icon() override;
|
||||
};
|
||||
class Snapshot : public ::App::Snapshot, public TabViewDataSource {
|
||||
class Snapshot : public ::SharedApp::Snapshot, public TabViewDataSource {
|
||||
public:
|
||||
Snapshot();
|
||||
App * unpack(Container * container) override;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "app.h"
|
||||
#include "../apps_container.h"
|
||||
#include "sequence_icon.h"
|
||||
#include "../shared/global_context.h"
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
@@ -20,7 +21,6 @@ const Image * App::Descriptor::icon() {
|
||||
|
||||
App::Snapshot::Snapshot() :
|
||||
Shared::FunctionApp::Snapshot::Snapshot(),
|
||||
m_sequenceStore(),
|
||||
m_graphRange()
|
||||
{
|
||||
}
|
||||
@@ -40,13 +40,12 @@ App::Descriptor * App::Snapshot::descriptor() {
|
||||
}
|
||||
|
||||
void App::Snapshot::tidy() {
|
||||
m_sequenceStore.tidy();
|
||||
m_graphRange.setDelegate(nullptr);
|
||||
}
|
||||
|
||||
App::App(Snapshot * snapshot) :
|
||||
FunctionApp(snapshot, &m_inputViewController),
|
||||
m_sequenceContext(AppsContainer::sharedAppsContainer()->globalContext(), snapshot->functionStore()),
|
||||
m_sequenceContext(AppsContainer::sharedAppsContainer()->globalContext(), static_cast<Shared::GlobalContext *>(AppsContainer::sharedAppsContainer()->globalContext())->sequenceStore()),
|
||||
m_listController(&m_listFooter, this, &m_listHeader, &m_listFooter),
|
||||
m_listFooter(&m_listHeader, &m_listController, &m_listController, ButtonRowController::Position::Bottom, ButtonRowController::Style::EmbossedGray),
|
||||
m_listHeader(nullptr, &m_listFooter, &m_listController),
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "values/values_controller.h"
|
||||
#include "../shared/function_app.h"
|
||||
#include "../shared/interval.h"
|
||||
#include "../shared/global_context.h"
|
||||
#include "../apps_container.h"
|
||||
|
||||
namespace Sequence {
|
||||
|
||||
@@ -27,12 +29,11 @@ public:
|
||||
App * unpack(Container * container) override;
|
||||
void reset() override;
|
||||
Descriptor * descriptor() override;
|
||||
Shared::SequenceStore * functionStore() override { return &m_sequenceStore; }
|
||||
Shared::SequenceStore * functionStore() override { return static_cast<Shared::GlobalContext *>(AppsContainer::sharedAppsContainer()->globalContext())->sequenceStore(); }
|
||||
CurveViewRange * graphRange() { return &m_graphRange; }
|
||||
Shared::Interval * interval() { return &m_interval; }
|
||||
private:
|
||||
void tidy() override;
|
||||
Shared::SequenceStore m_sequenceStore;
|
||||
CurveViewRange m_graphRange;
|
||||
Shared::Interval m_interval;
|
||||
};
|
||||
@@ -47,7 +48,7 @@ public:
|
||||
// NestedMenuController * variableBoxForInputEventHandler(InputEventHandler * textInput) override;
|
||||
CodePoint XNT() override { return 'n'; }
|
||||
Shared::SequenceContext * localContext() override;
|
||||
Shared::SequenceStore * functionStore() override { return snapshot()->functionStore(); }
|
||||
Shared::SequenceStore * functionStore() override { return static_cast<Shared::GlobalContext *>(AppsContainer::sharedAppsContainer()->globalContext())->sequenceStore(); }
|
||||
Shared::Interval * interval() { return snapshot()->interval(); }
|
||||
ValuesController * valuesController() override {
|
||||
return &m_valuesController;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "main_controller.h"
|
||||
#include "../shared/text_field_delegate_app.h"
|
||||
#include "../shared/shared_app.h"
|
||||
|
||||
namespace Settings {
|
||||
|
||||
@@ -14,7 +15,7 @@ public:
|
||||
I18n::Message upperName() override;
|
||||
const Image * icon() override;
|
||||
};
|
||||
class Snapshot : public ::App::Snapshot {
|
||||
class Snapshot : public ::SharedApp::Snapshot {
|
||||
public:
|
||||
App * unpack(Container * container) override;
|
||||
Descriptor * descriptor() override;
|
||||
|
||||
@@ -64,14 +64,15 @@ app_shared_src = $(addprefix apps/shared/,\
|
||||
range_parameter_controller.cpp \
|
||||
regular_table_view_data_source.cpp \
|
||||
round_cursor_view.cpp \
|
||||
scrollable_multiple_expressions_view.cpp \
|
||||
scrollable_two_expressions_cell.cpp \
|
||||
sequence.cpp\
|
||||
sequence_context.cpp\
|
||||
sequence_store.cpp\
|
||||
sequence_title_cell.cpp \
|
||||
scrollable_multiple_expressions_view.cpp \
|
||||
scrollable_two_expressions_cell.cpp \
|
||||
separable.cpp \
|
||||
separator_even_odd_buffer_text_cell.cpp \
|
||||
shared_app.cpp \
|
||||
simple_interactive_curve_view_controller.cpp \
|
||||
store_cell.cpp \
|
||||
store_controller.cpp \
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#include "cache_context.h"
|
||||
#include "sequence.h"
|
||||
#include "sequence_store.h"
|
||||
#include "../shared/poincare_helpers.h"
|
||||
#include "poincare_helpers.h"
|
||||
#include <poincare/serialization_helper.h>
|
||||
#include <poincare/addition.h>
|
||||
#include <poincare/rational.h>
|
||||
#include <cmath>
|
||||
|
||||
using namespace Poincare;
|
||||
@@ -20,23 +22,22 @@ template<typename T>
|
||||
const Expression CacheContext<T>::expressionForSymbolAbstract(const SymbolAbstract & symbol, bool clone) {
|
||||
// [u|v|w](n(+1)?)
|
||||
if (symbol.type() == ExpressionNode::Type::Sequence) {
|
||||
Symbol s = const_cast<Symbol &>(static_cast<const Symbol &>(symbol));
|
||||
if (s.childAtIndex(0).type() == ExpressionNode::Type::Symbol) {
|
||||
return Float<T>::Builder(m_values[nameIndexForSymbol(s)][0]);
|
||||
} else if (s.childAtIndex(0).type() == ExpressionNode::Type::Addition) {
|
||||
return Float<T>::Builder(m_values[nameIndexForSymbol(s)][1]);
|
||||
int index = nameIndexForSymbol(const_cast<Symbol &>(static_cast<const Symbol &>(symbol)));
|
||||
Expression rank = symbol.childAtIndex(0).clone();
|
||||
if (rank.isIdenticalTo(Symbol::Builder(UCodePointUnknown))) {
|
||||
return Float<T>::Builder(m_values[index][0]);
|
||||
} if (rank.isIdenticalTo(Addition::Builder(Symbol::Builder(UCodePointUnknown), Rational::Builder(1)))) {
|
||||
return Float<T>::Builder(m_values[index][1]);
|
||||
}
|
||||
Ion::Storage::Record record = m_sequenceContext->sequenceStore()->recordAtIndex(index);
|
||||
Sequence * seq = m_sequenceContext->sequenceStore()->modelForRecord(record);
|
||||
rank.replaceSymbolWithExpression(Symbol::Builder(UCodePointUnknown), Float<T>::Builder(m_nValue));
|
||||
T n = PoincareHelpers::ApproximateToScalar<T>(rank, this);
|
||||
// In case the rank is not int or sequence referenced is not defined, return NAN
|
||||
if (std::floor(n) == n && seq->fullName() != nullptr) {
|
||||
return Float<T>::Builder(seq->valueAtRank<T>(n, m_sequenceContext));
|
||||
} else {
|
||||
Sequence seq = m_sequenceContext->sequenceStore()->sequenceAtIndex(nameIndexForSymbol(s));
|
||||
// In case the sequence referenced is not defined, return NAN
|
||||
if (seq.fullName() == nullptr) {
|
||||
return Float<T>::Builder(NAN);
|
||||
}
|
||||
Expression rank = symbol.childAtIndex(0);
|
||||
if (rank.isNumber()) {
|
||||
return Float<T>::Builder(seq.valueAtRank<T>(rank.approximateToScalar<double>(this, Poincare::Preferences::ComplexFormat::Cartesian, Poincare::Preferences::AngleUnit::Radian), m_sequenceContext));
|
||||
} else {
|
||||
return Float<T>::Builder(NAN);
|
||||
}
|
||||
return Float<T>::Builder(NAN);
|
||||
}
|
||||
}
|
||||
return ContextWithParent::expressionForSymbolAbstract(symbol, clone);
|
||||
|
||||
@@ -14,11 +14,13 @@ public:
|
||||
CacheContext(Poincare::Context * parentContext);
|
||||
const Poincare::Expression expressionForSymbolAbstract(const Poincare::SymbolAbstract & symbol, bool clone) override;
|
||||
void setValueForSymbol(T value, const Poincare::Symbol & symbol);
|
||||
void setNValue(int n) { m_nValue = n; }
|
||||
void setSequenceContext(SequenceContext * sequenceContext) { m_sequenceContext = sequenceContext;}
|
||||
private:
|
||||
int nameIndexForSymbol(const Poincare::Symbol & symbol);
|
||||
int rankIndexForSymbol(const Poincare::Symbol & symbol);
|
||||
T m_values[MaxNumberOfSequences][MaxRecurrenceDepth];
|
||||
int m_nValue;
|
||||
SequenceContext * m_sequenceContext;
|
||||
};
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
|
||||
// Name
|
||||
int name(char * buffer, size_t bufferSize);
|
||||
int nameWithArgument(char * buffer, size_t bufferSize);
|
||||
virtual int nameWithArgument(char * buffer, size_t bufferSize);
|
||||
virtual int printValue(double cursorT, double cursorX, double cursorY, char * buffer, int bufferSize, int precision, Poincare::Context * context);
|
||||
virtual I18n::Message parameterMessageName() const = 0;
|
||||
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
#include "function_store.h"
|
||||
#include "curve_view_cursor.h"
|
||||
#include "values_controller.h"
|
||||
#include "shared_app.h"
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class FunctionApp : public ExpressionFieldDelegateApp {
|
||||
public:
|
||||
class Snapshot : public ::App::Snapshot, public TabViewDataSource {
|
||||
class Snapshot : public ::SharedApp::Snapshot, public TabViewDataSource {
|
||||
public:
|
||||
Snapshot();
|
||||
CurveViewCursor * cursor() { return &m_cursor; }
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "global_context.h"
|
||||
#include "continuous_function.h"
|
||||
#include "sequence.h"
|
||||
#include "poincare_helpers.h"
|
||||
#include <poincare/undefined.h>
|
||||
#include <assert.h>
|
||||
@@ -10,6 +11,13 @@ namespace Shared {
|
||||
|
||||
constexpr const char * GlobalContext::k_extensions[];
|
||||
|
||||
SequenceStore * GlobalContext::sequenceStore() {
|
||||
static SequenceStore sequenceStore;
|
||||
return &sequenceStore;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool GlobalContext::SymbolAbstractNameIsFree(const char * baseName) {
|
||||
return SymbolAbstractRecordWithBaseName(baseName).isNull();
|
||||
}
|
||||
@@ -18,9 +26,11 @@ const Layout GlobalContext::LayoutForRecord(Ion::Storage::Record record) {
|
||||
assert(!record.isNull());
|
||||
if (Ion::Storage::FullNameHasExtension(record.fullName(), Ion::Storage::expExtension, strlen(Ion::Storage::expExtension))) {
|
||||
return PoincareHelpers::CreateLayout(ExpressionForActualSymbol(record));
|
||||
} else {
|
||||
assert(Ion::Storage::FullNameHasExtension(record.fullName(), Ion::Storage::funcExtension, strlen(Ion::Storage::funcExtension)));
|
||||
} else if (Ion::Storage::FullNameHasExtension(record.fullName(), Ion::Storage::funcExtension, strlen(Ion::Storage::funcExtension))) {
|
||||
return ContinuousFunction(record).layout();
|
||||
} else {
|
||||
assert(Ion::Storage::FullNameHasExtension(record.fullName(), Ion::Storage::seqExtension, strlen(Ion::Storage::seqExtension)));
|
||||
return Sequence(record).layout();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,22 +46,26 @@ Context::SymbolAbstractType GlobalContext::expressionTypeForIdentifier(const cha
|
||||
const char * extension = Ion::Storage::sharedStorage()->extensionOfRecordBaseNamedWithExtensions(identifier, length, k_extensions, k_numberOfExtensions);
|
||||
if (extension == nullptr) {
|
||||
return Context::SymbolAbstractType::None;
|
||||
} else if (extension == Ion::Storage::expExtension) {
|
||||
return Context::SymbolAbstractType::Symbol;
|
||||
} else if (extension == Ion::Storage::funcExtension) {
|
||||
return Context::SymbolAbstractType::Function;
|
||||
} else {
|
||||
assert(extension == Ion::Storage::seqExtension);
|
||||
return Context::SymbolAbstractType::Sequence;
|
||||
}
|
||||
assert(k_numberOfExtensions == 2);
|
||||
assert(extension == Ion::Storage::expExtension || extension == Ion::Storage::funcExtension);
|
||||
return extension == Ion::Storage::expExtension ? Context::SymbolAbstractType::Symbol : Context::SymbolAbstractType::Function;
|
||||
}
|
||||
|
||||
const Expression GlobalContext::expressionForSymbolAbstract(const SymbolAbstract & symbol, bool clone) {
|
||||
Ion::Storage::Record r = SymbolAbstractRecordWithBaseName(symbol.name());
|
||||
return ExpressionForSymbolAndRecord(symbol, r);
|
||||
return ExpressionForSymbolAndRecord(symbol, r, this);
|
||||
}
|
||||
|
||||
void GlobalContext::setExpressionForSymbolAbstract(const Expression & expression, const SymbolAbstract & symbol) {
|
||||
/* If the new expression contains the symbol, replace it because it will be
|
||||
* destroyed afterwards (to be able to do A+2->A) */
|
||||
Ion::Storage::Record record = SymbolAbstractRecordWithBaseName(symbol.name());
|
||||
Expression e = ExpressionForSymbolAndRecord(symbol, record);
|
||||
Expression e = ExpressionForSymbolAndRecord(symbol, record, this);
|
||||
if (e.isUninitialized()) {
|
||||
e = Undefined::Builder();
|
||||
}
|
||||
@@ -69,12 +83,14 @@ void GlobalContext::setExpressionForSymbolAbstract(const Expression & expression
|
||||
}
|
||||
}
|
||||
|
||||
const Expression GlobalContext::ExpressionForSymbolAndRecord(const SymbolAbstract & symbol, Ion::Storage::Record r) {
|
||||
const Expression GlobalContext::ExpressionForSymbolAndRecord(const SymbolAbstract & symbol, Ion::Storage::Record r, Context * ctx) {
|
||||
if (symbol.type() == ExpressionNode::Type::Symbol) {
|
||||
return ExpressionForActualSymbol(r);
|
||||
} else if (symbol.type() == ExpressionNode::Type::Function) {
|
||||
return ExpressionForFunction(symbol, r);
|
||||
}
|
||||
assert(symbol.type() == ExpressionNode::Type::Function);
|
||||
return ExpressionForFunction(symbol, r);
|
||||
assert(symbol.type() == ExpressionNode::Type::Sequence);
|
||||
return ExpressionForSequence(symbol, r, ctx);
|
||||
}
|
||||
|
||||
const Expression GlobalContext::ExpressionForActualSymbol(Ion::Storage::Record r) {
|
||||
@@ -99,6 +115,22 @@ const Expression GlobalContext::ExpressionForFunction(const SymbolAbstract & sym
|
||||
return e;
|
||||
}
|
||||
|
||||
const Expression GlobalContext::ExpressionForSequence(const SymbolAbstract & symbol, Ion::Storage::Record r, Context * ctx) {
|
||||
if (!Ion::Storage::FullNameHasExtension(r.fullName(), Ion::Storage::seqExtension, strlen(Ion::Storage::seqExtension))) {
|
||||
return Expression();
|
||||
}
|
||||
/* An function record value has metadata before the expression. To get the
|
||||
* expression, use the function record handle. */
|
||||
Sequence seq(r);
|
||||
double rank = PoincareHelpers::ApproximateToScalar<float>(symbol.childAtIndex(0), ctx);
|
||||
if (std::floor(rank) == rank) {
|
||||
SequenceContext sqctx(ctx, sequenceStore());
|
||||
return Float<double>::Builder(seq.evaluateXYAtParameter(rank, &sqctx).x2());
|
||||
} else {
|
||||
return Float<double>::Builder(NAN);
|
||||
}
|
||||
}
|
||||
|
||||
Ion::Storage::Record::ErrorStatus GlobalContext::SetExpressionForActualSymbol(const Expression & expression, const SymbolAbstract & symbol, Ion::Storage::Record previousRecord) {
|
||||
if (!previousRecord.isNull() && Ion::Storage::FullNameHasExtension(previousRecord.fullName(), Ion::Storage::funcExtension, strlen(Ion::Storage::funcExtension))) {
|
||||
/* A function can overwrite a variable, but a variable cannot be created if
|
||||
|
||||
@@ -8,13 +8,14 @@
|
||||
#include <poincare/symbol.h>
|
||||
#include <ion/storage.h>
|
||||
#include <assert.h>
|
||||
#include "sequence_store.h"
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class GlobalContext final : public Poincare::Context {
|
||||
public:
|
||||
static constexpr int k_numberOfExtensions = 2;
|
||||
static constexpr const char * k_extensions[] = {Ion::Storage::expExtension, Ion::Storage::funcExtension};
|
||||
static constexpr int k_numberOfExtensions = 3;
|
||||
static constexpr const char * k_extensions[] = {Ion::Storage::expExtension, Ion::Storage::funcExtension, Ion::Storage::seqExtension};
|
||||
|
||||
// Storage information
|
||||
static bool SymbolAbstractNameIsFree(const char * baseName);
|
||||
@@ -30,19 +31,19 @@ public:
|
||||
SymbolAbstractType expressionTypeForIdentifier(const char * identifier, int length) override;
|
||||
const Poincare::Expression expressionForSymbolAbstract(const Poincare::SymbolAbstract & symbol, bool clone) override;
|
||||
void setExpressionForSymbolAbstract(const Poincare::Expression & expression, const Poincare::SymbolAbstract & symbol) override;
|
||||
|
||||
static SequenceStore * sequenceStore();
|
||||
private:
|
||||
// Expression getters
|
||||
static const Poincare::Expression ExpressionForSymbolAndRecord(const Poincare::SymbolAbstract & symbol, Ion::Storage::Record r);
|
||||
static const Poincare::Expression ExpressionForSymbolAndRecord(const Poincare::SymbolAbstract & symbol, Ion::Storage::Record r, Context * ctx);
|
||||
static const Poincare::Expression ExpressionForActualSymbol(Ion::Storage::Record r);
|
||||
static const Poincare::Expression ExpressionForFunction(const Poincare::SymbolAbstract & symbol, Ion::Storage::Record r);
|
||||
static const Poincare::Expression ExpressionForSequence(const Poincare::SymbolAbstract & symbol, Ion::Storage::Record r, Context * ctx);
|
||||
// Expression setters
|
||||
static Ion::Storage::Record::ErrorStatus SetExpressionForActualSymbol(const Poincare::Expression & expression, const Poincare::SymbolAbstract & symbol, Ion::Storage::Record previousRecord);
|
||||
static Ion::Storage::Record::ErrorStatus SetExpressionForFunction(const Poincare::Expression & expression, const Poincare::SymbolAbstract & symbol, Ion::Storage::Record previousRecord);
|
||||
// Record getter
|
||||
static Ion::Storage::Record SymbolAbstractRecordWithBaseName(const char * name);
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -20,6 +20,31 @@ I18n::Message Sequence::parameterMessageName() const {
|
||||
return I18n::Message::N;
|
||||
}
|
||||
|
||||
int Sequence::nameWithArgument(char * buffer, size_t bufferSize) {
|
||||
int seqNameSize = name(buffer, bufferSize);
|
||||
assert(seqNameSize > 0);
|
||||
size_t result = seqNameSize;
|
||||
assert(result <= bufferSize);
|
||||
buffer[result++] = '(';
|
||||
assert(result <= bufferSize);
|
||||
assert(UTF8Decoder::CharSizeOfCodePoint(symbol()) <= 2);
|
||||
result += UTF8Decoder::CodePointToChars(symbol(), buffer+result, bufferSize-result);
|
||||
assert(result <= bufferSize);
|
||||
switch (type())
|
||||
{
|
||||
case Type::Explicit:
|
||||
result += strlcpy(buffer+result, ")", bufferSize-result);
|
||||
break;
|
||||
case Type::SingleRecurrence:
|
||||
result += strlcpy(buffer+result, "+1)", bufferSize-result);
|
||||
break;
|
||||
default:
|
||||
result += strlcpy(buffer+result, "+2)", bufferSize-result);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Sequence::tidy() {
|
||||
m_definition.tidyName();
|
||||
Function::tidy(); // m_definitionName.tidy()
|
||||
@@ -111,7 +136,7 @@ T Sequence::templatedApproximateAtAbscissa(T x, SequenceContext * sqctx) const {
|
||||
T n = std::round(x);
|
||||
int sequenceIndex = SequenceStore::sequenceIndexForName(fullName()[0]);
|
||||
if (sqctx->iterateUntilRank<T>(n)) {
|
||||
return sqctx->valueOfSequenceAtPreviousRank<T>(sequenceIndex, 0);
|
||||
return sqctx->valueOfCommonRankSequenceAtPreviousRank<T>(sequenceIndex, 0);
|
||||
}
|
||||
return NAN;
|
||||
}
|
||||
@@ -122,20 +147,19 @@ T Sequence::valueAtRank(int n, SequenceContext *sqctx) {
|
||||
return NAN;
|
||||
}
|
||||
int sequenceIndex = SequenceStore::sequenceIndexForName(fullName()[0]);
|
||||
if (sqctx->independantSequenceRank<T>(sequenceIndex) > n || sqctx->independantSequenceRank<T>(sequenceIndex) < 0) {
|
||||
if (sqctx->independentSequenceRank<T>(sequenceIndex) > n || sqctx->independentSequenceRank<T>(sequenceIndex) < 0) {
|
||||
// Reset cache indexes and cache values
|
||||
sqctx->setIndependantSequenceRank<T>(-1, sequenceIndex);
|
||||
sqctx->setIndependentSequenceRank<T>(-1, sequenceIndex);
|
||||
for (int i = 0 ; i < MaxRecurrenceDepth+1; i++) {
|
||||
sqctx->setIndependantSequenceValue(NAN, sequenceIndex, i);
|
||||
sqctx->setIndependentSequenceValue(NAN, sequenceIndex, i);
|
||||
}
|
||||
}
|
||||
|
||||
while(sqctx->independantSequenceRank<T>(sequenceIndex) < n) {
|
||||
while(sqctx->independentSequenceRank<T>(sequenceIndex) < n) {
|
||||
sqctx->stepSequenceAtIndex<T>(sequenceIndex);
|
||||
}
|
||||
/* In case we have sqctx->independantSequenceRank<T>(sequenceIndex) = n, we can return the
|
||||
/* In case we have sqctx->independentSequenceRank<T>(sequenceIndex) = n, we can return the
|
||||
* value */
|
||||
T value = sqctx->independantSequenceValue<T>(sequenceIndex, 0);
|
||||
T value = sqctx->independentSequenceValue<T>(sequenceIndex, 0);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -156,22 +180,22 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx, int sequenceIn
|
||||
|
||||
/* In case we step only one sequence to the next step, the data stored in
|
||||
* values is not necessarily u(n), u(n-1).... Indeed, since the indexes are
|
||||
* independant, if the index for u is 3 but the one for v is 5, value will
|
||||
* independent, if the index for u is 3 but the one for v is 5, value will
|
||||
* hold u(3), u(2), u(1) | v(5), v(4), v(3). Therefore, the calculation will
|
||||
* be wrong if they relay on a symbol such as u(n). To prevent this, we align
|
||||
* all the values around the index of the sequence we are stepping. */
|
||||
int independantRank = sqctx->independantSequenceRank<T>(sequenceIndex);
|
||||
int independentRank = sqctx->independentSequenceRank<T>(sequenceIndex);
|
||||
for (int i = 0; i < MaxNumberOfSequences; i++) {
|
||||
if (sequenceIndex != -1 && sqctx->independantSequenceRank<T>(i) != independantRank) {
|
||||
int offset = independantRank - sqctx->independantSequenceRank<T>(i);
|
||||
if (sequenceIndex != -1 && sqctx->independentSequenceRank<T>(i) != independentRank) {
|
||||
int offset = independentRank - sqctx->independentSequenceRank<T>(i);
|
||||
if (offset != 0) {
|
||||
for (int j = MaxRecurrenceDepth; j >= 0; j--) {
|
||||
values[i][j] = j-offset < 0 ? NAN : sqctx->independantSequenceValue<T>(i, j-offset);
|
||||
values[i][j] = j-offset < 0 ? NAN : sqctx->independentSequenceValue<T>(i, j-offset);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < MaxRecurrenceDepth+1; j++) {
|
||||
values[i][j] = sequenceIndex != -1 ? sqctx->independantSequenceValue<T>(i, j) : sqctx->valueOfSequenceAtPreviousRank<T>(i, j);
|
||||
values[i][j] = sequenceIndex != -1 ? sqctx->independentSequenceValue<T>(i, j) : sqctx->valueOfCommonRankSequenceAtPreviousRank<T>(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,7 +208,7 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx, int sequenceIn
|
||||
symbols[i][j] = Symbol::Builder(name[j], strlen(name[j]));
|
||||
}
|
||||
}
|
||||
|
||||
ctx.setNValue(n);
|
||||
switch (type()) {
|
||||
case Type::Explicit:
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef SEQUENCE_SEQUENCE_H
|
||||
#define SEQUENCE_SEQUENCE_H
|
||||
#ifndef APPS_SHARED_SEQUENCE_H
|
||||
#define APPS_SHARED_SEQUENCE_H
|
||||
|
||||
#include "../shared/function.h"
|
||||
#include "sequence_context.h"
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
}
|
||||
I18n::Message parameterMessageName() const override;
|
||||
CodePoint symbol() const override { return 'n'; }
|
||||
int nameWithArgument(char * buffer, size_t bufferSize) override;
|
||||
void tidy() override;
|
||||
// MetaData getters
|
||||
Type type() const;
|
||||
|
||||
@@ -12,13 +12,13 @@ template<typename T>
|
||||
TemplatedSequenceContext<T>::TemplatedSequenceContext() :
|
||||
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}}
|
||||
m_independentRanks{-1, -1, -1},
|
||||
m_independentRankValues{{NAN, NAN, NAN}, {NAN, NAN, NAN}, {NAN, NAN, NAN}}
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T TemplatedSequenceContext<T>::valueOfSequenceAtPreviousRank(int sequenceIndex, int rank) const {
|
||||
T TemplatedSequenceContext<T>::valueOfCommonRankSequenceAtPreviousRank(int sequenceIndex, int rank) const {
|
||||
return m_commonRankValues[sequenceIndex][rank];
|
||||
}
|
||||
|
||||
@@ -26,11 +26,11 @@ 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_independantRankValues are dirty
|
||||
* 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_independantRanks[i] = -1;
|
||||
m_independentRanks[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ void TemplatedSequenceContext<T>::step(SequenceContext * sqctx, int sequenceInde
|
||||
if (stepMultipleSequences) {
|
||||
m_commonRank++;
|
||||
} else {
|
||||
setIndependantSequenceRank(independantSequenceRank(sequenceIndex) + 1, sequenceIndex);
|
||||
setIndependentSequenceRank(independentSequenceRank(sequenceIndex) + 1, sequenceIndex);
|
||||
}
|
||||
|
||||
// Then we shift the values stored in the arrays
|
||||
@@ -69,8 +69,8 @@ void TemplatedSequenceContext<T>::step(SequenceContext * sqctx, int sequenceInde
|
||||
} else {
|
||||
start = sequenceIndex;
|
||||
stop = sequenceIndex + 1;
|
||||
sequenceArray = reinterpret_cast<T*>(&m_independantRankValues);
|
||||
rank = independantSequenceRank(sequenceIndex);
|
||||
sequenceArray = reinterpret_cast<T*>(&m_independentRankValues);
|
||||
rank = independentSequenceRank(sequenceIndex);
|
||||
}
|
||||
|
||||
for (int i = start; i < stop; i++) {
|
||||
@@ -107,7 +107,7 @@ void TemplatedSequenceContext<T>::step(SequenceContext * sqctx, int sequenceInde
|
||||
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;
|
||||
*pointerToUpdate = sequences[j] ? sequences[j]->template approximateToNextRank<T>(rank, sqctx, sequenceIndex) : NAN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef SEQUENCE_SEQUENCE_CONTEXT_H
|
||||
#define SEQUENCE_SEQUENCE_CONTEXT_H
|
||||
#ifndef APPS_SHARED_SEQUENCE_CONTEXT_H
|
||||
#define APPS_SHARED_SEQUENCE_CONTEXT_H
|
||||
|
||||
#include <poincare/context_with_parent.h>
|
||||
#include <poincare/expression.h>
|
||||
@@ -17,14 +17,14 @@ template<typename T>
|
||||
class TemplatedSequenceContext {
|
||||
public:
|
||||
TemplatedSequenceContext();
|
||||
T valueOfSequenceAtPreviousRank(int sequenceIndex, int rank) const;
|
||||
T valueOfCommonRankSequenceAtPreviousRank(int sequenceIndex, int rank) const;
|
||||
void resetCache();
|
||||
bool iterateUntilRank(int n, SequenceStore * sequenceStore, SequenceContext * sqctx);
|
||||
|
||||
int independantSequenceRank(int sequenceIndex) { return m_independantRanks[sequenceIndex]; }
|
||||
void setIndependantSequenceRank(int rank, int sequenceIndex) { m_independantRanks[sequenceIndex] = rank; }
|
||||
T independantSequenceValue(int sequenceIndex, int depth) { return m_independantRankValues[sequenceIndex][depth]; }
|
||||
void setIndependantSequenceValue(T value, int sequenceIndex, int depth) { m_independantRankValues[sequenceIndex][depth] = value; }
|
||||
int independentSequenceRank(int sequenceIndex) { return m_independentRanks[sequenceIndex]; }
|
||||
void setIndependentSequenceRank(int rank, int sequenceIndex) { m_independentRanks[sequenceIndex] = rank; }
|
||||
T independentSequenceValue(int sequenceIndex, int depth) { return m_independentRankValues[sequenceIndex][depth]; }
|
||||
void setIndependentSequenceValue(T value, int sequenceIndex, int depth) { m_independentRankValues[sequenceIndex][depth] = value; }
|
||||
void step(SequenceContext * sqctx, int sequenceIndex = -1);
|
||||
private:
|
||||
constexpr static int k_maxRecurrentRank = 10000;
|
||||
@@ -41,16 +41,16 @@ private:
|
||||
* sequence is defined using a fixed term of another, u(3) for instance, we
|
||||
* compute its value through the second type of cache. This way, we do not
|
||||
* erase the data stored in the first type of cache and we can compute the
|
||||
* values of each sequence at independant rank. This means that
|
||||
* values of each sequence at independent rank. This means that
|
||||
* (u(3), v(5), w(10)) can be computed at the same time.
|
||||
* This cache is therefore used for independant steps of sequences
|
||||
* This cache is therefore used for independent steps of sequences
|
||||
*/
|
||||
int m_commonRank;
|
||||
T m_commonRankValues[MaxNumberOfSequences][MaxRecurrenceDepth+1];
|
||||
|
||||
// Used for fixed computations
|
||||
int m_independantRanks[MaxNumberOfSequences];
|
||||
T m_independantRankValues[MaxNumberOfSequences][MaxRecurrenceDepth+1];
|
||||
int m_independentRanks[MaxNumberOfSequences];
|
||||
T m_independentRankValues[MaxNumberOfSequences][MaxRecurrenceDepth+1];
|
||||
};
|
||||
|
||||
class SequenceContext : public Poincare::ContextWithParent {
|
||||
@@ -64,8 +64,8 @@ public:
|
||||
* 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. */
|
||||
template<typename T> T valueOfSequenceAtPreviousRank(int sequenceIndex, int rank) {
|
||||
return static_cast<TemplatedSequenceContext<T>*>(helper<T>())->valueOfSequenceAtPreviousRank(sequenceIndex, rank);
|
||||
template<typename T> T valueOfCommonRankSequenceAtPreviousRank(int sequenceIndex, int rank) {
|
||||
return static_cast<TemplatedSequenceContext<T>*>(helper<T>())->valueOfCommonRankSequenceAtPreviousRank(sequenceIndex, rank);
|
||||
}
|
||||
|
||||
void resetCache() {
|
||||
@@ -77,20 +77,20 @@ public:
|
||||
return static_cast<TemplatedSequenceContext<T>*>(helper<T>())->iterateUntilRank(n, m_sequenceStore, this);
|
||||
}
|
||||
|
||||
template<typename T> int independantSequenceRank(int sequenceIndex) {
|
||||
return static_cast<TemplatedSequenceContext<T>*>(helper<T>())->independantSequenceRank(sequenceIndex);
|
||||
template<typename T> int independentSequenceRank(int sequenceIndex) {
|
||||
return static_cast<TemplatedSequenceContext<T>*>(helper<T>())->independentSequenceRank(sequenceIndex);
|
||||
}
|
||||
|
||||
template<typename T> void setIndependantSequenceRank(int rank, int sequenceIndex) {
|
||||
static_cast<TemplatedSequenceContext<T>*>(helper<T>())->setIndependantSequenceRank(rank, sequenceIndex);
|
||||
template<typename T> void setIndependentSequenceRank(int rank, int sequenceIndex) {
|
||||
static_cast<TemplatedSequenceContext<T>*>(helper<T>())->setIndependentSequenceRank(rank, sequenceIndex);
|
||||
}
|
||||
|
||||
template<typename T> T independantSequenceValue(int sequenceIndex, int depth) {
|
||||
return static_cast<TemplatedSequenceContext<T>*>(helper<T>())->independantSequenceValue(sequenceIndex, depth);
|
||||
template<typename T> T independentSequenceValue(int sequenceIndex, int depth) {
|
||||
return static_cast<TemplatedSequenceContext<T>*>(helper<T>())->independentSequenceValue(sequenceIndex, depth);
|
||||
}
|
||||
|
||||
template<typename T> void setIndependantSequenceValue(T value, int sequenceIndex, int depth) {
|
||||
static_cast<TemplatedSequenceContext<T>*>(helper<T>())->setIndependantSequenceValue(value, sequenceIndex, depth);
|
||||
template<typename T> void setIndependentSequenceValue(T value, int sequenceIndex, int depth) {
|
||||
static_cast<TemplatedSequenceContext<T>*>(helper<T>())->setIndependentSequenceValue(value, sequenceIndex, depth);
|
||||
}
|
||||
|
||||
template<typename T> void stepSequenceAtIndex(int sequenceIndex) {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#ifndef SEQUENCE_SEQUENCE_STORE_H
|
||||
#define SEQUENCE_SEQUENCE_STORE_H
|
||||
#ifndef APPS_SHARED_SEQUENCE_STORE_H
|
||||
#define APPS_SHARED_SEQUENCE_STORE_H
|
||||
|
||||
#include "../shared/function_store.h"
|
||||
#include "../shared/global_context.h"
|
||||
#include "sequence.h"
|
||||
#include <stdint.h>
|
||||
#include <escher.h>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef SEQUENCE_SEQUENCE_TITLE_CELL_H
|
||||
#define SEQUENCE_SEQUENCE_TITLE_CELL_H
|
||||
#ifndef APPS_SHARED_SEQUENCE_TITLE_CELL_H
|
||||
#define APPS_SHARED_SEQUENCE_TITLE_CELL_H
|
||||
|
||||
#include "../shared/function_title_cell.h"
|
||||
#include <poincare_layouts.h>
|
||||
|
||||
10
apps/shared/shared_app.cpp
Normal file
10
apps/shared/shared_app.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#include "shared_app.h"
|
||||
#include "global_context.h"
|
||||
#include <apps/apps_container.h>
|
||||
|
||||
void SharedApp::Snapshot::pack(App * app) {
|
||||
/* Since the sequence store is now accessible from every app, when exiting
|
||||
* any application, we need to tidy it.*/
|
||||
static_cast<Shared::GlobalContext *>(AppsContainer::sharedAppsContainer()->globalContext())->sequenceStore()->tidy();
|
||||
App::Snapshot::pack(app);
|
||||
}
|
||||
14
apps/shared/shared_app.h
Normal file
14
apps/shared/shared_app.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef SHARED_APP_H
|
||||
#define SHARED_APP_H
|
||||
|
||||
#include <escher/app.h>
|
||||
|
||||
class SharedApp : public App {
|
||||
public:
|
||||
class Snapshot : public App::Snapshot {
|
||||
public:
|
||||
void pack(App * app) override;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "equation_store.h"
|
||||
#include "interval_controller.h"
|
||||
#include "solutions_controller.h"
|
||||
#include "../shared/shared_app.h"
|
||||
|
||||
namespace Solver {
|
||||
|
||||
@@ -18,7 +19,7 @@ public:
|
||||
I18n::Message upperName() override;
|
||||
const Image * icon() override;
|
||||
};
|
||||
class Snapshot : public ::App::Snapshot {
|
||||
class Snapshot : public ::SharedApp::Snapshot {
|
||||
public:
|
||||
Snapshot();
|
||||
App * unpack(Container * container) override;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "store.h"
|
||||
#include "store_controller.h"
|
||||
#include "../shared/text_field_delegate_app.h"
|
||||
#include "../shared/shared_app.h"
|
||||
|
||||
namespace Statistics {
|
||||
|
||||
@@ -19,7 +20,7 @@ public:
|
||||
I18n::Message upperName() override;
|
||||
const Image * icon() override;
|
||||
};
|
||||
class Snapshot : public ::App::Snapshot, public TabViewDataSource {
|
||||
class Snapshot : public ::SharedApp::Snapshot, public TabViewDataSource {
|
||||
public:
|
||||
Snapshot();
|
||||
App * unpack(Container * container) override;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "escher/include/escher/app.h"
|
||||
#include "usb_connected_controller.h"
|
||||
#include "../shared/shared_app.h"
|
||||
|
||||
namespace USB {
|
||||
|
||||
@@ -13,7 +14,7 @@ public:
|
||||
I18n::Message name() override;
|
||||
I18n::Message upperName() override;
|
||||
};
|
||||
class Snapshot : public ::App::Snapshot {
|
||||
class Snapshot : public ::SharedApp::Snapshot {
|
||||
public:
|
||||
App * unpack(Container * container) override;
|
||||
Descriptor * descriptor() override;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
Variables = "Variablen"
|
||||
Expressions = "Ausdrücke"
|
||||
Functions = "Funktionen"
|
||||
Sequences = "Folgen"
|
||||
EmptyExpressionBox0 = "Sie haben keine Variable definiert."
|
||||
EmptyFunctionBox0 = "Sie haben keine Funktion definiert."
|
||||
EmptySequenceBox0 = "Sie haben keine Folge definiert."
|
||||
EmptyExpressionBox1 = "Um eine Variable zu definieren:"
|
||||
EmptyFunctionBox1 = "Um eine Funktion zu definieren:"
|
||||
EmptyExpressionBox2 = "Erlaubte Zeichen im Namen:"
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
Variables = "Variables"
|
||||
Expressions = "Expressions"
|
||||
Functions = "Functions"
|
||||
Sequences = "Sequences"
|
||||
EmptyExpressionBox0 = "You have not defined any variables."
|
||||
EmptyFunctionBox0 = "You have not defined any functions."
|
||||
EmptySequenceBox0 = "You have not defined any sequences."
|
||||
EmptyExpressionBox1 = "To define a variable, type:"
|
||||
EmptyFunctionBox1 = "To define a function, type:"
|
||||
EmptyExpressionBox2 = "The variable name can contain:"
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
Variables = "Variables"
|
||||
Expressions = "Expresiones"
|
||||
Functions = "Funciones"
|
||||
Sequences = "Sucesiones"
|
||||
EmptyExpressionBox0 = "Ninguna variable definida."
|
||||
EmptyFunctionBox0 = "Ninguna función definida."
|
||||
EmptySequenceBox0 = "Ninguna sucesión definida."
|
||||
EmptyExpressionBox1 = "Para definir una, teclear :"
|
||||
EmptyFunctionBox1 = "Para definir una, teclear :"
|
||||
EmptyExpressionBox2 = "El nombre de variable debe"
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
Variables = "Variables"
|
||||
Expressions = "Expressions"
|
||||
Functions = "Fonctions"
|
||||
Sequences = "Suites"
|
||||
EmptyExpressionBox0 = "Vous n'avez défini aucune variable."
|
||||
EmptyFunctionBox0 = "Vous n'avez défini aucune fonction."
|
||||
EmptySequenceBox0 = "Vous n'avez défini aucune suite."
|
||||
EmptyExpressionBox1 = "Pour définir une variable, tapez :"
|
||||
EmptyFunctionBox1 = "Pour définir une fonction, tapez :"
|
||||
EmptyExpressionBox2 = "Le nom de la variable peut"
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
Variables = "Variabili"
|
||||
Expressions = "Espressioni"
|
||||
Functions = "Funzioni"
|
||||
Sequences = "Successioni"
|
||||
EmptyExpressionBox0 = "Non avete definito nessuna variabile."
|
||||
EmptyFunctionBox0 = "Non avete definito nessuna funzione."
|
||||
EmptySequenceBox0 = "Non avete definito nessuna successione."
|
||||
EmptyExpressionBox1 = "Per definire una variabile, digitare :"
|
||||
EmptyFunctionBox1 = "Per definire una funzione, digitare :"
|
||||
EmptyExpressionBox2 = "Il nome della variabile può"
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
Variables = "Variabelen"
|
||||
Expressions = "Uitdrukkingen"
|
||||
Functions = "Functies"
|
||||
Sequences = "Rijen"
|
||||
EmptyExpressionBox0 = "Je hebt geen variabelen gedefinieerd."
|
||||
EmptyFunctionBox0 = "Je hebt geen functies gedefinieerd."
|
||||
EmptySequenceBox0 = "Je hebt geen rij gedefinieerd."
|
||||
EmptyExpressionBox1 = "Om een variabele to definiëren, typ:"
|
||||
EmptyFunctionBox1 = "Om een functie to definiëren, typ:"
|
||||
EmptyExpressionBox2 = "De naam van de variabele kan bevatten:"
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
Variables = "Variáveis"
|
||||
Expressions = "Expressões"
|
||||
Functions = "Funções"
|
||||
Sequences = "Sequências"
|
||||
EmptyExpressionBox0 = "Nenhuma variável definida."
|
||||
EmptyFunctionBox0 = "Nenhuma função definida."
|
||||
EmptySequenceBox0 = "Nenhuma sequência definida."
|
||||
EmptyExpressionBox1 = "Para definir uma, digite :"
|
||||
EmptyFunctionBox1 = "Para definir uma, digite :"
|
||||
EmptyExpressionBox2 = "O nome da variável pode conter:"
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
class Snapshot {
|
||||
public:
|
||||
virtual App * unpack(Container * container) = 0;
|
||||
void pack(App * app);
|
||||
virtual void pack(App * app);
|
||||
/* reset all instances to their initial values */
|
||||
virtual void reset() {}
|
||||
virtual void storageDidChangeForRecord(Ion::Storage::Record) {}
|
||||
|
||||
@@ -98,6 +98,7 @@ class Expression : public TreeHandle {
|
||||
friend class SubtractionNode;
|
||||
friend class Sum;
|
||||
friend class SumAndProduct;
|
||||
friend class SumAndProductNode;
|
||||
friend class Symbol;
|
||||
friend class SymbolAbstractNode;
|
||||
friend class Tangent;
|
||||
|
||||
@@ -19,6 +19,7 @@ public:
|
||||
|
||||
Type type() const override { return Type::Sequence; }
|
||||
Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) override;
|
||||
int simplificationOrderSameType(const ExpressionNode * e, bool ascending, bool canBeInterrupted, bool ignoreParentheses) const override;
|
||||
|
||||
private:
|
||||
char m_name[0];
|
||||
|
||||
@@ -66,6 +66,7 @@ class SymbolAbstract : public Expression {
|
||||
friend class Symbol;
|
||||
friend class SymbolNode;
|
||||
friend class SymbolAbstractNode;
|
||||
friend class SumAndProductNode;
|
||||
public:
|
||||
const char * name() const { return node()->name(); }
|
||||
bool hasSameNameAs(const SymbolAbstract & other) const;
|
||||
|
||||
@@ -416,13 +416,9 @@ void Parser::parseSequence(Expression & leftHandSide, const char name, Token::Ty
|
||||
Expression rank = parseUntil(rightDelimiter);
|
||||
if (m_status != Status::Progress) {
|
||||
} else if (!popTokenIfType(rightDelimiter)) {
|
||||
m_status = Status::Error; // Right delimiter missing.
|
||||
} else if (rank.type() == ExpressionNode::Type::BasedInteger
|
||||
|| rank.isIdenticalTo(Symbol::Builder('n'))
|
||||
|| rank.isIdenticalTo(Addition::Builder(Symbol::Builder('n'), BasedInteger::Builder("1")))) {
|
||||
leftHandSide = Sequence::Builder(&name, 1, rank);
|
||||
m_status = Status::Error; // Right delimiter missing
|
||||
} else {
|
||||
m_status = Status::Error; // Unexpected parameter.
|
||||
leftHandSide = Sequence::Builder(&name, 1, rank);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,28 +20,29 @@ Expression SequenceNode::replaceSymbolWithExpression(const SymbolAbstract & symb
|
||||
return Sequence(this).replaceSymbolWithExpression(symbol, expression);
|
||||
}
|
||||
|
||||
int SequenceNode::simplificationOrderSameType(const ExpressionNode * e, bool ascending, bool canBeInterrupted, bool ignoreParentheses) const {
|
||||
/* This function ensures that terms like u(n) and u(n+1), u(n) and v(n),
|
||||
* u(a) and u(b) do not factorize.
|
||||
* We never want to factorize. The only cases where it could be useful are
|
||||
* like the following : u(n)+u(n). But thanks to the cache system, no
|
||||
* computation is needed for the second term.*/
|
||||
assert(type() == e->type());
|
||||
assert(numberOfChildren() == 1);
|
||||
assert(e->numberOfChildren() == 1);
|
||||
ExpressionNode * seq = const_cast<ExpressionNode*>(e);
|
||||
int delta = strcmp(name(), reinterpret_cast<SequenceNode *>(seq)->name());
|
||||
if (delta == 0) {
|
||||
return SimplificationOrder(childAtIndex(0), e->childAtIndex(0), ascending, canBeInterrupted, ignoreParentheses);
|
||||
}
|
||||
return delta;
|
||||
}
|
||||
|
||||
Layout SequenceNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
|
||||
assert(name()[0] >= 'u' && name()[0] <= 'w');
|
||||
Layout rank;
|
||||
for (char sequenceName = 'u'; sequenceName <= 'w'; sequenceName++) {
|
||||
if (name()[0] == sequenceName) {
|
||||
// Checking for the sequence children
|
||||
if (childAtIndex(0)->type() == Type::Symbol) {
|
||||
// u(n)
|
||||
rank = LayoutHelper::String("n", strlen("n"));
|
||||
} else if (childAtIndex(0)->type() == Type::Addition) {
|
||||
rank = LayoutHelper::String("n+1", strlen("n+1"));
|
||||
} else {
|
||||
assert(childAtIndex(0)->type() == Type::BasedInteger);
|
||||
rank = static_cast<BasedIntegerNode &>(*childAtIndex(0)).integer().createLayout();
|
||||
}
|
||||
return HorizontalLayout::Builder(
|
||||
CodePointLayout::Builder(sequenceName),
|
||||
VerticalOffsetLayout::Builder(rank, VerticalOffsetLayoutNode::Position::Subscript));
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
return LayoutHelper::String(name(), strlen(name()));
|
||||
Layout rank = childAtIndex(0)->createLayout(floatDisplayMode, numberOfSignificantDigits);
|
||||
return HorizontalLayout::Builder(
|
||||
CodePointLayout::Builder(name()[0]),
|
||||
VerticalOffsetLayout::Builder(rank, VerticalOffsetLayoutNode::Position::Subscript));
|
||||
}
|
||||
|
||||
int SequenceNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
|
||||
@@ -49,7 +50,7 @@ int SequenceNode::serialize(char * buffer, int bufferSize, Preferences::PrintFlo
|
||||
}
|
||||
|
||||
Expression SequenceNode::shallowReduce(ReductionContext reductionContext) {
|
||||
return Sequence(this).shallowReduce(reductionContext); // This uses Symbol::shallowReduce
|
||||
return Sequence(this).shallowReduce(reductionContext);
|
||||
}
|
||||
|
||||
Evaluation<float> SequenceNode::approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const {
|
||||
@@ -95,8 +96,12 @@ Expression Sequence::replaceSymbolWithExpression(const SymbolAbstract & symbol,
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Those two functions will be updated in a comming commit
|
||||
Expression Sequence::shallowReduce(ExpressionNode::ReductionContext reductionContext) {
|
||||
if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined
|
||||
|| childAtIndex(0).isUndefined())
|
||||
{
|
||||
return replaceWithUndefinedInPlace();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,14 +32,22 @@ Evaluation<T> SumAndProductNode::templatedApproximate(Context * context, Prefere
|
||||
if (std::isnan(start) || std::isnan(end) || start != (int)start || end != (int)end || end - start > k_maxNumberOfSteps) {
|
||||
return Complex<T>::Undefined();
|
||||
}
|
||||
VariableContext nContext = VariableContext(static_cast<SymbolNode *>(childAtIndex(1))->name(), context);
|
||||
SymbolNode * symbol = static_cast<SymbolNode *>(childAtIndex(1));
|
||||
VariableContext nContext = VariableContext(symbol->name(), context);
|
||||
Evaluation<T> result = Complex<T>::Builder((T)emptySumAndProductValue());
|
||||
for (int i = (int)start; i <= (int)end; i++) {
|
||||
if (Expression::ShouldStopProcessing()) {
|
||||
return Complex<T>::Undefined();
|
||||
}
|
||||
nContext.setApproximationForVariable<T>((T)i);
|
||||
result = evaluateWithNextTerm(T(), result, childAtIndex(0)->approximate(T(), &nContext, complexFormat, angleUnit), complexFormat);
|
||||
Expression child = Expression(childAtIndex(0)).clone();
|
||||
if (child.type() == ExpressionNode::Type::Sequence) {
|
||||
/* Since we cannot get the expression of a sequence term like we would for
|
||||
* a function, we replace its potential abstract rank by the value it should
|
||||
* have. We can then evaluate its value */
|
||||
child.childAtIndex(0).replaceSymbolWithExpression(symbol, Float<T>::Builder(i));
|
||||
}
|
||||
result = evaluateWithNextTerm(T(), result, child.node()->approximate(T(), &nContext, complexFormat, angleUnit), complexFormat);
|
||||
if (result.isUndefined()) {
|
||||
return Complex<T>::Undefined();
|
||||
}
|
||||
|
||||
@@ -37,11 +37,6 @@ Expression SymbolAbstractNode::setSign(ExpressionNode::Sign s, ReductionContext
|
||||
|
||||
int SymbolAbstractNode::simplificationOrderSameType(const ExpressionNode * e, bool ascending, bool canBeInterrupted, bool ignoreParentheses) const {
|
||||
assert(type() == e->type());
|
||||
/* We do not want the sequences to be factorized. Otherwise, u(n) will be
|
||||
* factorized with u(n+1). */
|
||||
if (type() == Type::Sequence) {
|
||||
return -1;
|
||||
}
|
||||
return strcmp(name(), static_cast<const SymbolAbstractNode *>(e)->name());
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include <poincare/preferences.h>
|
||||
#include <poincare/symbol.h>
|
||||
#include <poincare/undefined.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace Poincare {
|
||||
|
||||
Reference in New Issue
Block a user