From ed358590cec1d1e480e09aed61fb381c5ff0697d Mon Sep 17 00:00:00 2001 From: Arthur Camouseigt Date: Wed, 22 Jul 2020 17:22:37 +0200 Subject: [PATCH] [Sequence] Changed the way sequences are parsed Change-Id: If19b46a317e4f336ac857690827ab08e147ac75a --- apps/sequence/cache_context.cpp | 27 ++--- poincare/Makefile | 1 + poincare/include/poincare/context.h | 1 + poincare/include/poincare/expression.h | 2 + poincare/include/poincare/expression_node.h | 1 + poincare/include/poincare/product.h | 14 +-- poincare/include/poincare/sequence.h | 59 +++++---- poincare/include/poincare/sum.h | 12 +- poincare/include/poincare/sum_and_product.h | 36 ++++++ poincare/include/poincare/symbol_abstract.h | 2 + poincare/include/poincare_nodes.h | 1 + poincare/src/parsing/parser.cpp | 22 +--- poincare/src/product.cpp | 2 +- poincare/src/sequence.cpp | 127 +++++++++++++------- poincare/src/sum.cpp | 2 +- poincare/src/sum_and_product.cpp | 68 +++++++++++ poincare/src/symbol.cpp | 33 ----- poincare/src/symbol_abstract.cpp | 8 ++ 18 files changed, 271 insertions(+), 147 deletions(-) create mode 100644 poincare/include/poincare/sum_and_product.h create mode 100644 poincare/src/sum_and_product.cpp diff --git a/apps/sequence/cache_context.cpp b/apps/sequence/cache_context.cpp index f871eba5a..771bda1cb 100644 --- a/apps/sequence/cache_context.cpp +++ b/apps/sequence/cache_context.cpp @@ -19,29 +19,24 @@ CacheContext::CacheContext(Context * parentContext) : template const Expression CacheContext::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(static_cast(symbol)); - if (strcmp(symbol.name()+1, "(n)") == 0 || strcmp(symbol.name()+1, "(n+1)") == 0) { - return Float::Builder(m_values[nameIndexForSymbol(s)][rankIndexForSymbol(s)]); + if (s.childAtIndex(0).type() == ExpressionNode::Type::Symbol) { + return Float::Builder(m_values[nameIndexForSymbol(s)][0]); + } else if (s.childAtIndex(0).type() == ExpressionNode::Type::Addition) { + return Float::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::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::Builder(seq.valueAtRank(rank.approximateToScalar(this, Poincare::Preferences::ComplexFormat::Cartesian, Poincare::Preferences::AngleUnit::Radian), m_sequenceContext)); + } else { + return Float::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(); - return Float::Builder(seq.valueAtRank(x, m_sequenceContext)); } } return ContextWithParent::expressionForSymbolAbstract(symbol, clone); @@ -54,7 +49,7 @@ void CacheContext::setValueForSymbol(T value, const Poincare::Symbol & symbol template int CacheContext::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'; diff --git a/poincare/Makefile b/poincare/Makefile index c289935cc..790c7fa6c 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -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 \ diff --git a/poincare/include/poincare/context.h b/poincare/include/poincare/context.h index a36cc1eea..c695d4711 100644 --- a/poincare/include/poincare/context.h +++ b/poincare/include/poincare/context.h @@ -14,6 +14,7 @@ public: enum class SymbolAbstractType : uint8_t { None, Function, + Sequence, Symbol }; virtual SymbolAbstractType expressionTypeForIdentifier(const char * identifier, int length) = 0; diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 0b665ff86..20a5dee45 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -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; diff --git a/poincare/include/poincare/expression_node.h b/poincare/include/poincare/expression_node.h index 2e7e45c10..3393d8d26 100644 --- a/poincare/include/poincare/expression_node.h +++ b/poincare/include/poincare/expression_node.h @@ -95,6 +95,7 @@ public: Randint, RealPart, Round, + Sequence, SignFunction, SquareRoot, Subtraction, diff --git a/poincare/include/poincare/product.h b/poincare/include/poincare/product.h index 140fe5c4f..04c5605e8 100644 --- a/poincare/include/poincare/product.h +++ b/poincare/include/poincare/product.h @@ -1,11 +1,11 @@ #ifndef POINCARE_PRODUCT_H #define POINCARE_PRODUCT_H -#include +#include 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 evaluateWithNextTerm(DoublePrecision p, Evaluation a, Evaluation b, Preferences::ComplexFormat complexFormat) const override { return templatedApproximateWithNextTerm(a, b, complexFormat); @@ -30,10 +30,10 @@ private: template Evaluation templatedApproximateWithNextTerm(Evaluation a, Evaluation 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({child0, child1, child2, child3}); } static Expression UntypedBuilder(Expression children); @@ -42,4 +42,4 @@ public: } -#endif +#endif \ No newline at end of file diff --git a/poincare/include/poincare/sequence.h b/poincare/include/poincare/sequence.h index 0067f3790..7d15d2662 100644 --- a/poincare/include/poincare/sequence.h +++ b/poincare/include/poincare/sequence.h @@ -1,38 +1,55 @@ #ifndef POINCARE_SEQUENCE_H #define POINCARE_SEQUENCE_H -#include -#include -#include +#include 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 approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, complexFormat, angleUnit); } - Evaluation approximate(DoublePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, complexFormat, angleUnit); } - template Evaluation templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; - virtual float emptySequenceValue() const = 0; - virtual Evaluation evaluateWithNextTerm(SinglePrecision p, Evaluation a, Evaluation b, Preferences::ComplexFormat complexFormat) const = 0; - virtual Evaluation evaluateWithNextTerm(DoublePrecision p, Evaluation a, Evaluation 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 approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override; + Evaluation approximate(DoublePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override; + template Evaluation 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 \ No newline at end of file diff --git a/poincare/include/poincare/sum.h b/poincare/include/poincare/sum.h index af1542203..84b062a88 100644 --- a/poincare/include/poincare/sum.h +++ b/poincare/include/poincare/sum.h @@ -1,11 +1,11 @@ #ifndef POINCARE_SUM_H #define POINCARE_SUM_H -#include +#include 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 evaluateWithNextTerm(DoublePrecision p, Evaluation a, Evaluation b, Preferences::ComplexFormat complexFormat) const override { return templatedApproximateWithNextTerm(a, b, complexFormat); @@ -30,10 +30,10 @@ private: template Evaluation templatedApproximateWithNextTerm(Evaluation a, Evaluation 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({child0, child1, child2, child3}); } static Expression UntypedBuilder(Expression children); diff --git a/poincare/include/poincare/sum_and_product.h b/poincare/include/poincare/sum_and_product.h new file mode 100644 index 000000000..a74ecc0d2 --- /dev/null +++ b/poincare/include/poincare/sum_and_product.h @@ -0,0 +1,36 @@ +#ifndef POINCARE_SUM_AND_PRODUCT_H +#define POINCARE_SUM_AND_PRODUCT_H + +#include +#include +#include + +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 approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, complexFormat, angleUnit); } + Evaluation approximate(DoublePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, complexFormat, angleUnit); } + template Evaluation templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; + virtual float emptySumAndProductValue() const = 0; + virtual Evaluation evaluateWithNextTerm(SinglePrecision p, Evaluation a, Evaluation b, Preferences::ComplexFormat complexFormat) const = 0; + virtual Evaluation evaluateWithNextTerm(DoublePrecision p, Evaluation a, Evaluation b, Preferences::ComplexFormat complexFormat) const = 0; +}; + +class SumAndProduct : public Expression { +public: + SumAndProduct(const SumAndProductNode * n) : Expression(n) {} + Expression shallowReduce(Context * context); +}; + +} + +#endif \ No newline at end of file diff --git a/poincare/include/poincare/symbol_abstract.h b/poincare/include/poincare/symbol_abstract.h index 02b2e79a8..633ecad08 100644 --- a/poincare/include/poincare/symbol_abstract.h +++ b/poincare/include/poincare/symbol_abstract.h @@ -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; diff --git a/poincare/include/poincare_nodes.h b/poincare/include/poincare_nodes.h index ed7316b8e..c0d3a853e 100644 --- a/poincare/include/poincare_nodes.h +++ b/poincare/include/poincare_nodes.h @@ -76,6 +76,7 @@ #include #include #include +#include #include #include #include diff --git a/poincare/src/parsing/parser.cpp b/poincare/src/parsing/parser.cpp index 36c90252f..dfd85c16b 100644 --- a/poincare/src/parsing/parser.cpp +++ b/poincare/src/parsing/parser.cpp @@ -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(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. } diff --git a/poincare/src/product.cpp b/poincare/src/product.cpp index 51759f281..d168785d9 100644 --- a/poincare/src/product.cpp +++ b/poincare/src/product.cpp @@ -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); } diff --git a/poincare/src/sequence.cpp b/poincare/src/sequence.cpp index 9955cacfa..28d9f0a96 100644 --- a/poincare/src/sequence.cpp +++ b/poincare/src/sequence.cpp @@ -1,68 +1,107 @@ #include -#include -#include -#include -extern "C" { -#include -#include -} -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace Poincare { +SequenceNode::SequenceNode(const char * newName, int length) : SymbolAbstractNode() { + strlcpy(const_cast(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(*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 SequenceNode::approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { + return templatedApproximate(context, complexFormat, angleUnit); +} + +Evaluation SequenceNode::approximate(DoublePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { + return templatedApproximate(context, complexFormat, angleUnit); } template Evaluation SequenceNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { - Evaluation aInput = childAtIndex(2)->approximate(T(), context, complexFormat, angleUnit); - Evaluation 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::Undefined(); } - VariableContext nContext = VariableContext(static_cast(childAtIndex(1))->name(), context); - Evaluation result = Complex::Builder((T)emptySequenceValue()); - for (int i = (int)start; i <= (int)end; i++) { - if (Expression::ShouldStopProcessing()) { - return Complex::Undefined(); - } - nContext.setApproximationForVariable((T)i); - result = evaluateWithNextTerm(T(), result, childAtIndex(0)->approximate(T(), &nContext, complexFormat, angleUnit), complexFormat); - if (result.isUndefined()) { - return Complex::Undefined(); - } + Expression e = context->expressionForSymbolAbstract(this, false); + if (e.isUninitialized()) { + return Complex::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(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 SequenceNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; -template Evaluation 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; +} } diff --git a/poincare/src/sum.cpp b/poincare/src/sum.cpp index ceee70feb..84757093c 100644 --- a/poincare/src/sum.cpp +++ b/poincare/src/sum.cpp @@ -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); } diff --git a/poincare/src/sum_and_product.cpp b/poincare/src/sum_and_product.cpp new file mode 100644 index 000000000..8816dc958 --- /dev/null +++ b/poincare/src/sum_and_product.cpp @@ -0,0 +1,68 @@ +#include +#include +#include +#include +extern "C" { +#include +#include +} +#include + +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 +Evaluation SumAndProductNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { + Evaluation aInput = childAtIndex(2)->approximate(T(), context, complexFormat, angleUnit); + Evaluation 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::Undefined(); + } + VariableContext nContext = VariableContext(static_cast(childAtIndex(1))->name(), context); + Evaluation result = Complex::Builder((T)emptySumAndProductValue()); + for (int i = (int)start; i <= (int)end; i++) { + if (Expression::ShouldStopProcessing()) { + return Complex::Undefined(); + } + nContext.setApproximationForVariable((T)i); + result = evaluateWithNextTerm(T(), result, childAtIndex(0)->approximate(T(), &nContext, complexFormat, angleUnit), complexFormat); + if (result.isUndefined()) { + return Complex::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 SumAndProductNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; +template Evaluation SumAndProductNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; + +} \ No newline at end of file diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 369ed5832..29e0c28af 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -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)); } diff --git a/poincare/src/symbol_abstract.cpp b/poincare/src/symbol_abstract.cpp index 61c679767..541b1ee3f 100644 --- a/poincare/src/symbol_abstract.cpp +++ b/poincare/src/symbol_abstract.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -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(e)->name()); } @@ -81,6 +87,8 @@ Expression SymbolAbstract::Expand(const SymbolAbstract & symbol, Context * conte template Constant SymbolAbstract::Builder(char const*, int); template Function SymbolAbstract::Builder(char const*, int); +template Sequence SymbolAbstract::Builder(char const*, int); template Symbol SymbolAbstract::Builder(char const*, int); + }