[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:
Arthur Camouseigt
2020-09-04 16:20:33 +02:00
committed by Émilie Feral
parent c006ed7b10
commit 3dca515441
50 changed files with 297 additions and 152 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -13,7 +13,8 @@ public:
enum class Type {
None = 0,
Expressions = 1,
Functions = 2
Functions = 2,
Sequence = 3
};
void setType(Type type);
// View Controller

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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
View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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ò"

View File

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

View File

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

View File

@@ -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) {}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,7 +2,6 @@
#include <poincare/preferences.h>
#include <poincare/symbol.h>
#include <poincare/undefined.h>
#include <cmath>
namespace Poincare {