[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

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