diff --git a/poincare/Makefile b/poincare/Makefile index ce449acea..0f37c2428 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -99,12 +99,15 @@ objs += $(addprefix poincare/src/,\ power.o\ print_float.o\ preferences.o\ + product.o\ rational.o\ + sequence.o\ serialization_helper.o\ simplification_helper.o\ sine.o\ square_root.o\ subtraction.o\ + sum.o\ symbol.o\ tangent.o\ tree_node.o\ diff --git a/poincare/include/poincare.h b/poincare/include/poincare.h index 50117db35..f66d52cec 100644 --- a/poincare/include/poincare.h +++ b/poincare/include/poincare.h @@ -133,6 +133,7 @@ #include #include #include +#include #include #include #include @@ -156,6 +157,7 @@ #include #include #include +#include #include #include #include diff --git a/poincare/include/poincare/product.h b/poincare/include/poincare/product.h index f212b2c16..288752f8b 100644 --- a/poincare/include/poincare/product.h +++ b/poincare/include/poincare/product.h @@ -5,21 +5,43 @@ namespace Poincare { -class Product : public Sequence { - using Sequence::Sequence; +class ProductNode : public SequenceNode { public: - Type type() const override; + // Allocation Failure + static ProductNode * FailedAllocationStaticNode(); + ProductNode * failedAllocationStaticNode() override { return FailedAllocationStaticNode(); } + // TreeNode + size_t size() const override { return sizeof(ProductNode); } +#if POINCARE_TREE_LOG + virtual void logNodeName(std::ostream & stream) const override { + stream << "Product"; + } +#endif + + Type type() const override { return Type::Product; } private: - const char * name() const override; - int emptySequenceValue() const override; + const char * name() const override { return "product"; } + float emptySequenceValue() const override { return 1.0f; } LayoutRef createSequenceLayout(LayoutRef argumentLayout, LayoutRef subscriptLayout, LayoutRef superscriptLayout) const override; - Evaluation evaluateWithNextTerm(DoublePrecision p, Evaluation * a, Evaluation * b) const override { + Evaluation evaluateWithNextTerm(DoublePrecision p, Evaluation a, Evaluation b) const override { return templatedApproximateWithNextTerm(a, b); } - Evaluation evaluateWithNextTerm(SinglePrecision p, Evaluation * a, Evaluation * b) const override { + Evaluation evaluateWithNextTerm(SinglePrecision p, Evaluation a, Evaluation b) const override { return templatedApproximateWithNextTerm(a, b); } - template Evaluation templatedApproximateWithNextTerm(Evaluation * a, Evaluation * b) const; + template Evaluation templatedApproximateWithNextTerm(Evaluation a, Evaluation b) const; +}; + +class Product : public Expression { +friend class ProductNode; +public: + Product() : Expression(TreePool::sharedPool()->createTreeNode()) {} + Product(const ProductNode * n) : Expression(n) {} + Product(Expression operand0, Expression operand1, Expression operand2) : Product() { + replaceChildAtIndexInPlace(0, operand0); + replaceChildAtIndexInPlace(1, operand1); + replaceChildAtIndexInPlace(2, operand2); + } }; } diff --git a/poincare/include/poincare/sequence.h b/poincare/include/poincare/sequence.h index 70bd296bc..8c4f2dd33 100644 --- a/poincare/include/poincare/sequence.h +++ b/poincare/include/poincare/sequence.h @@ -2,13 +2,15 @@ #define POINCARE_SEQUENCE_H #include -#include +#include +#include #include namespace Poincare { -class Sequence : public StaticHierarchy<3> { - using StaticHierarchy<3>::StaticHierarchy; +class SequenceNode : public ExpressionNode { +public: + int numberOfChildren() const override { return 3; } private: LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -16,13 +18,13 @@ private: } virtual LayoutRef createSequenceLayout(LayoutRef subscriptLayout, LayoutRef superscriptLayout, LayoutRef argumentLayout) const = 0; virtual const char * name() const = 0; - /* Evaluation */ + /* Approximation */ Evaluation approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } Evaluation approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } template Evaluation templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; - virtual int emptySequenceValue() const = 0; - virtual Evaluation evaluateWithNextTerm(SinglePrecision p, Evaluation * a, Evaluation * b) const = 0; - virtual Evaluation evaluateWithNextTerm(DoublePrecision p, Evaluation * a, Evaluation * b) const = 0; + virtual float emptySequenceValue() const = 0; + virtual Evaluation evaluateWithNextTerm(SinglePrecision p, Evaluation a, Evaluation b) const = 0; + virtual Evaluation evaluateWithNextTerm(DoublePrecision p, Evaluation a, Evaluation b) const = 0; }; } diff --git a/poincare/include/poincare/sum.h b/poincare/include/poincare/sum.h index 7592893f9..0fa3b84fa 100644 --- a/poincare/include/poincare/sum.h +++ b/poincare/include/poincare/sum.h @@ -5,21 +5,43 @@ namespace Poincare { -class Sum : public Sequence { - using Sequence::Sequence; +class SumNode : public SequenceNode { public: - Type type() const override; + // Allocation Failure + static SumNode * FailedAllocationStaticNode(); + SumNode * failedAllocationStaticNode() override { return FailedAllocationStaticNode(); } + // TreeNode + size_t size() const override { return sizeof(SumNode); } +#if POINCARE_TREE_LOG + virtual void logNodeName(std::ostream & stream) const override { + stream << "Sum"; + } +#endif + + Type type() const override { return Type::Sum; } private: - const char * name() const override; - int emptySequenceValue() const override; + const char * name() const override { return "sum"; } + float emptySequenceValue() const override { return 0.0f; } LayoutRef createSequenceLayout(LayoutRef argumentLayout, LayoutRef subscriptLayout, LayoutRef superscriptLayout) const override; - Evaluation evaluateWithNextTerm(DoublePrecision p, Evaluation * a, Evaluation * b) const override { + Evaluation evaluateWithNextTerm(DoublePrecision p, Evaluation a, Evaluation b) const override { return templatedApproximateWithNextTerm(a, b); } - Evaluation evaluateWithNextTerm(SinglePrecision p, Evaluation * a, Evaluation * b) const override { + Evaluation evaluateWithNextTerm(SinglePrecision p, Evaluation a, Evaluation b) const override { return templatedApproximateWithNextTerm(a, b); } - template Evaluation templatedApproximateWithNextTerm(Evaluation * a, Evaluation * b) const; + template Evaluation templatedApproximateWithNextTerm(Evaluation a, Evaluation b) const; +}; + +class Sum : public Expression { +friend class SumNode; +public: + Sum() : Expression(TreePool::sharedPool()->createTreeNode()) {} + Sum(const SumNode * n) : Expression(n) {} + Sum(Expression operand0, Expression operand1, Expression operand2) : Sum() { + replaceChildAtIndexInPlace(0, operand0); + replaceChildAtIndexInPlace(1, operand1); + replaceChildAtIndexInPlace(2, operand2); + } }; } diff --git a/poincare/src/expression_lexer.l b/poincare/src/expression_lexer.l index cb4197c2d..50e3092cf 100644 --- a/poincare/src/expression_lexer.l +++ b/poincare/src/expression_lexer.l @@ -143,8 +143,7 @@ log { return LOGFUNCTION; } prediction95 { poincare_expression_yylval.expression = new PredictionInterval(); return FUNCTION; } */ prediction { poincare_expression_yylval.expression = SimplePredictionInterval(); return FUNCTION; } - /*product { poincare_expression_yylval.expression = new Product(); return FUNCTION; } -*/ +product { poincare_expression_yylval.expression = Product(); return FUNCTION; } quo { poincare_expression_yylval.expression = DivisionQuotient(); return FUNCTION; } /*random { poincare_expression_yylval.expression = new Random(); return FUNCTION; } randint { poincare_expression_yylval.expression = new Randint(); return FUNCTION; } @@ -156,8 +155,7 @@ root { poincare_expression_yylval.expression = NthRoot(); return FUNCTION; } */ sin { poincare_expression_yylval.expression = Sine(); return FUNCTION; } sinh { poincare_expression_yylval.expression = HyperbolicSine(); return FUNCTION; } - /*sum { poincare_expression_yylval.expression = new Sum(); return FUNCTION; } -*/ +sum { poincare_expression_yylval.expression = Sum(); return FUNCTION; } tan { poincare_expression_yylval.expression = Tangent(); return FUNCTION; } tanh { poincare_expression_yylval.expression = HyperbolicTangent(); return FUNCTION; } trace { poincare_expression_yylval.expression = MatrixTrace(); return FUNCTION; } diff --git a/poincare/src/product.cpp b/poincare/src/product.cpp index 209956bb0..4419b1a46 100644 --- a/poincare/src/product.cpp +++ b/poincare/src/product.cpp @@ -9,45 +9,34 @@ extern "C" { namespace Poincare { -ExpressionNode::Type Product::type() const { - return Type::Product; +ProductNode * ProductNode::FailedAllocationStaticNode() { + static AllocationFailureExpressionNode failure; + TreePool::sharedPool()->registerStaticNodeIfRequired(&failure); + return &failure; } -Expression * Product::clone() const { - Product * a = new Product(m_operands, true); - return a; -} - -const char * Product::name() const { - return "product"; -} - -int Product::emptySequenceValue() const { - return 1; -} - -LayoutRef Product::createSequenceLayout(LayoutRef argumentLayout, LayoutRef subscriptLayout, LayoutRef superscriptLayout) const { +LayoutRef ProductNode::createSequenceLayout(LayoutRef argumentLayout, LayoutRef subscriptLayout, LayoutRef superscriptLayout) const { return ProductLayoutRef(argumentLayout, subscriptLayout, superscriptLayout); } template -Evaluation * Product::templatedApproximateWithNextTerm(Evaluation * a, Evaluation * b) const { - if (a->type() == Evaluation::Type::Complex && b->type() == Evaluation::Type::Complex) { - Complex * c = static_cast *>(a); - Complex * d = static_cast *>(b); - return new Complex((*c)*(*d)); +Evaluation ProductNode::templatedApproximateWithNextTerm(Evaluation a, Evaluation b) const { + if (a.type() == EvaluationNode::Type::Complex && b.type() == EvaluationNode::Type::Complex) { + Complex c = static_cast&>(a); + Complex d = static_cast&>(b); + return Complex(c.stdComplex()*d.stdComplex()); } - if (a->type() == Evaluation::Type::Complex) { - Complex * c = static_cast *>(a); - assert(b->type() == Evaluation::Type::MatrixComplex); - MatrixComplex * m = static_cast *>(b); - return new MatrixComplex(Multiplication::computeOnComplexAndMatrix(*c, *m)); + if (a.type() == EvaluationNode::Type::Complex) { + Complex c = static_cast &>(a); + assert(b.type() == EvaluationNode::Type::MatrixComplex); + MatrixComplex m = static_cast &>(b); + return MultiplicationNode::computeOnComplexAndMatrix(c.stdComplex(), m); } - assert(a->type() == Evaluation::Type::MatrixComplex); - assert(b->type() == Evaluation::Type::MatrixComplex); - MatrixComplex * m = static_cast *>(a); - MatrixComplex * n = static_cast *>(b); - return new MatrixComplex(Multiplication::computeOnMatrices(*m, *n)); + assert(a.type() == EvaluationNode::Type::MatrixComplex); + assert(b.type() == EvaluationNode::Type::MatrixComplex); + MatrixComplex m = static_cast&>(a); + MatrixComplex n = static_cast&>(b); + return MultiplicationNode::computeOnMatrices(m, n); } } diff --git a/poincare/src/sequence.cpp b/poincare/src/sequence.cpp index b02fa72d2..524ba1a8b 100644 --- a/poincare/src/sequence.cpp +++ b/poincare/src/sequence.cpp @@ -11,36 +11,29 @@ extern "C" { namespace Poincare { -LayoutRef Sequence::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { +LayoutRef 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)); } template -Evaluation Sequence::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { - Evaluation * aInput = childAtIndex(1)->approximate(T(), context, angleUnit); - Evaluation * bInput = childAtIndex(2)->approximate(T(), context, angleUnit); - T start = aInput->toScalar(); - T end = bInput->toScalar(); - delete aInput; - delete bInput; +Evaluation SequenceNode::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { + Evaluation aInput = childAtIndex(1)->approximate(T(), context, angleUnit); + Evaluation bInput = childAtIndex(2)->approximate(T(), context, 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 new Complex(Complex::Undefined()); + return Complex::Undefined(); } VariableContext nContext = VariableContext('n', &context); - Evaluation * result = new Complex(emptySequenceValue()); + Evaluation result = Complex((T)emptySequenceValue()); for (int i = (int)start; i <= (int)end; i++) { - if (shouldStopProcessing()) { - delete result; - return new Complex(Complex::Undefined()); + if (Expression::shouldStopProcessing()) { + return Complex::Undefined(); } nContext.setApproximationForVariable((T)i); - Evaluation * expression = childAtIndex(0)->approximate(T(), nContext, angleUnit); - Evaluation * newResult = evaluateWithNextTerm(T(), result, expression); - delete result; - delete expression; - result = newResult; - if (result == nullptr) { - return new Complex(Complex::Undefined()); + result = evaluateWithNextTerm(T(), result, childAtIndex(0)->approximate(T(), nContext, angleUnit)); + if (result.isUndefined()) { + return Complex::Undefined(); } } return result; diff --git a/poincare/src/sum.cpp b/poincare/src/sum.cpp index 5aed51127..63f13017b 100644 --- a/poincare/src/sum.cpp +++ b/poincare/src/sum.cpp @@ -10,45 +10,35 @@ extern "C" { namespace Poincare { -ExpressionNode::Type Sum::type() const { - return Type::Sum; +SumNode * SumNode::FailedAllocationStaticNode() { + static AllocationFailureExpressionNode failure; + TreePool::sharedPool()->registerStaticNodeIfRequired(&failure); + return &failure; } -Expression * Sum::clone() const { - Sum * a = new Sum(m_operands, true); - return a; -} -const char * Sum::name() const { - return "sum"; -} - -int Sum::emptySequenceValue() const { - return 0; -} - -LayoutRef Sum::createSequenceLayout(LayoutRef argumentLayout, LayoutRef subscriptLayout, LayoutRef superscriptLayout) const { +LayoutRef SumNode::createSequenceLayout(LayoutRef argumentLayout, LayoutRef subscriptLayout, LayoutRef superscriptLayout) const { return SumLayoutRef(argumentLayout, subscriptLayout, superscriptLayout); } template -Evaluation * Sum::templatedApproximateWithNextTerm(Evaluation * a, Evaluation * b) const { - if (a->type() == Evaluation::Type::Complex && b->type() == Evaluation::Type::Complex) { - Complex * c = static_cast *>(a); - Complex * d = static_cast *>(b); - return new Complex((*c)+(*d)); +Evaluation SumNode::templatedApproximateWithNextTerm(Evaluation a, Evaluation b) const { + if (a.type() == EvaluationNode::Type::Complex && b.type() == EvaluationNode::Type::Complex) { + Complex c = static_cast&>(a); + Complex d = static_cast&>(b); + return Complex(c.stdComplex()+d.stdComplex()); } - if (a->type() == Evaluation::Type::Complex) { - Complex * c = static_cast *>(a); - assert(b->type() == Evaluation::Type::MatrixComplex); - MatrixComplex * m = static_cast *>(b); - return new MatrixComplex(Addition::computeOnComplexAndMatrix(*c, *m)); + if (a.type() == EvaluationNode::Type::Complex) { + Complex c = static_cast &>(a); + assert(b.type() == EvaluationNode::Type::MatrixComplex); + MatrixComplex m = static_cast &>(b); + return AdditionNode::computeOnComplexAndMatrix(c.stdComplex(), m); } - assert(a->type() == Evaluation::Type::MatrixComplex); - assert(b->type() == Evaluation::Type::MatrixComplex); - MatrixComplex * m = static_cast *>(a); - MatrixComplex * n = static_cast *>(b); - return new MatrixComplex(Addition::computeOnMatrices(*m, *n)); + assert(a.type() == EvaluationNode::Type::MatrixComplex); + assert(b.type() == EvaluationNode::Type::MatrixComplex); + MatrixComplex m = static_cast&>(a); + MatrixComplex n = static_cast&>(b); + return AdditionNode::computeOnMatrices(m, n); } } diff --git a/poincare/test/function.cpp b/poincare/test/function.cpp index 96fa70b25..400ca0024 100644 --- a/poincare/test/function.cpp +++ b/poincare/test/function.cpp @@ -45,8 +45,8 @@ QUIZ_CASE(poincare_parse_function) { assert_parsed_expression_type("prediction(0.1, 100)", ExpressionNode::Type::ConfidenceInterval); #if 0 assert_parsed_expression_type("prediction95(0.1, 100)", ExpressionNode::Type::PredictionInterval); - assert_parsed_expression_type("product(n, 4, 10)", ExpressionNode::Type::Product); #endif + assert_parsed_expression_type("product(n, 4, 10)", ExpressionNode::Type::Product); assert_parsed_expression_type("quo(29, 10)", ExpressionNode::Type::DivisionQuotient); #if 0 assert_parsed_expression_type("random()", ExpressionNode::Type::Random); @@ -58,8 +58,8 @@ QUIZ_CASE(poincare_parse_function) { assert_parsed_expression_type("R(2)", ExpressionNode::Type::SquareRoot); #if 0 assert_parsed_expression_type("round(2,3)", ExpressionNode::Type::Round); - assert_parsed_expression_type("sum(n, 4, 10)", ExpressionNode::Type::Sum); #endif + assert_parsed_expression_type("sum(n, 4, 10)", ExpressionNode::Type::Sum); #if MATRICES_ARE_DEFINED assert_parsed_expression_type("trace([[1,2,3][4,5,6][7,8,9]])", ExpressionNode::Type::MatrixTrace); assert_parsed_expression_type("transpose([[1,2,3][4,5,6][7,8,9]])", ExpressionNode::Type::MatrixTranspose); @@ -124,10 +124,10 @@ QUIZ_CASE(poincare_function_evaluate) { assert_parsed_expression_evaluates_to("permute(10, 4)", "5040"); assert_parsed_expression_evaluates_to("permute(10, 4)", "5040"); +#endif assert_parsed_expression_evaluates_to("product(n, 4, 10)", "604800"); assert_parsed_expression_evaluates_to("product(n, 4, 10)", "604800"); -#endif assert_parsed_expression_evaluates_to("quo(29, 10)", "2"); assert_parsed_expression_evaluates_to("quo(29, 10)", "2"); @@ -146,11 +146,9 @@ QUIZ_CASE(poincare_function_evaluate) { assert_parsed_expression_evaluates_to("R(-1)", "I"); assert_parsed_expression_evaluates_to("R(-1)", "I"); -#if 0 assert_parsed_expression_evaluates_to("sum(n, 4, 10)", "49"); assert_parsed_expression_evaluates_to("sum(n, 4, 10)", "49"); -#endif #if MATRICES_ARE_DEFINED assert_parsed_expression_evaluates_to("trace([[1,2,3][4,5,6][7,8,9]])", "15"); @@ -184,9 +182,9 @@ QUIZ_CASE(poincare_function_evaluate) { assert_parsed_expression_evaluates_to("prediction95(0.1, 100)", "[[0.0412,0.1588]]"); assert_parsed_expression_evaluates_to("prediction95(0.1, 100)", "[[0.0412,0.1588]]"); +#endif assert_parsed_expression_evaluates_to("product(2+n*I, 1, 5)", "(-100)-540*I"); assert_parsed_expression_evaluates_to("product(2+n*I, 1, 5)", "(-100)-540*I"); -#endif assert_parsed_expression_evaluates_to("root(3+I, 3)", "1.459366+0.1571201*I"); assert_parsed_expression_evaluates_to("root(3+I, 3)", "1.4593656008684+1.5712012294394E-1*I"); @@ -199,11 +197,10 @@ QUIZ_CASE(poincare_function_evaluate) { assert_parsed_expression_evaluates_to("R(3+I)", "1.755317+0.2848488*I"); assert_parsed_expression_evaluates_to("R(3+I)", "1.7553173018244+2.8484878459314E-1*I"); -#if 0 assert_parsed_expression_evaluates_to("sum(2+n*I,1,5)", "10+15*I"); assert_parsed_expression_evaluates_to("sum(2+n*I,1,5)", "10+15*I"); -#endif + #if MATRICES_ARE_DEFINED assert_parsed_expression_evaluates_to("transpose([[1,2,3][4,5,-6][7,8,9]])", "[[1,4,7][2,5,8][3,-6,9]]"); assert_parsed_expression_evaluates_to("transpose([[1,7,5][4,2,8]])", "[[1,4][7,2][5,8]]");