[poincare] Fix Sum, Product, Sequence

This commit is contained in:
Émilie Feral
2018-08-28 14:10:40 +02:00
parent abd18a508c
commit 3262c885aa
10 changed files with 134 additions and 116 deletions

View File

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

View File

@@ -133,6 +133,7 @@
#include <poincare/matrix_inverse.h>
#include <poincare/matrix_trace.h>
#include <poincare/matrix_transpose.h>
#include <poincare/product.h>
#include <poincare/sine.h>
#include <poincare/tangent.h>
#include <poincare/hyperbolic_arc_cosine.h>
@@ -156,6 +157,7 @@
#include <poincare/opposite.h>
#include <poincare/decimal.h>
#include <poincare/rational.h>
#include <poincare/sum.h>
#include <poincare/symbol.h>
#include <poincare/float.h>
#include <poincare/parenthesis.h>

View File

@@ -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<double> evaluateWithNextTerm(DoublePrecision p, Evaluation<double> * a, Evaluation<double> * b) const override {
Evaluation<double> evaluateWithNextTerm(DoublePrecision p, Evaluation<double> a, Evaluation<double> b) const override {
return templatedApproximateWithNextTerm<double>(a, b);
}
Evaluation<float> evaluateWithNextTerm(SinglePrecision p, Evaluation<float> * a, Evaluation<float> * b) const override {
Evaluation<float> evaluateWithNextTerm(SinglePrecision p, Evaluation<float> a, Evaluation<float> b) const override {
return templatedApproximateWithNextTerm<float>(a, b);
}
template<typename T> Evaluation<T> templatedApproximateWithNextTerm(Evaluation<T> * a, Evaluation<T> * b) const;
template<typename T> Evaluation<T> templatedApproximateWithNextTerm(Evaluation<T> a, Evaluation<T> b) const;
};
class Product : public Expression {
friend class ProductNode;
public:
Product() : Expression(TreePool::sharedPool()->createTreeNode<ProductNode>()) {}
Product(const ProductNode * n) : Expression(n) {}
Product(Expression operand0, Expression operand1, Expression operand2) : Product() {
replaceChildAtIndexInPlace(0, operand0);
replaceChildAtIndexInPlace(1, operand1);
replaceChildAtIndexInPlace(2, operand2);
}
};
}

View File

@@ -2,13 +2,15 @@
#define POINCARE_SEQUENCE_H
#include <poincare/layout_helper.h>
#include <poincare/static_hierarchy.h>
#include <poincare/serialization_helper.h>
#include <poincare/expression.h>
#include <poincare/approximation_helper.h>
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<float> approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<float>(context, angleUnit); }
Evaluation<double> approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<double>(context, angleUnit); }
template<typename T> Evaluation<T> templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const;
virtual int emptySequenceValue() const = 0;
virtual Evaluation<float> evaluateWithNextTerm(SinglePrecision p, Evaluation<float> * a, Evaluation<float> * b) const = 0;
virtual Evaluation<double> evaluateWithNextTerm(DoublePrecision p, Evaluation<double> * a, Evaluation<double> * b) const = 0;
virtual float emptySequenceValue() const = 0;
virtual Evaluation<float> evaluateWithNextTerm(SinglePrecision p, Evaluation<float> a, Evaluation<float> b) const = 0;
virtual Evaluation<double> evaluateWithNextTerm(DoublePrecision p, Evaluation<double> a, Evaluation<double> b) const = 0;
};
}

View File

@@ -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<double> evaluateWithNextTerm(DoublePrecision p, Evaluation<double> * a, Evaluation<double> * b) const override {
Evaluation<double> evaluateWithNextTerm(DoublePrecision p, Evaluation<double> a, Evaluation<double> b) const override {
return templatedApproximateWithNextTerm<double>(a, b);
}
Evaluation<float> evaluateWithNextTerm(SinglePrecision p, Evaluation<float> * a, Evaluation<float> * b) const override {
Evaluation<float> evaluateWithNextTerm(SinglePrecision p, Evaluation<float> a, Evaluation<float> b) const override {
return templatedApproximateWithNextTerm<float>(a, b);
}
template<typename T> Evaluation<T> templatedApproximateWithNextTerm(Evaluation<T> * a, Evaluation<T> * b) const;
template<typename T> Evaluation<T> templatedApproximateWithNextTerm(Evaluation<T> a, Evaluation<T> b) const;
};
class Sum : public Expression {
friend class SumNode;
public:
Sum() : Expression(TreePool::sharedPool()->createTreeNode<SumNode>()) {}
Sum(const SumNode * n) : Expression(n) {}
Sum(Expression operand0, Expression operand1, Expression operand2) : Sum() {
replaceChildAtIndexInPlace(0, operand0);
replaceChildAtIndexInPlace(1, operand1);
replaceChildAtIndexInPlace(2, operand2);
}
};
}

View File

@@ -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; }

View File

@@ -9,45 +9,34 @@ extern "C" {
namespace Poincare {
ExpressionNode::Type Product::type() const {
return Type::Product;
ProductNode * ProductNode::FailedAllocationStaticNode() {
static AllocationFailureExpressionNode<ProductNode> 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<typename T>
Evaluation<T> * Product::templatedApproximateWithNextTerm(Evaluation<T> * a, Evaluation<T> * b) const {
if (a->type() == Evaluation<T>::Type::Complex && b->type() == Evaluation<T>::Type::Complex) {
Complex<T> * c = static_cast<Complex<T> *>(a);
Complex<T> * d = static_cast<Complex<T> *>(b);
return new Complex<T>((*c)*(*d));
Evaluation<T> ProductNode::templatedApproximateWithNextTerm(Evaluation<T> a, Evaluation<T> b) const {
if (a.type() == EvaluationNode<T>::Type::Complex && b.type() == EvaluationNode<T>::Type::Complex) {
Complex<T> c = static_cast<Complex<T>&>(a);
Complex<T> d = static_cast<Complex<T>&>(b);
return Complex<T>(c.stdComplex()*d.stdComplex());
}
if (a->type() == Evaluation<T>::Type::Complex) {
Complex<T> * c = static_cast<Complex<T> *>(a);
assert(b->type() == Evaluation<T>::Type::MatrixComplex);
MatrixComplex<T> * m = static_cast<MatrixComplex<T> *>(b);
return new MatrixComplex<T>(Multiplication::computeOnComplexAndMatrix(*c, *m));
if (a.type() == EvaluationNode<T>::Type::Complex) {
Complex<T> c = static_cast<Complex<T> &>(a);
assert(b.type() == EvaluationNode<T>::Type::MatrixComplex);
MatrixComplex<T> m = static_cast<MatrixComplex<T> &>(b);
return MultiplicationNode::computeOnComplexAndMatrix(c.stdComplex(), m);
}
assert(a->type() == Evaluation<T>::Type::MatrixComplex);
assert(b->type() == Evaluation<T>::Type::MatrixComplex);
MatrixComplex<T> * m = static_cast<MatrixComplex<T> *>(a);
MatrixComplex<T> * n = static_cast<MatrixComplex<T> *>(b);
return new MatrixComplex<T>(Multiplication::computeOnMatrices<T>(*m, *n));
assert(a.type() == EvaluationNode<T>::Type::MatrixComplex);
assert(b.type() == EvaluationNode<T>::Type::MatrixComplex);
MatrixComplex<T> m = static_cast<MatrixComplex<T>&>(a);
MatrixComplex<T> n = static_cast<MatrixComplex<T>&>(b);
return MultiplicationNode::computeOnMatrices<T>(m, n);
}
}

View File

@@ -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<typename T>
Evaluation<T> Sequence::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const {
Evaluation<T> * aInput = childAtIndex(1)->approximate(T(), context, angleUnit);
Evaluation<T> * bInput = childAtIndex(2)->approximate(T(), context, angleUnit);
T start = aInput->toScalar();
T end = bInput->toScalar();
delete aInput;
delete bInput;
Evaluation<T> SequenceNode::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const {
Evaluation<T> aInput = childAtIndex(1)->approximate(T(), context, angleUnit);
Evaluation<T> 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<T>(Complex<T>::Undefined());
return Complex<T>::Undefined();
}
VariableContext<T> nContext = VariableContext<T>('n', &context);
Evaluation<T> * result = new Complex<T>(emptySequenceValue());
Evaluation<T> result = Complex<T>((T)emptySequenceValue());
for (int i = (int)start; i <= (int)end; i++) {
if (shouldStopProcessing()) {
delete result;
return new Complex<T>(Complex<T>::Undefined());
if (Expression::shouldStopProcessing()) {
return Complex<T>::Undefined();
}
nContext.setApproximationForVariable((T)i);
Evaluation<T> * expression = childAtIndex(0)->approximate(T(), nContext, angleUnit);
Evaluation<T> * newResult = evaluateWithNextTerm(T(), result, expression);
delete result;
delete expression;
result = newResult;
if (result == nullptr) {
return new Complex<T>(Complex<T>::Undefined());
result = evaluateWithNextTerm(T(), result, childAtIndex(0)->approximate(T(), nContext, angleUnit));
if (result.isUndefined()) {
return Complex<T>::Undefined();
}
}
return result;

View File

@@ -10,45 +10,35 @@ extern "C" {
namespace Poincare {
ExpressionNode::Type Sum::type() const {
return Type::Sum;
SumNode * SumNode::FailedAllocationStaticNode() {
static AllocationFailureExpressionNode<SumNode> 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<typename T>
Evaluation<T> * Sum::templatedApproximateWithNextTerm(Evaluation<T> * a, Evaluation<T> * b) const {
if (a->type() == Evaluation<T>::Type::Complex && b->type() == Evaluation<T>::Type::Complex) {
Complex<T> * c = static_cast<Complex<T> *>(a);
Complex<T> * d = static_cast<Complex<T> *>(b);
return new Complex<T>((*c)+(*d));
Evaluation<T> SumNode::templatedApproximateWithNextTerm(Evaluation<T> a, Evaluation<T> b) const {
if (a.type() == EvaluationNode<T>::Type::Complex && b.type() == EvaluationNode<T>::Type::Complex) {
Complex<T> c = static_cast<Complex<T>&>(a);
Complex<T> d = static_cast<Complex<T>&>(b);
return Complex<T>(c.stdComplex()+d.stdComplex());
}
if (a->type() == Evaluation<T>::Type::Complex) {
Complex<T> * c = static_cast<Complex<T> *>(a);
assert(b->type() == Evaluation<T>::Type::MatrixComplex);
MatrixComplex<T> * m = static_cast<MatrixComplex<T> *>(b);
return new MatrixComplex<T>(Addition::computeOnComplexAndMatrix(*c, *m));
if (a.type() == EvaluationNode<T>::Type::Complex) {
Complex<T> c = static_cast<Complex<T> &>(a);
assert(b.type() == EvaluationNode<T>::Type::MatrixComplex);
MatrixComplex<T> m = static_cast<MatrixComplex<T> &>(b);
return AdditionNode::computeOnComplexAndMatrix(c.stdComplex(), m);
}
assert(a->type() == Evaluation<T>::Type::MatrixComplex);
assert(b->type() == Evaluation<T>::Type::MatrixComplex);
MatrixComplex<T> * m = static_cast<MatrixComplex<T> *>(a);
MatrixComplex<T> * n = static_cast<MatrixComplex<T> *>(b);
return new MatrixComplex<T>(Addition::computeOnMatrices<T>(*m, *n));
assert(a.type() == EvaluationNode<T>::Type::MatrixComplex);
assert(b.type() == EvaluationNode<T>::Type::MatrixComplex);
MatrixComplex<T> m = static_cast<MatrixComplex<T>&>(a);
MatrixComplex<T> n = static_cast<MatrixComplex<T>&>(b);
return AdditionNode::computeOnMatrices<T>(m, n);
}
}

View File

@@ -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<float>("permute(10, 4)", "5040");
assert_parsed_expression_evaluates_to<double>("permute(10, 4)", "5040");
#endif
assert_parsed_expression_evaluates_to<float>("product(n, 4, 10)", "604800");
assert_parsed_expression_evaluates_to<double>("product(n, 4, 10)", "604800");
#endif
assert_parsed_expression_evaluates_to<float>("quo(29, 10)", "2");
assert_parsed_expression_evaluates_to<double>("quo(29, 10)", "2");
@@ -146,11 +146,9 @@ QUIZ_CASE(poincare_function_evaluate) {
assert_parsed_expression_evaluates_to<float>("R(-1)", "I");
assert_parsed_expression_evaluates_to<double>("R(-1)", "I");
#if 0
assert_parsed_expression_evaluates_to<float>("sum(n, 4, 10)", "49");
assert_parsed_expression_evaluates_to<double>("sum(n, 4, 10)", "49");
#endif
#if MATRICES_ARE_DEFINED
assert_parsed_expression_evaluates_to<float>("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<float>("prediction95(0.1, 100)", "[[0.0412,0.1588]]");
assert_parsed_expression_evaluates_to<double>("prediction95(0.1, 100)", "[[0.0412,0.1588]]");
#endif
assert_parsed_expression_evaluates_to<float>("product(2+n*I, 1, 5)", "(-100)-540*I");
assert_parsed_expression_evaluates_to<double>("product(2+n*I, 1, 5)", "(-100)-540*I");
#endif
assert_parsed_expression_evaluates_to<float>("root(3+I, 3)", "1.459366+0.1571201*I");
assert_parsed_expression_evaluates_to<double>("root(3+I, 3)", "1.4593656008684+1.5712012294394E-1*I");
@@ -199,11 +197,10 @@ QUIZ_CASE(poincare_function_evaluate) {
assert_parsed_expression_evaluates_to<float>("R(3+I)", "1.755317+0.2848488*I");
assert_parsed_expression_evaluates_to<double>("R(3+I)", "1.7553173018244+2.8484878459314E-1*I");
#if 0
assert_parsed_expression_evaluates_to<double>("sum(2+n*I,1,5)", "10+15*I");
assert_parsed_expression_evaluates_to<double>("sum(2+n*I,1,5)", "10+15*I");
#endif
#if MATRICES_ARE_DEFINED
assert_parsed_expression_evaluates_to<float>("transpose([[1,2,3][4,5,-6][7,8,9]])", "[[1,4,7][2,5,8][3,-6,9]]");
assert_parsed_expression_evaluates_to<float>("transpose([[1,7,5][4,2,8]])", "[[1,4][7,2][5,8]]");