[Sequence] Changed the way sequences are parsed

Change-Id: If19b46a317e4f336ac857690827ab08e147ac75a
This commit is contained in:
Arthur Camouseigt
2020-07-22 17:22:37 +02:00
committed by Émilie Feral
parent 8434da60ef
commit ed358590ce
18 changed files with 271 additions and 147 deletions

View File

@@ -19,29 +19,24 @@ CacheContext<T>::CacheContext(Context * parentContext) :
template<typename T>
const Expression CacheContext<T>::expressionForSymbolAbstract(const SymbolAbstract & symbol, bool clone) {
// [u|v|w](n(+1)?)
// u,v,w are reserved names. They can only be set through the sequence app
if (symbol.type() == ExpressionNode::Type::Symbol
&& symbol.name()[0] >= SequenceStore::k_sequenceNames[0][0]
&& symbol.name()[0] <= SequenceStore::k_sequenceNames[MaxNumberOfSequences-1][0]) {
assert((symbol.name()+1)[0] == '(');
if (symbol.type() == ExpressionNode::Type::Sequence) {
Symbol s = const_cast<Symbol &>(static_cast<const Symbol &>(symbol));
if (strcmp(symbol.name()+1, "(n)") == 0 || strcmp(symbol.name()+1, "(n+1)") == 0) {
return Float<T>::Builder(m_values[nameIndexForSymbol(s)][rankIndexForSymbol(s)]);
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]);
} 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);
}
int numberOfDigits = 1;
constexpr int offset = 2; // 2 = 1 for ('u') + 1 for ('(')
while (symbol.name()[offset+numberOfDigits] != ')') {
numberOfDigits++;
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);
}
// Get the value of k in u(k) and store it in x
Integer integer(symbol.name()+2, numberOfDigits, false);
T x = integer.approximate<T>();
return Float<T>::Builder(seq.valueAtRank<T>(x, m_sequenceContext));
}
}
return ContextWithParent::expressionForSymbolAbstract(symbol, clone);
@@ -54,7 +49,7 @@ void CacheContext<T>::setValueForSymbol(T value, const Poincare::Symbol & symbol
template<typename T>
int CacheContext<T>::nameIndexForSymbol(const Poincare::Symbol & symbol) {
assert(strlen(symbol.name()) >= 4); // [u|v|w](n(+1) or k ?)
assert(symbol.name()[0] >= 'u' && symbol.name()[0] <= 'w'); // [u|v|w]
char name = symbol.name()[0];
assert(name >= SequenceStore::k_sequenceNames[0][0] && name <= SequenceStore::k_sequenceNames[MaxNumberOfSequences-1][0]); // u, v or w
return name - 'u';

View File

@@ -137,6 +137,7 @@ poincare_src += $(addprefix poincare/src/,\
solver.cpp \
square_root.cpp \
store.cpp \
sum_and_product.cpp \
subtraction.cpp \
sum.cpp \
symbol.cpp \

View File

@@ -14,6 +14,7 @@ public:
enum class SymbolAbstractType : uint8_t {
None,
Function,
Sequence,
Symbol
};
virtual SymbolAbstractType expressionTypeForIdentifier(const char * identifier, int length) = 0;

View File

@@ -88,6 +88,7 @@ class Expression : public TreeHandle {
friend class RealPart;
friend class Round;
friend class Sequence;
friend class SequenceNode;
friend class SignFunction;
friend class Sine;
friend class SquareRoot;
@@ -96,6 +97,7 @@ class Expression : public TreeHandle {
friend class Subtraction;
friend class SubtractionNode;
friend class Sum;
friend class SumAndProduct;
friend class Symbol;
friend class SymbolAbstractNode;
friend class Tangent;

View File

@@ -95,6 +95,7 @@ public:
Randint,
RealPart,
Round,
Sequence,
SignFunction,
SquareRoot,
Subtraction,

View File

@@ -1,11 +1,11 @@
#ifndef POINCARE_PRODUCT_H
#define POINCARE_PRODUCT_H
#include <poincare/sequence.h>
#include <poincare/sum_and_product.h>
namespace Poincare {
class ProductNode final : public SequenceNode {
class ProductNode final : public SumAndProductNode {
public:
// TreeNode
size_t size() const override { return sizeof(ProductNode); }
@@ -18,8 +18,8 @@ public:
Type type() const override { return Type::Product; }
private:
float emptySequenceValue() const override { return 1.0f; }
Layout createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const override;
float emptySumAndProductValue() const override { return 1.0f; }
Layout createSumAndProductLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const override;
int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
Evaluation<double> evaluateWithNextTerm(DoublePrecision p, Evaluation<double> a, Evaluation<double> b, Preferences::ComplexFormat complexFormat) const override {
return templatedApproximateWithNextTerm<double>(a, b, complexFormat);
@@ -30,10 +30,10 @@ private:
template<typename T> Evaluation<T> templatedApproximateWithNextTerm(Evaluation<T> a, Evaluation<T> b, Preferences::ComplexFormat complexFormat) const;
};
class Product final : public Sequence {
class Product final : public SumAndProduct {
friend class ProductNode;
public:
Product(const ProductNode * n) : Sequence(n) {}
Product(const ProductNode * n) : SumAndProduct(n) {}
static Product Builder(Expression child0, Symbol child1, Expression child2, Expression child3) { return TreeHandle::FixedArityBuilder<Product, ProductNode>({child0, child1, child2, child3}); }
static Expression UntypedBuilder(Expression children);
@@ -42,4 +42,4 @@ public:
}
#endif
#endif

View File

@@ -1,38 +1,55 @@
#ifndef POINCARE_SEQUENCE_H
#define POINCARE_SEQUENCE_H
#include <poincare/parametered_expression.h>
#include <poincare/symbol.h>
#include <poincare/approximation_helper.h>
#include <poincare/symbol_abstract.h>
namespace Poincare {
// Sequences are Product and Sum
class SequenceNode : public ParameteredExpressionNode {
class SequenceNode : public SymbolAbstractNode {
public:
int numberOfChildren() const override { return 4; }
SequenceNode(const char * newName, int length);
const char * name() const override { return m_name; }
int numberOfChildren() const override { return 1; }
#if POINCARE_TREE_LOG
void logNodeName(std::ostream & stream) const override {
stream << "Sequence";
}
#endif
Type type() const override { return Type::Sequence; }
Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) override;
private:
char m_name[0];
size_t nodeSize() const override { return sizeof(SequenceNode); }
// Layout
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
virtual Layout createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const = 0;
// Simplication
int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
// Simplification
Expression shallowReduce(ReductionContext reductionContext) override;
LayoutShape leftLayoutShape() const override { return LayoutShape::BoundaryPunctuation; };
/* Approximation */
Evaluation<float> approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<float>(context, complexFormat, angleUnit); }
Evaluation<double> approximate(DoublePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<double>(context, complexFormat, angleUnit); }
template<typename T> Evaluation<T> templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
virtual float emptySequenceValue() const = 0;
virtual Evaluation<float> evaluateWithNextTerm(SinglePrecision p, Evaluation<float> a, Evaluation<float> b, Preferences::ComplexFormat complexFormat) const = 0;
virtual Evaluation<double> evaluateWithNextTerm(DoublePrecision p, Evaluation<double> a, Evaluation<double> b, Preferences::ComplexFormat complexFormat) const = 0;
LayoutShape leftLayoutShape() const override { return strlen(m_name) > 1 ? LayoutShape::MoreLetters : LayoutShape::OneLetter; };
LayoutShape rightLayoutShape() const override { return LayoutShape::BoundaryPunctuation; }
// Evaluation
Evaluation<float> approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override;
Evaluation<double> approximate(DoublePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override;
template<typename T> Evaluation<T> templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
};
class Sequence : public Expression {
class Sequence : public SymbolAbstract {
friend SequenceNode;
public:
Sequence(const SequenceNode * n) : Expression(n) {}
Expression shallowReduce(Context * context);
Sequence(const SequenceNode * n) : SymbolAbstract(n) {}
static Sequence Builder(const char * name, size_t length, Expression child = Expression());
// Simplification
Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression);
Expression shallowReduce(ExpressionNode::ReductionContext reductionContext);
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount);
};
}
#endif
#endif

View File

@@ -1,11 +1,11 @@
#ifndef POINCARE_SUM_H
#define POINCARE_SUM_H
#include <poincare/sequence.h>
#include <poincare/sum_and_product.h>
namespace Poincare {
class SumNode final : public SequenceNode {
class SumNode final : public SumAndProductNode {
public:
// TreeNode
size_t size() const override { return sizeof(SumNode); }
@@ -18,8 +18,8 @@ public:
Type type() const override { return Type::Sum; }
private:
float emptySequenceValue() const override { return 0.0f; }
Layout createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const override;
float emptySumAndProductValue() const override { return 0.0f; }
Layout createSumAndProductLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const override;
int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
Evaluation<double> evaluateWithNextTerm(DoublePrecision p, Evaluation<double> a, Evaluation<double> b, Preferences::ComplexFormat complexFormat) const override {
return templatedApproximateWithNextTerm<double>(a, b, complexFormat);
@@ -30,10 +30,10 @@ private:
template<typename T> Evaluation<T> templatedApproximateWithNextTerm(Evaluation<T> a, Evaluation<T> b, Preferences::ComplexFormat complexFormat) const;
};
class Sum final : public Sequence {
class Sum final : public SumAndProduct {
friend class SumNode;
public:
Sum(const SumNode * n) : Sequence(n) {}
Sum(const SumNode * n) : SumAndProduct(n) {}
static Sum Builder(Expression child0, Symbol child1, Expression child2, Expression child3) { return TreeHandle::FixedArityBuilder<Sum, SumNode>({child0, child1, child2, child3}); }
static Expression UntypedBuilder(Expression children);

View File

@@ -0,0 +1,36 @@
#ifndef POINCARE_SUM_AND_PRODUCT_H
#define POINCARE_SUM_AND_PRODUCT_H
#include <poincare/parametered_expression.h>
#include <poincare/symbol.h>
#include <poincare/approximation_helper.h>
namespace Poincare {
class SumAndProductNode : public ParameteredExpressionNode {
public:
int numberOfChildren() const override { return 4; }
private:
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
virtual Layout createSumAndProductLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const = 0;
// Simplication
Expression shallowReduce(ReductionContext reductionContext) override;
LayoutShape leftLayoutShape() const override { return LayoutShape::BoundaryPunctuation; };
/* Approximation */
Evaluation<float> approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<float>(context, complexFormat, angleUnit); }
Evaluation<double> approximate(DoublePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<double>(context, complexFormat, angleUnit); }
template<typename T> Evaluation<T> templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
virtual float emptySumAndProductValue() const = 0;
virtual Evaluation<float> evaluateWithNextTerm(SinglePrecision p, Evaluation<float> a, Evaluation<float> b, Preferences::ComplexFormat complexFormat) const = 0;
virtual Evaluation<double> evaluateWithNextTerm(DoublePrecision p, Evaluation<double> a, Evaluation<double> b, Preferences::ComplexFormat complexFormat) const = 0;
};
class SumAndProduct : public Expression {
public:
SumAndProduct(const SumAndProductNode * n) : Expression(n) {}
Expression shallowReduce(Context * context);
};
}
#endif

View File

@@ -61,6 +61,8 @@ class SymbolAbstract : public Expression {
friend class Constant;
friend class Function;
friend class FunctionNode;
friend class Sequence;
friend class SequenceNode;
friend class Symbol;
friend class SymbolNode;
friend class SymbolAbstractNode;

View File

@@ -76,6 +76,7 @@
#include <poincare/rational.h>
#include <poincare/real_part.h>
#include <poincare/round.h>
#include <poincare/sequence.h>
#include <poincare/sign_function.h>
#include <poincare/sine.h>
#include <poincare/square_root.h>

View File

@@ -417,24 +417,10 @@ void Parser::parseSequence(Expression & leftHandSide, const char name, Token::Ty
if (m_status != Status::Progress) {
} else if (!popTokenIfType(rightDelimiter)) {
m_status = Status::Error; // Right delimiter missing.
} else if (rank.isIdenticalTo(Symbol::Builder('n'))) {
constexpr int symbolNameSize = 5;
char sym[symbolNameSize] = {name, '(', 'n', ')', 0};
leftHandSide = Symbol::Builder(sym, symbolNameSize);
} else if (rank.type() == ExpressionNode::Type::BasedInteger) {
Integer integer = static_cast<BasedInteger &>(rank).integer();
int symbolNameSize = 4 + Integer::NumberOfBase10DigitsWithoutSign(integer);
char sym[symbolNameSize];
sym[0] = name;
sym[1] = '(';
integer.serialize(&sym[2], Integer::NumberOfBase10DigitsWithoutSign(integer)+1);
sym[symbolNameSize-2] = ')';
sym[symbolNameSize-1] = '\0';
leftHandSide = Symbol::Builder(sym, symbolNameSize);
} else if (rank.isIdenticalTo(Addition::Builder(Symbol::Builder('n'), BasedInteger::Builder("1")))) {
constexpr int symbolNameSize = 7;
char sym[symbolNameSize] = {name, '(', 'n', '+', '1', ')', 0};
leftHandSide = Symbol::Builder(sym, symbolNameSize);
} 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);
} else {
m_status = Status::Error; // Unexpected parameter.
}

View File

@@ -13,7 +13,7 @@ namespace Poincare {
constexpr Expression::FunctionHelper Product::s_functionHelper;
Layout ProductNode::createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const {
Layout ProductNode::createSumAndProductLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const {
return ProductLayout::Builder(argumentLayout, symbolLayout, subscriptLayout, superscriptLayout);
}

View File

@@ -1,68 +1,107 @@
#include <poincare/sequence.h>
#include <poincare/decimal.h>
#include <poincare/undefined.h>
#include <poincare/variable_context.h>
extern "C" {
#include <assert.h>
#include <stdlib.h>
}
#include <cmath>
#include <poincare/integer.h>
#include <poincare/code_point_layout.h>
#include <poincare/horizontal_layout.h>
#include <poincare/vertical_offset_layout.h>
#include <poincare/based_integer.h>
#include <poincare/layout_helper.h>
#include <poincare/serialization_helper.h>
#include <poincare/parenthesis.h>
#include <poincare/complex.h>
#include <apps/sequence/sequence.h>
namespace Poincare {
SequenceNode::SequenceNode(const char * newName, int length) : SymbolAbstractNode() {
strlcpy(const_cast<char*>(name()), newName, length+1);
}
Expression SequenceNode::replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) {
return Sequence(this).replaceSymbolWithExpression(symbol, expression);
}
Layout SequenceNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
return createSequenceLayout(
childAtIndex(0)->createLayout(floatDisplayMode, numberOfSignificantDigits),
childAtIndex(1)->createLayout(floatDisplayMode, numberOfSignificantDigits),
childAtIndex(2)->createLayout(floatDisplayMode, numberOfSignificantDigits),
childAtIndex(3)->createLayout(floatDisplayMode, numberOfSignificantDigits)
);
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()));
}
int SequenceNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, name());
}
Expression SequenceNode::shallowReduce(ReductionContext reductionContext) {
return Sequence(this).shallowReduce(reductionContext.context());
return Sequence(this).shallowReduce(reductionContext); // This uses Symbol::shallowReduce
}
Evaluation<float> SequenceNode::approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const {
return templatedApproximate<float>(context, complexFormat, angleUnit);
}
Evaluation<double> SequenceNode::approximate(DoublePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const {
return templatedApproximate<double>(context, complexFormat, angleUnit);
}
template<typename T>
Evaluation<T> SequenceNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const {
Evaluation<T> aInput = childAtIndex(2)->approximate(T(), context, complexFormat, angleUnit);
Evaluation<T> bInput = childAtIndex(3)->approximate(T(), context, complexFormat, angleUnit);
T start = aInput.toScalar();
T end = bInput.toScalar();
if (std::isnan(start) || std::isnan(end) || start != (int)start || end != (int)end || end - start > k_maxNumberOfSteps) {
if (childAtIndex(0)->approximate((T)1, context, complexFormat, angleUnit).isUndefined()) {
return Complex<T>::Undefined();
}
VariableContext nContext = VariableContext(static_cast<SymbolNode *>(childAtIndex(1))->name(), context);
Evaluation<T> result = Complex<T>::Builder((T)emptySequenceValue());
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);
if (result.isUndefined()) {
return Complex<T>::Undefined();
}
Expression e = context->expressionForSymbolAbstract(this, false);
if (e.isUninitialized()) {
return Complex<T>::Undefined();
}
return result;
return e.node()->approximate(T(), context, complexFormat, angleUnit);
}
Expression Sequence::shallowReduce(Context * context) {
{
Expression e = Expression::defaultShallowReduce();
e = e.defaultHandleUnitsInChildren();
if (e.isUndefined()) {
return e;
}
Sequence Sequence::Builder(const char * name, size_t length, Expression child) {
Sequence seq = SymbolAbstract::Builder<Sequence, SequenceNode>(name, length);
if (!child.isUninitialized()) {
seq.replaceChildAtIndexInPlace(0, child);
}
assert(!childAtIndex(1).deepIsMatrix(context));
if (childAtIndex(2).deepIsMatrix(context) || childAtIndex(3).deepIsMatrix(context)) {
return replaceWithUndefinedInPlace();
return seq;
}
Expression Sequence::replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) {
// Replace the symbol in the child
childAtIndex(0).replaceSymbolWithExpression(symbol, expression);
if (symbol.type() == ExpressionNode::Type::Sequence && hasSameNameAs(symbol)) {
Expression value = expression.clone();
Expression p = parent();
if (!p.isUninitialized() && p.node()->childAtIndexNeedsUserParentheses(value, p.indexOfChild(*this))) {
value = Parenthesis::Builder(value);
}
replaceWithInPlace(value);
return value;
}
return *this;
}
template Evaluation<float> SequenceNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
template Evaluation<double> SequenceNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
// Those two functions will be updated in a comming commit
Expression Sequence::shallowReduce(ExpressionNode::ReductionContext reductionContext) {
return *this;
}
Expression Sequence::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) {
return *this;
}
}

View File

@@ -13,7 +13,7 @@ namespace Poincare {
constexpr Expression::FunctionHelper Sum::s_functionHelper;
Layout SumNode::createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const {
Layout SumNode::createSumAndProductLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const {
return SumLayout::Builder(argumentLayout, symbolLayout, subscriptLayout, superscriptLayout);
}

View File

@@ -0,0 +1,68 @@
#include <poincare/sum_and_product.h>
#include <poincare/decimal.h>
#include <poincare/undefined.h>
#include <poincare/variable_context.h>
extern "C" {
#include <assert.h>
#include <stdlib.h>
}
#include <cmath>
namespace Poincare {
Layout SumAndProductNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
return createSumAndProductLayout(
childAtIndex(0)->createLayout(floatDisplayMode, numberOfSignificantDigits),
childAtIndex(1)->createLayout(floatDisplayMode, numberOfSignificantDigits),
childAtIndex(2)->createLayout(floatDisplayMode, numberOfSignificantDigits),
childAtIndex(3)->createLayout(floatDisplayMode, numberOfSignificantDigits)
);
}
Expression SumAndProductNode::shallowReduce(ReductionContext reductionContext) {
return SumAndProduct(this).shallowReduce(reductionContext.context());
}
template<typename T>
Evaluation<T> SumAndProductNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const {
Evaluation<T> aInput = childAtIndex(2)->approximate(T(), context, complexFormat, angleUnit);
Evaluation<T> bInput = childAtIndex(3)->approximate(T(), context, complexFormat, angleUnit);
T start = aInput.toScalar();
T end = bInput.toScalar();
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);
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);
if (result.isUndefined()) {
return Complex<T>::Undefined();
}
}
return result;
}
Expression SumAndProduct::shallowReduce(Context * context) {
{
Expression e = Expression::defaultShallowReduce();
e = e.defaultHandleUnitsInChildren();
if (e.isUndefined()) {
return e;
}
}
assert(!childAtIndex(1).deepIsMatrix(context));
if (childAtIndex(2).deepIsMatrix(context) || childAtIndex(3).deepIsMatrix(context)) {
return replaceWithUndefinedInPlace();
}
return *this;
}
template Evaluation<float> SumAndProductNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
template Evaluation<double> SumAndProductNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
}

View File

@@ -66,39 +66,6 @@ int SymbolNode::getVariables(Context * context, isVariableTest isVariable, char
Layout SymbolNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
assert(!isUnknown());
// TODO return Parse(m_name).createLayout() ?
// Special case for the symbol names: u(n), u(n+1), v(n), v(n+1), w(n), w(n+1)
const char * sequenceIndex[] = {"n", "n+1"};
for (char sequenceName = 'u'; sequenceName <= 'w'; sequenceName++) {
if (m_name[0] == sequenceName) {
for (size_t i = 0; i < sizeof(sequenceIndex)/sizeof(char *); i++) {
size_t sequenceIndexLength = strlen(sequenceIndex[i]);
if (m_name[1] == '(' && strncmp(sequenceIndex[i], m_name+2, sequenceIndexLength) == 0 && m_name[2+sequenceIndexLength] == ')' && m_name[3+sequenceIndexLength] == 0) {
return HorizontalLayout::Builder(
CodePointLayout::Builder(sequenceName),
VerticalOffsetLayout::Builder(
LayoutHelper::String(sequenceIndex[i], sequenceIndexLength),
VerticalOffsetLayoutNode::Position::Subscript));
}
}
/* Checking for u(k) forms with k positive integer. Since the sequence
* parser only handles sequenceIndexes like above and BasedIntegers, there
* is no need to be carefull with how we process m_name. */
if (m_name[1] == '(') {
int numberOfDigits = 0;
while (m_name[numberOfDigits + 2] != ')') {
if (m_name[numberOfDigits + 2] <= '9' && m_name[numberOfDigits + 2] >= '0') {
numberOfDigits++;
}
}
return HorizontalLayout::Builder(
CodePointLayout::Builder(sequenceName),
VerticalOffsetLayout::Builder(
LayoutHelper::String(m_name+2, numberOfDigits),
VerticalOffsetLayoutNode::Position::Subscript));
}
}
}
return LayoutHelper::String(m_name, strlen(m_name));
}

View File

@@ -3,6 +3,7 @@
#include <poincare/constant.h>
#include <poincare/function.h>
#include <poincare/rational.h>
#include <poincare/sequence.h>
#include <poincare/symbol.h>
#include <poincare/undefined.h>
#include <poincare/helpers.h>
@@ -36,6 +37,11 @@ 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());
}
@@ -81,6 +87,8 @@ Expression SymbolAbstract::Expand(const SymbolAbstract & symbol, Context * conte
template Constant SymbolAbstract::Builder<Constant, ConstantNode>(char const*, int);
template Function SymbolAbstract::Builder<Function, FunctionNode>(char const*, int);
template Sequence SymbolAbstract::Builder<Sequence, SequenceNode>(char const*, int);
template Symbol SymbolAbstract::Builder<Symbol, SymbolNode>(char const*, int);
}