mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-18 21:30:38 +01:00
[Sequence] Changed the way sequences are parsed
Change-Id: If19b46a317e4f336ac857690827ab08e147ac75a
This commit is contained in:
committed by
Émilie Feral
parent
8434da60ef
commit
ed358590ce
@@ -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';
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -14,6 +14,7 @@ public:
|
||||
enum class SymbolAbstractType : uint8_t {
|
||||
None,
|
||||
Function,
|
||||
Sequence,
|
||||
Symbol
|
||||
};
|
||||
virtual SymbolAbstractType expressionTypeForIdentifier(const char * identifier, int length) = 0;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -95,6 +95,7 @@ public:
|
||||
Randint,
|
||||
RealPart,
|
||||
Round,
|
||||
Sequence,
|
||||
SignFunction,
|
||||
SquareRoot,
|
||||
Subtraction,
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
|
||||
36
poincare/include/poincare/sum_and_product.h
Normal file
36
poincare/include/poincare/sum_and_product.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
68
poincare/src/sum_and_product.cpp
Normal file
68
poincare/src/sum_and_product.cpp
Normal 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;
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user