From 54f9ea2d46fafa6254c3168dd5f8c5a91446c6ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 2 Aug 2018 15:46:31 +0200 Subject: [PATCH] [poincare] Redesign of Expression: first attempt --- apps/solver/equation.cpp | 2 +- poincare/include/poincare/absolute_value.h | 9 +- poincare/include/poincare/addition.h | 9 +- .../poincare/allocation_failed_evaluation.h | 39 + .../allocation_failed_expression_node.h | 38 + poincare/include/poincare/approximation.h | 61 - .../include/poincare/approximation_engine.h | 23 +- poincare/include/poincare/arc_cosine.h | 7 +- poincare/include/poincare/arc_sine.h | 7 +- poincare/include/poincare/arc_tangent.h | 7 +- poincare/include/poincare/arithmetic.h | 6 +- .../include/poincare/binomial_coefficient.h | 9 +- poincare/include/poincare/ceiling.h | 7 +- poincare/include/poincare/complex.h | 46 + poincare/include/poincare/complex_argument.h | 7 +- .../include/poincare/confidence_interval.h | 7 +- poincare/include/poincare/conjugate.h | 7 +- poincare/include/poincare/context.h | 10 +- poincare/include/poincare/cosine.h | 7 +- poincare/include/poincare/decimal.h | 16 +- poincare/include/poincare/derivative.h | 9 +- poincare/include/poincare/determinant.h | 9 +- poincare/include/poincare/division.h | 9 +- poincare/include/poincare/division_quotient.h | 9 +- .../include/poincare/division_remainder.h | 9 +- poincare/include/poincare/dynamic_hierarchy.h | 2 +- poincare/include/poincare/empty_expression.h | 7 +- poincare/include/poincare/equal.h | 9 +- poincare/include/poincare/evaluation.h | 119 +- poincare/include/poincare/expression.h | 10 +- poincare/include/poincare/expression_node.h | 165 +++ .../include/poincare/expression_reference.h | 234 ++++ poincare/include/poincare/factor.h | 9 +- poincare/include/poincare/factorial.h | 11 +- poincare/include/poincare/float.h | 68 ++ poincare/include/poincare/floor.h | 7 +- poincare/include/poincare/frac_part.h | 7 +- poincare/include/poincare/global_context.h | 15 +- .../include/poincare/great_common_divisor.h | 9 +- .../include/poincare/hyperbolic_arc_cosine.h | 7 +- .../include/poincare/hyperbolic_arc_sine.h | 7 +- .../include/poincare/hyperbolic_arc_tangent.h | 7 +- poincare/include/poincare/hyperbolic_cosine.h | 7 +- poincare/include/poincare/hyperbolic_sine.h | 7 +- .../include/poincare/hyperbolic_tangent.h | 7 +- poincare/include/poincare/imaginary_part.h | 7 +- poincare/include/poincare/infinity.h | 49 + poincare/include/poincare/integer.h | 240 ++-- poincare/include/poincare/integral.h | 9 +- poincare/include/poincare/layout_engine.h | 27 +- .../include/poincare/least_common_multiple.h | 9 +- poincare/include/poincare/logarithm.h | 9 +- poincare/include/poincare/matrix.h | 67 +- poincare/include/poincare/matrix_complex.h | 59 + poincare/include/poincare/matrix_dimension.h | 9 +- poincare/include/poincare/matrix_inverse.h | 9 +- poincare/include/poincare/matrix_trace.h | 9 +- poincare/include/poincare/matrix_transpose.h | 9 +- poincare/include/poincare/multiplication.h | 11 +- .../include/poincare/n_ary_expression_node.h | 28 + .../include/poincare/naperian_logarithm.h | 7 +- poincare/include/poincare/nth_root.h | 9 +- poincare/include/poincare/number.h | 50 + poincare/include/poincare/opposite.h | 49 +- poincare/include/poincare/parenthesis.h | 43 +- .../include/poincare/permute_coefficient.h | 9 +- poincare/include/poincare/power.h | 13 +- .../include/poincare/prediction_interval.h | 7 +- poincare/include/poincare/product.h | 7 +- poincare/include/poincare/randint.h | 7 +- poincare/include/poincare/random.h | 9 +- poincare/include/poincare/rational.h | 115 +- poincare/include/poincare/real_part.h | 7 +- poincare/include/poincare/round.h | 9 +- poincare/include/poincare/sequence.h | 10 +- poincare/include/poincare/serializable_node.h | 2 +- .../include/poincare/simplification_root.h | 7 +- poincare/include/poincare/sine.h | 7 +- poincare/include/poincare/square_root.h | 7 +- poincare/include/poincare/static_hierarchy.h | 2 +- poincare/include/poincare/store.h | 9 +- poincare/include/poincare/subtraction.h | 9 +- poincare/include/poincare/sum.h | 7 +- poincare/include/poincare/symbol.h | 86 +- poincare/include/poincare/tangent.h | 7 +- poincare/include/poincare/tree_reference.h | 2 + poincare/include/poincare/undefined.h | 41 +- poincare/src/absolute_value.cpp | 2 +- poincare/src/addition.cpp | 4 +- poincare/src/allocation_failed_evaluation.cpp | 12 + poincare/src/approximation_engine.cpp | 156 +-- poincare/src/arc_cosine.cpp | 2 +- poincare/src/arc_sine.cpp | 2 +- poincare/src/arc_tangent.cpp | 2 +- poincare/src/arithmetic.cpp | 86 +- poincare/src/binomial_coefficient.cpp | 2 +- poincare/src/ceiling.cpp | 2 +- poincare/src/complex.cpp | 146 +++ poincare/src/complex_argument.cpp | 2 +- poincare/src/confidence_interval.cpp | 4 +- poincare/src/conjugate.cpp | 2 +- poincare/src/cosine.cpp | 2 +- poincare/src/decimal.cpp | 8 +- poincare/src/derivative.cpp | 2 +- poincare/src/determinant.cpp | 4 +- poincare/src/division.cpp | 2 +- poincare/src/division_quotient.cpp | 2 +- poincare/src/division_remainder.cpp | 2 +- poincare/src/dynamic_hierarchy.cpp | 2 +- poincare/src/equal.cpp | 6 +- poincare/src/evaluation.cpp | 261 +---- poincare/src/expression.cpp | 4 +- poincare/src/expression_node.cpp | 117 ++ poincare/src/expression_reference.cpp | 568 +++++++++ poincare/src/factor.cpp | 2 +- poincare/src/factorial.cpp | 4 +- poincare/src/floor.cpp | 2 +- poincare/src/frac_part.cpp | 2 +- poincare/src/global_context.cpp | 10 +- poincare/src/great_common_divisor.cpp | 2 +- poincare/src/hyperbolic_arc_cosine.cpp | 2 +- poincare/src/hyperbolic_arc_sine.cpp | 2 +- poincare/src/hyperbolic_arc_tangent.cpp | 2 +- poincare/src/hyperbolic_cosine.cpp | 2 +- poincare/src/hyperbolic_sine.cpp | 2 +- poincare/src/hyperbolic_tangent.cpp | 2 +- poincare/src/imaginary_part.cpp | 4 +- poincare/src/infinity.cpp | 30 + poincare/src/integer.cpp | 1042 +++++++++-------- poincare/src/integral.cpp | 2 +- poincare/src/layout_engine.cpp | 90 -- poincare/src/least_common_multiple.cpp | 2 +- poincare/src/logarithm.cpp | 12 +- poincare/src/matrix.cpp | 218 ++-- poincare/src/matrix_complex.cpp | 181 +++ poincare/src/matrix_dimension.cpp | 8 +- poincare/src/matrix_inverse.cpp | 4 +- poincare/src/matrix_trace.cpp | 2 +- poincare/src/matrix_transpose.cpp | 4 +- poincare/src/multiplication.cpp | 12 +- poincare/src/n_ary_expression_node.cpp | 80 ++ poincare/src/naperian_logarithm.cpp | 2 +- poincare/src/nth_root.cpp | 4 +- poincare/src/number.cpp | 121 ++ poincare/src/opposite.cpp | 77 +- poincare/src/parenthesis.cpp | 30 +- poincare/src/permute_coefficient.cpp | 4 +- poincare/src/power.cpp | 22 +- poincare/src/prediction_interval.cpp | 4 +- poincare/src/print_float.cpp | 4 +- poincare/src/rational.cpp | 368 +++--- poincare/src/real_part.cpp | 2 +- poincare/src/round.cpp | 2 +- poincare/src/sequence.cpp | 2 +- poincare/src/sine.cpp | 2 +- poincare/src/square_root.cpp | 2 +- poincare/src/store.cpp | 4 +- poincare/src/subtraction.cpp | 2 +- poincare/src/symbol.cpp | 388 +++--- poincare/src/tangent.cpp | 2 +- poincare/src/tree_reference.cpp | 15 + poincare/src/undefined.cpp | 29 +- 162 files changed, 4102 insertions(+), 2284 deletions(-) create mode 100644 poincare/include/poincare/allocation_failed_evaluation.h create mode 100644 poincare/include/poincare/allocation_failed_expression_node.h delete mode 100644 poincare/include/poincare/approximation.h create mode 100644 poincare/include/poincare/complex.h create mode 100644 poincare/include/poincare/expression_node.h create mode 100644 poincare/include/poincare/expression_reference.h create mode 100644 poincare/include/poincare/float.h create mode 100644 poincare/include/poincare/infinity.h create mode 100644 poincare/include/poincare/matrix_complex.h create mode 100644 poincare/include/poincare/n_ary_expression_node.h create mode 100644 poincare/include/poincare/number.h create mode 100644 poincare/src/allocation_failed_evaluation.cpp create mode 100644 poincare/src/complex.cpp create mode 100644 poincare/src/expression_node.cpp create mode 100644 poincare/src/expression_reference.cpp create mode 100644 poincare/src/infinity.cpp create mode 100644 poincare/src/matrix_complex.cpp create mode 100644 poincare/src/n_ary_expression_node.cpp create mode 100644 poincare/src/number.cpp diff --git a/apps/solver/equation.cpp b/apps/solver/equation.cpp index 602d0522b..fdd14914e 100644 --- a/apps/solver/equation.cpp +++ b/apps/solver/equation.cpp @@ -40,7 +40,7 @@ Expression * Equation::standardForm(Context * context) const { m_standardForm = static_cast(e)->standardEquation(*context, Preferences::sharedPreferences()->angleUnit()); } else if (e->type() == Expression::Type::Rational && static_cast(e)->isOne()) { // The equality was reduced which means the equality was always true. - m_standardForm = new Rational(0); + m_standardForm = RationalReference(0); } else { // The equality has an undefined operand assert(e->type() == Expression::Type::Undefined); diff --git a/poincare/include/poincare/absolute_value.h b/poincare/include/poincare/absolute_value.h index 3ece7c591..ee9253397 100644 --- a/poincare/include/poincare/absolute_value.h +++ b/poincare/include/poincare/absolute_value.h @@ -11,23 +11,22 @@ class AbsoluteValue : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; Sign sign() const override { return Sign::Positive; } private: - Expression * setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit) override; + ExpressionReference setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit) override; /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { return LayoutEngine::writePrefixExpressionTextInBuffer(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, "abs"); } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/addition.h b/poincare/include/poincare/addition.h index da62f5301..adcb5ea50 100644 --- a/poincare/include/poincare/addition.h +++ b/poincare/include/poincare/addition.h @@ -18,7 +18,6 @@ class Addition : public DynamicHierarchy { friend class Complex; public: Type type() const override; - Expression * clone() const override; int polynomialDegree(char symbolName) const override; int privateGetPolynomialCoefficients(char symbolName, Expression * coefficients[]) const override; /* Evaluation */ @@ -31,7 +30,7 @@ public: } private: /* Layout */ - bool needParenthesisWithParent(const Expression * e) const override; + bool needsParenthesisWithParent(SerializableNode * parentNode) const override; LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { return LayoutEngine::createInfixLayout(this, floatDisplayMode, numberOfSignificantDigits, name()); } @@ -41,7 +40,7 @@ private: static const char * name() { return "+"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; Expression * shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) override; Expression * factorizeOnCommonDenominator(Context & context, Preferences::AngleUnit angleUnit); void factorizeOperands(Expression * e1, Expression * e2, Context & context, Preferences::AngleUnit angleUnit); @@ -51,10 +50,10 @@ private: template static MatrixComplex computeOnMatrixAndComplex(const MatrixComplex m, const std::complex c) { return ApproximationEngine::elementWiseOnMatrixComplexAndComplex(m, c, compute); } - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } }; diff --git a/poincare/include/poincare/allocation_failed_evaluation.h b/poincare/include/poincare/allocation_failed_evaluation.h new file mode 100644 index 000000000..9315bdc3a --- /dev/null +++ b/poincare/include/poincare/allocation_failed_evaluation.h @@ -0,0 +1,39 @@ +#ifndef POINCARE_ALLOCATION_FAILED_EVALUATION_H +#define POINCARE_ALLOCATION_FAILED_EVALUATION_H + +#include +#include + +namespace Poincare { + +template +class AllocationFailedEvaluationNode : public EvaluationNode { +public: + // EvaluationNode + typename EvaluationNode::Type type() const override { return EvaluationNode::Type::AllocationFailure; } + bool isUndefined() const override { return true; } + T toScalar() const override{ return NAN; } + ExpressionReference complexToExpression(Preferences::Preferences::ComplexFormat complexFormat) const override; + std::complex trace() const override { return std::complex(NAN); } + std::complex determinant() const override { return std::complex(NAN); } + EvaluationReference inverse() const override { return ComplexReference::Undefined(); } + virtual EvaluationReference transpose() const override { return ComplexReference::Undefined(); } + // TreeNode + size_t size() const override { return sizeof(AllocationFailedEvaluationNode); } + const char * description() const override { return "Allocation Failed"; } + bool isAllocationFailure() const override { return true; } +}; + +template +class AllocationFailedEvaluationReference : public EvaluationReference { +public: + AllocationFailedEvaluationReference() : EvaluationReference() { + TreeNode * node = TreePool::sharedPool()->createTreeNode>(); + this->m_identifier = node->identifier(); + } + AllocationFailedEvaluationReference(TreeNode * n) : EvaluationReference(n) {} +}; + +} + +#endif diff --git a/poincare/include/poincare/allocation_failed_expression_node.h b/poincare/include/poincare/allocation_failed_expression_node.h new file mode 100644 index 000000000..86d24c413 --- /dev/null +++ b/poincare/include/poincare/allocation_failed_expression_node.h @@ -0,0 +1,38 @@ +#ifndef POINCARE_ALLOCATION_FAILED_EXPRESSION_NODE_H +#define POINCARE_ALLOCATION_FAILED_EXPRESSION_NODE_H + +#include +#include +#include +#include + +namespace Poincare { + +class AllocationFailedExpressionNode : public ExpressionNode { +public: + // ExpressionNode + Type type() const override { return Type::AllocationFailure; } + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ComplexReference::Undefined(); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ComplexReference::Undefined(); } + LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode = Preferences::PrintFloatMode::Decimal, int numberOfSignificantDigits = 0) const override; + + // TreeNode + size_t size() const override { return sizeof(AllocationFailedExpressionNode); } + const char * description() const override { return "Allocation Failed"; } + int numberOfChildren() const override { return 0; } + bool isAllocationFailure() const override { return true; } +}; + +class AllocationFailedExpressionRef : public ExpressionReference { +public: + AllocationFailedExpressionRef() : ExpressionReference() { + TreeNode * node = TreePool::sharedPool()->createTreeNode(); + m_identifier = node->identifier(); + } + AllocationFailedExpressionRef(TreeNode * n) : ExpressionReference(n) {} +}; + +} + +#endif diff --git a/poincare/include/poincare/approximation.h b/poincare/include/poincare/approximation.h deleted file mode 100644 index d46e47fb9..000000000 --- a/poincare/include/poincare/approximation.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef POINCARE_APPROXIMATION_H -#define POINCARE_APPROXIMATION_H - -#include -#include - -namespace Poincare { - -/* Approximation reprensents an approximated complex. This class is - * theoritecally unecessary as it can be reprensented by an Addition of Decimals - * and I Symbol for example. However, performances are dramatically affected if - * we keep turning float/double into Decimal back and forth (for instance, when - * plotting a graph, we need to set a float/double value for a symbol and - * approximate an expression containing the symbol for each dot displayed). We - * thus use the Approximation class that hold an std::complex and can only - * be approximated. Indeed, the usual methods of expression are not implemented - * to avoid code duplication with Decimal. */ - -template -class Approximation : public Expression { -public: - Approximation(T a, T b = 0.0) : - Expression(), - m_complex(a, b) - {} - Type type() const override { - return Expression::Type::Approximation; - } - Expression * clone() const override { - return new Approximation(m_complex.real(), m_complex.imag()); - } - const Expression * const * operands() const override { - assert(false); - return nullptr; - } - int numberOfOperands() const override { - assert(false); - return 0; - } - int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { - assert(false); - return 0; - } -private: - /* Layout */ - LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { - assert(false); - return nullptr; - } - /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Complex * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { - return new Complex((U)m_complex.real(), (U)m_complex.imag()); - } - std::complex m_complex; -}; - -} - -#endif diff --git a/poincare/include/poincare/approximation_engine.h b/poincare/include/poincare/approximation_engine.h index d50f819d8..c0c32a205 100644 --- a/poincare/include/poincare/approximation_engine.h +++ b/poincare/include/poincare/approximation_engine.h @@ -1,8 +1,9 @@ #ifndef POINCARE_APPROXIMATION_ENGINE_H #define POINCARE_APPROXIMATION_ENGINE_H -#include -#include +#include +#include +#include #include namespace Poincare { @@ -11,17 +12,17 @@ class ApproximationEngine { public: template static std::complex truncateRealOrImaginaryPartAccordingToArgument(std::complex c); - template using ComplexCompute = std::complex(*)(const std::complex, Preferences::AngleUnit angleUnit); - template static Evaluation * map(const Expression * expression, Context& context, Preferences::AngleUnit angleUnit, ComplexCompute compute); + template using ComplexCompute = ComplexReference(*)(const std::complex, Preferences::AngleUnit angleUnit); + template static EvaluationReference map(const ExpressionNode * expression, Context& context, Preferences::AngleUnit angleUnit, ComplexCompute compute); - template using ComplexAndComplexReduction = std::complex(*)(const std::complex, const std::complex); - template using ComplexAndMatrixReduction = MatrixComplex(*)(const std::complex c, const MatrixComplex m); - template using MatrixAndComplexReduction = MatrixComplex(*)(const MatrixComplex m, const std::complex c); - template using MatrixAndMatrixReduction = MatrixComplex(*)(const MatrixComplex m, const MatrixComplex n); - template static Evaluation * mapReduce(const Expression * expression, Context& context, Preferences::AngleUnit angleUnit, ComplexAndComplexReduction computeOnComplexes, ComplexAndMatrixReduction computeOnComplexAndMatrix, MatrixAndComplexReduction computeOnMatrixAndComplex, MatrixAndMatrixReduction computeOnMatrices); + template using ComplexAndComplexReduction = ComplexReference(*)(const std::complex, const std::complex); + template using ComplexAndMatrixReduction = MatrixComplexReference(*)(const std::complex c, const MatrixComplexReference m); + template using MatrixAndComplexReduction = MatrixComplexReference(*)(const MatrixComplexReference m, const std::complex c); + template using MatrixAndMatrixReduction = MatrixComplexReference(*)(const MatrixComplexReference m, const MatrixComplexReference n); + template static EvaluationReference mapReduce(const ExpressionNode * expression, Context& context, Preferences::AngleUnit angleUnit, ComplexAndComplexReduction computeOnComplexes, ComplexAndMatrixReduction computeOnComplexAndMatrix, MatrixAndComplexReduction computeOnMatrixAndComplex, MatrixAndMatrixReduction computeOnMatrices); - template static MatrixComplex elementWiseOnMatrixComplexAndComplex(const MatrixComplex n, const std::complex c, ComplexAndComplexReduction computeOnComplexes); - template static MatrixComplex elementWiseOnComplexMatrices(const MatrixComplex m, const MatrixComplex n, ComplexAndComplexReduction computeOnComplexes); + template static MatrixComplexReference elementWiseOnMatrixComplexAndComplex(const MatrixComplexReference n, std::complex c, ComplexAndComplexReduction computeOnComplexes); + template static MatrixComplexReference elementWiseOnComplexMatrices(const MatrixComplexReference m, const MatrixComplexReference n, ComplexAndComplexReduction computeOnComplexes); }; diff --git a/poincare/include/poincare/arc_cosine.h b/poincare/include/poincare/arc_cosine.h index 940dbed26..b80e4094a 100644 --- a/poincare/include/poincare/arc_cosine.h +++ b/poincare/include/poincare/arc_cosine.h @@ -12,7 +12,6 @@ class ArcCosine : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -25,13 +24,13 @@ private: return "acos"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/arc_sine.h b/poincare/include/poincare/arc_sine.h index 38ee27c8e..45f348923 100644 --- a/poincare/include/poincare/arc_sine.h +++ b/poincare/include/poincare/arc_sine.h @@ -12,7 +12,6 @@ class ArcSine : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -23,13 +22,13 @@ private: } const char * name() const { return "asin"; } /* Simplification */ - Expression * shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/arc_tangent.h b/poincare/include/poincare/arc_tangent.h index c31154c33..4f95036eb 100644 --- a/poincare/include/poincare/arc_tangent.h +++ b/poincare/include/poincare/arc_tangent.h @@ -12,7 +12,6 @@ class ArcTangent : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -23,13 +22,13 @@ private: } const char * name() const { return "atan"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/arithmetic.h b/poincare/include/poincare/arithmetic.h index fd93804f4..0f162434e 100644 --- a/poincare/include/poincare/arithmetic.h +++ b/poincare/include/poincare/arithmetic.h @@ -6,11 +6,11 @@ namespace Poincare { class Arithmetic { public: - static Integer LCM(const Integer * i, const Integer * j); - static Integer GCD(const Integer * i, const Integer * j); + static IntegerReference LCM(const IntegerReference i, const IntegerReference j); + static IntegerReference GCD(const IntegerReference i, const IntegerReference j); /* When outputCoefficients[0] is set to -1, that indicates a special case: * i could not be factorized. */ - static void PrimeFactorization(const Integer * i, Integer * outputFactors, Integer * outputCoefficients, int outputLength); + static void PrimeFactorization(const IntegerReference i, IntegerReference outputFactors[], IntegerReference outputCoefficients[], int outputLength); constexpr static int k_numberOfPrimeFactors = 1000; constexpr static int k_maxNumberOfPrimeFactors = 32; private: diff --git a/poincare/include/poincare/binomial_coefficient.h b/poincare/include/poincare/binomial_coefficient.h index 0981fd7d2..b81d7ca77 100644 --- a/poincare/include/poincare/binomial_coefficient.h +++ b/poincare/include/poincare/binomial_coefficient.h @@ -11,7 +11,6 @@ class BinomialCoefficient : public StaticHierarchy<2> { using StaticHierarchy<2>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; template static T compute(T k, T n); private: constexpr static int k_maxNValue = 300; @@ -21,11 +20,11 @@ private: return LayoutEngine::writePrefixExpressionTextInBuffer(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, "binomial"); } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Complex * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/ceiling.h b/poincare/include/poincare/ceiling.h index 4ce13cdef..4d7af44c4 100644 --- a/poincare/include/poincare/ceiling.h +++ b/poincare/include/poincare/ceiling.h @@ -11,7 +11,6 @@ class Ceiling : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; @@ -20,13 +19,13 @@ private: } const char * name() const { return "ceil"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/complex.h b/poincare/include/poincare/complex.h new file mode 100644 index 000000000..df46476a2 --- /dev/null +++ b/poincare/include/poincare/complex.h @@ -0,0 +1,46 @@ +#ifndef POINCARE_COMPLEX_H +#define POINCARE_COMPLEX_H + +#include + +namespace Poincare { + +template +class ComplexReference; + +template +class ComplexNode : public std::complex, public EvaluationNode { +public: + // TreeNode + size_t size() const override { return sizeof(ComplexNode); } + const char * description() const override { return "Evaluation complex"; } + int numberOfChildren() const override { return 0; } + + void setComplex(std::complex c); + typename Poincare::EvaluationNode::Type type() const override { return Poincare::EvaluationNode::Type::Complex; } + bool isUndefined() const override { + return (std::isnan(this->real()) && std::isnan(this->imag())); + } + T toScalar() const override; + ExpressionReference complexToExpression(Preferences::Preferences::ComplexFormat complexFormat) const override; + std::complex trace() const override { return *this; } + std::complex determinant() const override { return *this; } + EvaluationReference inverse() const override; + EvaluationReference transpose() const override { return ComplexReference(*this); } +}; + +template +class ComplexReference : public std::complex, public EvaluationReference { +public: + ComplexReference(TreeNode * t) : EvaluationReference(t) {} + ComplexReference(T a, T b = 0.0) : ComplexReference(std::complex(a, b)) {} + ComplexReference(std::complex c); + static ComplexReference Undefined() { + return ComplexReference(NAN, NAN); + } +}; + + +} + +#endif diff --git a/poincare/include/poincare/complex_argument.h b/poincare/include/poincare/complex_argument.h index 6fbb6541d..88e9900fc 100644 --- a/poincare/include/poincare/complex_argument.h +++ b/poincare/include/poincare/complex_argument.h @@ -11,7 +11,6 @@ class ComplexArgument : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -22,13 +21,13 @@ private: } const char * name() const { return "arg"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/confidence_interval.h b/poincare/include/poincare/confidence_interval.h index 2eb1899ea..14402d507 100644 --- a/poincare/include/poincare/confidence_interval.h +++ b/poincare/include/poincare/confidence_interval.h @@ -10,7 +10,6 @@ class ConfidenceInterval : public StaticHierarchy<2> { using StaticHierarchy<2>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; int polynomialDegree(char symbolName) const override; private: /* Layout */ @@ -22,11 +21,11 @@ private: } virtual const char * name() const { return "confidence"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(Expression::SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(Expression::SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } Evaluation * privateApproximate(Expression::DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Evaluation * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; }; class SimplePredictionInterval : public ConfidenceInterval { diff --git a/poincare/include/poincare/conjugate.h b/poincare/include/poincare/conjugate.h index 5cd8c02bf..60724c365 100644 --- a/poincare/include/poincare/conjugate.h +++ b/poincare/include/poincare/conjugate.h @@ -11,7 +11,6 @@ class Conjugate : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; @@ -19,13 +18,13 @@ private: return LayoutEngine::writePrefixExpressionTextInBuffer(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, "conj"); } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/context.h b/poincare/include/poincare/context.h index a414dede7..6ce7ebd06 100644 --- a/poincare/include/poincare/context.h +++ b/poincare/include/poincare/context.h @@ -1,15 +1,15 @@ #ifndef POINCARE_CONTEXT_H #define POINCARE_CONTEXT_H -#include -#include - namespace Poincare { +class ExpressionReference; +class SymbolReference; + class Context { public: - virtual const Expression * expressionForSymbol(const Symbol * symbol) = 0; - virtual void setExpressionForSymbolName(const Expression * expression, const Symbol * symbol, Context & context) = 0; + virtual const ExpressionReference expressionForSymbol(const SymbolReference symbol) = 0; + virtual void setExpressionForSymbolName(const ExpressionReference expression, const SymbolReference symbol, Context & context) = 0; }; } diff --git a/poincare/include/poincare/cosine.h b/poincare/include/poincare/cosine.h index f1a7ec119..0f956e15a 100644 --- a/poincare/include/poincare/cosine.h +++ b/poincare/include/poincare/cosine.h @@ -14,7 +14,6 @@ class Cosine : public StaticHierarchy<1>::StaticHierarchy { friend class Tangent; public: Type type() const override; - Expression * clone() const override; float characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const override; template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit = Preferences::AngleUnit::Radian); private: @@ -27,12 +26,12 @@ private: } const char * name() const { return "cos"; } /* Simplication */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/decimal.h b/poincare/include/poincare/decimal.h index 08300cba1..3bc70229d 100644 --- a/poincare/include/poincare/decimal.h +++ b/poincare/include/poincare/decimal.h @@ -21,24 +21,24 @@ public: Integer mantissa() const { return m_mantissa; } // Expression subclassing Type type() const override; - Expression * clone() const override; int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; Sign sign() const override { return m_mantissa.isNegative() ? Sign::Negative : Sign::Positive; } + constexpr static int k_maxExponentLength = 4; private: constexpr static double k_biggestMantissaFromDouble = 999999999999999; constexpr static int k_maxDoubleExponent = 308; /* Comparison */ - int simplificationOrderSameType(const Expression * e, bool canBeInterrupted) const override; + int simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const override; /* Layout */ - bool needParenthesisWithParent(const Expression * e) const override; + bool needsParenthesisWithParent(SerializableNode * parentNode) const override; LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; - Expression * shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Evaluation * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; int convertToText(char * buffer, int bufferSize, Preferences::PrintFloatMode mode, int numberOfSignificantDigits) const; // Worst case is -1.2345678901234E-1000 diff --git a/poincare/include/poincare/derivative.h b/poincare/include/poincare/derivative.h index 5254860df..a7096b595 100644 --- a/poincare/include/poincare/derivative.h +++ b/poincare/include/poincare/derivative.h @@ -11,7 +11,6 @@ class Derivative : public StaticHierarchy<2> { using StaticHierarchy<2>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; int polynomialDegree(char symbolName) const override; private: /* Layout */ @@ -23,11 +22,11 @@ private: } const char * name() const { return "diff"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Complex * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; template T growthRateAroundAbscissa(T x, T h, Context & context, Preferences::AngleUnit angleUnit) const; template T riddersApproximation(Context & context, Preferences::AngleUnit angleUnit, T x, T h, T * error) const; // TODO: Change coefficients? diff --git a/poincare/include/poincare/determinant.h b/poincare/include/poincare/determinant.h index fac092239..e04d509af 100644 --- a/poincare/include/poincare/determinant.h +++ b/poincare/include/poincare/determinant.h @@ -10,7 +10,6 @@ class Determinant : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -21,11 +20,11 @@ private: } const char * name() const { return "det"; } /* Simplification */ - Expression * shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Evaluation * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/division.h b/poincare/include/poincare/division.h index 705099e3a..3489ca4e6 100644 --- a/poincare/include/poincare/division.h +++ b/poincare/include/poincare/division.h @@ -14,28 +14,27 @@ class Division : public StaticHierarchy<2> { friend class Power; public: Type type() const override; - Expression * clone() const override; template static std::complex compute(const std::complex c, const std::complex d); int polynomialDegree(char symbolName) const override; private: /* Layout */ - bool needParenthesisWithParent(const Expression * e) const override; + bool needsParenthesisWithParent(SerializableNode * parentNode) const override; LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { return LayoutEngine::writeInfixExpressionTextInBuffer(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, "/"); } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static MatrixComplex computeOnMatrixAndComplex(const MatrixComplex m, const std::complex c) { return ApproximationEngine::elementWiseOnMatrixComplexAndComplex(m, c, compute); } template static MatrixComplex computeOnComplexAndMatrix(const std::complex c, const MatrixComplex n); template static MatrixComplex computeOnMatrices(const MatrixComplex m, const MatrixComplex n); - virtual Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + virtual EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } - virtual Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + virtual EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } }; diff --git a/poincare/include/poincare/division_quotient.h b/poincare/include/poincare/division_quotient.h index 934f61a4f..3d2a4d1db 100644 --- a/poincare/include/poincare/division_quotient.h +++ b/poincare/include/poincare/division_quotient.h @@ -12,7 +12,6 @@ class DivisionQuotient : public StaticHierarchy<2> { using StaticHierarchy<2>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -23,11 +22,11 @@ private: } const char * name() const { return "quo"; } /* Simplification */ - Expression * shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Complex * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/division_remainder.h b/poincare/include/poincare/division_remainder.h index 344840f9c..54ed268a7 100644 --- a/poincare/include/poincare/division_remainder.h +++ b/poincare/include/poincare/division_remainder.h @@ -11,7 +11,6 @@ class DivisionRemainder : public StaticHierarchy<2> { using StaticHierarchy<2>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -22,11 +21,11 @@ private: } const char * name() const { return "rem"; } /* Simplification */ - Expression * shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Complex * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/dynamic_hierarchy.h b/poincare/include/poincare/dynamic_hierarchy.h index 915656cc5..733ad6bd3 100644 --- a/poincare/include/poincare/dynamic_hierarchy.h +++ b/poincare/include/poincare/dynamic_hierarchy.h @@ -35,7 +35,7 @@ protected: int m_numberOfOperands; private: void removeOperandAtIndex(int i, bool deleteAfterRemoval); - int simplificationOrderSameType(const Expression * e, bool canBeInterrupted) const override; + int simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const override; int simplificationOrderGreaterType(const Expression * e, bool canBeInterrupted) const override; }; diff --git a/poincare/include/poincare/empty_expression.h b/poincare/include/poincare/empty_expression.h index c070cc628..21093bce2 100644 --- a/poincare/include/poincare/empty_expression.h +++ b/poincare/include/poincare/empty_expression.h @@ -13,15 +13,14 @@ public: Type type() const override { return Type::EmptyExpression; } - Expression * clone() const override; int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Complex * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/equal.h b/poincare/include/poincare/equal.h index f591059bb..76a3a18a5 100644 --- a/poincare/include/poincare/equal.h +++ b/poincare/include/poincare/equal.h @@ -11,22 +11,21 @@ class Equal : public StaticHierarchy<2> { public: using StaticHierarchy<2>::StaticHierarchy; Type type() const override; - Expression * clone() const override; int polynomialDegree(char symbolName) const override; // For the equation A = B, create the reduced expression A-B Expression * standardEquation(Context & context, Preferences::AngleUnit angleUnit) const; private: /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { return LayoutEngine::writeInfixExpressionTextInBuffer(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, "="); } /* Evalutation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Evaluation * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/evaluation.h b/poincare/include/poincare/evaluation.h index 13af6a966..238da5b3d 100644 --- a/poincare/include/poincare/evaluation.h +++ b/poincare/include/poincare/evaluation.h @@ -5,111 +5,58 @@ extern "C" { #include } -#include +#include +#include +#include namespace Poincare { -/* acos, asin, arctan, acosh, asinh, arctanh and log have branch cuts on the - * complex plan. - * - acos, asin, atanh: ]-inf, -1[U]1, +inf[ - * - atan, asinh: ]-inf*i, -i[U]i, +inf*i[ - * - acosh: ]-inf, 1] - * - log: ]-inf, 0] - * They are then multivalued on these cuts. We followed the convention chosen - * by the lib c++ of llvm but it might differ from a calculator to another - * (ie acos(2) = -1.3169578969248*I or 1.3169578969248*I). */ +class ExpressionReference; +template +class EvaluationReference; template -class Evaluation { +class EvaluationNode : public TreeNode { public: enum class Type : uint8_t { + AllocationFailure, Complex, MatrixComplex }; + EvaluationNode * childAtIndex(int index) const override { return static_cast *>(TreeNode::childAtIndex(index)); } virtual Type type() const = 0; - virtual ~Evaluation() {} + virtual ~EvaluationNode() = default; virtual bool isUndefined() const = 0; virtual T toScalar() const { return NAN; } - virtual Expression * complexToExpression(Preferences::ComplexFormat complexFormat) const = 0; - virtual std::complex createTrace() const = 0; - virtual std::complex createDeterminant() const = 0; - virtual Evaluation * createInverse() const = 0; - virtual Evaluation * createTranspose() const = 0; -}; + virtual ExpressionReference complexToExpression(Preferences::ComplexFormat complexFormat) const = 0; + virtual std::complex trace() const = 0; + virtual std::complex determinant() const = 0; + virtual EvaluationReference inverse() const = 0; + virtual EvaluationReference transpose() const = 0; -template -using ComplexFunction = std::complex (*)(const std::complex&); + // TreeNode + static TreeNode * FailedAllocationStaticNode(); + TreeNode * failedAllocationStaticNode() override { return FailedAllocationStaticNode(); } -template -class Complex : public std::complex, public Evaluation { -public: - Complex(T a, T b = 0.0) : std::complex(a, b) {} - Complex(std::complex c) : std::complex(c) { - if (this->real() == -0) { - this->real(0); - } - if (this->imag() == -0) { - this->imag(0); - } - } - static Complex Undefined() { - return Complex(NAN, NAN); - } - virtual ~Complex() {} - typename Poincare::Evaluation::Type type() const override { return Poincare::Evaluation::Type::Complex; } - bool isUndefined() const override { - return (std::isnan(this->real()) && std::isnan(this->imag())); - } - T toScalar() const override; - Expression * complexToExpression(Preferences::ComplexFormat complexFormat) const override; - std::complex createTrace() const override { return *this; } - std::complex createDeterminant() const override { return *this; } - Complex * createInverse() const override; - Complex * createTranspose() const override { return new Complex(*this); } - /* Complex functions */ - static std::complex pow(const std::complex &c, const std::complex &d); - static std::complex sqrt(const std::complex &c) { - return approximate(c, std::sqrt); - } - static std::complex cos(const std::complex &c) { - return approximate(c, std::cos); - } - static std::complex sin(const std::complex &c) { - return approximate(c, std::sin); - } - static std::complex tan(const std::complex &c) { - return approximate(c, std::tan); - } - static std::complex approximate(const std::complex& c, ComplexFunction approximation); + // Tree + //LayoutNode * childAtIndex(int i) { return static_cast(TreeNode::childAtIndex(i)); } }; template -class MatrixComplex : public Evaluation { +class EvaluationReference : public TreeReference { public: - MatrixComplex(std::complex * operands, int numberOfRows, int numberOfColumns); - static MatrixComplex Undefined() { - std::complex undef = std::complex(NAN, NAN); - return MatrixComplex(&undef, 1, 1); - } - virtual ~MatrixComplex() {} - typename Poincare::Evaluation::Type type() const override { return Poincare::Evaluation::Type::MatrixComplex; } - const std::complex complexOperand(int i) const { return m_operands[i]; } - int numberOfComplexOperands() const { return m_numberOfRows*m_numberOfColumns; } - int numberOfRows() const { return m_numberOfRows; } - int numberOfColumns() const { return m_numberOfColumns; } - bool isUndefined() const override { - return (numberOfRows() == 1 && numberOfColumns() == 1 && std::isnan(complexOperand(0).real()) && std::isnan(complexOperand(0).imag())); - } - Expression * complexToExpression(Preferences::ComplexFormat complexFormat) const override; - std::complex createTrace() const override; - std::complex createDeterminant() const override; - MatrixComplex * createInverse() const override; - MatrixComplex * createTranspose() const override; - static MatrixComplex createIdentity(int dim); -private: - std::complex * m_operands; - int m_numberOfRows; - int m_numberOfColumns; + EvaluationReference(TreeNode * t) : TreeReference(t) {} + EvaluationNode * node() const override{ return static_cast *>(TreeReference::node()); } + typename Poincare::EvaluationNode::Type type() const { return node()->type(); } + bool isUndefined() const { return node()->isUndefined(); } + T toScalar() const { return node()->toScalar(); } + ExpressionReference complexToExpression(Preferences::ComplexFormat complexFormat) const; + std::complex trace() const { return node()->trace(); } + std::complex determinant() const { return node()->determinant(); } + EvaluationReference inverse() const { return node()->inverse(); } + EvaluationReference transpose() const { return node()->transpose(); } +protected: + EvaluationReference() : TreeReference() {} }; } diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 7f248fd2f..ea6f1f141 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -292,9 +292,9 @@ protected: private: virtual Expression * replaceSymbolWithExpression(char symbol, Expression * expression); /* Properties */ - virtual Expression * setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit) { assert(false); return nullptr; } + virtual ExpressionReference setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit) { assert(false); return nullptr; } bool isOfType(Type * types, int length) const; - virtual bool needParenthesisWithParent(const Expression * e) const; + virtual bool needsParenthesisWithParent(SerializableNode * parentNode) const; virtual int privateGetPolynomialCoefficients(char symbolName, Expression * coefficients[]) const; /* Comparison */ /* In the simplification order, most expressions are compared by only @@ -310,7 +310,7 @@ private: Expression * deepBeautify(Context & context, Preferences::AngleUnit angleUnit); Expression * deepReduce(Context & context, Preferences::AngleUnit angleUnit); // TODO: should be virtual pure - virtual Expression * shallowReduce(Context & context, Preferences::AngleUnit angleUnit); + virtual ExpressionReference shallowReduce(Context & context, Preferences::AngleUnit angleUnit); virtual Expression * shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) { return this; }; // Private methods used in simplification process @@ -318,8 +318,8 @@ private: return nullptr; } /* Evaluation Engine */ - virtual Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const = 0; - virtual Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const = 0; + virtual EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const = 0; + virtual EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const = 0; /* Expression roots/extrema solver*/ constexpr static double k_solverPrecision = 1.0E-5; diff --git a/poincare/include/poincare/expression_node.h b/poincare/include/poincare/expression_node.h new file mode 100644 index 000000000..0dcfdfee9 --- /dev/null +++ b/poincare/include/poincare/expression_node.h @@ -0,0 +1,165 @@ +#ifndef POINCARE_EXPRESSION_NODE_H +#define POINCARE_EXPRESSION_NODE_H + +#include +#include +#include +#include +#include + +namespace Poincare { + +/* Methods preceded by a '*!*' interfere with the expression pools which can + * make 'this' outdated. They should only be call only be call in a wrapper on + * ExpressionRef. */ + +class ExpressionNode : public SerializableNode { +friend class ApproximationEngine; +friend class SymbolNode; + friend class NAryExpressionNode; +public: + enum class Type : uint8_t { + AllocationFailure = 0, + Undefined = 1, + Integer = 2, + Rational, + Decimal, + Float, + Infinity, + Multiplication, + Power, + Addition, + Factorial, + Division, + Store, + Equal, + Sine, + Cosine, + Tangent, + AbsoluteValue, + ArcCosine, + ArcSine, + ArcTangent, + BinomialCoefficient, + Ceiling, + ComplexArgument, + Conjugate, + Derivative, + Determinant, + DivisionQuotient, + DivisionRemainder, + Factor, + Floor, + FracPart, + GreatCommonDivisor, + HyperbolicArcCosine, + HyperbolicArcSine, + HyperbolicArcTangent, + HyperbolicCosine, + HyperbolicSine, + HyperbolicTangent, + ImaginaryPart, + Integral, + LeastCommonMultiple, + Logarithm, + MatrixTrace, + NaperianLogarithm, + NthRoot, + Opposite, + Parenthesis, + PermuteCoefficient, + Product, + Random, + Randint, + RealPart, + Round, + SquareRoot, + Subtraction, + Sum, + Symbol, + + Matrix, + ConfidenceInterval, + MatrixDimension, + MatrixInverse, + MatrixTranspose, + PredictionInterval, + EmptyExpression + }; + /* Allocation failure */ + static TreeNode * FailedAllocationStaticNode(); + TreeNode * failedAllocationStaticNode() override { return FailedAllocationStaticNode(); } + + /* Poor man's RTTI */ + virtual Type type() const = 0; + + /* Properties */ + enum class Sign { + Negative = -1, + Unknown = 0, + Positive = 1 + }; + virtual Sign sign() const { return Sign::Unknown; } + virtual bool isNumber() const { return false; } + /*!*/ virtual ExpressionReference replaceSymbolWithExpression(char symbol, ExpressionReference expression); + /*!*/ virtual ExpressionReference setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit); + virtual int polynomialDegree(char symbolName) const; + /*!*/ virtual int getPolynomialCoefficients(char symbolName, ExpressionReference coefficients[]) const; + typedef bool (*isVariableTest)(char c); + virtual int getVariables(isVariableTest isVariable, char * variables) const; + virtual float characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const; + bool isOfType(Type * types, int length) const; + + // Useful to avoid parsing incorrect expressions as cos(2,3,4) + virtual bool hasValidNumberOfOperands(int numberOfOperands) const { return numberOfChildren() == numberOfOperands; } + + /* Comparison */ + + /* Simplification */ + /* SimplificationOrder returns: + * 1 if e1 > e2 + * -1 if e1 < e2 + * 0 if e1 == e + * The order groups like terms together to avoid quadratic complexity when + * factorizing addition or multiplication. For example, it groups terms with + * same bases together (ie Pi, Pi^3) and with same non-rational factors + * together (ie Pi, 2*Pi). + * Because SimplificationOrder is a recursive call, we sometimes enable its + * interruption to avoid freezing in the simplification process. */ + static int SimplificationOrder(const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted = false); + /* In the simplification order, most expressions are compared by only + * comparing their types. However hierarchical expressions of same type would + * compare their operands and thus need to reimplement + * simplificationOrderSameType. Besides, operations that can be simplified + * (ie +, *, ^, !) have specific rules to group like terms together and thus + * reimplement simplificationOrderGreaterType. */ + virtual int simplificationOrderGreaterType(const ExpressionNode * e, bool canBeInterrupted) const { return -1; } + //TODO: What should be the implementation for complex? + virtual int simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const { return 0; } + + /* Layout Engine */ + virtual LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const = 0; + + /* Evaluation Engine */ + typedef float SinglePrecision; + typedef double DoublePrecision; + constexpr static int k_maxNumberOfSteps = 10000; + virtual EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const = 0; + virtual EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const = 0; + + /* Simplification */ + /*!*/ virtual ExpressionReference shallowReduce(Context & context, Preferences::AngleUnit angleUnit); + /*!*/ virtual ExpressionReference shallowBeautify(Context & context, Preferences::AngleUnit angleUnit); + +protected: + // Private methods used in simplification process + /*!*/ virtual ExpressionReference cloneDenominator(Context & context, Preferences::AngleUnit angleUnit) const; + + /* Hierarchy */ + ExpressionNode * childAtIndex(int i) const override { return static_cast(SerializableNode::childAtIndex(i)); } + ExpressionNode * parent() const override { return static_cast(SerializableNode::parent()); } +}; + +} + +#endif diff --git a/poincare/include/poincare/expression_reference.h b/poincare/include/poincare/expression_reference.h new file mode 100644 index 000000000..dd49e1245 --- /dev/null +++ b/poincare/include/poincare/expression_reference.h @@ -0,0 +1,234 @@ +#ifndef POINCARE_EXPRESSION_REFERENCE_H +#define POINCARE_EXPRESSION_REFERENCE_H + +#include +#include +#include +#include + +#include + +namespace Poincare { + +class Context; + +class ExpressionReference : public SerializableReference { + friend class ExpressionNode; + friend class NAryExpressionNode; + friend class SymbolNode; +public: + using SerializableReference::SerializableReference; + + /* Constructor & Destructor */ + virtual ~ExpressionReference() = default; + static ExpressionReference parse(char const * string); + static void ReplaceSymbolWithExpression(ExpressionReference * expressionAddress, char symbol, ExpressionReference expression); + ExpressionReference clone() const; + + /* Reference */ + ExpressionNode * node() const override { return static_cast(SerializableReference::node()); } + + /* Circuit breaker */ + typedef bool (*CircuitBreaker)(); + static void setCircuitBreaker(CircuitBreaker cb); + static bool shouldStopProcessing(); + + /* Properties */ + ExpressionNode::Sign sign() const { return node()->sign(); } + ExpressionReference setSign(ExpressionNode::Sign s, Context & context, Preferences::AngleUnit angleUnit) { return node()->setSign(s, context, angleUnit); } + bool isNumber() const { return node()->isNumber(); } + bool isRationalZero() const; + typedef bool (*ExpressionTest)(const ExpressionReference e, Context & context); + bool recursivelyMatches(ExpressionTest test, Context & context) const; + bool isApproximate(Context & context) const; + static bool IsMatrix(const ExpressionReference e, Context & context); + /* 'characteristicXRange' tries to assess the range on x where the expression + * (considered as a function on x) has an interesting evolution. For example, + * the period of the function on 'x' if it is periodic. If + * the function is x-independent, the return value is 0.0f (because any + * x-range is equivalent). If the function does not have an interesting range, + * the return value is NAN. + * NB: so far, we consider that the only way of building a periodic function + * is to use sin/tan/cos(f(x)) with f a linear function. */ + float characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const { return this->node()->characteristicXRange(context, angleUnit); } + /* polynomialDegree returns: + * - (-1) if the expression is not a polynome + * - the degree of the polynome otherwise */ + int polynomialDegree(char symbolName) const { return this->node()->polynomialDegree(symbolName); } + /* getVariables fills the table variables with the variable present in the + * expression and returns the number of entries in filled in variables. + * For instance getVariables('x+y+2*w/cos(4)') would result in + * variables = « xyw » and would return 3. If the final number of + * variables would overflow the maxNumberOfVariables, getVariables return -1 */ + static constexpr int k_maxNumberOfVariables = 6; + int getVariables(ExpressionNode::isVariableTest isVariable, char * variables) const { return this->node()->getVariables(isVariable, variables); } + /* getLinearCoefficients return false if the expression is not linear with + * the variables hold in 'variables'. Otherwise, it fills 'coefficients' with + * the coefficients of the variables hold in 'variables' (following the same + * order) and 'constant' with the constant of the expression. */ + bool getLinearCoefficients(char * variables, ExpressionReference coefficients[], ExpressionReference constant[], Context & context, Preferences::AngleUnit angleUnit) const; + /* getPolynomialCoefficients fills the table coefficients with the expressions + * of the first 3 polynomial coefficients and return polynomialDegree. + * coefficients has up to 3 entries. It supposed to be called on Reduced + * expression. */ + static constexpr int k_maxPolynomialDegree = 2; + static constexpr int k_maxNumberOfPolynomialCoefficients = k_maxPolynomialDegree+1; + int getPolynomialCoefficients(char symbolName, ExpressionReference coefficients[], Context & context, Preferences::AngleUnit angleUnit) const; + + /* Comparison */ + /* isIdenticalTo is the "easy" equality, it returns true if both trees have + * same structures and all their nodes have same types and values (ie, + * sqrt(pi^2) is NOT identical to pi). */ + bool isIdenticalTo(const ExpressionReference e) const { + /* We use the simplification order only because it is a already-coded total + * order on expresssions. */ + return ExpressionNode::SimplificationOrder(this->node(), e.node(), true) == 0; + } + bool isEqualToItsApproximationLayout(ExpressionReference approximation, int bufferSize, Preferences::AngleUnit angleUnit, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits, Context & context); + + /* Layout Engine */ + LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { return this->node()->createLayout(floatDisplayMode, numberOfSignificantDigits); } + int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const { return this->node()->writeTextInBuffer(buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits); } + + /* Simplification */ + static ExpressionReference ParseAndSimplify(const char * text, Context & context, Preferences::AngleUnit angleUnit); + static void Simplify(ExpressionReference * expressionAddress, Context & context, Preferences::AngleUnit angleUnit); + + /* Approximation Engine */ + template ExpressionReference approximate(Context& context, Preferences::AngleUnit angleUnit, Preferences::Preferences::ComplexFormat complexFormat) const; + template U approximateToScalar(Context& context, Preferences::AngleUnit angleUnit) const; + template static U approximateToScalar(const char * text, Context& context, Preferences::AngleUnit angleUnit); + template U approximateWithValueForSymbol(char symbol, U x, Context & context, Preferences::AngleUnit angleUnit) const; + + /* Expression roots/extrema solver*/ + struct Coordinate2D { + double abscissa; + double value; + }; + Coordinate2D nextMinimum(char symbol, double start, double step, double max, Context & context, Preferences::AngleUnit angleUnit) const; + Coordinate2D nextMaximum(char symbol, double start, double step, double max, Context & context, Preferences::AngleUnit angleUnit) const; + double nextRoot(char symbol, double start, double step, double max, Context & context, Preferences::AngleUnit angleUnit) const; + Coordinate2D nextIntersection(char symbol, double start, double step, double max, Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression) const; + +private: + /* Hierarchy */ + ExpressionReference childAtIndex(int i) const { + return ExpressionReference(TreeReference::treeChildAtIndex(i).node()); + } + + /* Simplification */ + ExpressionReference deepBeautify(Context & context, Preferences::AngleUnit angleUnit); + ExpressionReference deepReduce(Context & context, Preferences::AngleUnit angleUnit); + // TODO: should be virtual pure + virtual ExpressionReference shallowReduce(Context & context, Preferences::AngleUnit angleUnit) { return this->node()->shallowReduce(context, angleUnit); } + virtual ExpressionReference shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) { return this->node()->shallowBeautify(context, angleUnit); }; + + /* Approximation */ + template static U epsilon(); + + /* Expression roots/extrema solver*/ + constexpr static double k_solverPrecision = 1.0E-5; + constexpr static double k_sqrtEps = 1.4901161193847656E-8; // sqrt(DBL_EPSILON) + constexpr static double k_goldenRatio = 0.381966011250105151795413165634361882279690820194237137864; // (3-sqrt(5))/2 + constexpr static double k_maxFloat = 1e100; + typedef double (*EvaluationAtAbscissa)(char symbol, double abscissa, Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression0, const ExpressionReference expression1); + Coordinate2D nextMinimumOfExpression(char symbol, double start, double step, double max, EvaluationAtAbscissa evaluation, Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression = ExpressionReference(nullptr), bool lookForRootMinimum = false) const; + void bracketMinimum(char symbol, double start, double step, double max, double result[3], EvaluationAtAbscissa evaluation, Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression = ExpressionReference(nullptr)) const; + Coordinate2D brentMinimum(char symbol, double ax, double bx, EvaluationAtAbscissa evaluation, Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression = ExpressionReference(nullptr)) const; + double nextIntersectionWithExpression(char symbol, double start, double step, double max, EvaluationAtAbscissa evaluation, Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression) const; + void bracketRoot(char symbol, double start, double step, double max, double result[2], EvaluationAtAbscissa evaluation, Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression) const; + double brentRoot(char symbol, double ax, double bx, double precision, EvaluationAtAbscissa evaluation, Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression) const; +}; + + + +/* +class UndefinedNode : public ExpressionNode { +public: + // ExpressionNode + Type type() const override { return Type::Undefined; } + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return Complex::Undefined().storeEvaluation(); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return Complex::Undefined().storeEvaluation(); } + LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode = Preferences::PrintFloatMode::Decimal, int numberOfSignificantDigits = 0) const override; + + // TreeNode + size_t size() const override { return sizeof(UndefinedNode); } + const char * description() const override { return "Allocation Failed"; } + int numberOfChildren() const override { return 0; } + bool isAllocationFailure() const override { return true; } +}; + +class SymbolNode : public ExpressionNode { +public: + bool isApproximate(Context & context) const; + bool isMatrixSymbol() const; + char name() const; + // ExpressionNode + Type type() const override { return Type::Undefined; } + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return Complex::Undefined().storeEvaluation(); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return Complex::Undefined().storeEvaluation(); } + LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode = Preferences::PrintFloatMode::Decimal, int numberOfSignificantDigits = 0) const override; + + // TreeNode + size_t size() const override { return sizeof(UndefinedNode); } + const char * description() const override { return "Allocation Failed"; } + int numberOfChildren() const override { return 0; } + bool isAllocationFailure() const override { return true; } +}; + +class RationalNode : public ExpressionNode { +public: + // ExpressionNode + Type type() const override { return Type::Rational; } + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return Complex::Undefined().storeEvaluation(); } + Evaluation * approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return Complex::Undefined().storeEvaluation(); } + LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode = Preferences::PrintFloatMode::Decimal, int numberOfSignificantDigits = 0) const override; + + // TreeNode + size_t size() const override { return sizeof(UndefinedNode); } + const char * description() const override { return "Allocation Failed"; } + int numberOfChildren() const override { return 0; } + bool isAllocationFailure() const override { return true; } +}; + +class OppositeNode : public ExpressionNode { +public: + // ExpressionNode + Type type() const override { return Type::Opposite; } + Evaluation * approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return Complex::Undefined().storeEvaluation(); } + Evaluation * approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return Complex::Undefined().storeEvaluation(); } + LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode = Preferences::PrintFloatMode::Decimal, int numberOfSignificantDigits = 0) const override; + + // TreeNode + size_t size() const override { return sizeof(UndefinedNode); } + const char * description() const override { return "Allocation Failed"; } + int numberOfChildren() const override { return 0; } + bool isAllocationFailure() const override { return true; } +}; + + +typedef ExpressionReference UndefinedRef; +typedef ExpressionReference SymbolRef; +class RationalRef : public ExpressionReference { +public: + RationalRef(int i) : + ExpressionReference() + { + } +}; + +class OppositeRef : public ExpressionReference { +public: + OppositeRef(ExpressionReference child) : + ExpressionReference() + { + } +}; +*/ +} + +#endif diff --git a/poincare/include/poincare/factor.h b/poincare/include/poincare/factor.h index 153d6284b..cb41e6404 100644 --- a/poincare/include/poincare/factor.h +++ b/poincare/include/poincare/factor.h @@ -13,7 +13,6 @@ class Factor : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -24,12 +23,12 @@ private: } const char * name() const { return "factor"; } /* Simplification */ - Expression * shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) override; Expression * createMultiplicationOfIntegerPrimeDecomposition(Integer i, Context & context, Preferences::AngleUnit angleUnit); /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Evaluation * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { return operand(0)->privateApproximate(T(), context, angleUnit); } }; diff --git a/poincare/include/poincare/factorial.h b/poincare/include/poincare/factorial.h index 28616225f..18649373a 100644 --- a/poincare/include/poincare/factorial.h +++ b/poincare/include/poincare/factorial.h @@ -10,22 +10,21 @@ class Factorial : public StaticHierarchy<1> { public: Factorial(const Expression * argument, bool clone = true); Type type() const override; - Expression * clone() const override; private: constexpr static int k_maxOperandValue = 100; /* Layout */ - bool needParenthesisWithParent(const Expression * e) const override; + bool needsParenthesisWithParent(SerializableNode * parentNode) const override; LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; /* Simplication */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; - Expression * shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } diff --git a/poincare/include/poincare/float.h b/poincare/include/poincare/float.h new file mode 100644 index 000000000..d72b9cb21 --- /dev/null +++ b/poincare/include/poincare/float.h @@ -0,0 +1,68 @@ +#ifndef POINCARE_FLOAT_H +#define POINCARE_FLOAT_H + +#include + +namespace Poincare { + +/* Float reprensents an approximated number. This class is use when: + * - a rational overflows + * - to avoid turning float/double into Decimal back and forth because + * performances are dramatically affected when doing so. For instance, when + * plotting a graph, we need to set a float/double value for a symbol and + * approximate an expression containing the symbol for each dot displayed). + * We thus use the Float class that hold a float/double. + * Float can only be approximated ; Float is an INTERNAL node only. Indeed, + * they are always turned back into Decimal when beautifying. Thus, the usual + * methods of expression are not implemented to avoid code duplication with + * Decimal. */ + +template +class FloatNode : public NumberNode { +public: + void setFloat(T a) { m_value = a; } + T value() const { return m_value; } + + // TreeNode + size_t size() const override { return sizeof(FloatNode); } + const char * description() const override { return "Float"; } + + // Properties + Type type() const override { return Type::Float; } + + // Layout + int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { + assert(false); + return 0; + } + /* Layout */ + LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { + assert(false); + return nullptr; + } + /* Evaluation */ + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } +private: + template EvaluationReference * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { + return ComplexReference((U)m_value); + } + T m_value; +}; + +template +class FloatReference : public NumberReference { +public: + FloatReference(T value) : NumberReference() { + TreeNode * node = TreePool::sharedPool()->createTreeNode(); + m_identifier = node->identifier(); + if (!node->isAllocationFailure()) { + static_cast *>(node)->setFloat(value); + } + } +}; + + +} + +#endif diff --git a/poincare/include/poincare/floor.h b/poincare/include/poincare/floor.h index 51caa5102..f8bb390f8 100644 --- a/poincare/include/poincare/floor.h +++ b/poincare/include/poincare/floor.h @@ -11,7 +11,6 @@ class Floor : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; @@ -20,13 +19,13 @@ private: } const char * name() const { return "floor"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/frac_part.h b/poincare/include/poincare/frac_part.h index 5cf00f572..0a0cf4785 100644 --- a/poincare/include/poincare/frac_part.h +++ b/poincare/include/poincare/frac_part.h @@ -11,7 +11,6 @@ class FracPart : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -22,13 +21,13 @@ private: } const char * name() const { return "frac"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/global_context.h b/poincare/include/poincare/global_context.h index 786442697..de4881647 100644 --- a/poincare/include/poincare/global_context.h +++ b/poincare/include/poincare/global_context.h @@ -15,24 +15,19 @@ class Integer; class GlobalContext : public Context { public: GlobalContext(); - ~GlobalContext(); - GlobalContext(const GlobalContext& other) = delete; - GlobalContext(GlobalContext&& other) = delete; - GlobalContext& operator=(const GlobalContext& other) = delete; - GlobalContext& operator=(GlobalContext&& other) = delete; /* The expression recorded in global context is already a expression. * Otherwise, we would need the context and the angle unit to evaluate it */ - const Expression * expressionForSymbol(const Symbol * symbol) override; - LayoutRef layoutForSymbol(const Symbol * symbol, int numberOfSignificantDigits); - void setExpressionForSymbolName(const Expression * expression, const Symbol * symbol, Context & context) override; + const ExpressionReference expressionForSymbol(const SymbolReference symbol) override; + LayoutRef layoutForSymbol(const SymbolReference symbol, int numberOfSignificantDigits); + void setExpressionForSymbolName(const ExpressionReference expression, const SymbolReference symbol, Context & context) override; static constexpr uint16_t k_maxNumberOfScalarExpressions = 26; static constexpr uint16_t k_maxNumberOfListExpressions = 10; static constexpr uint16_t k_maxNumberOfMatrixExpressions = 10; private: static Decimal * defaultExpression(); int symbolIndex(const Symbol * symbol) const; - Expression * m_expressions[k_maxNumberOfScalarExpressions]; - Matrix * m_matrixExpressions[k_maxNumberOfMatrixExpressions]; + ExpressionReference m_expressions[k_maxNumberOfScalarExpressions]; + MatrixReference m_matrixExpressions[k_maxNumberOfMatrixExpressions]; /* Matrix layout memoization */ LayoutRef m_matrixLayouts[k_maxNumberOfMatrixExpressions]; Approximation m_pi; diff --git a/poincare/include/poincare/great_common_divisor.h b/poincare/include/poincare/great_common_divisor.h index c841b7aec..cf53bd5b0 100644 --- a/poincare/include/poincare/great_common_divisor.h +++ b/poincare/include/poincare/great_common_divisor.h @@ -11,7 +11,6 @@ class GreatCommonDivisor : public StaticHierarchy<2> { using StaticHierarchy<2>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -22,11 +21,11 @@ private: } const char * name() const { return "gcd"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Complex * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/hyperbolic_arc_cosine.h b/poincare/include/poincare/hyperbolic_arc_cosine.h index 6b3201e33..532d7a0e1 100644 --- a/poincare/include/poincare/hyperbolic_arc_cosine.h +++ b/poincare/include/poincare/hyperbolic_arc_cosine.h @@ -11,7 +11,6 @@ class HyperbolicArcCosine : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -22,13 +21,13 @@ private: } const char * name() const { return "acosh"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/hyperbolic_arc_sine.h b/poincare/include/poincare/hyperbolic_arc_sine.h index fc3434d40..b370f1c78 100644 --- a/poincare/include/poincare/hyperbolic_arc_sine.h +++ b/poincare/include/poincare/hyperbolic_arc_sine.h @@ -11,7 +11,6 @@ class HyperbolicArcSine : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -22,13 +21,13 @@ private: } const char * name() const { return "asinh"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/hyperbolic_arc_tangent.h b/poincare/include/poincare/hyperbolic_arc_tangent.h index 6e58d6a11..1a2c35deb 100644 --- a/poincare/include/poincare/hyperbolic_arc_tangent.h +++ b/poincare/include/poincare/hyperbolic_arc_tangent.h @@ -11,7 +11,6 @@ class HyperbolicArcTangent : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -22,13 +21,13 @@ private: } const char * name() const { return "atanh"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/hyperbolic_cosine.h b/poincare/include/poincare/hyperbolic_cosine.h index 759f392cb..bebf1e1f2 100644 --- a/poincare/include/poincare/hyperbolic_cosine.h +++ b/poincare/include/poincare/hyperbolic_cosine.h @@ -11,7 +11,6 @@ class HyperbolicCosine : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); private: /* Layout */ @@ -23,12 +22,12 @@ private: } const char * name() const { return "cosh"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/hyperbolic_sine.h b/poincare/include/poincare/hyperbolic_sine.h index 0085bd80b..4314b2397 100644 --- a/poincare/include/poincare/hyperbolic_sine.h +++ b/poincare/include/poincare/hyperbolic_sine.h @@ -11,7 +11,6 @@ class HyperbolicSine : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); private: /* Layout */ @@ -23,12 +22,12 @@ private: } const char * name() const { return "sinh"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/hyperbolic_tangent.h b/poincare/include/poincare/hyperbolic_tangent.h index c5b608715..17555832a 100644 --- a/poincare/include/poincare/hyperbolic_tangent.h +++ b/poincare/include/poincare/hyperbolic_tangent.h @@ -11,7 +11,6 @@ class HyperbolicTangent : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); private: /* Layout */ @@ -23,12 +22,12 @@ private: } const char * name() const { return "tanh"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/imaginary_part.h b/poincare/include/poincare/imaginary_part.h index 2be675aa7..f89b03bd3 100644 --- a/poincare/include/poincare/imaginary_part.h +++ b/poincare/include/poincare/imaginary_part.h @@ -11,7 +11,6 @@ class ImaginaryPart : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -22,13 +21,13 @@ private: } const char * name() const { return "im"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/infinity.h b/poincare/include/poincare/infinity.h new file mode 100644 index 000000000..684cb0d1b --- /dev/null +++ b/poincare/include/poincare/infinity.h @@ -0,0 +1,49 @@ +#ifndef POINCARE_INFINITY_H +#define POINCARE_INFINITY_H + +#include + +namespace Poincare { + +class InfinityNode : public NumberNode { +public: + void setNegative(bool negative) { m_negative = negative; } + + // TreeNode + size_t size() const override { return sizeof(InfinityNode); } + const char * description() const override { return "Infinity"; } + + // Properties + Type type() const override { return Type::Infinity; } + Sign sign() const override { return m_negative ? Sign::Negative : Sign::Positive; } + + // Approximation + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + return templatedApproximate(); + } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + return templatedApproximate(); + } + + // Layout + LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode = Preferences::PrintFloatMode::Decimal, int numberOfSignificantDigits = 0) const override; +private: + template EvaluationReference templatedApproximate() const; + bool m_negative; +}; + +class InfinityReference : public NumberReference { +public: + InfinityReference(bool negative) { + TreeNode * node = TreePool::sharedPool()->createTreeNode(); + m_identifier = node->identifier(); + if (!node->isAllocationFailure()) { + static_cast(node)->setNegative(negative); + } + } +}; + +} + +#endif diff --git a/poincare/include/poincare/integer.h b/poincare/include/poincare/integer.h index 2b47f5dc8..ea89318bf 100644 --- a/poincare/include/poincare/integer.h +++ b/poincare/include/poincare/integer.h @@ -3,54 +3,33 @@ #include #include +#include +#include namespace Poincare { class ExpressionLayout; class LayoutReference; class LayoutNode; +class IntegerReference; +struct IntegerDivisionReference; + +typedef uint16_t half_native_uint_t; +typedef int32_t native_int_t; +typedef int64_t double_native_int_t; +typedef uint32_t native_uint_t; +typedef uint64_t double_native_uint_t; /* All algorithm should be improved with: * Modern Computer Arithmetic, Richard P. Brent and Paul Zimmermann */ -struct IntegerDivision; - -class Integer { +class NaturalIntegerAbstract { +friend class IntegerReference; +friend class RationalReference; public: - typedef uint16_t half_native_uint_t; - typedef int32_t native_int_t; - typedef int64_t double_native_int_t; - typedef uint32_t native_uint_t; - typedef uint64_t double_native_uint_t; - - // FIXME: This constructor should be constexpr - Integer(native_int_t i = 0) : - m_digit(i>0 ? i : -i), - m_numberOfDigits(1), - m_negative(i<0) - { - } - Integer(double_native_int_t i); - Integer(const char * digits, bool negative = false); // Digits are NOT NULL-terminated - static Integer exponent(int fractionalPartLength, const char * exponent, int exponentLength, bool exponentNegative); - static Integer numerator(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, bool negative, Integer * exponent); - static Integer denominator(Integer * exponent); - - ~Integer(); - Integer(Integer&& other); // C++11 move constructor - Integer& operator=(Integer&& other); // C++11 move assignment operator - Integer(const Integer& other); // C++11 copy constructor - Integer& operator=(const Integer& other); // C++11 copy assignment operator - - // Getter & Setter - bool isNegative() const { return m_negative; } - void setNegative(bool negative); - int extractedInt() const { assert(m_numberOfDigits == 1 && m_digit <= k_maxExtractableInteger); return m_negative ? -m_digit : m_digit; } - - // Comparison - static int NaturalOrder(const Integer & i, const Integer & j); - bool isEqualTo(const Integer & other) const; - bool isLowerThan(const Integer & other) const; + // Getters + uint32_t digit(int i) const { assert(i < m_numberOfDigits); return digits()[i]; } + size_t numberOfDigits() const { return m_numberOfDigits; } // Layout int writeTextInBuffer(char * buffer, int bufferSize) const; @@ -59,36 +38,38 @@ public: // Approximation template T approximate() const; - // Arithmetic - static Integer Addition(const Integer & i, const Integer & j); - static Integer Subtraction(const Integer & i, const Integer & j); - static Integer Multiplication(const Integer & i, const Integer & j); - static Integer Factorial(const Integer & i); - static IntegerDivision Division(const Integer & numerator, const Integer & denominator); - static Integer Power(const Integer & i, const Integer & j); - static int numberOfDigitsWithoutSign(const Integer & i); - //static Integer Division(const Integer & i, const Integer & j); - //static IntegerDivision division(const Integer & i, const Integer & j); - bool isOne() const { return (m_numberOfDigits == 1 && digit(0) == 1 && !m_negative); }; - bool isTwo() const { return (m_numberOfDigits == 1 && digit(0) == 2 && !m_negative); }; - bool isTen() const { return (m_numberOfDigits == 1 && digit(0) == 10 && !m_negative); }; - bool isMinusOne() const { return (m_numberOfDigits == 1 && digit(0) == 1 && m_negative); }; - bool isZero() const { return (m_numberOfDigits == 1 && digit(0) == 0); }; - constexpr static int k_maxExtractableInteger = 0x7FFFFFFF; -private: - Integer(const native_uint_t * digits, uint16_t numberOfDigits, bool negative); - static Integer IntegerWithHalfDigitAtIndex(half_native_uint_t halfDigit, int index); + // Properties + static int numberOfDigits(const NaturalIntegerAbstract * i); + virtual bool isOne() const { return (m_numberOfDigits == 1 && digit(0) == 1); }; + virtual bool isTwo() const { return (m_numberOfDigits == 1 && digit(0) == 2); }; + virtual bool isTen() const { return (m_numberOfDigits == 1 && digit(0) == 10); }; + bool isZero() const { return (m_numberOfDigits == 0); }; + bool isInfinity() const { return m_numberOfDigits > k_maxNumberOfDigits; } + bool isEven() const { return (m_numberOfDigits == 0 || ((digit(0) & 1) == 0)); } - void releaseDynamicIvars(); - static int8_t ucmp(const Integer & a, const Integer & b); // -1, 0, or 1 - static Integer usum(const Integer & a, const Integer & b, bool subtract, bool outputNegative); - static Integer addition(const Integer & a, const Integer & b, bool inverseBNegative); - static IntegerDivision udiv(const Integer & a, const Integer & b); - bool usesImmediateDigit() const { return m_numberOfDigits == 1; } - native_uint_t digit(int i) const { - assert(i >= 0 && i < m_numberOfDigits); - return (usesImmediateDigit() ? m_digit : m_digits[i]); + // Arithmetic + /* buffer has to be k_maxNumberOfDigits+1 to allow ...*/ + static int8_t ucmp(const NaturalIntegerAbstract * a, const NaturalIntegerAbstract * b); // -1, 0, or 1 + static IntegerReference usum(const NaturalIntegerAbstract * a, const NaturalIntegerAbstract * b, bool subtract); + static IntegerReference umult(const NaturalIntegerAbstract * a, const NaturalIntegerAbstract * b); + static IntegerDivisionReference udiv(const NaturalIntegerAbstract * a, const NaturalIntegerAbstract * b); + static IntegerReference upow(const NaturalIntegerAbstract * a, const NaturalIntegerAbstract * b); + static IntegerReference ufact(const NaturalIntegerAbstract * a); + + constexpr static int k_maxNumberOfDigits = 11; +protected: + constexpr static int k_maxNumberOfDigitsBase10 = 105; // (2^32)^k_maxNumberOfDigits-1 ~ 10^105 + NaturalIntegerAbstract(size_t numberOfDigits = 0) : + m_numberOfDigits(numberOfDigits) + { } + virtual native_uint_t * digits() const = 0; + virtual void setDigitAtIndex(native_uint_t digit, int index) = 0; + + size_t m_numberOfDigits; // In base native_uint_max +private: + static IntegerReference IntegerWithHalfDigitAtIndex(half_native_uint_t halfDigit, int index); + uint16_t numberOfHalfDigits() const { native_uint_t d = digit(m_numberOfDigits-1); native_uint_t halfBase = 1 << (8*sizeof(half_native_uint_t)); @@ -99,23 +80,128 @@ private: if (i >= numberOfHalfDigits()) { return 0; } - return (usesImmediateDigit() ? ((half_native_uint_t *)&m_digit)[i] : ((half_native_uint_t *)m_digits)[i]); + return ((half_native_uint_t *)digits())[i]; } - // Small integer optimization. Similar to short string optimization. - union { - const native_uint_t * m_digits; // Little-endian - native_uint_t m_digit; - }; - uint16_t m_numberOfDigits; // In base native_uint_max - bool m_negative; // Make sure zero cannot be negative - static_assert(sizeof(native_int_t) <= sizeof(native_uint_t), "native_uint_t should be able to contain native_int_t data"); + static_assert(sizeof(double_native_int_t) <= sizeof(double_native_uint_t), "double_native_int_t type has not the right size compared to double_native_uint_t"); + static_assert(sizeof(native_int_t) == sizeof(native_uint_t), "native_int_t type has not the right size compared to native_uint_t"); static_assert(sizeof(double_native_uint_t) == 2*sizeof(native_uint_t), "double_native_uint_t should be twice the size of native_uint_t"); + static_assert(sizeof(double_native_int_t) == 2*sizeof(native_int_t), "double_native_int_t type has not the right size compared to native_int_t"); }; -struct IntegerDivision { - Integer quotient; - Integer remainder; +class NaturalIntegerPointer : public NaturalIntegerAbstract { +public: + NaturalIntegerPointer(native_uint_t * buffer, size_t size); +private: + native_uint_t * digits() const override { return m_digits; } + void setDigitAtIndex(native_uint_t digit, int index) override { assert(index < m_numberOfDigits); m_digits[index] = digit; } + native_uint_t * m_digits; +}; + +class IntegerNode : public NumberNode, public NaturalIntegerAbstract { +public: + IntegerNode() : + NaturalIntegerAbstract(), + m_negative(false) {} + void setDigits(native_int_t i); + void setDigits(double_native_int_t i); + void setDigits(const native_uint_t * digits, size_t size, bool negative); + + // Getters + native_uint_t * digits() const override { return (native_uint_t *)m_digits; } + + // ExpressionNode + Type type() const override { return Type::Integer; } + + // Simplification + ExpressionReference shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override; + + // Approximation + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ComplexReference(templatedApproximate()); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ComplexReference(templatedApproximate()); } + template T templatedApproximate() const; + + // Layout + LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode = Preferences::PrintFloatMode::Decimal, int numberOfSignificantDigits = 0) const override; + + // TreeNode + size_t size() const override; + const char * description() const override { return "Integer"; } + + // ExpressionNode + Sign sign() const override { return m_negative ? Sign::Negative : Sign::Positive; } + ExpressionReference setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit) override; + + void setNegative(bool negative); + + // Comparison + static int NaturalOrder(const IntegerNode * i, const IntegerNode * j); + int simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const override { return NaturalOrder(this, static_cast(e)); } + + // Properties + bool isOne() const override { return (NaturalIntegerAbstract::isOne() && !m_negative); }; + bool isTwo() const override { return (NaturalIntegerAbstract::isTwo() && !m_negative); }; + bool isTen() const override{ return (NaturalIntegerAbstract::isTen() && !m_negative); }; + bool isMinusOne() const { return (NaturalIntegerAbstract::isOne() && m_negative); }; +private: + void setDigitAtIndex(native_uint_t digit, int index) override { m_digits[index] = digit; } + bool m_negative; // Make sure zero cannot be negative + native_uint_t m_digits[0]; +}; + + +class IntegerReference : public NumberReference { +friend class NaturalIntegerAbstract; +friend class NaturalIntegerPointer; +friend class IntegerNode; +friend class RationalReference; +public: + IntegerReference(TreeNode * n) : NumberReference(n) {} + IntegerReference(const char * digits, size_t length, bool negative); + IntegerReference(const NaturalIntegerAbstract * naturalInteger); + IntegerReference(native_int_t i); + IntegerReference(double_native_int_t i); + static IntegerReference Overflow() { return IntegerReference((native_uint_t *)nullptr, IntegerNode::k_maxNumberOfDigits+1, false); } + + // TreeNode + IntegerNode * typedNode() const { assert(node()->type() == ExpressionNode::Type::Integer); return static_cast(node()); } + + constexpr static int k_maxExtractableInteger = 0x7FFFFFFF; + int extractedInt() const; + + // Comparison + static int NaturalOrder(const IntegerReference i, const IntegerReference j); + + // Properties + bool isZero() const; + bool isOne() const; + bool isInfinity() const; + bool isEven() const; + bool isNegative() const { return node()->sign() == ExpressionNode::Sign::Negative; } + void setNegative(bool negative); + + // Arithmetic + static IntegerReference Addition(const IntegerReference i, const IntegerReference j); + static IntegerReference Subtraction(const IntegerReference i, const IntegerReference j); + static IntegerReference Multiplication(const IntegerReference i, const IntegerReference j); + static IntegerDivisionReference Division(const IntegerReference numerator, const IntegerReference denominator); + static IntegerReference Power(const IntegerReference i, const IntegerReference j); + static IntegerReference Factorial(const IntegerReference i); +private: + IntegerReference(const native_uint_t * digits, size_t numberOfDigits, bool negative); + IntegerReference(size_t size) : NumberReference() { + TreeNode * node = TreePool::sharedPool()->createTreeNode(size); + m_identifier = node->identifier(); + } + static IntegerReference addition(const IntegerReference a, const IntegerReference b, bool inverseBNegative); + size_t numberOfDigits() const { return typedNode()->numberOfDigits(); } + uint32_t digit(int i) const { return typedNode()->digit(i); } +}; + +struct IntegerDivisionReference { + IntegerReference quotient; + IntegerReference remainder; }; } diff --git a/poincare/include/poincare/integral.h b/poincare/include/poincare/integral.h index 1cd90710a..3bdedce57 100644 --- a/poincare/include/poincare/integral.h +++ b/poincare/include/poincare/integral.h @@ -11,7 +11,6 @@ class Integral : public StaticHierarchy<3> { using StaticHierarchy<3>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; int polynomialDegree(char symbolName) const override; private: /* Layout */ @@ -20,11 +19,11 @@ private: return LayoutEngine::writePrefixExpressionTextInBuffer(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, "int"); } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Complex * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; template struct DetailedResult { diff --git a/poincare/include/poincare/layout_engine.h b/poincare/include/poincare/layout_engine.h index b48d21e8f..7609d417b 100644 --- a/poincare/include/poincare/layout_engine.h +++ b/poincare/include/poincare/layout_engine.h @@ -1,7 +1,7 @@ #ifndef POINCARE_LAYOUT_ENGINE_H #define POINCARE_LAYOUT_ENGINE_H -#include +#include #include namespace Poincare { @@ -10,30 +10,14 @@ class LayoutEngine { public: /* Expression to Layout */ - static LayoutRef createInfixLayout(const Expression * expression, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits, const char * operatorName); - static LayoutRef createPrefixLayout(const Expression * expression, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits, const char * operatorName); + static LayoutRef createInfixLayout(const ExpressionReference expression, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits, const char * operatorName); + static LayoutRef createPrefixLayout(const ExpressionReference expression, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits, const char * operatorName); /* Create special layouts */ static LayoutRef createParenthesedLayout(LayoutRef layout, bool cloneLayout); static LayoutRef createStringLayout(const char * buffer, int bufferSize, KDText::FontSize fontSize = KDText::FontSize::Large); static LayoutRef createLogLayout(LayoutRef argument, LayoutRef index); - /* Expression to Text */ - static int writeInfixExpressionTextInBuffer( - const Expression * expression, - char * buffer, - int bufferSize, - Preferences::PrintFloatMode floatDisplayMode, - int numberOfDigits, - const char * operatorName); - static int writePrefixExpressionTextInBuffer( - const Expression * expression, - char * buffer, - int bufferSize, - Preferences::PrintFloatMode floatDisplayMode, - int numberOfDigits, - const char * operatorName); - /* SerializableReference to Text */ static int writeInfixSerializableRefTextInBuffer( const SerializableRef serializableRef, @@ -58,11 +42,6 @@ public: static int writeOneCharInBuffer(char * buffer, int bufferSize, char charToWrite); private: - static constexpr char divideChar = '/'; - // These two functions return the index of the null-terminating char. - static int writeInfixExpressionOrExpressionLayoutTextInBuffer(const Expression * expression, void * expressionLayout, char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfDigits, const char * operatorName, int firstChildIndex, int lastChildIndex); - static int writePrefixExpressionOrExpressionLayoutTextInBuffer(const Expression * expression, void * expressionLayout, char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfDigits, const char * operatorName, bool writeFirstChild = true); - static void writeChildTreeInBuffer(SerializableRef childRef, SerializableRef parentRef, char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfDigits, int * numberOfChar); }; diff --git a/poincare/include/poincare/least_common_multiple.h b/poincare/include/poincare/least_common_multiple.h index e2a557e8f..0be9f192d 100644 --- a/poincare/include/poincare/least_common_multiple.h +++ b/poincare/include/poincare/least_common_multiple.h @@ -11,7 +11,6 @@ class LeastCommonMultiple : public StaticHierarchy<2> { using StaticHierarchy<2>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -22,11 +21,11 @@ private: } const char * name() const { return "lcm"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Complex * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/logarithm.h b/poincare/include/poincare/logarithm.h index c59c6a17f..b500b6b72 100644 --- a/poincare/include/poincare/logarithm.h +++ b/poincare/include/poincare/logarithm.h @@ -12,7 +12,6 @@ class Logarithm : public BoundedStaticHierarchy<2> { friend class NaperianLogarithm; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; @@ -20,16 +19,16 @@ private: return LayoutEngine::writePrefixExpressionTextInBuffer(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, "log"); } /* Simplification */ - Expression * shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override; Expression * simpleShallowReduce(Context & context, Preferences::AngleUnit angleUnit); Expression * shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) override; bool parentIsAPowerOfSameBase() const; Expression * splitInteger(Integer i, bool isDenominator, Context & context, Preferences::AngleUnit angleUnit); /* Evaluation */ template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Evaluation * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/matrix.h b/poincare/include/poincare/matrix.h index 64a13abd3..7d4d46314 100644 --- a/poincare/include/poincare/matrix.h +++ b/poincare/include/poincare/matrix.h @@ -1,53 +1,72 @@ #ifndef POINCARE_MATRIX_H #define POINCARE_MATRIX_H -#include +#include #include namespace Poincare { class Multiplication; -class Matrix : public DynamicHierarchy { -template friend class MatrixComplex; +class MatrixNode : public ExpressionNode { +public: + void setDimensions(int numberOfRows, int numberOfColumns) { + m_numberOfRows = numberOfRows; + m_numberOfColumns = m_numberOfColumns; + } + int numberOfRows() const { return m_numberOfRows; } + int numberOfColumns() const { return m_numberOfColumns; } + + // TreeNode + size_t size() const override { return sizeof(MatrixNode); } + const char * description() const override { return "Matrix"; } + int numberOfChildren() const { return m_numberOfRows*m_numberOfColumns; } + + // Properties + Type type() const override { return Type::Matrix; } + int polynomialDegree(char symbolName) const override; + + // Approximation + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + return templatedApproximate(); + } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + return templatedApproximate(); + } + + // Layout + LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode = Preferences::PrintFloatMode::Decimal, int numberOfSignificantDigits = 0) const override; +private: + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; +}; + +class MatrixReference : public ExpressionReference { +template friend class MatrixComplexNode; friend class GlobalContext; public: - Matrix(MatrixData * matrixData); // pilfer the operands of matrixData - Matrix(const Expression * const * operands, int numberOfRows, int numberOfColumns, bool cloneOperands = true); - Expression * matrixOperand(int i, int j) { return editableOperand(i*numberOfColumns()+j); } + MatrixNode * typedNode() const { assert(!isAllocationFailure()); return static_cast(node()); } int numberOfRows() const; int numberOfColumns() const; - - /* Expression */ - Type type() const override; - Expression * clone() const override; - int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - int polynomialDegree(char symbolName) const override; + ExpressionReference matrixChild(int i, int j) { assert(!isAllocationFailure()); return childAtIndex(i*numberOfColumns()+j); } /* Operation on matrix */ int rank(Context & context, Preferences::AngleUnit angleUnit, bool inPlace); // Inverse the array in-place. Array has to be given in the form array[row_index][column_index] template static int ArrayInverse(T * array, int numberOfRows, int numberOfColumns); #if MATRIX_EXACT_REDUCING - //template Expression * createTrace() const; - //template Expression * createDeterminant() const; - Matrix * createTranspose() const; - static Matrix * createIdentity(int dim); + ExpressionReference trace() const; + ExpressionReference determinant() const; + MatrixReference transpose() const; + static MatrixReference createIdentity(int dim); /* createInverse can be called on any matrix reduce or not, approximate or not. */ - Expression * createInverse(Context & context, Preferences::AngleUnit angleUnit) const; + ExpressionReference inverse(Context & context, Preferences::AngleUnit angleUnit) const; #endif private: /* rowCanonize turns a matrix in its reduced row echelon form. */ void rowCanonize(Context & context, Preferences::AngleUnit angleUnit, Multiplication * m = nullptr); // Row canonize the array in place template static void ArrayRowCanonize(T * array, int numberOfRows, int numberOfColumns, T * c = nullptr); - /* Layout */ - LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Evaluation * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; - int m_numberOfRows; }; } diff --git a/poincare/include/poincare/matrix_complex.h b/poincare/include/poincare/matrix_complex.h new file mode 100644 index 000000000..9b075432f --- /dev/null +++ b/poincare/include/poincare/matrix_complex.h @@ -0,0 +1,59 @@ +#ifndef POINCARE_MATRIX_COMPLEX_H +#define POINCARE_MATRIX_COMPLEX_H + +#include +#include + +namespace Poincare { + +template +class MatrixComplexReference; + +template +class MatrixComplexNode : public EvaluationNode { +public: + // TreeNode + size_t size() const override { return sizeof(MatrixComplexNode); } + const char * description() const override { return "Evaluation matrix complex"; } + int numberOfChildren() const override { return m_numberOfRows*m_numberOfColumns; } + + void setMatrixComplexDimension(int numberOfRows, int numberOfColumns); + typename Poincare::EvaluationNode::Type type() const override { return Poincare::EvaluationNode::Type::MatrixComplex; } + int numberOfComplexOperands() const { return m_numberOfRows*m_numberOfColumns; } + // WARNING: complexOperand may return a nullptr + ComplexNode * childAtIndex(int index) const override; + int numberOfRows() const { return m_numberOfRows; } + int numberOfColumns() const { return m_numberOfColumns; } + bool isUndefined() const override; + ExpressionReference complexToExpression(Preferences::Preferences::ComplexFormat complexFormat) const override; + std::complex trace() const override; + std::complex determinant() const override; + EvaluationReference inverse() const override; + EvaluationReference transpose() const override; +private: + // TODO: find another solution for inverse and determinant (avoid capping the matrix) + static constexpr int k_maxNumberOfCoefficients = 100; + int m_numberOfRows; + int m_numberOfColumns; +}; + +template +class MatrixComplexReference : public EvaluationReference { +public: + MatrixComplexReference(TreeNode * t) : EvaluationReference(t) {} + MatrixComplexReference(int numberOfRows, int numberOfColumns); + static MatrixComplexReference Undefined() { + std::complex undef = std::complex(NAN, NAN); + return MatrixComplexReference((std::complex *)&undef, 1, 1); + } + static MatrixComplexReference createIdentity(int dim); + int numberOfRows() const; + int numberOfColumns() const; +private: + MatrixComplexReference(std::complex * operands, int numberOfRows, int numberOfColumns); + MatrixComplexNode * node() const override{ return static_cast *>(TreeReference::node()); } +}; + +} + +#endif diff --git a/poincare/include/poincare/matrix_dimension.h b/poincare/include/poincare/matrix_dimension.h index 935698c00..c49401377 100644 --- a/poincare/include/poincare/matrix_dimension.h +++ b/poincare/include/poincare/matrix_dimension.h @@ -10,7 +10,6 @@ class MatrixDimension : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -21,11 +20,11 @@ private: } const char * name() const { return "dim"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Evaluation * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/matrix_inverse.h b/poincare/include/poincare/matrix_inverse.h index fbe59a69a..97d4060c1 100644 --- a/poincare/include/poincare/matrix_inverse.h +++ b/poincare/include/poincare/matrix_inverse.h @@ -10,7 +10,6 @@ class MatrixInverse : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Evaluation */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -21,11 +20,11 @@ private: } const char * name() const { return "inverse"; } /* Simplification */ - Expression * shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Evaluation * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/matrix_trace.h b/poincare/include/poincare/matrix_trace.h index 75917d79f..8682846dd 100644 --- a/poincare/include/poincare/matrix_trace.h +++ b/poincare/include/poincare/matrix_trace.h @@ -11,7 +11,6 @@ class MatrixTrace : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -22,11 +21,11 @@ private: } const char * name() const { return "trace"; } /* Simplification */ - Expression * shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Complex * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/matrix_transpose.h b/poincare/include/poincare/matrix_transpose.h index 52c84c81c..af6dbd1e9 100644 --- a/poincare/include/poincare/matrix_transpose.h +++ b/poincare/include/poincare/matrix_transpose.h @@ -10,7 +10,6 @@ class MatrixTranspose : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -21,11 +20,11 @@ private: } const char * name() const { return "transpose"; } /* Simplification */ - Expression * shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Evaluation * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/multiplication.h b/poincare/include/poincare/multiplication.h index fa0763220..fc24ce564 100644 --- a/poincare/include/poincare/multiplication.h +++ b/poincare/include/poincare/multiplication.h @@ -20,7 +20,6 @@ class Multiplication : public DynamicHierarchy { friend class Complex; public: Type type() const override; - Expression * clone() const override; Sign sign() const override; int polynomialDegree(char symbolName) const override; int privateGetPolynomialCoefficients(char symbolName, Expression * coefficients[]) const override; @@ -33,13 +32,13 @@ public: template static MatrixComplex computeOnMatrices(const MatrixComplex m, const MatrixComplex n); private: /* Property */ - Expression * setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit) override; + ExpressionReference setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit) override; /* Layout */ - bool needParenthesisWithParent(const Expression * e) const override; + bool needsParenthesisWithParent(SerializableNode * parentNode) const override; LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; Expression * privateShallowReduce(Context& context, Preferences::AngleUnit angleUnit, bool expand, bool canBeInterrupted); void mergeMultiplicationOperands(); void factorizeBase(Expression * e1, Expression * e2, Context & context, Preferences::AngleUnit angleUnit); @@ -62,10 +61,10 @@ private: template static MatrixComplex computeOnMatrixAndComplex(const MatrixComplex m, const std::complex c) { return ApproximationEngine::elementWiseOnMatrixComplexAndComplex(m, c, compute); } - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } }; diff --git a/poincare/include/poincare/n_ary_expression_node.h b/poincare/include/poincare/n_ary_expression_node.h new file mode 100644 index 000000000..f1d5750e1 --- /dev/null +++ b/poincare/include/poincare/n_ary_expression_node.h @@ -0,0 +1,28 @@ +#ifndef POINCARE_NARY_EXPRESSION_NODE_H +#define POINCARE_NARY_EXPRESSION_NODE_H + +#include + +namespace Poincare { + +class NAryExpressionNode : public ExpressionNode { // TODO: VariableArityExpressionNode? +public: + int numberOfChildren() const override { return m_numberOfChildren; } + + // Comparison + typedef int (*ExpressionOrder)(const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted); + + // Commutative properties + void sortOperands(ExpressionOrder order, bool canBeInterrupted); + ExpressionReference squashUnaryHierarchy(); + +protected: + int m_numberOfChildren; +private: + int simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const override; + int simplificationOrderGreaterType(const ExpressionNode * e, bool canBeInterrupted) const override; +}; + +} + +#endif diff --git a/poincare/include/poincare/naperian_logarithm.h b/poincare/include/poincare/naperian_logarithm.h index 5d6642bc6..72adbca93 100644 --- a/poincare/include/poincare/naperian_logarithm.h +++ b/poincare/include/poincare/naperian_logarithm.h @@ -11,7 +11,6 @@ class NaperianLogarithm : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -22,13 +21,13 @@ private: } const char * name() const { return "ln"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/nth_root.h b/poincare/include/poincare/nth_root.h index 551fdddc0..caba54a7a 100644 --- a/poincare/include/poincare/nth_root.h +++ b/poincare/include/poincare/nth_root.h @@ -10,7 +10,6 @@ class NthRoot : public StaticHierarchy<2> { using StaticHierarchy<2>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; @@ -18,11 +17,11 @@ private: return LayoutEngine::writePrefixExpressionTextInBuffer(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, "root"); } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Evaluation * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; }; diff --git a/poincare/include/poincare/number.h b/poincare/include/poincare/number.h new file mode 100644 index 000000000..c7dd5d01e --- /dev/null +++ b/poincare/include/poincare/number.h @@ -0,0 +1,50 @@ +#ifndef POINCARE_NUMBER_H +#define POINCARE_NUMBER_H + +#include + +namespace Poincare { + +/* Number class has 3 subclasses: + * - Undefined + * - Integer + * - Rational + * - Float + * - Decimal + * - Infinite + */ + +class IntegerReference; +class RationalReference; + +class NumberNode : public ExpressionNode { +public: + bool isNumber() const override { return true; } + int numberOfChildren() const override { return 0; } + + double doubleApproximation() const; +}; + +class NumberReference : public ExpressionReference { +public: + using ExpressionReference::ExpressionReference; + NumberNode * numberNode() const { assert(!isAllocationFailure()); return static_cast(node()); } + /* Return either a IntegerReference, a DecimalReference or an InfiniteReference. */ + static NumberReference Integer(const char * digits, size_t length, bool negative); + /* This set of Functions return either a RationalReference or a FloatReference + * or InfiniteReference in case of overflow. DecimalReference are not taken into + * account as it is not an internal node - it will always be truned into a + * Rational/Float beforehand. */ + static NumberReference Addition(const NumberReference i, const NumberReference j); + static NumberReference Multiplication(const NumberReference i, const NumberReference j); + static NumberReference Power(const NumberReference i, const NumberReference j); +private: + typedef IntegerReference (*IntegerBinaryOperation)(const IntegerReference, const IntegerReference); + typedef RationalReference (*RationalBinaryOperation)(const RationalReference, const RationalReference); + typedef double (*DoubleBinaryOperation)(double, double); + static NumberReference BinaryOperation(const NumberReference i, const NumberReference j, IntegerBinaryOperation integerOp, RationalBinaryOperation rationalOp, DoubleBinaryOperation doubleOp); +}; + +} + +#endif diff --git a/poincare/include/poincare/opposite.h b/poincare/include/poincare/opposite.h index 992f48b28..993371e3d 100644 --- a/poincare/include/poincare/opposite.h +++ b/poincare/include/poincare/opposite.h @@ -1,34 +1,49 @@ #ifndef POINCARE_OPPOSITE_H #define POINCARE_OPPOSITE_H -#include -#include +#include #include namespace Poincare { -class Opposite : public StaticHierarchy<1> { - using StaticHierarchy<1>::StaticHierarchy; +class OppositeNode : public ExpressionNode { public: - Expression * clone() const override; - Type type() const override; + // TreeNode + size_t size() const override { return sizeof(OppositeNode); } + const char * description() const override { return "Opposite"; } + int numberOfChildren() const override { return 0; } + + // Properties + Type type() const override { return Type::Opposite; } int polynomialDegree(char symbolName) const override; Sign sign() const override; - template static std::complex compute(const std::complex c, Preferences::AngleUnit angleUnit); -private: - /* Layout */ - bool needParenthesisWithParent(const Expression * e) const override; - LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; - /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + + // Approximation + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, compute); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, compute); } + + // Layout + bool needsParenthesisWithParent(SerializableNode * parentNode) const override; + LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode = Preferences::PrintFloatMode::Decimal, int numberOfSignificantDigits = 0) const override; + + // Simplification + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + +private: + template static ComplexReference compute(const std::complex c, Preferences::AngleUnit angleUnit) { return ComplexReference(-c); } +}; + +class OppositeReference : public ExpressionReference { +public: + OppositeReference(ExpressionReference operand) { + TreeNode * node = TreePool::sharedPool()->createTreeNode(); + m_identifier = node->identifier(); + } }; } diff --git a/poincare/include/poincare/parenthesis.h b/poincare/include/poincare/parenthesis.h index 49f3ad9a4..fecf06fee 100644 --- a/poincare/include/poincare/parenthesis.h +++ b/poincare/include/poincare/parenthesis.h @@ -1,31 +1,44 @@ #ifndef POINCARE_PARENTHESIS_H #define POINCARE_PARENTHESIS_H -#include +#include #include namespace Poincare { -class Parenthesis : public StaticHierarchy<1> { +class ParenthesisNode : public ExpressionNode { public: - using StaticHierarchy<1>::StaticHierarchy; -public: - Expression * clone() const override; - Type type() const override; + // TreeNode + size_t size() const override { return sizeof(ParenthesisNode); } + const char * description() const override { return "Parenthesis"; } + int numberOfChildren() const override { return 1; } + + // Properties + Type type() const override { return Type::Parenthesis; } int polynomialDegree(char symbolName) const override; -private: - /* Layout */ + + // Layout LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { - return LayoutEngine::writePrefixExpressionTextInBuffer(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, ""); + return LayoutEngine::writePrefixSerializableRefTextInBuffer(ExpressionReference(this), buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, ""); } - /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; - /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Evaluation * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + // Simplification + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + // Approximation + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } +private: + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; +}; + +class ParenthesisReference : public ExpressionReference { +public: + ParenthesisReference(ExpressionReference exp) { + TreeNode * node = TreePool::sharedPool()->createTreeNode(); + m_identifier = node->identifier(); + addChildTreeAtIndex(exp, 0, 0); + } }; } diff --git a/poincare/include/poincare/permute_coefficient.h b/poincare/include/poincare/permute_coefficient.h index 07356073f..8b762bcdd 100644 --- a/poincare/include/poincare/permute_coefficient.h +++ b/poincare/include/poincare/permute_coefficient.h @@ -11,7 +11,6 @@ class PermuteCoefficient : public StaticHierarchy<2> { using StaticHierarchy<2>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: constexpr static int k_maxNValue = 100; /* Layout */ @@ -23,11 +22,11 @@ private: } const char * name() const { return "permute"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Complex * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/power.h b/poincare/include/poincare/power.h index 48403b194..c0f6477cd 100644 --- a/poincare/include/poincare/power.h +++ b/poincare/include/poincare/power.h @@ -20,7 +20,6 @@ class Power : public StaticHierarchy<2> { friend class Symbol; public: Type type() const override; - Expression * clone() const override; Sign sign() const override; int polynomialDegree(char symbolName) const override; int privateGetPolynomialCoefficients(char symbolName, Expression * coefficients[]) const override; @@ -29,19 +28,19 @@ private: constexpr static int k_maxNumberOfTermsInExpandedMultinome = 25; constexpr static int k_maxExactPowerMatrix = 100; /* Property */ - Expression * setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit) override; + ExpressionReference setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit) override; /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - bool needParenthesisWithParent(const Expression * e) const override; + bool needsParenthesisWithParent(SerializableNode * parentNode) const override; int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { return LayoutEngine::writeInfixExpressionTextInBuffer(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, name()); } static const char * name() { return "^"; } /* Simplify */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; Expression * shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) override; int simplificationOrderGreaterType(const Expression * e, bool canBeInterrupted) const override; - int simplificationOrderSameType(const Expression * e, bool canBeInterrupted) const override; + int simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const override; Expression * simplifyPowerPower(Power * p, Expression * r, Context & context, Preferences::AngleUnit angleUnit); Expression * cloneDenominator(Context & context, Preferences::AngleUnit angleUnit) const override; Expression * simplifyPowerMultiplication(Multiplication * m, Expression * r, Context & context, Preferences::AngleUnit angleUnit); @@ -60,10 +59,10 @@ private: template static MatrixComplex computeOnComplexAndMatrix(const std::complex c, const MatrixComplex n); template static MatrixComplex computeOnMatrixAndComplex(const MatrixComplex m, const std::complex d); template static MatrixComplex computeOnMatrices(const MatrixComplex m, const MatrixComplex n); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } }; diff --git a/poincare/include/poincare/prediction_interval.h b/poincare/include/poincare/prediction_interval.h index 9436fd59b..a267bea16 100644 --- a/poincare/include/poincare/prediction_interval.h +++ b/poincare/include/poincare/prediction_interval.h @@ -10,7 +10,6 @@ class PredictionInterval : public StaticHierarchy<2> { using StaticHierarchy<2>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; int polynomialDegree(char symbolName) const override; private: /* Layout */ @@ -22,11 +21,11 @@ private: } const char * name() const { return "prediction95"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(Expression::SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(Expression::SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } Evaluation * privateApproximate(Expression::DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Evaluation * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/product.h b/poincare/include/poincare/product.h index 40df4e924..1845eecf0 100644 --- a/poincare/include/poincare/product.h +++ b/poincare/include/poincare/product.h @@ -9,18 +9,17 @@ class Product : public Sequence { using Sequence::Sequence; public: Type type() const override; - Expression * clone() const override; private: const char * name() const override; int emptySequenceValue() const override; LayoutRef createSequenceLayout(LayoutRef argumentLayout, LayoutRef subscriptLayout, LayoutRef superscriptLayout) const override; - Evaluation * evaluateWithNextTerm(DoublePrecision p, Evaluation * a, Evaluation * b) const override { + EvaluationReference evaluateWithNextTerm(DoublePrecision p, Evaluation * a, Evaluation * b) const override { return templatedApproximateWithNextTerm(a, b); } - Evaluation * evaluateWithNextTerm(SinglePrecision p, Evaluation * a, Evaluation * b) const override { + EvaluationReference evaluateWithNextTerm(SinglePrecision p, Evaluation * a, Evaluation * b) const override { return templatedApproximateWithNextTerm(a, b); } - template Evaluation * templatedApproximateWithNextTerm(Evaluation * a, Evaluation * b) const; + template EvaluationReference templatedApproximateWithNextTerm(Evaluation * a, Evaluation * b) const; }; } diff --git a/poincare/include/poincare/randint.h b/poincare/include/poincare/randint.h index 61a8ea7da..3d9e33a16 100644 --- a/poincare/include/poincare/randint.h +++ b/poincare/include/poincare/randint.h @@ -10,7 +10,6 @@ class Randint : public StaticHierarchy<2> { using StaticHierarchy<2>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -21,13 +20,13 @@ private: } const char * name() const { return "randint"; } /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templateApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templateApproximate(context, angleUnit); } - template Evaluation * templateApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + template EvaluationReference templateApproximate()Context& context, Preferences::AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/random.h b/poincare/include/poincare/random.h index 426ee201c..0b8a05b0a 100644 --- a/poincare/include/poincare/random.h +++ b/poincare/include/poincare/random.h @@ -11,11 +11,10 @@ class Random : public StaticHierarchy<0> { using StaticHierarchy<0>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; Sign sign() const override { return Sign::Positive; } template static T random(); private: - Expression * setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit) override; + ExpressionReference setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit) override; /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { return LayoutEngine::createPrefixLayout(this, floatDisplayMode, numberOfSignificantDigits, name()); @@ -25,13 +24,13 @@ private: } const char * name() const { return "random"; } /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templateApproximate(); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templateApproximate(); } - template Evaluation * templateApproximate() const { + template EvaluationReference templateApproximate()) const { return new Complex(random()); } }; diff --git a/poincare/include/poincare/rational.h b/poincare/include/poincare/rational.h index 0d1acda70..47bfd93a9 100644 --- a/poincare/include/poincare/rational.h +++ b/poincare/include/poincare/rational.h @@ -2,63 +2,90 @@ #define POINCARE_RATIONAL_H #include -#include -#include namespace Poincare { -class Rational : public StaticHierarchy<0> { - friend class Power; - friend class Multiplication; +class RationalNode : public NumberNode { public: - /* The constructor build a irreductible fraction whose sign is on numerator */ - Rational(const Integer numerator, const Integer denominator); - Rational(const Integer numerator); - Rational(Integer::native_int_t i) : Rational(Integer(i)) {} - Rational(Integer::native_int_t i, Integer::native_int_t j) : Rational(Integer(i), Integer(j)) {} + void setDigits(native_uint_t * i, size_t numeratorSize, native_uint_t * j, size_t denominatorSize, bool negative); + + NaturalIntegerPointer numerator() const; + NaturalIntegerPointer denominator() const; + + // TreeNode + size_t size() const override; + const char * description() const override { return "Rational"; } + + // Serialization Node + bool needsParenthesisWithParent(SerializableNode * e) const override; + int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - Rational(const Rational & other); - Rational & operator=(const Rational & other); - // Getter - const Integer numerator() const; - const Integer denominator() const; // Expression subclassing - Type type() const override; - Expression * clone() const override; + Type type() const override { return Type::Rational; } Sign sign() const override; - Expression * cloneDenominator(Context & context, Preferences::AngleUnit angleUnit) const override; + void setSign(Sign s); + + // Layout + LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + + // Approximation + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ComplexReference(templatedApproximate()); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ComplexReference(templatedApproximate()); } + template T templatedApproximate() const; // Basic test - bool isZero() const { return m_numerator.isZero(); } - bool isOne() const { return m_numerator.isOne() && m_denominator.isOne(); } - bool isMinusOne() const { return m_numerator.isMinusOne() && m_denominator.isOne(); } - bool isHalf() const { return m_numerator.isOne() && m_denominator.isTwo(); } - bool isMinusHalf() const { return m_numerator.isMinusOne() && m_denominator.isTwo(); } - bool isTen() const { return m_numerator.isTen() && m_denominator.isOne(); } + bool isZero() const { return numerator().isZero(); } + bool isOne() const { return numerator().isOne() && denominator().isOne() && !m_negative; } + bool isMinusOne() const { return numerator().isOne() && denominator().isOne() && m_negative; } + bool isHalf() const { return numerator().isOne() && denominator().isTwo() && !m_negative; } + bool isMinusHalf() const { return numerator().isOne() && denominator().isTwo() && m_negative; } + bool isTen() const { return numerator().isTen() && denominator().isOne() && !m_negative; } + + static int NaturalOrder(const RationalNode i, const RationalNode j); +private: + int simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const override; + ExpressionReference shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) override; + ExpressionReference setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit) override { + setSign(s); + return ExpressionReference(this); + } + ExpressionReference cloneDenominator(Context & context, Preferences::AngleUnit angleUnit) const override; + bool m_negative; + size_t m_numberOfDigitsNumerator; + size_t m_numberOfDigitsDenominator; + native_uint_t m_digits[0]; +}; + +class RationalReference : public NumberReference { +public: + /* The constructor build a irreductible fraction */ + RationalReference(IntegerReference numerator, IntegerReference denominator); + RationalReference(const IntegerReference numerator); + RationalReference(const NaturalIntegerAbstract * numerator, bool negative); + RationalReference(native_int_t i); + RationalReference(native_int_t i, native_int_t j); + + // TreeNode + RationalNode * typedNode() const { assert(node()->type() == ExpressionNode::Type::Rational); return static_cast(node()); } + + // Properties + bool isOne() const; + bool numeratorOrDenominatorIsInfinity() const; // Arithmetic - static Rational Addition(const Rational & i, const Rational & j); - static Rational Multiplication(const Rational & i, const Rational & j); - static Rational Power(const Rational & i, const Integer & j); - static int NaturalOrder(const Rational & i, const Rational & j); + /* Warning: when using this function, always assert that the result does not + * involve infinity numerator or denominator or handle these cases. */ + static RationalReference Addition(const RationalReference i, const RationalReference j); + static RationalReference Multiplication(const RationalReference i, const RationalReference j); + // IntegerPower of (p1/q1)^(p2/q2) --> (p1^p2)/(q1^p2) + static RationalReference IntegerPower(const RationalReference i, const RationalReference j); + static int NaturalOrder(const RationalReference i, const RationalReference j); + private: - bool needParenthesisWithParent(const Expression * e) const override; - LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Complex * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; - Expression * shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) override; - Expression * setSign(Sign s); - Expression * setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit) override { - return setSign(s); + RationalReference(size_t size) : NumberReference() { + TreeNode * node = TreePool::sharedPool()->createTreeNode(size); + m_identifier = node->identifier(); } - - /* Sorting */ - int simplificationOrderSameType(const Expression * e, bool canBeInterrupted) const override; - - Integer m_numerator; - Integer m_denominator; }; } diff --git a/poincare/include/poincare/real_part.h b/poincare/include/poincare/real_part.h index 816410eed..187df1fb5 100644 --- a/poincare/include/poincare/real_part.h +++ b/poincare/include/poincare/real_part.h @@ -11,7 +11,6 @@ class RealPart : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -22,13 +21,13 @@ private: } const char * name() const { return "re"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/round.h b/poincare/include/poincare/round.h index 10e590028..fa7a16e19 100644 --- a/poincare/include/poincare/round.h +++ b/poincare/include/poincare/round.h @@ -11,7 +11,6 @@ class Round : public StaticHierarchy<2> { using StaticHierarchy<2>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { @@ -22,11 +21,11 @@ private: } const char * name() const { return "round"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Complex */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Complex * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/sequence.h b/poincare/include/poincare/sequence.h index d56f0fdb4..72d9f813d 100644 --- a/poincare/include/poincare/sequence.h +++ b/poincare/include/poincare/sequence.h @@ -17,12 +17,12 @@ private: virtual LayoutRef createSequenceLayout(LayoutRef subscriptLayout, LayoutRef superscriptLayout, LayoutRef argumentLayout) const = 0; virtual const char * name() const = 0; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Evaluation * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference 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 EvaluationReference evaluateWithNextTerm(SinglePrecision p, Evaluation * a, Evaluation * b) const = 0; + virtual EvaluationReference evaluateWithNextTerm(DoublePrecision p, Evaluation * a, Evaluation * b) const = 0; }; } diff --git a/poincare/include/poincare/serializable_node.h b/poincare/include/poincare/serializable_node.h index 1949bf89c..71d8ad105 100644 --- a/poincare/include/poincare/serializable_node.h +++ b/poincare/include/poincare/serializable_node.h @@ -9,7 +9,7 @@ namespace Poincare { class SerializableNode : public TreeNode { public: using TreeNode::TreeNode; - virtual bool needsParenthesisWithParent(SerializableNode * parentNode) { return false; } //TODO + virtual bool needsParenthesisWithParent(SerializableNode * parentNode) const { return false; } //TODO virtual int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode = Preferences::PrintFloatMode::Decimal, int numberOfSignificantDigits = 0) const = 0; }; diff --git a/poincare/include/poincare/simplification_root.h b/poincare/include/poincare/simplification_root.h index be3afa7fb..e8111cefb 100644 --- a/poincare/include/poincare/simplification_root.h +++ b/poincare/include/poincare/simplification_root.h @@ -17,23 +17,22 @@ public: /* We don't want to clone the expression provided at construction. * So we don't want it to be deleted when we're destroyed (parent destructor). */ } - Expression * clone() const override { return nullptr; } int polynomialDegree(char symbolName) const override { return -1; } Type type() const override { return Expression::Type::SimplificationRoot; } LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { return nullptr; } int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { return 0; } - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { assert(false); return nullptr; } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { assert(false); return nullptr; } private: - Expression * shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override { return this; } + ExpressionReference shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override { return this; } }; } diff --git a/poincare/include/poincare/sine.h b/poincare/include/poincare/sine.h index bc15c8760..ad2d13738 100644 --- a/poincare/include/poincare/sine.h +++ b/poincare/include/poincare/sine.h @@ -14,7 +14,6 @@ class Sine : public StaticHierarchy<1> { float characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const override; public: Type type() const override; - Expression * clone() const override; template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit = Preferences::AngleUnit::Radian); private: /* Layout */ @@ -26,12 +25,12 @@ private: } const char * name() const { return "sin"; } /* Simplication */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/square_root.h b/poincare/include/poincare/square_root.h index 5f378738d..692630a37 100644 --- a/poincare/include/poincare/square_root.h +++ b/poincare/include/poincare/square_root.h @@ -11,19 +11,18 @@ class SquareRoot : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; private: /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } diff --git a/poincare/include/poincare/static_hierarchy.h b/poincare/include/poincare/static_hierarchy.h index 68f0b1c91..bf7a990e6 100644 --- a/poincare/include/poincare/static_hierarchy.h +++ b/poincare/include/poincare/static_hierarchy.h @@ -25,7 +25,7 @@ public: virtual bool hasValidNumberOfOperands(int numberOfOperands) const; protected: void build(const Expression * const * operands, int numberOfOperands, bool cloneOperands); - int simplificationOrderSameType(const Expression * e, bool canBeInterrupted) const override; + int simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const override; const Expression * m_operands[T]; }; diff --git a/poincare/include/poincare/store.h b/poincare/include/poincare/store.h index b09c666f7..3700962e3 100644 --- a/poincare/include/poincare/store.h +++ b/poincare/include/poincare/store.h @@ -13,18 +13,17 @@ class Store : public StaticHierarchy<2> { public: using StaticHierarchy<2>::StaticHierarchy; Type type() const override; - Expression * clone() const override; int polynomialDegree(char symbolName) const override; private: /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Layout */ LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; /* Evalutation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Evaluation * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; const Symbol * symbol() const { return static_cast(operand(1)); } const Expression * value() const { return operand(0); } diff --git a/poincare/include/poincare/subtraction.h b/poincare/include/poincare/subtraction.h index bd495792e..1d0671679 100644 --- a/poincare/include/poincare/subtraction.h +++ b/poincare/include/poincare/subtraction.h @@ -11,12 +11,11 @@ class Subtraction : public StaticHierarchy<2> { using StaticHierarchy<2>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; template static std::complex compute(const std::complex c, const std::complex d); int polynomialDegree(char symbolName) const override; private: /* Layout */ - bool needParenthesisWithParent(const Expression * e) const override; + bool needsParenthesisWithParent(SerializableNode * parentNode) const override; LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { return LayoutEngine::createInfixLayout(this, floatDisplayMode, numberOfSignificantDigits, name()); } @@ -25,7 +24,7 @@ private: } static const char * name() { return "-"; } /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static MatrixComplex computeOnMatrixAndComplex(const MatrixComplex m, const std::complex c) { return ApproximationEngine::elementWiseOnMatrixComplexAndComplex(m, c, compute); @@ -35,10 +34,10 @@ private: return ApproximationEngine::elementWiseOnComplexMatrices(m, n, compute); } - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } }; diff --git a/poincare/include/poincare/sum.h b/poincare/include/poincare/sum.h index c911214c6..9a033b043 100644 --- a/poincare/include/poincare/sum.h +++ b/poincare/include/poincare/sum.h @@ -9,18 +9,17 @@ class Sum : public Sequence { using Sequence::Sequence; public: Type type() const override; - Expression * clone() const override; private: const char * name() const override; int emptySequenceValue() const override; LayoutRef createSequenceLayout(LayoutRef argumentLayout, LayoutRef subscriptLayout, LayoutRef superscriptLayout) const override; - Evaluation * evaluateWithNextTerm(DoublePrecision p, Evaluation * a, Evaluation * b) const override { + EvaluationReference evaluateWithNextTerm(DoublePrecision p, Evaluation * a, Evaluation * b) const override { return templatedApproximateWithNextTerm(a, b); } - Evaluation * evaluateWithNextTerm(SinglePrecision p, Evaluation * a, Evaluation * b) const override { + EvaluationReference evaluateWithNextTerm(SinglePrecision p, Evaluation * a, Evaluation * b) const override { return templatedApproximateWithNextTerm(a, b); } - template Evaluation * templatedApproximateWithNextTerm(Evaluation * a, Evaluation * b) const; + template EvaluationReference templatedApproximateWithNextTerm(Evaluation * a, Evaluation * b) const; }; } diff --git a/poincare/include/poincare/symbol.h b/poincare/include/poincare/symbol.h index 61148a04a..750204243 100644 --- a/poincare/include/poincare/symbol.h +++ b/poincare/include/poincare/symbol.h @@ -1,12 +1,52 @@ #ifndef POINCARE_SYMBOL_H #define POINCARE_SYMBOL_H -#include +#include namespace Poincare { -class Symbol : public StaticHierarchy<0> { +class SymbolNode : public ExpressionNode { friend class Store; +public: + void setName(const char name) { m_name = name; } + char name() const { return m_name; } + + // TreeNode + size_t size() const override { return sizeof(SymbolNode); } + const char * description() const override { return "Symbol"; } + int numberOfChildren() const override { return 0; } + + // Expression Properties + Type type() const override { return Type::Symbol; } + Sign sign() const override; + ExpressionReference replaceSymbolWithExpression(char symbol, ExpressionReference expression) override; + int polynomialDegree(char symbolName) const override; + int getPolynomialCoefficients(char symbolName, ExpressionReference coefficients[]) const override; + int getVariables(isVariableTest isVariable, char * variables) const override; + float characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const override; + + /* Comparison */ + int simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const override; + +/* Layout */ + LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + + /* Simplification */ + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + + /* Approximation */ + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + +private: + bool hasAnExactRepresentation(Context & context) const; + template EvaluationReference templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + + char m_name; +}; + +class SymbolReference : public ExpressionReference { public: enum SpecialSymbols : char { /* We can use characters from 1 to 31 as they do not correspond to usual @@ -41,40 +81,22 @@ public: X3, Y3 = 29 }; + SymbolReference(const char name) { + TreeNode * node = TreePool::sharedPool()->createTreeNode(); + m_identifier = node->identifier(); + if (!node->isAllocationFailure()) { + static_cast(node)->setName(name); + } + } + // Symbol properties + static const char * textForSpecialSymbols(char name); static SpecialSymbols matrixSymbol(char index); - Symbol(char name); - Symbol(Symbol&& other); // C++11 move constructor - Symbol(const Symbol& other); // C++11 copy constructor - char name() const; - Type type() const override; - Expression * clone() const override; - int polynomialDegree(char symbolName) const override; - int privateGetPolynomialCoefficients(char symbolName, Expression * coefficients[]) const override; - Sign sign() const override; - bool isMatrixSymbol() const; - bool isScalarSymbol() const; + static bool isMatrixSymbol(char c); + static bool isScalarSymbol(char c); static bool isVariableSymbol(char c); static bool isSeriesSymbol(char c); static bool isRegressionSymbol(char c); - bool isApproximate(Context & context) const; - float characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const override; - bool hasAnExactRepresentation(Context & context) const; - static const char * textForSpecialSymbols(char name); - int getVariables(isVariableTest isVariable, char * variables) const override; -private: - Expression * replaceSymbolWithExpression(char symbol, Expression * expression) override; - /* Simplification */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; - /* Comparison */ - int simplificationOrderSameType(const Expression * e, bool canBeInterrupted) const override; - /* Layout */ - LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Evaluation * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; - const char m_name; + static bool isApproximate(char c, Context & context); }; } diff --git a/poincare/include/poincare/tangent.h b/poincare/include/poincare/tangent.h index 4e666cb2f..198de45ae 100644 --- a/poincare/include/poincare/tangent.h +++ b/poincare/include/poincare/tangent.h @@ -12,7 +12,6 @@ class Tangent : public StaticHierarchy<1> { using StaticHierarchy<1>::StaticHierarchy; public: Type type() const override; - Expression * clone() const override; float characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const override; private: /* Layout */ @@ -24,13 +23,13 @@ private: } const char * name() const { return "tan"; } /* Simplication */ - Expression * shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + ExpressionReference shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; /* Evaluation */ template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit = Preferences::AngleUnit::Radian); - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/tree_reference.h b/poincare/include/poincare/tree_reference.h index 95ec9e834..7900c607d 100644 --- a/poincare/include/poincare/tree_reference.h +++ b/poincare/include/poincare/tree_reference.h @@ -104,6 +104,8 @@ public: } } + void swapChildren(int i, int j); + protected: TreeReference() : m_identifier(-1) {} void setIdentifierAndRetain(int newId) { diff --git a/poincare/include/poincare/undefined.h b/poincare/include/poincare/undefined.h index 21ee58438..9c6808fc1 100644 --- a/poincare/include/poincare/undefined.h +++ b/poincare/include/poincare/undefined.h @@ -1,24 +1,41 @@ #ifndef POINCARE_UNDEFINED_H #define POINCARE_UNDEFINED_H -#include -#include +#include namespace Poincare { -class Undefined : public StaticHierarchy<0> { +class UndefinedNode : public NumberNode { public: - Type type() const override; - Expression * clone() const override; - int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + // TreeNode + size_t size() const override { return sizeof(UndefinedNode); } + const char * description() const override { return "Undefined"; } + + // Properties + Type type() const override { return Type::Undefined; } int polynomialDegree(char symbolName) const override; -private: - /* Layout */ + + // Approximation + EvaluationReference approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + return templatedApproximate(); + } + EvaluationReference approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { + return templatedApproximate(); + } + + // Layout LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - /* Evaluation */ - Evaluation * privateApproximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - Evaluation * privateApproximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } - template Complex * templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; + int writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode = Preferences::PrintFloatMode::Decimal, int numberOfSignificantDigits = 0) const override; +private: + template EvaluationReference templatedApproximate() const; +}; + +class UndefinedReference : public NumberReference { +public: + UndefinedReference() { + TreeNode * node = TreePool::sharedPool()->createTreeNode(); + m_identifier = node->identifier(); + } }; } diff --git a/poincare/src/absolute_value.cpp b/poincare/src/absolute_value.cpp index 25f252b43..e5e69116c 100644 --- a/poincare/src/absolute_value.cpp +++ b/poincare/src/absolute_value.cpp @@ -27,7 +27,7 @@ LayoutRef AbsoluteValue::createLayout(Preferences::PrintFloatMode floatDisplayMo return AbsoluteValueLayoutRef(operand(0)->createLayout(floatDisplayMode, numberOfSignificantDigits)); } -Expression * AbsoluteValue::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference AbsoluteValue::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/addition.cpp b/poincare/src/addition.cpp index 048d850c4..6a7fc34fa 100644 --- a/poincare/src/addition.cpp +++ b/poincare/src/addition.cpp @@ -35,7 +35,7 @@ int Addition::polynomialDegree(char symbolName) const { return degree; } -int Addition::privateGetPolynomialCoefficients(char symbolName, Expression * coefficients[]) const { +int Addition::getPolynomialCoefficients(char symbolName, ExpressionReference coefficients[]) const { int deg = polynomialDegree(symbolName); if (deg < 0 || deg > k_maxPolynomialDegree) { return -1; @@ -63,7 +63,7 @@ bool Addition::needParenthesisWithParent(const Expression * e) const { /* Simplication */ -Expression * Addition::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Addition::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/allocation_failed_evaluation.cpp b/poincare/src/allocation_failed_evaluation.cpp new file mode 100644 index 000000000..1d3e40c01 --- /dev/null +++ b/poincare/src/allocation_failed_evaluation.cpp @@ -0,0 +1,12 @@ +#include +#include +#include + +namespace Poincare { + +template +ExpressionReference AllocationFailedEvaluationNode::complexToExpression(Preferences::Preferences::ComplexFormat complexFormat) const { + return UndefinedReference(); +} + +} diff --git a/poincare/src/approximation_engine.cpp b/poincare/src/approximation_engine.cpp index dc7a9395e..e4ce564d1 100644 --- a/poincare/src/approximation_engine.cpp +++ b/poincare/src/approximation_engine.cpp @@ -25,101 +25,113 @@ template std::complex ApproximationEngine::truncateRealOrImagina return c; } -template Evaluation * ApproximationEngine::map(const Expression * expression, Context& context, Preferences::AngleUnit angleUnit, ComplexCompute compute) { - assert(expression->numberOfOperands() == 1); - Evaluation * input = expression->operand(0)->privateApproximate(T(), context, angleUnit); - Evaluation * result = nullptr; - if (input->type() == Evaluation::Type::Complex) { - Complex * c = static_cast *>(input); - result = new Complex(compute(*c, angleUnit)); +template EvaluationReference ApproximationEngine::map(const ExpressionNode * expression, Context& context, Preferences::AngleUnit angleUnit, ComplexCompute compute) { + assert(expression->numberOfChildren() == 1); + EvaluationReference input = expression->childAtIndex(0)->approximate(T(), context, angleUnit); + if (input.node()->type() == EvaluationNode::Type::AllocationFailure) { + return EvaluationReference(EvaluationNode::FailedAllocationStaticNode()); + } else if (input.node()->type() == EvaluationNode::Type::Complex) { + const ComplexNode * c = static_cast *>(input.node()); + return compute(*c, angleUnit); } else { - assert(input->type() == Evaluation::Type::MatrixComplex); - MatrixComplex * m = static_cast *>(input); - std::complex * operands = new std::complex [m->numberOfComplexOperands()]; - for (int i = 0; i < m->numberOfComplexOperands(); i++) { - const std::complex c = m->complexOperand(i); - operands[i] = compute(c, angleUnit); + assert(input.node()->type() == EvaluationNode::Type::MatrixComplex); + MatrixComplexReference m = MatrixComplexReference(input.node()); + MatrixComplexReference result(m.numberOfRows(), m.numberOfColumns()); + for (int i = 0; i < result.numberOfRows()*result.numberOfColumns(); i++) { + ComplexNode * child = static_cast *>(m.node())->childAtIndex(i); + if (child) { + result.addChildTreeAtIndex(compute(*child, angleUnit), i, i); + } else { + result.addChildTreeAtIndex(ComplexReference::Undefined(), i, i); + } } - result = new MatrixComplex(operands, m->numberOfRows(), m->numberOfColumns()); - delete[] operands; + return result; } - delete input; - return result; } -template Evaluation * ApproximationEngine::mapReduce(const Expression * expression, Context& context, Preferences::AngleUnit angleUnit, ComplexAndComplexReduction computeOnComplexes, ComplexAndMatrixReduction computeOnComplexAndMatrix, MatrixAndComplexReduction computeOnMatrixAndComplex, MatrixAndMatrixReduction computeOnMatrices) { - Evaluation * result = expression->operand(0)->privateApproximate(T(), context, angleUnit); - for (int i = 1; i < expression->numberOfOperands(); i++) { - Evaluation * intermediateResult = nullptr; - Evaluation * nextOperandEvaluation = expression->operand(i)->privateApproximate(T(), context, angleUnit); - if (result->type() == Evaluation::Type::Complex && nextOperandEvaluation->type() == Evaluation::Type::Complex) { - const Complex * c = static_cast *>(result); - const Complex * d = static_cast *>(nextOperandEvaluation); - intermediateResult = new Complex(computeOnComplexes(*c, *d)); - } else if (result->type() == Evaluation::Type::Complex) { - const Complex * c = static_cast *>(result); - assert(nextOperandEvaluation->type() == Evaluation::Type::MatrixComplex); - const MatrixComplex * n = static_cast *>(nextOperandEvaluation); - intermediateResult = new MatrixComplex(computeOnComplexAndMatrix(*c, *n)); - } else if (nextOperandEvaluation->type() == Evaluation::Type::Complex) { - assert(result->type() == Evaluation::Type::MatrixComplex); - const MatrixComplex * m = static_cast *>(result); - const Complex * d = static_cast *>(nextOperandEvaluation); - intermediateResult = new MatrixComplex(computeOnMatrixAndComplex(*m, *d)); +template EvaluationReference ApproximationEngine::mapReduce(const ExpressionNode * expression, Context& context, Preferences::AngleUnit angleUnit, ComplexAndComplexReduction computeOnComplexes, ComplexAndMatrixReduction computeOnComplexAndMatrix, MatrixAndComplexReduction computeOnMatrixAndComplex, MatrixAndMatrixReduction computeOnMatrices) { + EvaluationReference result = expression->childAtIndex(0)->approximate(T(), context, angleUnit); + for (int i = 1; i < expression->numberOfChildren(); i++) { + EvaluationReference intermediateResult(nullptr); + EvaluationReference nextOperandEvaluation = expression->childAtIndex(i)->approximate(T(), context, angleUnit); + if (result.node()->type() == EvaluationNode::Type::AllocationFailure || nextOperandEvaluation.node()->type() == EvaluationNode::Type::AllocationFailure) { + return EvaluationReference(EvaluationNode::FailedAllocationStaticNode()); + } + if (result.node()->type() == EvaluationNode::Type::Complex && nextOperandEvaluation.node()->type() == EvaluationNode::Type::Complex) { + const ComplexNode * c = static_cast *>(result.node()); + const ComplexNode * d = static_cast *>(nextOperandEvaluation.node()); + intermediateResult = computeOnComplexes(*c, *d); + } else if (result.node()->type() == EvaluationNode::Type::Complex) { + assert(nextOperandEvaluation.node()->type() == EvaluationNode::Type::MatrixComplex); + const ComplexNode * c = static_cast *>(result.node()); + MatrixComplexReference n = MatrixComplexReference(nextOperandEvaluation.node()); + intermediateResult = computeOnComplexAndMatrix(*c, n); + } else if (nextOperandEvaluation.node()->type() == EvaluationNode::Type::Complex) { + assert(result.node()->type() == EvaluationNode::Type::MatrixComplex); + MatrixComplexReference m = MatrixComplexReference(result.node()); + const ComplexNode * d = static_cast *>(nextOperandEvaluation.node()); + intermediateResult = computeOnMatrixAndComplex(m, *d); } else { - assert(result->type() == Evaluation::Type::MatrixComplex); - const MatrixComplex * m = static_cast *>(result); - assert(nextOperandEvaluation->type() == Evaluation::Type::MatrixComplex); - const MatrixComplex * n = static_cast *>(nextOperandEvaluation); - intermediateResult = new MatrixComplex(computeOnMatrices(*m, *n)); + assert(result.node()->type() == EvaluationNode::Type::MatrixComplex); + assert(nextOperandEvaluation.node()->type() == EvaluationNode::Type::MatrixComplex); + MatrixComplexReference m = MatrixComplexReference(result.node()); + MatrixComplexReference n = MatrixComplexReference(nextOperandEvaluation.node()); + intermediateResult = computeOnMatrices(m, n); } - delete result; - delete nextOperandEvaluation; result = intermediateResult; - assert(result != nullptr); - if (result->isUndefined()) { - return new Complex(Complex::Undefined()); + if (result.isUndefined()) { + return ComplexReference::Undefined(); } } return result; } -template MatrixComplex ApproximationEngine::elementWiseOnMatrixComplexAndComplex(const MatrixComplex m, const std::complex c, ComplexAndComplexReduction computeOnComplexes) { - std::complex * operands = new std::complex [m.numberOfRows()*m.numberOfColumns()]; - for (int i = 0; i < m.numberOfComplexOperands(); i++) { - const std::complex d = m.complexOperand(i); - operands[i] = computeOnComplexes(d, c); +template MatrixComplexReference ApproximationEngine::elementWiseOnMatrixComplexAndComplex(const MatrixComplexReference m, const std::complex c, ComplexAndComplexReduction computeOnComplexes) { + if (m.isAllocationFailure()) { + return MatrixComplexReference(EvaluationNode::FailedAllocationStaticNode()); } - MatrixComplex result = MatrixComplex(operands, m.numberOfRows(), m.numberOfColumns()); - delete[] operands; - return result; + MatrixComplexReference matrix(m.numberOfRows(), m.numberOfColumns()); + for (int i = 0; i < m.numberOfChildren(); i++) { + ComplexNode * child = static_cast *>(m.node())->childAtIndex(i); + if (child) { + matrix.addChildTreeAtIndex(computeOnComplexes(*child, c), i, i); + } else { + matrix.addChildTreeAtIndex(ComplexReference::Undefined(), i, i); + } + } + return matrix; } -template MatrixComplex ApproximationEngine::elementWiseOnComplexMatrices(const MatrixComplex m, const MatrixComplex n, ComplexAndComplexReduction computeOnComplexes) { +template MatrixComplexReference ApproximationEngine::elementWiseOnComplexMatrices(const MatrixComplexReference m, const MatrixComplexReference n, ComplexAndComplexReduction computeOnComplexes) { + if (m.isAllocationFailure() || n.isAllocationFailure()) { + return MatrixComplexReference(EvaluationNode::FailedAllocationStaticNode()); + } if (m.numberOfRows() != n.numberOfRows() || m.numberOfColumns() != n.numberOfColumns()) { - return MatrixComplex::Undefined(); + return MatrixComplexReference::Undefined(); } - std::complex * operands = new std::complex [m.numberOfRows()*m.numberOfColumns()]; - for (int i = 0; i < m.numberOfComplexOperands(); i++) { - const Complex c = m.complexOperand(i); - const Complex d = n.complexOperand(i); - operands[i] = computeOnComplexes(c, d); + MatrixComplexReference matrix(m.numberOfRows(), m.numberOfColumns()); + for (int i = 0; i < m.numberOfChildren(); i++) { + ComplexNode * childM = static_cast *>(m.node())->childAtIndex(i); + ComplexNode * childN = static_cast *>(n.node())->childAtIndex(i); + if (childM && childN) { + matrix.addChildTreeAtIndex(computeOnComplexes(*childM, *childN), i, i); + } else { + matrix.addChildTreeAtIndex(ComplexReference::Undefined(), i, i); + } } - MatrixComplex result = MatrixComplex(operands, m.numberOfRows(), m.numberOfColumns()); - delete[] operands; - return result; + return matrix; } template std::complex Poincare::ApproximationEngine::truncateRealOrImaginaryPartAccordingToArgument(std::complex); template std::complex Poincare::ApproximationEngine::truncateRealOrImaginaryPartAccordingToArgument(std::complex); -template Poincare::Evaluation * Poincare::ApproximationEngine::map(const Poincare::Expression * expression, Poincare::Context& context, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationEngine::ComplexCompute compute); -template Poincare::Evaluation * Poincare::ApproximationEngine::map(const Poincare::Expression * expression, Poincare::Context& context, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationEngine::ComplexCompute compute); -template Poincare::Evaluation * Poincare::ApproximationEngine::mapReduce(const Poincare::Expression * expression, Poincare::Context& context, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationEngine::ComplexAndComplexReduction computeOnComplexes, Poincare::ApproximationEngine::ComplexAndMatrixReduction computeOnComplexAndMatrix, Poincare::ApproximationEngine::MatrixAndComplexReduction computeOnMatrixAndComplex, Poincare::ApproximationEngine::MatrixAndMatrixReduction computeOnMatrices); -template Poincare::Evaluation * Poincare::ApproximationEngine::mapReduce(const Poincare::Expression * expression, Poincare::Context& context, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationEngine::ComplexAndComplexReduction computeOnComplexes, Poincare::ApproximationEngine::ComplexAndMatrixReduction computeOnComplexAndMatrix, Poincare::ApproximationEngine::MatrixAndComplexReduction computeOnMatrixAndComplex, Poincare::ApproximationEngine::MatrixAndMatrixReduction computeOnMatrices); -template Poincare::MatrixComplex Poincare::ApproximationEngine::elementWiseOnMatrixComplexAndComplex(const Poincare::MatrixComplex, const std::complex, std::complex (*)(std::complex, std::complex)); -template Poincare::MatrixComplex Poincare::ApproximationEngine::elementWiseOnMatrixComplexAndComplex(const Poincare::MatrixComplex, std::complex const, std::complex (*)(std::complex, std::complex)); -template Poincare::MatrixComplex Poincare::ApproximationEngine::elementWiseOnComplexMatrices(const Poincare::MatrixComplex, const Poincare::MatrixComplex, std::complex (*)(std::complex, std::complex)); -template Poincare::MatrixComplex Poincare::ApproximationEngine::elementWiseOnComplexMatrices(const Poincare::MatrixComplex, const Poincare::MatrixComplex, std::complex (*)(std::complex, std::complex)); +template Poincare::EvaluationReference Poincare::ApproximationEngine::map(const Poincare::ExpressionNode * expression, Poincare::Context& context, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationEngine::ComplexCompute compute); +template Poincare::EvaluationReference Poincare::ApproximationEngine::map(const Poincare::ExpressionNode * expression, Poincare::Context& context, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationEngine::ComplexCompute compute); +template Poincare::EvaluationReference Poincare::ApproximationEngine::mapReduce(const Poincare::ExpressionNode * expression, Poincare::Context& context, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationEngine::ComplexAndComplexReduction computeOnComplexes, Poincare::ApproximationEngine::ComplexAndMatrixReduction computeOnComplexAndMatrix, Poincare::ApproximationEngine::MatrixAndComplexReduction computeOnMatrixAndComplex, Poincare::ApproximationEngine::MatrixAndMatrixReduction computeOnMatrices); +template Poincare::EvaluationReference Poincare::ApproximationEngine::mapReduce(const Poincare::ExpressionNode * expression, Poincare::Context& context, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationEngine::ComplexAndComplexReduction computeOnComplexes, Poincare::ApproximationEngine::ComplexAndMatrixReduction computeOnComplexAndMatrix, Poincare::ApproximationEngine::MatrixAndComplexReduction computeOnMatrixAndComplex, Poincare::ApproximationEngine::MatrixAndMatrixReduction computeOnMatrices); +template Poincare::MatrixComplexReference Poincare::ApproximationEngine::elementWiseOnMatrixComplexAndComplex(const Poincare::MatrixComplexReference, const std::complex, Poincare::ComplexReference (*)(std::complex, std::complex)); +template Poincare::MatrixComplexReference Poincare::ApproximationEngine::elementWiseOnMatrixComplexAndComplex(const Poincare::MatrixComplexReference, std::complex const, Poincare::ComplexReference (*)(std::complex, std::complex)); +template Poincare::MatrixComplexReference Poincare::ApproximationEngine::elementWiseOnComplexMatrices(const Poincare::MatrixComplexReference, const Poincare::MatrixComplexReference, Poincare::ComplexReference (*)(std::complex, std::complex)); +template Poincare::MatrixComplexReference Poincare::ApproximationEngine::elementWiseOnComplexMatrices(const Poincare::MatrixComplexReference, const Poincare::MatrixComplexReference, Poincare::ComplexReference (*)(std::complex, std::complex)); } diff --git a/poincare/src/arc_cosine.cpp b/poincare/src/arc_cosine.cpp index 245e5df4b..0aa59aa67 100644 --- a/poincare/src/arc_cosine.cpp +++ b/poincare/src/arc_cosine.cpp @@ -17,7 +17,7 @@ Expression * ArcCosine::clone() const { return a; } -Expression * ArcCosine::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference ArcCosine::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/arc_sine.cpp b/poincare/src/arc_sine.cpp index 46dc7b648..1e0df8859 100644 --- a/poincare/src/arc_sine.cpp +++ b/poincare/src/arc_sine.cpp @@ -17,7 +17,7 @@ Expression * ArcSine::clone() const { return a; } -Expression * ArcSine::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference ArcSine::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/arc_tangent.cpp b/poincare/src/arc_tangent.cpp index ea6301ab9..e52c84b84 100644 --- a/poincare/src/arc_tangent.cpp +++ b/poincare/src/arc_tangent.cpp @@ -17,7 +17,7 @@ Expression * ArcTangent::clone() const { return a; } -Expression * ArcTangent::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference ArcTangent::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/arithmetic.cpp b/poincare/src/arithmetic.cpp index 3181a5ccc..ee79a6923 100644 --- a/poincare/src/arithmetic.cpp +++ b/poincare/src/arithmetic.cpp @@ -3,18 +3,24 @@ namespace Poincare { -Integer Arithmetic::LCM(const Integer * a, const Integer * b) { - if (a->isZero() || b->isZero()) { - return Integer(0); +IntegerReference Arithmetic::LCM(const IntegerReference a, const IntegerReference b) { + if (a.isAllocationFailure() || b.isAllocationFailure()) { + return IntegerReference(ExpressionNode::FailedAllocationStaticNode()); } - Integer signResult = Integer::Division(Integer::Multiplication(*a, *b), GCD(a,b)).quotient; + if (a.isZero() || b.isZero()) { + return IntegerReference(0); + } + IntegerReference signResult = IntegerReference::Division(IntegerReference::Multiplication(a, b), GCD(a,b)).quotient; signResult.setNegative(false); return signResult; } -Integer Arithmetic::GCD(const Integer * a, const Integer * b) { - Integer i = *a; - Integer j = *b; +IntegerReference Arithmetic::GCD(const IntegerReference a, const IntegerReference b) { + if (a.isAllocationFailure() || b.isAllocationFailure()) { + return IntegerReference(ExpressionNode::FailedAllocationStaticNode()); + } + IntegerReference i = IntegerReference(a.clone().node()); + IntegerReference j = IntegerReference(b.clone().node()); i.setNegative(false); j.setNegative(false); do { @@ -24,10 +30,10 @@ Integer Arithmetic::GCD(const Integer * a, const Integer * b) { if (j.isZero()) { return i; } - if (j.isLowerThan(i)) { - i = Integer::Division(i, j).remainder; + if (IntegerReference::NaturalOrder(i, j) > 0) { + i = IntegerReference::Division(i, j).remainder; } else { - j = Integer::Division(j, i).remainder; + j = IntegerReference::Division(j, i).remainder; } } while(true); } @@ -36,62 +42,74 @@ int primeFactors[Arithmetic::k_numberOfPrimeFactors] = {2, 3, 5, 7, 11, 13, 17, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919}; // we can go to 7907*7907 = 62 520 649 -void Arithmetic::PrimeFactorization(const Integer * n, Integer * outputFactors, Integer * outputCoefficients, int outputLength) { +void Arithmetic::PrimeFactorization(const IntegerReference n, IntegerReference outputFactors[], IntegerReference outputCoefficients[], int outputLength) { + if (n.isAllocationFailure()) { + /* Special case 0: Allocation failure. */ + outputCoefficients[0] = -1; + return; + } + // To avoid cloning n to get its absolute value m, we change n sign and reset it before returning + bool nIsNegative = n.isNegative(); + IntegerReference m = *(const_cast(&n)); + m.setNegative(false); + /* First we look for prime divisors in the table primeFactors (to speed up * the prime factorization for low numbers). When k_numberOfPrimeFactors is * overflow, try every number as divisor. */ - Integer m = *n; - m.setNegative(false); - if (m.isEqualTo(Integer(1))) { + if (IntegerReference::NaturalOrder(m, IntegerReference(1))) { + m.setNegative(nIsNegative); return; } - const Integer primorial32("525896479052627740771371797072411912900610967452630"); - if (primorial32.isLowerThan(m)) { + const IntegerReference primorial32("525896479052627740771371797072411912900610967452630", false); + if (IntegerReference::NaturalOrder(primorial32, m) < 0) { /* Special case 1: We do not want to break i in prime factor because it * might take too many factors... More than k_maxNumberOfPrimeFactors. * outputCoefficients[0] is set to -1 to indicate a special case. */ - outputCoefficients[0] = Integer(-1); + outputCoefficients[0] = -1; + m.setNegative(nIsNegative); return; } for (int index = 0; index < outputLength; index++) { - outputCoefficients[index] = Integer(0); + outputCoefficients[index] = IntegerReference(0); } int t = 0; // n prime factor index int k = 0; // prime factor index - Integer testedPrimeFactor = Integer(primeFactors[k]); // prime factor + IntegerReference testedPrimeFactor(primeFactors[k]); // prime factor outputFactors[t] = testedPrimeFactor; - IntegerDivision d = {.quotient = 0, .remainder = 0}; + IntegerDivisionReference d = {.quotient = 0, .remainder = 0}; bool stopCondition; do { - stopCondition = Integer::Power(outputFactors[t], Integer(2)).isLowerThan(m); - d = Integer::Division(m, testedPrimeFactor); - if (d.remainder.isEqualTo(Integer(0))) { - outputCoefficients[t] = Integer::Addition(outputCoefficients[t], Integer(1)); - m = std::move(d.quotient); - if (m.isEqualTo(Integer(1))) { + stopCondition = IntegerReference::NaturalOrder(IntegerReference::Power(outputFactors[t], IntegerReference(2)), m) < 0; + d = IntegerReference::Division(m, testedPrimeFactor); + if (d.remainder.isZero()) { + outputCoefficients[t] = IntegerReference::Addition(outputCoefficients[t], IntegerReference(1)); + m = d.quotient; + if (m.isOne()) { + m.setNegative(nIsNegative); return; } continue; } - if (!outputCoefficients[t].isEqualTo(Integer(0))) { + if (!outputCoefficients[t].isZero()) { t++; } k++; - testedPrimeFactor = k < k_numberOfPrimeFactors ? Integer(primeFactors[k]) : Integer::Addition(testedPrimeFactor, Integer(1)); + testedPrimeFactor = k < k_numberOfPrimeFactors ? IntegerReference(primeFactors[k]) : IntegerReference::Addition(testedPrimeFactor, IntegerReference(1)); outputFactors[t] = testedPrimeFactor; - } while (stopCondition && testedPrimeFactor.isLowerThan(Integer(k_biggestPrimeFactor))); - if (Integer::Power(Integer(k_biggestPrimeFactor), Integer(2)).isLowerThan(m)) { + } while (stopCondition && IntegerReference::NaturalOrder(testedPrimeFactor,IntegerReference(k_biggestPrimeFactor)) < 0); + if (IntegerReference::NaturalOrder(IntegerReference::Power(IntegerReference(k_biggestPrimeFactor), IntegerReference(2)), m) < 0) { /* Special case 2: We do not want to break i in prime factor because it * take too much time: the prime factor that should be tested is above * k_biggestPrimeFactor. * outputCoefficients[0] is set to -1 to indicate a special case. */ outputCoefficients[0] = -1; + m.setNegative(nIsNegative); return; } - outputFactors[t] = std::move(m); - outputCoefficients[t] = Integer::Addition(outputCoefficients[t], Integer(1)); -} + outputFactors[t] = m; + outputCoefficients[t] = IntegerReference::Addition(outputCoefficients[t], IntegerReference(1)); + m.setNegative(nIsNegative); } - +} diff --git a/poincare/src/binomial_coefficient.cpp b/poincare/src/binomial_coefficient.cpp index 8b43ca27e..2e85fff7a 100644 --- a/poincare/src/binomial_coefficient.cpp +++ b/poincare/src/binomial_coefficient.cpp @@ -20,7 +20,7 @@ Expression * BinomialCoefficient::clone() const { return b; } -Expression * BinomialCoefficient::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference BinomialCoefficient::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/ceiling.cpp b/poincare/src/ceiling.cpp index 8623da6c4..076641f1d 100644 --- a/poincare/src/ceiling.cpp +++ b/poincare/src/ceiling.cpp @@ -20,7 +20,7 @@ Expression * Ceiling::clone() const { return c; } -Expression * Ceiling::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Ceiling::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/complex.cpp b/poincare/src/complex.cpp new file mode 100644 index 000000000..0a49178c3 --- /dev/null +++ b/poincare/src/complex.cpp @@ -0,0 +1,146 @@ +extern "C" { +#include +#include +#include +} +#include +//#include +//#include +#include +#include +#include +//#include +//#include +#include +//#include +//#include +//#include +//#include +#include +#include +#include + +namespace Poincare { + +template +void ComplexNode::setComplex(std::complex c) { + this->real(c.real()); + this->imag(c.imag()); + if (this->real() == -0) { + this->real(0); + } + if (this->imag() == -0) { + this->imag(0); + } +} + +template +T ComplexNode::toScalar() const { + if (this->imag() == 0.0) { + return this->real(); + } + return NAN; +} + +template +static ExpressionReference CreateDecimal(T f) { + if (std::isnan(f)) { + return UndefinedReference(); + } + if (std::isinf(f)) { + return InfiniteReference(f < 0.0); + } + return DecimalReference(f); +} + +template +ExpressionReference ComplexNode::complexToExpression(Preferences::ComplexFormat complexFormat) const { + if (std::isnan(this->real()) || std::isnan(this->imag())) { + return UndefinedReference(); + } + switch (complexFormat) { + case Preferences::ComplexFormat::Cartesian: + { + ExpressionReference real(nullptr); + ExpressionReference imag(nullptr); + if (this->real() != 0 || this->imag() == 0) { + real = CreateDecimal(this->real()); + } + if (this->imag() != 0) { + if (this->imag() == 1.0 || this->imag() == -1) { + imag = SymbolReference(Ion::Charset::IComplex); + } else if (this->imag() > 0) { + imag = MultiplicationReference(CreateDecimal(this->imag()), SymbolReference(Ion::Charset::IComplex)); + } else { + imag = MultiplicationReference(CreateDecimal(-this->imag()), SymbolReference(Ion::Charset::IComplex)); + } + } + if (!imag.isDefined()) { + return real; + } else if (!real.isDefined()) { + if (this->imag() > 0) { + return imag; + } else { + return OppositeReference(imag); + } + return imag; + } else if (this->imag() > 0) { + return AdditionReference(real, imag); + } else { + return SubtractionReference(real, imag); + } + } + default: + { + assert(complexFormat == Preferences::ComplexFormat::Polar); + ExpressionReference norm(nullptr); + ExpressionReference exp(nullptr); + T r = std::abs(*this); + T th = std::arg(*this); + if (r != 1 || th == 0) { + norm = CreateDecimal(r); + } + if (r != 0 && th != 0) { + ExpressionReference arg(nullptr); + if (th == 1.0) { + arg = SymbolReference(Ion::Charset::IComplex); + } else if (th == -1.0) { + arg = OppositeReference(SymbolReference(Ion::Charset::IComplex)); + } else if (th > 0) { + arg = MultiplicationReference(CreateDecimal(th), SymbolReference(Ion::Charset::IComplex)); + } else { + arg = OppositeRefrence(MultiplicationReference(CreateDecimal(-th), SymbolReference(Ion::Charset::IComplex))); + } + exp = PowerReference(SymbolReference(Ion::Charset::Exponential), arg); + } + if (!exp.isDefined()) { + return norm; + } else if (!norm.isDefined()) { + return exp; + } else { + return MultiplicationReference(norm, exp); + } + } + } +} + +template +EvaluationReference ComplexNode::inverse() const { + return ComplexReference(Division::compute(std::complex(1.0), *this)); +} + +template +ComplexReference::ComplexReference(std::complex c) : + EvaluationReference() +{ + TreeNode * node = TreePool::sharedPool()->createTreeNode>(); + this->m_identifier = node->identifier(); + if (!(node->isAllocationFailure())) { + static_cast *>(node)->setComplex(c); + } +} + +template class ComplexReference; +template class ComplexReference; + +} diff --git a/poincare/src/complex_argument.cpp b/poincare/src/complex_argument.cpp index 89afb8044..91a0148d1 100644 --- a/poincare/src/complex_argument.cpp +++ b/poincare/src/complex_argument.cpp @@ -16,7 +16,7 @@ Expression * ComplexArgument::clone() const { return a; } -Expression * ComplexArgument::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference ComplexArgument::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/confidence_interval.cpp b/poincare/src/confidence_interval.cpp index 4c4d0156a..bcef5496a 100644 --- a/poincare/src/confidence_interval.cpp +++ b/poincare/src/confidence_interval.cpp @@ -24,7 +24,7 @@ int ConfidenceInterval::polynomialDegree(char symbolName) const { return -1; } -Expression * ConfidenceInterval::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference ConfidenceInterval::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; @@ -62,7 +62,7 @@ Expression * ConfidenceInterval::shallowReduce(Context& context, Preferences::An } template -Evaluation * ConfidenceInterval::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { +EvaluationReference ConfidenceInterval::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { Evaluation * fInput = operand(0)->privateApproximate(T(), context, angleUnit); Evaluation * nInput = operand(1)->privateApproximate(T(), context, angleUnit); T f = static_cast *>(fInput)->toScalar(); diff --git a/poincare/src/conjugate.cpp b/poincare/src/conjugate.cpp index 30cc6b9e6..fe5e7f52e 100644 --- a/poincare/src/conjugate.cpp +++ b/poincare/src/conjugate.cpp @@ -19,7 +19,7 @@ LayoutRef Conjugate::createLayout(Preferences::PrintFloatMode floatDisplayMode, return ConjugateLayoutRef(operand(0)->createLayout(floatDisplayMode, numberOfSignificantDigits)); } -Expression * Conjugate::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Conjugate::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/cosine.cpp b/poincare/src/cosine.cpp index 94a746f02..dffda5643 100644 --- a/poincare/src/cosine.cpp +++ b/poincare/src/cosine.cpp @@ -32,7 +32,7 @@ std::complex Cosine::computeOnComplex(const std::complex c, Preferences::A return Trigonometry::RoundToMeaningfulDigits(res); } -Expression * Cosine::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Cosine::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/decimal.cpp b/poincare/src/decimal.cpp index 94cd4907d..1c3b8a72d 100644 --- a/poincare/src/decimal.cpp +++ b/poincare/src/decimal.cpp @@ -87,7 +87,7 @@ Expression * Decimal::clone() const { return new Decimal(m_mantissa, m_exponent); } -template Evaluation * Decimal::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { +template EvaluationReference Decimal::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { T m = m_mantissa.approximate(); int numberOfDigits = Integer::numberOfDigitsWithoutSign(m_mantissa); return new Complex(m*std::pow((T)10.0, (T)(m_exponent-numberOfDigits+1))); @@ -221,14 +221,14 @@ LayoutRef Decimal::createLayout(Preferences::PrintFloatMode floatDisplayMode, in return LayoutEngine::createStringLayout(buffer, numberOfChars); } -Expression * Decimal::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Decimal::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; } // Do not reduce decimal to rational if the exponent is too big or too small. if (m_exponent > k_maxDoubleExponent || m_exponent < -k_maxDoubleExponent) { - return this; // TODO: return new Infinite() ? new Rational(0) ? + return this; // TODO: return new Infinite() ? RationalReference(0) ? } Integer numerator = m_mantissa; removeZeroAtTheEnd(numerator); @@ -251,7 +251,7 @@ Expression * Decimal::shallowBeautify(Context & context, Preferences::AngleUnit return this; } -int Decimal::simplificationOrderSameType(const Expression * e, bool canBeInterrupted) const { +int Decimal::simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const { assert(e->type() == Type::Decimal); const Decimal * other = static_cast(e); if (sign() == Sign::Negative && other->sign() == Sign::Positive) { diff --git a/poincare/src/derivative.cpp b/poincare/src/derivative.cpp index 1533acd2c..c5004d557 100644 --- a/poincare/src/derivative.cpp +++ b/poincare/src/derivative.cpp @@ -29,7 +29,7 @@ int Derivative::polynomialDegree(char symbolName) const { return Expression::polynomialDegree(symbolName); } -Expression * Derivative::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Derivative::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/determinant.cpp b/poincare/src/determinant.cpp index ce80046ac..a5a30dd43 100644 --- a/poincare/src/determinant.cpp +++ b/poincare/src/determinant.cpp @@ -16,7 +16,7 @@ Expression * Determinant::clone() const { return a; } -Expression * Determinant::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Determinant::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; @@ -34,7 +34,7 @@ Expression * Determinant::shallowReduce(Context& context, Preferences::AngleUnit // TODO: handle this exactly in shallowReduce for small dimensions. template -Evaluation * Determinant::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { +EvaluationReference Determinant::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { Evaluation * input = operand(0)->privateApproximate(T(), context, angleUnit); Complex * result = new Complex(input->createDeterminant()); delete input; diff --git a/poincare/src/division.cpp b/poincare/src/division.cpp index a441a1bb1..bb1909743 100644 --- a/poincare/src/division.cpp +++ b/poincare/src/division.cpp @@ -35,7 +35,7 @@ bool Division::needParenthesisWithParent(const Expression * e) const { return e->isOfType(types, 3); } -Expression * Division::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Division::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/division_quotient.cpp b/poincare/src/division_quotient.cpp index f4ef0ada5..3c0827176 100644 --- a/poincare/src/division_quotient.cpp +++ b/poincare/src/division_quotient.cpp @@ -18,7 +18,7 @@ Expression * DivisionQuotient::clone() const { return a; } -Expression * DivisionQuotient::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference DivisionQuotient::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/division_remainder.cpp b/poincare/src/division_remainder.cpp index 38abb2a39..d2c52e496 100644 --- a/poincare/src/division_remainder.cpp +++ b/poincare/src/division_remainder.cpp @@ -18,7 +18,7 @@ Expression * DivisionRemainder::clone() const { return a; } -Expression * DivisionRemainder::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference DivisionRemainder::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/dynamic_hierarchy.cpp b/poincare/src/dynamic_hierarchy.cpp index 699937941..c57ed7e93 100644 --- a/poincare/src/dynamic_hierarchy.cpp +++ b/poincare/src/dynamic_hierarchy.cpp @@ -141,7 +141,7 @@ void DynamicHierarchy::removeOperandAtIndex(int i, bool deleteAfterRemoval) { } } -int DynamicHierarchy::simplificationOrderSameType(const Expression * e, bool canBeInterrupted) const { +int DynamicHierarchy::simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const { int m = this->numberOfOperands(); int n = e->numberOfOperands(); for (int i = 1; i <= m; i++) { diff --git a/poincare/src/equal.cpp b/poincare/src/equal.cpp index 06f8a69d4..b03c992ee 100644 --- a/poincare/src/equal.cpp +++ b/poincare/src/equal.cpp @@ -38,13 +38,13 @@ Expression * Equal::standardEquation(Context & context, Preferences::AngleUnit a return sub; } -Expression * Equal::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Equal::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; } if (operand(0)->isIdenticalTo(operand(1))) { - return replaceWith(new Rational(1), true); + return replaceWith(RationalReference(1), true); } return this; } @@ -58,7 +58,7 @@ LayoutRef Equal::createLayout(Preferences::PrintFloatMode floatDisplayMode, int } template -Evaluation * Equal::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { +EvaluationReference Equal::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { return new Complex(Complex::Undefined()); } diff --git a/poincare/src/evaluation.cpp b/poincare/src/evaluation.cpp index 55980bb0b..295288d90 100644 --- a/poincare/src/evaluation.cpp +++ b/poincare/src/evaluation.cpp @@ -1,264 +1,19 @@ -extern "C" { -#include -#include -#include -} #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include namespace Poincare { template -T Complex::toScalar() const { - if (this->imag() == 0.0) { - return this->real(); - } - return NAN; -} - -template -static Expression * CreateDecimal(T f) { - if (std::isnan(f) || std::isinf(f)) { - return new Undefined(); - } - return new Decimal(f); +TreeNode * EvaluationNode::FailedAllocationStaticNode() { + static AllocationFailedEvaluationNode FailureNode; + TreePool::sharedPool()->registerStaticNodeIfRequired(&FailureNode); + return &FailureNode; } template -Expression * Complex::complexToExpression(Preferences::ComplexFormat complexFormat) const { - if (std::isnan(this->real()) || std::isnan(this->imag()) || std::isinf(this->real()) || std::isinf(this->imag())) { - return new Poincare::Undefined(); - } - - switch (complexFormat) { - case Preferences::ComplexFormat::Cartesian: - { - Expression * real = nullptr; - Expression * imag = nullptr; - if (this->real() != 0 || this->imag() == 0) { - real = CreateDecimal(this->real()); - } - if (this->imag() != 0) { - if (this->imag() == 1.0 || this->imag() == -1) { - imag = new Symbol(Ion::Charset::IComplex); - } else if (this->imag() > 0) { - imag = new Multiplication(CreateDecimal(this->imag()), new Symbol(Ion::Charset::IComplex), false); - } else { - imag = new Multiplication(CreateDecimal(-this->imag()), new Symbol(Ion::Charset::IComplex), false); - } - } - if (imag == nullptr) { - return real; - } else if (real == nullptr) { - if (this->imag() > 0) { - return imag; - } else { - return new Opposite(imag, false); - } - return imag; - } else if (this->imag() > 0) { - return new Addition(real, imag, false); - } else { - return new Subtraction(real, imag, false); - } - } - default: - { - assert(complexFormat == Preferences::ComplexFormat::Polar); - Expression * norm = nullptr; - Expression * exp = nullptr; - T r = std::abs(*this); - T th = std::arg(*this); - if (r != 1 || th == 0) { - norm = CreateDecimal(r); - } - if (r != 0 && th != 0) { - Expression * arg = nullptr; - if (th == 1.0) { - arg = new Symbol(Ion::Charset::IComplex); - } else if (th == -1.0) { - arg = new Opposite(new Symbol(Ion::Charset::IComplex), false); - } else if (th > 0) { - arg = new Multiplication(CreateDecimal(th), new Symbol(Ion::Charset::IComplex), false); - } else { - arg = new Opposite(new Multiplication(CreateDecimal(-th), new Symbol(Ion::Charset::IComplex), false), false); - } - exp = new Power(new Symbol(Ion::Charset::Exponential), arg, false); - } - if (exp == nullptr) { - return norm; - } else if (norm == nullptr) { - return exp; - } else { - return new Multiplication(norm, exp, false); - } - } - } +ExpressionReference EvaluationReference::complexToExpression(Preferences::ComplexFormat complexFormat) const { + return node()->complexToExpression(complexFormat); } -template -Complex * Complex::createInverse() const { - return new Complex(Division::compute(std::complex(1.0), *this)); -} - -template -std::complex Complex::pow(const std::complex &c, const std::complex &d) { - std::complex result = std::pow(c, d); - /* Cheat: pow openbsd immplementationd is a numerical approximation. - * We though want to avoid evaluating e^(i*pi) to -1+1E-17i. We thus round - * real and imaginary parts to 0 if they are negligible compared to their - * norm. */ - T norm = std::norm(result); - if (norm != 0 && std::fabs(result.real()/norm) <= Expression::epsilon()) { - result.real(0); - } - if (norm != 0 && std::fabs(result.imag()/norm) <= Expression::epsilon()) { - result.imag(0); - } - if (c.imag() == 0 && d.imag() == 0 && (c.real() >= 0 || d.real() == std::round(d.real()))) { - result.imag(0); - } - return result; -} - -template -std::complex Complex::approximate(const std::complex& c, ComplexFunction function) { - std::complex result = function(c); - /* Cheat: openbsd trigonometric functions (cos, sin, tan, sqrt) are numerical - * implementation and thus are approximative. The error epsilon is ~1E-7 - * on float and ~1E-15 on double. In order to avoid weird results as - * cos(90) = 6E-17, we neglect the result when its ratio with the argument - * (pi in the exemple) is smaller than epsilon. - * We can't do that for all evaluation as the user can operate on values as - * small as 1E-308 (in double) and most results still be correct. */ - T inputNorm = std::abs(c); - if (inputNorm != 0 && std::fabs(result.real()/inputNorm) <= Expression::epsilon()) { - result.real(0); - } - if (inputNorm != 0 && std::fabs(result.imag()/inputNorm) <= Expression::epsilon()) { - result.imag(0); - } - return result; -} - -template -MatrixComplex::MatrixComplex(std::complex * operands, int numberOfRows, int numberOfColumns) : - m_numberOfRows(numberOfRows), - m_numberOfColumns(numberOfColumns) -{ - m_operands = new std::complex [numberOfRows*numberOfColumns]; - for (int i=0; i -Expression * MatrixComplex::complexToExpression(Preferences::ComplexFormat complexFormat) const { - Expression ** operands = new Expression * [numberOfComplexOperands()]; - for (int i = 0; i < numberOfComplexOperands(); i++) { - operands[i] = Complex(complexOperand(i)).complexToExpression(complexFormat); - } - Expression * result = new Matrix(operands, numberOfRows(), numberOfColumns(), false); - delete[] operands; - return result; -} - -template -std::complex MatrixComplex::createTrace() const { - if (numberOfRows() != numberOfColumns()) { - return std::complex(NAN, NAN); - } - int dim = numberOfRows(); - std::complex c = std::complex(0); - for (int i = 0; i < dim; i++) { - c += complexOperand(i*dim+i); - } - return c; -} - -template -std::complex MatrixComplex::createDeterminant() const { - if (numberOfRows() != numberOfColumns()) { - return std::complex(NAN, NAN); - } - std::complex * operandsCopy = new std::complex [m_numberOfRows*m_numberOfColumns]; - for (int i=0; i determinant = std::complex(1); - Matrix::ArrayRowCanonize(operandsCopy, m_numberOfRows, m_numberOfColumns, &determinant); - delete[] operandsCopy; - return determinant; -} - -template -MatrixComplex * MatrixComplex::createInverse() const { - std::complex * operandsCopy = new std::complex [m_numberOfRows*m_numberOfColumns]; - for (int i=0; i * inverse = nullptr; - if (result == 0) { - // Intentionally swapping dimensions for inverse, although it doesn't make a difference because it is square - inverse = new MatrixComplex(operandsCopy, m_numberOfColumns, m_numberOfRows); - } - delete [] operandsCopy; - return inverse; -} - -template -MatrixComplex * MatrixComplex::createTranspose() const { - std::complex * operands = new std::complex [numberOfComplexOperands()]; - for (int i = 0; i < numberOfRows(); i++) { - for (int j = 0; j < numberOfColumns(); j++) { - operands[j*numberOfRows()+i] = complexOperand(i*numberOfColumns()+j); - } - } - // Intentionally swapping dimensions for transpose - MatrixComplex * matrix = new MatrixComplex(operands, numberOfColumns(), numberOfRows()); - delete[] operands; - return matrix; -} - -template -MatrixComplex MatrixComplex::createIdentity(int dim) { - std::complex * operands = new std::complex [dim*dim]; - for (int i = 0; i < dim; i++) { - for (int j = 0; j < dim; j++) { - if (i == j) { - operands[i*dim+j] = std::complex(1); - } else { - operands[i*dim+j] = std::complex(0); - } - } - } - MatrixComplex matrix = MatrixComplex(operands, dim, dim); - delete [] operands; - return matrix; -} - -template class Complex; -template class Complex; -template class MatrixComplex; -template class MatrixComplex; } diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 82da8c317..0dfe7db36 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -246,7 +246,7 @@ bool Expression::getLinearCoefficients(char * variables, Expression * coefficien coefficients[index] = polynomialCoefficients[1]; } else { assert(degree == 0); - coefficients[index] = new Rational(0); + coefficients[index] = RationalReference(0); } delete equation; equation = polynomialCoefficients[0]; @@ -285,7 +285,7 @@ int Expression::getPolynomialCoefficients(char symbolName, Expression * coeffici return degree; } -int Expression::privateGetPolynomialCoefficients(char symbolName, Expression * coefficients[]) const { +int Expression::getPolynomialCoefficients(char symbolName, ExpressionReference coefficients[]) const { int deg = polynomialDegree(symbolName); if (deg == 0) { coefficients[0] = clone(); diff --git a/poincare/src/expression_node.cpp b/poincare/src/expression_node.cpp new file mode 100644 index 000000000..b1399f073 --- /dev/null +++ b/poincare/src/expression_node.cpp @@ -0,0 +1,117 @@ +#include +#include +#include + +namespace Poincare { + +TreeNode * ExpressionNode::FailedAllocationStaticNode() { + static AllocationFailedExpressionNode FailureNode; + TreePool::sharedPool()->registerStaticNodeIfRequired(&FailureNode); + return &FailureNode; +} + +ExpressionReference ExpressionNode::replaceSymbolWithExpression(char symbol, ExpressionReference expression) { + ExpressionReference reference(this); + for (int i = 0; i < reference.numberOfChildren(); i++) { + reference.replaceTreeChildAtIndex(i, reference.childAtIndex(i).node()->replaceSymbolWithExpression(symbol, expression)); + } + return reference; +} + +ExpressionReference ExpressionNode::setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit) { + assert(false); + return ExpressionReference(nullptr); +} + +int ExpressionNode::polynomialDegree(char symbolName) const { + for (int i = 0; i < numberOfChildren(); i++) { + if (childAtIndex(i)->polynomialDegree(symbolName) != 0) { + return -1; + } + } + return 0; +} + +int ExpressionNode::getPolynomialCoefficients(char symbolName, ExpressionReference coefficients[]) const { + int deg = polynomialDegree(symbolName); + if (deg == 0) { + coefficients[0] = ExpressionReference(this).clone(); + return 0; + } + return -1; +} + +int ExpressionNode::getVariables(isVariableTest isVariable, char * variables) const { + int numberOfVariables = 0; + for (int i = 0; i < numberOfChildren(); i++) { + int n = childAtIndex(i)->getVariables(isVariable, variables); + if (n < 0) { + return -1; + } + numberOfVariables = n > numberOfVariables ? n : numberOfVariables; + } + return numberOfVariables; +} + +float ExpressionNode::characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const { + /* A expression has a characteristic range if at least one of its childAtIndex has + * one and the other are x-independant. We keep the biggest interesting range + * among the childAtIndex interesting ranges. */ + float range = 0.0f; + for (int i = 0; i < numberOfChildren(); i++) { + float opRange = childAtIndex(i)->characteristicXRange(context, angleUnit); + if (std::isnan(opRange)) { + return NAN; + } else if (range < opRange) { + range = opRange; + } + } + return range; +} + +int ExpressionNode::SimplificationOrder(const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { + if (e1->type() > e2->type()) { + if (canBeInterrupted && ExpressionReference::shouldStopProcessing()) { + return 1; + } + return -(e2->simplificationOrderGreaterType(e1, canBeInterrupted)); + } else if (e1->type() == e2->type()) { + return e1->simplificationOrderSameType(e2, canBeInterrupted); + } else { + if (canBeInterrupted && ExpressionReference::shouldStopProcessing()) { + return -1; + } + return e1->simplificationOrderGreaterType(e2, canBeInterrupted); + } +} + +ExpressionReference ExpressionNode::shallowReduce(Context & context, Preferences::AngleUnit angleUnit) { + for (int i = 0; i < numberOfChildren(); i++) { + if (childAtIndex(i)->isAllocationFailure()) { + return failedAllocationStaticNode(); + } + if (childAtIndex(i)->type() == Type::Undefined) { + return UndefinedReference(); + } + } + return ExpressionReference(this); +} + +ExpressionReference ExpressionNode::shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) { + return ExpressionReference(this); +} + +bool ExpressionNode::isOfType(Type * types, int length) const { + for (int i = 0; i < length; i++) { + if (type() == types[i]) { + return true; + } + } + return false; +} + +ExpressionReference ExpressionNode::cloneDenominator(Context & context, Preferences::AngleUnit angleUnit) const { + return ExpressionReference(nullptr); +} + +} diff --git a/poincare/src/expression_reference.cpp b/poincare/src/expression_reference.cpp new file mode 100644 index 000000000..4b09b17af --- /dev/null +++ b/poincare/src/expression_reference.cpp @@ -0,0 +1,568 @@ +#include +#include +//#include +//#include +#include +#include +#include +#include +//#include +#include +#include +#include +//#include "expression_parser.hpp" +//#include "expression_lexer.hpp" + +int poincare_expression_yyparse(Poincare::ExpressionReference * expressionOutput); + +namespace Poincare { + +#include + +/* Constructor & Destructor */ + +ExpressionReference ExpressionReference::parse(char const * string) { + if (string[0] == 0) { + return nullptr; + } + YY_BUFFER_STATE buf = poincare_expression_yy_scan_string(string); + ExpressionReference expression(nullptr); + if (poincare_expression_yyparse(&expression) != 0) { + // Parsing failed because of invalid input or memory exhaustion + expression = ExpressionReference(nullptr); + } + poincare_expression_yy_delete_buffer(buf); + + return expression; +} + +void ExpressionReference::ReplaceSymbolWithExpression(ExpressionReference * expressionAddress, char symbol, ExpressionReference expression) { + *expressionAddress = expressionAddress->node()->replaceSymbolWithExpression(symbol, expression); +} + +ExpressionReference ExpressionReference::clone() const { + TreeReference c = this->treeClone(); + ExpressionReference * cast = static_cast(&c); + return *cast; +} + +/* Circuit breaker */ + +static ExpressionReference::CircuitBreaker sCircuitBreaker = nullptr; +static bool sSimplificationHasBeenInterrupted = false; + +void ExpressionReference::setCircuitBreaker(CircuitBreaker cb) { + sCircuitBreaker = cb; +} + +bool ExpressionReference::shouldStopProcessing() { + if (sCircuitBreaker == nullptr) { + return false; + } + if (sCircuitBreaker()) { + sSimplificationHasBeenInterrupted = true; + return true; + } + return false; +} + +/* Properties */ + +bool ExpressionReference::isRationalZero() const { + return this->node()->type() == ExpressionNode::Type::Rational && static_cast(this->node())->isZero(); +} + +bool ExpressionReference::recursivelyMatches(ExpressionTest test, Context & context) const { + if (test(*this, context)) { + return true; + } + for (int i = 0; i < this->numberOfChildren(); i++) { + if (childAtIndex(i).recursivelyMatches(test, context)) { + return true; + } + } + return false; +} + +bool ExpressionReference::isApproximate(Context & context) const { + return recursivelyMatches([](const ExpressionReference e, Context & context) { + return e.node()->type() == ExpressionNode::Type::Decimal || e.node()->type() == ExpressionNode::Type::Double || ExpressionReference::IsMatrix(e, context) || (e.node()->type() == ExpressionNode::Type::Symbol && SymbolReference::isApproximate(static_cast(e.node())->name(), context)); + }, context); +} + +bool ExpressionReference::IsMatrix(const ExpressionReference e, Context & context) { + return e.node()->type() == ExpressionNode::Type::Matrix || e.node()->type() == ExpressionNode::Type::ConfidenceInterval || e.node()->type() == ExpressionNode::Type::MatrixDimension || e.node()->type() == ExpressionNode::Type::PredictionInterval || e.node()->type() == ExpressionNode::Type::MatrixInverse || e.node()->type() == ExpressionNode::Type::MatrixTranspose || (e.node()->type() == ExpressionNode::Type::Symbol && SymbolReference::isMatrixSymbol(static_cast(e.node())->name())); +} + +bool dependsOnVariables(const ExpressionReference e, Context & context) { + return e.node()->type() == ExpressionNode::Type::Symbol && SymbolReference::isVariableSymbol(static_cast(e.node())->name()); +} + +bool ExpressionReference::getLinearCoefficients(char * variables, ExpressionReference coefficients[], ExpressionReference constant[], Context & context, Preferences::AngleUnit angleUnit) const { + char * x = variables; + while (*x != 0) { + int degree = polynomialDegree(*x); + if (degree > 1 || degree < 0) { + return false; + } + x++; + } + ExpressionReference equation = *this; + x = variables; + int index = 0; + ExpressionReference polynomialCoefficients[k_maxNumberOfPolynomialCoefficients]; + while (*x != 0) { + int degree = equation.getPolynomialCoefficients(*x, polynomialCoefficients, context, angleUnit); + if (degree == 1) { + coefficients[index] = polynomialCoefficients[1]; + } else { + assert(degree == 0); + coefficients[index] = RationalReference(0); + } + equation = polynomialCoefficients[0]; + x++; + index++; + } + constant[0] = OppositeReference(equation).deepReduce(context, angleUnit); + /* The expression can be linear on all coefficients taken one by one but + * non-linear (ex: xy = 2). We delete the results and return false if one of + * the coefficients contains a variable. */ + bool isMultivariablePolynomial = (constant[0]).recursivelyMatches(dependsOnVariables, context); + for (int i = 0; i < index; i++) { + if (isMultivariablePolynomial) { + break; + } + isMultivariablePolynomial |= coefficients[i].recursivelyMatches(dependsOnVariables, context); + } + if (isMultivariablePolynomial) { + for (int i = 0; i < index; i++) { + coefficients[i] = ExpressionReference(nullptr); + } + constant[0] = ExpressionReference(nullptr); + return false; + } + return true; +} + +int ExpressionReference::getPolynomialCoefficients(char symbolName, ExpressionReference coefficients[], Context & context, Preferences::AngleUnit angleUnit) const { + int degree = this->node()->getPolynomialCoefficients(symbolName, coefficients); + for (int i = 0; i <= degree; i++) { + coefficients[i] = coefficients[i].deepReduce(context, angleUnit); + } + return degree; +} + +/* Comparison */ + +bool ExpressionReference::isEqualToItsApproximationLayout(ExpressionReference approximation, int bufferSize, Preferences::AngleUnit angleUnit, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits, Context & context) { + char buffer[bufferSize]; + approximation.writeTextInBuffer(buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits); + /* Warning: we cannot use directly the the approximate expression but we have + * to re-serialize it because the number of stored significative + * numbers and the number of displayed significative numbers might not be + * identical. (For example, 0.000025 might be displayed "0.00003" and stored + * as Decimal(0.000025) and isEqualToItsApproximationLayout should return + * false) */ + ExpressionReference approximateOutput = ExpressionReference::ParseAndSimplify(buffer, context, angleUnit); + bool equal = isIdenticalTo(approximateOutput); + return equal; +} + +/* Simplification */ + +ExpressionReference ExpressionReference::ParseAndSimplify(const char * text, Context & context, Preferences::AngleUnit angleUnit) { + ExpressionReference exp = parse(text); + if (!exp.isDefined()) { + return UndefinedReference(); + } + Simplify(&exp, context, angleUnit); + if (!exp.isDefined()) { + return parse(text); + } + return exp; +} + +void ExpressionReference::Simplify(ExpressionReference * expressionAddress, Context & context, Preferences::AngleUnit angleUnit) { + sSimplificationHasBeenInterrupted = false; +#if MATRIX_EXACT_REDUCING +#else + if (expressionAddress->recursivelyMatches(IsMatrix, context)) { + return; + } +#endif + *expressionAddress = expressionAddress->deepReduce(context, angleUnit); + *expressionAddress = expressionAddress->deepBeautify(context, angleUnit); + if (sSimplificationHasBeenInterrupted) { + *expressionAddress = ExpressionReference(nullptr); + } +} + +ExpressionReference ExpressionReference::deepReduce(Context & context, Preferences::AngleUnit angleUnit) { + for (int i = 0; i < this->numberOfChildren(); i++) { + replaceTreeChildAtIndex(i, childAtIndex(i).deepReduce(context, angleUnit)); + } + return shallowReduce(context, angleUnit); +} + +ExpressionReference ExpressionReference::deepBeautify(Context & context, Preferences::AngleUnit angleUnit) { + ExpressionReference beautifiedExpression = shallowBeautify(context, angleUnit); + for (int i = 0; i < beautifiedExpression.numberOfChildren(); i++) { + beautifiedExpression.replaceTreeChildAtIndex(i, beautifiedExpression.childAtIndex(i).deepBeautify(context, angleUnit)); + } + return beautifiedExpression; +} + +/* Evaluation */ + +template +ExpressionReference ExpressionReference::approximate(Context& context, Preferences::AngleUnit angleUnit, Preferences::Preferences::ComplexFormat complexFormat) const { + EvaluationReference e = this->node()->approximate(U(), context, angleUnit); + return e->complexToExpression(complexFormat); +} + +template +U ExpressionReference::approximateToScalar(Context& context, Preferences::AngleUnit angleUnit) const { + EvaluationReference evaluation = this->node()->approximate(U(), context, angleUnit); + return evaluation->toScalar(); +} + +template +U ExpressionReference::approximateToScalar(const char * text, Context& context, Preferences::AngleUnit angleUnit) { + ExpressionReference exp = ParseAndSimplify(text, context, angleUnit); + return exp.approximateToScalar(context, angleUnit); +} + +template +U ExpressionReference::approximateWithValueForSymbol(char symbol, U x, Context & context, Preferences::AngleUnit angleUnit) const { + VariableContext variableContext = VariableContext(symbol, &context); + variableContext.setApproximationForVariable(x); + return approximateToScalar(variableContext, angleUnit); +} + +template +U ExpressionReference::epsilon() { + static U epsilon = sizeof(U) == sizeof(double) ? 1E-15 : 1E-7f; + return epsilon; +} + +/* Expression roots/extrema solver*/ + +typename ExpressionReference::Coordinate2D ExpressionReference::nextMinimum(char symbol, double start, double step, double max, Context & context, Preferences::AngleUnit angleUnit) const { + return nextMinimumOfExpression(symbol, start, step, max, [](char symbol, double x, Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression0, const ExpressionReference expression1 = nullptr) { + return expression0.approximateWithValueForSymbol(symbol, x, context, angleUnit); + }, context, angleUnit); +} + +typename ExpressionReference::Coordinate2D ExpressionReference::nextMaximum(char symbol, double start, double step, double max, Context & context, Preferences::AngleUnit angleUnit) const { + Coordinate2D minimumOfOpposite = nextMinimumOfExpression(symbol, start, step, max, [](char symbol, double x, Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression0, const ExpressionReference expression1 = nullptr) { + return -expression0.approximateWithValueForSymbol(symbol, x, context, angleUnit); + }, context, angleUnit); + return {.abscissa = minimumOfOpposite.abscissa, .value = -minimumOfOpposite.value}; +} + +double ExpressionReference::nextRoot(char symbol, double start, double step, double max, Context & context, Preferences::AngleUnit angleUnit) const { + return nextIntersectionWithExpression(symbol, start, step, max, [](char symbol, double x, Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression0, const ExpressionReference expression1 = nullptr) { + return expression0.approximateWithValueForSymbol(symbol, x, context, angleUnit); + }, context, angleUnit, nullptr); +} + +typename ExpressionReference::Coordinate2D ExpressionReference::nextIntersection(char symbol, double start, double step, double max, Poincare::Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression) const { + double resultAbscissa = nextIntersectionWithExpression(symbol, start, step, max, [](char symbol, double x, Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression0, const ExpressionReference expression1) { + return expression0.approximateWithValueForSymbol(symbol, x, context, angleUnit)-expression1.approximateWithValueForSymbol(symbol, x, context, angleUnit); + }, context, angleUnit, expression); + typename ExpressionReference::Coordinate2D result = {.abscissa = resultAbscissa, .value = approximateWithValueForSymbol(symbol, resultAbscissa, context, angleUnit)}; + if (std::fabs(result.value) < step*k_solverPrecision) { + result.value = 0.0; + } + return result; +} + +typename ExpressionReference::Coordinate2D ExpressionReference::nextMinimumOfExpression(char symbol, double start, double step, double max, EvaluationAtAbscissa evaluate, Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression, bool lookForRootMinimum) const { + Coordinate2D result = {.abscissa = NAN, .value = NAN}; + if (start == max || step == 0.0) { + return result; + } + double bracket[3]; + double x = start; + bool endCondition = false; + do { + bracketMinimum(symbol, x, step, max, bracket, evaluate, context, angleUnit, expression); + result = brentMinimum(symbol, bracket[0], bracket[2], evaluate, context, angleUnit, expression); + x = bracket[1]; + // Because of float approximation, exact zero is never reached + if (std::fabs(result.abscissa) < std::fabs(step)*k_solverPrecision) { + result.abscissa = 0; + result.value = evaluate(symbol, 0, context, angleUnit, *this, expression); + } + /* Ignore extremum whose value is undefined or too big because they are + * really unlikely to be local extremum. */ + if (std::isnan(result.value) || std::fabs(result.value) > k_maxFloat) { + result.abscissa = NAN; + } + // Idem, exact 0 never reached + if (std::fabs(result.value) < std::fabs(step)*k_solverPrecision) { + result.value = 0; + } + endCondition = std::isnan(result.abscissa) && (step > 0.0 ? x <= max : x >= max); + if (lookForRootMinimum) { + endCondition |= std::fabs(result.value) > 0 && (step > 0.0 ? x <= max : x >= max); + } + } while (endCondition); + if (lookForRootMinimum) { + result.abscissa = std::fabs(result.value) > 0 ? NAN : result.abscissa; + } + return result; +} + +void ExpressionReference::bracketMinimum(char symbol, double start, double step, double max, double result[3], EvaluationAtAbscissa evaluate, Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression) const { + Coordinate2D p[3]; + p[0] = {.abscissa = start, .value = evaluate(symbol, start, context, angleUnit, *this, expression)}; + p[1] = {.abscissa = start+step, .value = evaluate(symbol, start+step, context, angleUnit, *this, expression)}; + double x = start+2.0*step; + while (step > 0.0 ? x <= max : x >= max) { + p[2] = {.abscissa = x, .value = evaluate(symbol, x, context, angleUnit, *this, expression)}; + if ((p[0].value > p[1].value || std::isnan(p[0].value)) && (p[2].value > p[1].value || std::isnan(p[2].value)) && (!std::isnan(p[0].value) || !std::isnan(p[2].value))) { + result[0] = p[0].abscissa; + result[1] = p[1].abscissa; + result[2] = p[2].abscissa; + return; + } + if (p[0].value > p[1].value && p[1].value == p[2].value) { + } else { + p[0] = p[1]; + p[1] = p[2]; + } + x += step; + } + result[0] = NAN; + result[1] = NAN; + result[2] = NAN; +} + +typename ExpressionReference::Coordinate2D ExpressionReference::brentMinimum(char symbol, double ax, double bx, EvaluationAtAbscissa evaluate, Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression) const { + /* Bibliography: R. P. Brent, Algorithms for finding zeros and extrema of + * functions without calculating derivatives */ + if (ax > bx) { + return brentMinimum(symbol, bx, ax, evaluate, context, angleUnit, expression); + } + double e = 0.0; + double a = ax; + double b = bx; + double x = a+k_goldenRatio*(b-a); + double v = x; + double w = x; + double fx = evaluate(symbol, x, context, angleUnit, *this, expression); + double fw = fx; + double fv = fw; + + double d = NAN; + double u, fu; + + for (int i = 0; i < 100; i++) { + double m = 0.5*(a+b); + double tol1 = k_sqrtEps*std::fabs(x)+1E-10; + double tol2 = 2.0*tol1; + if (std::fabs(x-m) <= tol2-0.5*(b-a)) { + double middleFax = evaluate(symbol, (x+a)/2.0, context, angleUnit, *this, expression); + double middleFbx = evaluate(symbol, (x+b)/2.0, context, angleUnit, *this, expression); + double fa = evaluate(symbol, a, context, angleUnit, *this, expression); + double fb = evaluate(symbol, b, context, angleUnit, *this, expression); + if (middleFax-fa <= k_sqrtEps && fx-middleFax <= k_sqrtEps && fx-middleFbx <= k_sqrtEps && middleFbx-fb <= k_sqrtEps) { + Coordinate2D result = {.abscissa = x, .value = fx}; + return result; + } + } + double p = 0; + double q = 0; + double r = 0; + if (std::fabs(e) > tol1) { + r = (x-w)*(fx-fv); + q = (x-v)*(fx-fw); + p = (x-v)*q -(x-w)*r; + q = 2.0*(q-r); + if (q>0.0) { + p = -p; + } else { + q = -q; + } + r = e; + e = d; + } + if (std::fabs(p) < std::fabs(0.5*q*r) && p= tol1 ? d : (d>0 ? tol1 : -tol1)); + fu = evaluate(symbol, u, context, angleUnit, *this, expression); + if (fu <= fx) { + if (u 0.0 ? x <= max : x >= max)); + + double extremumMax = std::isnan(result) ? max : result; + Coordinate2D resultExtremum[2] = { + nextMinimumOfExpression(symbol, start, step, extremumMax, [](char symbol, double x, Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression0, const ExpressionReference expression1) { + if (expression1.isDefined()) { + return expression0.approximateWithValueForSymbol(symbol, x, context, angleUnit)-expression1.approximateWithValueForSymbol(symbol, x, context, angleUnit); + } else { + return expression0.approximateWithValueForSymbol(symbol, x, context, angleUnit); + } + }, context, angleUnit, expression, true), + nextMinimumOfExpression(symbol, start, step, extremumMax, [](char symbol, double x, Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression0, const ExpressionReference expression1) { + if (expression1.isDefined()) { + return expression1.approximateWithValueForSymbol(symbol, x, context, angleUnit)-expression0.approximateWithValueForSymbol(symbol, x, context, angleUnit); + } else { + return -expression0.approximateWithValueForSymbol(symbol, x, context, angleUnit); + } + }, context, angleUnit, expression, true)}; + for (int i = 0; i < 2; i++) { + if (!std::isnan(resultExtremum[i].abscissa) && (std::isnan(result) || std::fabs(result - start) > std::fabs(resultExtremum[i].abscissa - start))) { + result = resultExtremum[i].abscissa; + } + } + if (std::fabs(result) < std::fabs(step)*k_solverPrecision) { + result = 0; + } + return result; +} + +void ExpressionReference::bracketRoot(char symbol, double start, double step, double max, double result[2], EvaluationAtAbscissa evaluation, Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression) const { + double a = start; + double b = start+step; + while (step > 0.0 ? b <= max : b >= max) { + double fa = evaluation(symbol, a, context, angleUnit, *this, expression); + double fb = evaluation(symbol, b, context, angleUnit,* this, expression); + if (fa*fb <= 0) { + result[0] = a; + result[1] = b; + return; + } + a = b; + b = b+step; + } + result[0] = NAN; + result[1] = NAN; +} + +double ExpressionReference::brentRoot(char symbol, double ax, double bx, double precision, EvaluationAtAbscissa evaluation, Context & context, Preferences::AngleUnit angleUnit, const ExpressionReference expression) const { + if (ax > bx) { + return brentRoot(symbol, bx, ax, precision, evaluation, context, angleUnit, expression); + } + double a = ax; + double b = bx; + double c = bx; + double d = b-a; + double e = b-a; + double fa = evaluation(symbol, a, context, angleUnit, *this, expression); + double fb = evaluation(symbol, b, context, angleUnit, *this, expression); + double fc = fb; + for (int i = 0; i < 100; i++) { + if ((fb > 0.0 && fc > 0.0) || (fb < 0.0 && fc < 0.0)) { + c = a; + fc = fa; + e = b-a; + d = b-a; + } + if (std::fabs(fc) < std::fabs(fb)) { + a = b; + b = c; + c = a; + fa = fb; + fb = fc; + fc = fa; + } + double tol1 = 2.0*DBL_EPSILON*std::fabs(b)+0.5*precision; + double xm = 0.5*(c-b); + if (std::fabs(xm) <= tol1 || fb == 0.0) { + double fbcMiddle = evaluation(symbol, 0.5*(b+c), context, angleUnit, *this, expression); + double isContinuous = (fb <= fbcMiddle && fbcMiddle <= fc) || (fc <= fbcMiddle && fbcMiddle <= fb); + if (isContinuous) { + return b; + } + } + if (std::fabs(e) >= tol1 && std::fabs(fa) > std::fabs(b)) { + double s = fb/fa; + double p = 2.0*xm*s; + double q = 1.0-s; + if (a != c) { + q = fa/fc; + double r = fb/fc; + p = s*(2.0*xm*q*(q-r)-(b-a)*(r-1.0)); + q = (q-1.0)*(r-1.0)*(s-1.0); + } + q = p > 0.0 ? -q : q; + p = std::fabs(p); + double min1 = 3.0*xm*q-std::fabs(tol1*q); + double min2 = std::fabs(e*q); + if (2.0*p < (min1 < min2 ? min1 : min2)) { + e = d; + d = p/q; + } else { + d = xm; + e =d; + } + } else { + d = xm; + e = d; + } + a = b; + fa = fb; + if (std::fabs(d) > tol1) { + b += d; + } else { + b += xm > 0.0 ? tol1 : tol1; + } + fb = evaluation(symbol, b, context, angleUnit, *this, expression); + } + return NAN; +} + +} diff --git a/poincare/src/factor.cpp b/poincare/src/factor.cpp index 01503dfd9..248147973 100644 --- a/poincare/src/factor.cpp +++ b/poincare/src/factor.cpp @@ -22,7 +22,7 @@ Expression * Factor::clone() const { return b; } -Expression * Factor::shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Factor::shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) { Expression * op = editableOperand(0); if (op->type() != Type::Rational) { return new Undefined(); diff --git a/poincare/src/factorial.cpp b/poincare/src/factorial.cpp index 2f0deecb4..88e2ac670 100644 --- a/poincare/src/factorial.cpp +++ b/poincare/src/factorial.cpp @@ -36,7 +36,7 @@ bool Factorial::needParenthesisWithParent(const Expression * e) const { /* Simplification */ -Expression * Factorial::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Factorial::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; @@ -66,7 +66,7 @@ Expression * Factorial::shallowReduce(Context& context, Preferences::AngleUnit a return this; } -Expression * Factorial::shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Factorial::shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) { // +(a,b)! ->(+(a,b))! if (operand(0)->type() == Type::Addition || operand(0)->type() == Type::Multiplication || operand(0)->type() == Type::Power) { const Expression * o[1] = {operand(0)}; diff --git a/poincare/src/floor.cpp b/poincare/src/floor.cpp index f498edf18..bd5e23ba1 100644 --- a/poincare/src/floor.cpp +++ b/poincare/src/floor.cpp @@ -20,7 +20,7 @@ Expression * Floor::clone() const { return c; } -Expression * Floor::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Floor::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/frac_part.cpp b/poincare/src/frac_part.cpp index 219a2756a..019fb5076 100644 --- a/poincare/src/frac_part.cpp +++ b/poincare/src/frac_part.cpp @@ -17,7 +17,7 @@ Expression * FracPart::clone() const { return c; } -Expression * FracPart::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference FracPart::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/global_context.cpp b/poincare/src/global_context.cpp index 0042604c8..116aa7243 100644 --- a/poincare/src/global_context.cpp +++ b/poincare/src/global_context.cpp @@ -53,10 +53,10 @@ Decimal * GlobalContext::defaultExpression() { } int GlobalContext::symbolIndex(const Symbol * symbol) const { - if (symbol->isMatrixSymbol()) { + if (SymbolReference::isMatrixSymbol(symbol->name())) { return symbol->name() - (char)Symbol::SpecialSymbols::M0; } - if (symbol->isScalarSymbol()) { + if (SymbolReference::isScalarSymbol(symbol->name())) { return symbol->name() - 'A'; } return -1; @@ -73,7 +73,7 @@ const Expression * GlobalContext::expressionForSymbol(const Symbol * symbol) { return &m_e; } int index = symbolIndex(symbol); - if (symbol->isMatrixSymbol()) { + if (SymbolReference::isMatrixSymbol(symbol->name()) { return m_matrixExpressions[index]; } if (index < 0 || index >= k_maxNumberOfScalarExpressions) { @@ -86,7 +86,7 @@ const Expression * GlobalContext::expressionForSymbol(const Symbol * symbol) { } LayoutRef GlobalContext::layoutForSymbol(const Symbol * symbol, int numberOfSignificantDigits) { - if (symbol->isMatrixSymbol()) { + if (SymbolReference::isMatrixSymbol(symbol->name()) { int index = symbolIndex(symbol); if (!m_matrixLayouts[index].isDefined() && m_matrixExpressions[index] != nullptr) { m_matrixLayouts[index] = m_matrixExpressions[index]->createLayout(Preferences::PrintFloatMode::Decimal, numberOfSignificantDigits); @@ -98,7 +98,7 @@ LayoutRef GlobalContext::layoutForSymbol(const Symbol * symbol, int numberOfSign void GlobalContext::setExpressionForSymbolName(const Expression * expression, const Symbol * symbol, Context & context) { int index = symbolIndex(symbol); - if (symbol->isMatrixSymbol()) { + if (SymbolReference::isMatrixSymbol(symbol->name()) { int indexMatrix = symbol->name() - (char)Symbol::SpecialSymbols::M0; assert(indexMatrix >= 0 && indexMatrix < k_maxNumberOfMatrixExpressions); Expression * evaluation = expression ? expression->approximate(context, Preferences::sharedPreferences()->angleUnit(), Preferences::sharedPreferences()->complexFormat()) : nullptr; // evaluate before deleting anything (to be able to evaluate M1+2->M1) diff --git a/poincare/src/great_common_divisor.cpp b/poincare/src/great_common_divisor.cpp index 7ed8ce783..ef0069bff 100644 --- a/poincare/src/great_common_divisor.cpp +++ b/poincare/src/great_common_divisor.cpp @@ -19,7 +19,7 @@ Expression * GreatCommonDivisor::clone() const { return a; } -Expression * GreatCommonDivisor::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference GreatCommonDivisor::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/hyperbolic_arc_cosine.cpp b/poincare/src/hyperbolic_arc_cosine.cpp index ded66656c..a1954c459 100644 --- a/poincare/src/hyperbolic_arc_cosine.cpp +++ b/poincare/src/hyperbolic_arc_cosine.cpp @@ -17,7 +17,7 @@ Expression * HyperbolicArcCosine::clone() const { return a; } -Expression * HyperbolicArcCosine::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference HyperbolicArcCosine::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/hyperbolic_arc_sine.cpp b/poincare/src/hyperbolic_arc_sine.cpp index 5e78c5f7b..2fd88acda 100644 --- a/poincare/src/hyperbolic_arc_sine.cpp +++ b/poincare/src/hyperbolic_arc_sine.cpp @@ -17,7 +17,7 @@ Expression * HyperbolicArcSine::clone() const { return a; } -Expression * HyperbolicArcSine::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference HyperbolicArcSine::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/hyperbolic_arc_tangent.cpp b/poincare/src/hyperbolic_arc_tangent.cpp index e1d136ef6..87d990d53 100644 --- a/poincare/src/hyperbolic_arc_tangent.cpp +++ b/poincare/src/hyperbolic_arc_tangent.cpp @@ -17,7 +17,7 @@ Expression * HyperbolicArcTangent::clone() const { return a; } -Expression * HyperbolicArcTangent::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference HyperbolicArcTangent::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/hyperbolic_cosine.cpp b/poincare/src/hyperbolic_cosine.cpp index d9d94d760..cdad8a2cc 100644 --- a/poincare/src/hyperbolic_cosine.cpp +++ b/poincare/src/hyperbolic_cosine.cpp @@ -21,7 +21,7 @@ Expression * HyperbolicCosine::clone() const { return a; } -Expression * HyperbolicCosine::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference HyperbolicCosine::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/hyperbolic_sine.cpp b/poincare/src/hyperbolic_sine.cpp index 2e88eba62..214194281 100644 --- a/poincare/src/hyperbolic_sine.cpp +++ b/poincare/src/hyperbolic_sine.cpp @@ -21,7 +21,7 @@ Expression * HyperbolicSine::clone() const { return a; } -Expression * HyperbolicSine::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference HyperbolicSine::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/hyperbolic_tangent.cpp b/poincare/src/hyperbolic_tangent.cpp index 115d1cee8..f6feebb89 100644 --- a/poincare/src/hyperbolic_tangent.cpp +++ b/poincare/src/hyperbolic_tangent.cpp @@ -20,7 +20,7 @@ Expression * HyperbolicTangent::clone() const { return a; } -Expression * HyperbolicTangent::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference HyperbolicTangent::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/imaginary_part.cpp b/poincare/src/imaginary_part.cpp index be4f6503e..3f8c89d59 100644 --- a/poincare/src/imaginary_part.cpp +++ b/poincare/src/imaginary_part.cpp @@ -18,7 +18,7 @@ Expression * ImaginaryPart::clone() const { } -Expression * ImaginaryPart::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference ImaginaryPart::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; @@ -30,7 +30,7 @@ Expression * ImaginaryPart::shallowReduce(Context& context, Preferences::AngleUn } #endif if (op->type() == Type::Rational) { - return replaceWith(new Rational(0), true); + return replaceWith(RationalReference(0), true); } return this; } diff --git a/poincare/src/infinity.cpp b/poincare/src/infinity.cpp new file mode 100644 index 000000000..c4929eec2 --- /dev/null +++ b/poincare/src/infinity.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +extern "C" { +#include +#include +} + +namespace Poincare { + +LayoutRef InfinityNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + char buffer[5]; + int numberOfChars = writeTextInBuffer(buffer, 5, floatDisplayMode, numberOfSignificantDigits); + return LayoutEngine::createStringLayout(buffer, numberOfChars); +} + +int InfinityNode::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + if (bufferSize == 0) { + return -1; + } + return PrintFloat::convertFloatToText(m_negative ? -INFINITY : INFINITY, buffer, bufferSize, numberOfSignificantDigits, floatDisplayMode); +} + +template EvaluationReference InfinityNode::templatedApproximate() const { + return ComplexReference(INFINITY); +} + +} + diff --git a/poincare/src/integer.cpp b/poincare/src/integer.cpp index d06b8e11b..f4542d268 100644 --- a/poincare/src/integer.cpp +++ b/poincare/src/integer.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include extern "C" { @@ -11,24 +12,23 @@ extern "C" { } #include #include -#include namespace Poincare { static inline int max(int x, int y) { return (x>y ? x : y); } -uint8_t log2(Integer::native_uint_t v) { - constexpr int nativeUnsignedIntegerBitCount = 8*sizeof(Integer::native_uint_t); +uint8_t log2(native_uint_t v) { + constexpr int nativeUnsignedIntegerBitCount = 8*sizeof(native_uint_t); static_assert(nativeUnsignedIntegerBitCount < 256, "uint8_t cannot contain the log2 of a native_uint_t"); for (uint8_t i=0; i= '0' && *digits <= '9') { - result = Multiplication(result, base); - result = Addition(result, Integer(*digits-'0')); - digits++; - } + IntegerReference base(10); + IntegerReference ref(this); + IntegerDivisionReference d = IntegerReference::Division(ref, base); + int size = 0; + if (bufferSize == 1) { + return 0; } - - *this = std::move(result); - if (isZero()) { - negative = false; + buffer[size++] = '0'; } - m_negative = negative; -} - -Integer Integer::exponent(int fractionalPartLength, const char * exponent, int exponentLength, bool exponentNegative) { - Integer base = Integer(10); - Integer power = Integer(0); - for (int i = 0; i < exponentLength; i++) { - power = Multiplication(power, base); - power = Addition(power, Integer(*exponent-'0')); - exponent++; - } - if (exponentNegative) { - power.setNegative(true); - } - return Subtraction(Integer(fractionalPartLength), power); -} - -Integer Integer::numerator(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, bool negative, Integer * exponent) { - Integer base = Integer(10); - Integer numerator = Integer(integralPart, negative); - for (int i = 0; i < fractionalPartLength; i++) { - numerator = Multiplication(numerator, base); - numerator = Addition(numerator, Integer(*fractionalPart-'0')); - fractionalPart++; - } - if (exponent->isNegative()) { - while (!exponent->isEqualTo(Integer(0))) { - numerator = Multiplication(numerator, base); - *exponent = Addition(*exponent, Integer(1)); + while (!(d.remainder.isZero() && + d.quotient.isZero())) { + char c = char_from_digit(d.remainder.digit(0)); + if (size >= bufferSize-1) { + return strlcpy(buffer, "undef", bufferSize); } + buffer[size++] = c; + d = IntegerReference::Division(d.quotient, base); } - return numerator; + buffer[size] = 0; + + // Flip the string + for (int i=0, j=size-1 ; i < j ; i++, j--) { + char c = buffer[i]; + buffer[i] = buffer[j]; + buffer[j] = c; + } + return size; } -Integer Integer::denominator(Integer * exponent) { - Integer base = Integer(10); - Integer denominator = Integer(1); - if (!exponent->isNegative()) { - while (!exponent->isEqualTo(Integer(0))) { - denominator = Multiplication(denominator, base); - *exponent = Subtraction(*exponent, Integer(1)); - } - } - return denominator; +LayoutRef NaturalIntegerAbstract::createLayout() const { + char buffer[k_maxNumberOfDigitsBase10]; + int numberOfChars = writeTextInBuffer(buffer, k_maxNumberOfDigitsBase10); + return LayoutEngine::createStringLayout(buffer, numberOfChars); } -Integer::~Integer() { - releaseDynamicIvars(); -} - -Integer::Integer(Integer && other) { - // Pilfer other's data - if (other.usesImmediateDigit()) { - m_digit = other.m_digit; - } else { - m_digits = other.m_digits; - } - m_numberOfDigits = other.m_numberOfDigits; - m_negative = other.m_negative; - - // Reset other - other.m_digit = 0; - other.m_numberOfDigits = 1; - other.m_negative = 0; -} - -Integer::Integer(const Integer& other) { - // Copy other's data - if (other.usesImmediateDigit()) { - m_digit = other.m_digit; - } else { - native_uint_t * digits = new native_uint_t [other.m_numberOfDigits]; - for (int i=0; i1) { - productSize--; - /* At this point we could realloc m_digits to a smaller size. */ - } - - return Integer(digits, productSize, a.m_negative != b.m_negative); -} - -Integer Integer::Factorial(const Integer & i) { - Integer j = Integer(2); - Integer result = Integer(1); - while (!i.isLowerThan(j)) { - result = Multiplication(j, result); - j = Addition(j, Integer(1)); - } - return result; -} - -IntegerDivision Integer::Division(const Integer & numerator, const Integer & denominator) { - if (!numerator.isNegative() && !denominator.isNegative()) { - return udiv(numerator, denominator); - } - Integer absNumerator = numerator; - absNumerator.setNegative(false); - Integer absDenominator = denominator; - absDenominator.setNegative(false); - IntegerDivision usignedDiv = udiv(absNumerator, absDenominator); - if (usignedDiv.remainder.isEqualTo(Integer(0))) { - if (!numerator.isNegative() || !denominator.isNegative()) { - usignedDiv.quotient.setNegative(true); - } - return usignedDiv; - } - if (numerator.isNegative()) { - if (denominator.isNegative()) { - usignedDiv.remainder.setNegative(true); - usignedDiv.quotient = Addition(usignedDiv.quotient, Integer(1)); - usignedDiv.remainder = Integer::Subtraction(usignedDiv.remainder, denominator); - } else { - usignedDiv.quotient.setNegative(true); - usignedDiv.quotient = Subtraction(usignedDiv.quotient, Integer(1)); - usignedDiv.remainder = Integer::Subtraction(denominator, usignedDiv.remainder); - } - } else { - assert(denominator.isNegative()); - usignedDiv.quotient.setNegative(true); - } - return usignedDiv; -} - -Integer Integer::Power(const Integer & i, const Integer & j) { - // TODO: optimize with dichotomia - assert(!j.isNegative()); - Integer index = j; - Integer result = Integer(1); - while (!index.isEqualTo(Integer(0))) { - result = Multiplication(result, i); - index = Subtraction(index, Integer(1)); - } - return result; -} - -int Integer::numberOfDigitsWithoutSign(const Integer & i) { - int numberOfDigits = 1; - Integer copy = i; - copy.setNegative(false); - IntegerDivision d = Integer::Division(copy, Integer(10)); - while (!d.quotient.isZero()) { - copy = d.quotient; - d = Integer::Division(copy, Integer(10)); - numberOfDigits++; - } - return numberOfDigits; -} - -// Private methods - - /* WARNING: This constructor takes ownership of the digits array! */ -Integer::Integer(const native_uint_t * digits, uint16_t numberOfDigits, bool negative) : - m_numberOfDigits(numberOfDigits), - m_negative(negative) -{ - assert(digits != nullptr); - if (numberOfDigits == 1) { - m_digit = digits[0]; - delete[] digits; - if (isZero()) { - // Normalize zero - m_negative = false; - } - } else { - assert(numberOfDigits > 1); - m_digits = digits; - } -} - -void Integer::releaseDynamicIvars() { - if (!usesImmediateDigit()) { - assert(m_digits != nullptr); - delete[] m_digits; - } -} - -int8_t Integer::ucmp(const Integer & a, const Integer & b) { - if (a.m_numberOfDigits < b.m_numberOfDigits) { - return -1; - } else if (a.m_numberOfDigits > b.m_numberOfDigits) { - return 1; - } - for (uint16_t i = 0; i < a.m_numberOfDigits; i++) { - // Digits are stored most-significant last - native_uint_t aDigit = a.digit(a.m_numberOfDigits-i-1); - native_uint_t bDigit = b.digit(b.m_numberOfDigits-i-1); - if (aDigit < bDigit) { - return -1; - } else if (aDigit > bDigit) { - return 1; - } - } - return 0; -} - -Integer Integer::usum(const Integer & a, const Integer & b, bool subtract, bool outputNegative) { - uint16_t size = max(a.m_numberOfDigits, b.m_numberOfDigits); - if (!subtract) { - // Addition can overflow - size += 1; - } - native_uint_t * digits = new native_uint_t [size]; - bool carry = false; - for (uint16_t i = 0; i= a.m_numberOfDigits ? 0 : a.digit(i)); - native_uint_t bDigit = (i >= b.m_numberOfDigits ? 0 : b.digit(i)); - native_uint_t result = (subtract ? aDigit - bDigit - carry : aDigit + bDigit + carry); - digits[i] = result; - if (subtract) { - carry = (aDigit < result) || (carry && aDigit == result); // There's been an underflow - } else { - carry = (aDigit > result) || (bDigit > result); // There's been an overflow - } - } - while (digits[size-1] == 0 && size>1) { - size--; - // We could realloc digits to a smaller size. Probably not worth the trouble. - } - return Integer(digits, size, outputNegative); -} - - -Integer Integer::addition(const Integer & a, const Integer & b, bool inverseBNegative) { - bool bNegative = (inverseBNegative ? !b.m_negative : b.m_negative); - if (a.m_negative == bNegative) { - return usum(a, b, false, a.m_negative); - } else { - /* The signs are different, this is in fact a subtraction - * s = a+b = (abs(a)-abs(b) OR abs(b)-abs(a)) - * 1/abs(a)>abs(b) : s = sign*udiff(a, b) - * 2/abs(b)>abs(a) : s = sign*udiff(b, a) - * sign? sign of the greater! */ - if (ucmp(a, b) >= 0) { - return usum(a, b, true, a.m_negative); - } else { - return usum(b, a, true, bNegative); - } - } -} - -Integer Integer::IntegerWithHalfDigitAtIndex(half_native_uint_t halfDigit, int index) { - assert(halfDigit != 0); - half_native_uint_t * digits = (half_native_uint_t *)new native_uint_t [(index+1)/2]; - memset(digits, 0, (index+1)/2*sizeof(native_uint_t)); - digits[index-1] = halfDigit; - int indexInBase32 = index%2 == 1 ? index/2+1 : index/2; - return Integer((native_uint_t *)digits, indexInBase32, false); -} - -IntegerDivision Integer::udiv(const Integer & numerator, const Integer & denominator) { - /* Modern Computer Arithmetic, Richard P. Brent and Paul Zimmermann - * (Algorithm 1.6) */ - assert(!denominator.isZero()); - if (numerator.isLowerThan(denominator)) { - IntegerDivision div = {.quotient = 0, .remainder = numerator}; - return div; - } - - Integer A = numerator; - Integer B = denominator; - native_int_t base = 1 << 16; - // TODO: optimize by just swifting digit and finding 2^kB that makes B normalized - native_int_t d = base/(native_int_t)(B.halfDigit(B.numberOfHalfDigits()-1)+1); - A = Multiplication(Integer(d), A); - B = Multiplication(Integer(d), B); - - int n = B.numberOfHalfDigits(); - int m = A.numberOfHalfDigits()-n; - half_native_uint_t * qDigits = (half_native_uint_t *)new native_uint_t [m/2+1]; - memset(qDigits, 0, (m/2+1)*sizeof(native_uint_t)); - Integer betam = IntegerWithHalfDigitAtIndex(1, m+1); - Integer betaMB = Multiplication(betam, B); // TODO: can swift all digits by m! B.swift16(mg) - if (!A.isLowerThan(betaMB)) { - qDigits[m] = 1; - A = Subtraction(A, betaMB); - } - for (int j = m-1; j >= 0; j--) { - native_uint_t qj2 = ((native_uint_t)A.halfDigit(n+j)*base+(native_uint_t)A.halfDigit(n+j-1))/(native_uint_t)B.halfDigit(n-1); - half_native_uint_t baseMinus1 = (1 << 16) -1; - qDigits[j] = qj2 < (native_uint_t)baseMinus1 ? (half_native_uint_t)qj2 : baseMinus1; - Integer factor = qDigits[j] > 0 ? IntegerWithHalfDigitAtIndex(qDigits[j], j+1) : Integer(0); - A = Subtraction(A, Multiplication(factor, B)); - Integer m = Multiplication(IntegerWithHalfDigitAtIndex(1, j+1), B); - while (A.isLowerThan(Integer(0))) { - qDigits[j] = qDigits[j]-1; - A = Addition(A, m); - } - } - int qNumberOfDigits = m+1; - while (qDigits[qNumberOfDigits-1] == 0 && qNumberOfDigits > 1) { - qNumberOfDigits--; - // We could realloc digits to a smaller size. Probably not worth the trouble. - } - int qNumberOfDigitsInBase32 = qNumberOfDigits%2 == 1 ? qNumberOfDigits/2+1 : qNumberOfDigits/2; - IntegerDivision div = {.quotient = Integer((native_uint_t *)qDigits, qNumberOfDigitsInBase32, false), .remainder = A}; - if (d != 1 && !div.remainder.isZero()) { - div.remainder = udiv(div.remainder, Integer(d)).quotient; - } - return div; -} +// Approximation template -T Integer::approximate() const { +T NaturalIntegerAbstract::approximate() const { if (isZero()) { /* This special case for 0 is needed, because the current algorithm assumes * that the big integer is non zero, thus puts the exponent to 126 (integer * area), the issue is that when the mantissa is 0, a "shadow bit" is * assumed to be there, thus 126 0x000000 is equal to 0.5 and not zero. */ - T result = m_negative ? -0.0 : 0.0; - return result; + return (T)0.0; } assert(sizeof(T) == 4 || sizeof(T) == 8); /* We're generating an IEEE 754 compliant float(double). @@ -513,8 +109,6 @@ T Integer::approximate() const { native_uint_t lastDigit = digit(m_numberOfDigits-1); uint8_t numberOfBitsInLastDigit = log2(lastDigit); - bool sign = m_negative; - uint16_t exponent = IEEE754::exponentOffset(); /* Escape case if the exponent is too big to be stored */ if ((m_numberOfDigits-1)*32+numberOfBitsInLastDigit-1> IEEE754::maxExponent()-IEEE754::exponentOffset()) { @@ -548,7 +142,7 @@ T Integer::approximate() const { digitIndex++; } - T result = IEEE754::buildFloat(sign, exponent, mantissa); + T result = IEEE754::buildFloat(false, exponent, mantissa); /* If exponent is 255 and the float is undefined, we have exceed IEEE 754 * representable float. */ @@ -558,58 +152,532 @@ T Integer::approximate() const { return result; } -int Integer::writeTextInBuffer(char * buffer, int bufferSize) const { +// Properties + +int NaturalIntegerAbstract::numberOfDigits(const NaturalIntegerAbstract * i) { + int numberOfDigits = 1; + IntegerReference ref(i); + IntegerReference base(10); + IntegerDivisionReference d = IntegerReference::Division(ref, base); + while (!d.quotient.isZero()) { + ref = d.quotient; + d = IntegerReference::Division(ref, base); + numberOfDigits++; + } + return numberOfDigits; +} + +// Arithmetic + +int8_t NaturalIntegerAbstract::ucmp(const NaturalIntegerAbstract * a, const NaturalIntegerAbstract * b) { + if (a->m_numberOfDigits < b->m_numberOfDigits) { + return -1; + } else if (a->m_numberOfDigits > b->m_numberOfDigits) { + return 1; + } + for (uint16_t i = 0; i < a->m_numberOfDigits; i++) { + // Digits are stored most-significant last + native_uint_t aDigit = a->digit(a->m_numberOfDigits-i-1); + native_uint_t bDigit = b->digit(b->m_numberOfDigits-i-1); + if (aDigit < bDigit) { + return -1; + } else if (aDigit > bDigit) { + return 1; + } + } + return 0; +} + +IntegerReference NaturalIntegerAbstract::usum(const NaturalIntegerAbstract * a, const NaturalIntegerAbstract * b, bool subtract) { + size_t size = max(a->m_numberOfDigits, b->m_numberOfDigits); + if (!subtract) { + // Addition can overflow + size++; + } + // Overflow + if (size > k_maxNumberOfDigits + 1) { + return IntegerReference::Overflow(); + } + native_uint_t digits[k_maxNumberOfDigits+1]; + bool carry = false; + for (size_t i = 0; i < size; i++) { + native_uint_t aDigit = (i >= a->m_numberOfDigits ? 0 : a->digit(i)); + native_uint_t bDigit = (i >= b->m_numberOfDigits ? 0 : b->digit(i)); + native_uint_t result = (subtract ? aDigit - bDigit - carry : aDigit + bDigit + carry); + digits[i] = result; + if (subtract) { + carry = (aDigit < result) || (carry && aDigit == result); // There's been an underflow + } else { + carry = (aDigit > result) || (bDigit > result); // There's been an overflow + } + } + while (digits[size-1] == 0 && size>1) { + size--; + } + if (size > k_maxNumberOfDigits) { + return IntegerReference::Overflow(); + } + return IntegerReference::IntegerReference(digits, size, false); +} + +IntegerReference NaturalIntegerAbstract::umult(const NaturalIntegerAbstract * a, const NaturalIntegerAbstract * b){ + size_t size = a->m_numberOfDigits + b->m_numberOfDigits; + // Overflow + if (size > k_maxNumberOfDigits + 1) { + return IntegerReference::Overflow(); + } + + native_uint_t digits[k_maxNumberOfDigits+1]; + memset(digits, 0, size*sizeof(native_uint_t)); + + double_native_uint_t carry = 0; + for (size_t i=0; im_numberOfDigits; i++) { + double_native_uint_t aDigit = a->digit(i); + carry = 0; + for (size_t j=0; jm_numberOfDigits; j++) { + double_native_uint_t bDigit = b->digit(j); + /* The fact that aDigit and bDigit are double_native is very important, + * otherwise the product might end up being computed on single_native size + * and then zero-padded. */ + double_native_uint_t p = aDigit*bDigit + carry + (double_native_uint_t)(digits[i+j]); // TODO: Prove it cannot overflow double_native type + native_uint_t * l = (native_uint_t *)&p; + digits[i+j] = l[0]; + carry = l[1]; + } + digits[i+b->m_numberOfDigits] += carry; + } + + while (digits[size-1] == 0 && size>1) { + size--; + } + // Overflow + if (size > k_maxNumberOfDigits + 1) { + return IntegerReference::Overflow(); + } + return IntegerReference::IntegerReference(digits, size, false); +} + +// TODO: OPTIMIZE +IntegerDivisionReference NaturalIntegerAbstract::udiv(const NaturalIntegerAbstract * numerator, const NaturalIntegerAbstract * denominator) { + /* Modern Computer Arithmetic, Richard P. Brent and Paul Zimmermann + * (Algorithm 1.6) */ + assert(!denominator->isZero()); + if (ucmp(numerator,denominator) < 0) { + IntegerDivisionReference div = {.quotient = IntegerReference(0), .remainder = IntegerReference(numerator)}; + return div; + } + + IntegerReference A(numerator); + IntegerReference B(denominator); + native_int_t base = 1 << 16; + // TODO: optimize by just swifting digit and finding 2^kB that makes B normalized + // Afterwards, we require B to hold Integer node, we check then for allocation failures + if (B.isAllocationFailure()) { + return {.quotient = IntegerReference(ExpressionNode::FailedAllocationStaticNode()), .remainder = IntegerReference(ExpressionNode::FailedAllocationStaticNode())}; + } + native_int_t d = base/(native_int_t)(B.typedNode()->halfDigit(B.typedNode()->numberOfHalfDigits()-1)+1); + A = IntegerReference::Multiplication(IntegerReference(d), A); + B = IntegerReference::Multiplication(IntegerReference(d), B); + + // Afterwards, we require A and B to hold Integer node, we check then for allocation failures + if (A.isAllocationFailure() || B.isAllocationFailure()) { + return {.quotient = IntegerReference(ExpressionNode::FailedAllocationStaticNode()), .remainder = IntegerReference(ExpressionNode::FailedAllocationStaticNode())}; + } + int n = B.typedNode()->numberOfHalfDigits(); + int m = A.typedNode()->numberOfHalfDigits()-n; + half_native_uint_t qDigits[k_maxNumberOfDigits+1]; + memset(qDigits, 0, (m/2+1)*sizeof(native_uint_t)); + IntegerReference betam = IntegerWithHalfDigitAtIndex(1, m+1); + IntegerReference betaMB = IntegerReference::Multiplication(betam, B); // TODO: can swift all digits by m! B.swift16(mg) + if (IntegerReference::NaturalOrder(A,betaMB) > 0) { + qDigits[m] = 1; + A = IntegerReference::Subtraction(A, betaMB); + } + for (int j = m-1; j >= 0; j--) { + // Afterwards, we require A to hold Integer node, we check then for allocation failure + if (A.isAllocationFailure()) { + return {.quotient = IntegerReference(ExpressionNode::FailedAllocationStaticNode()), .remainder = IntegerReference(ExpressionNode::FailedAllocationStaticNode())}; + } + native_uint_t qj2 = ((native_uint_t)A.typedNode()->halfDigit(n+j)*base+(native_uint_t)A.typedNode()->halfDigit(n+j-1))/(native_uint_t)B.typedNode()->halfDigit(n-1); + half_native_uint_t baseMinus1 = (1 << 16) -1; + qDigits[j] = qj2 < (native_uint_t)baseMinus1 ? (half_native_uint_t)qj2 : baseMinus1; + IntegerReference factor = qDigits[j] > 0 ? IntegerWithHalfDigitAtIndex(qDigits[j], j+1) : IntegerReference(0); + A = IntegerReference::Subtraction(A, IntegerReference::Multiplication(factor, B)); + IntegerReference m = IntegerReference::Multiplication(IntegerWithHalfDigitAtIndex(1, j+1), B); + while (A.sign() == ExpressionNode::Sign::Negative) { + qDigits[j] = qDigits[j]-1; + A = IntegerReference::Addition(A, m); + } + } + int qNumberOfDigits = m+1; + while (qDigits[qNumberOfDigits-1] == 0 && qNumberOfDigits > 1) { + qNumberOfDigits--; + } + int qNumberOfDigitsInBase32 = qNumberOfDigits%2 == 1 ? qNumberOfDigits/2+1 : qNumberOfDigits/2; + IntegerDivisionReference div = {.quotient = IntegerReference((native_uint_t *)qDigits, qNumberOfDigitsInBase32, false), .remainder = A}; + if (d != 1 && !div.remainder.isZero()) { + IntegerReference dReference(d); + if (div.remainder.isAllocationFailure() || dReference.isAllocationFailure()) { + return {.quotient = IntegerReference(ExpressionNode::FailedAllocationStaticNode()), .remainder = IntegerReference(ExpressionNode::FailedAllocationStaticNode())}; + } + div.remainder = udiv(div.remainder.typedNode(), dReference.typedNode()).quotient; + } + return div; +} + +IntegerReference NaturalIntegerAbstract::upow(const NaturalIntegerAbstract * i, const NaturalIntegerAbstract * j) { + // TODO: optimize with dichotomia + IntegerReference index(j); + IntegerReference result(1); + while (!index.isZero()) { + result = IntegerReference::Multiplication(result, i); + index = IntegerReference::Subtraction(index, IntegerReference(1)); + } + return result; +} + +IntegerReference NaturalIntegerAbstract::ufact(const NaturalIntegerAbstract * i) { + IntegerReference j(2); + if (j.isAllocationFailure()) { + return IntegerReference(ExpressionNode::FailedAllocationStaticNode()); + } + IntegerReference result(1); + while (ucmp(i,j.typedNode()) > 0) { + result = IntegerReference::Multiplication(j, result); + j = IntegerReference::Addition(j, IntegerReference(1)); + } + return result; +} + +IntegerReference NaturalIntegerAbstract::IntegerWithHalfDigitAtIndex(half_native_uint_t halfDigit, int index) { + assert(halfDigit != 0); + // Overflow + if ((index + 1)/2) { + return IntegerReference::Overflow(); + } + half_native_uint_t digits[k_maxNumberOfDigits+1]; + memset(digits, 0, (index+1)/2*sizeof(native_uint_t)); + digits[index-1] = halfDigit; + int indexInBase32 = index%2 == 1 ? index/2+1 : index/2; + return IntegerReference((native_uint_t *)digits, indexInBase32, false); +} + +/* Natural Integer Pointer */ + +NaturalIntegerPointer::NaturalIntegerPointer(native_uint_t * buffer, size_t size) : + NaturalIntegerAbstract(size) +{ + memcpy(m_digits, buffer, size*sizeof(native_uint_t)); +} + +/* Integer Node */ + +void IntegerNode::setDigits(native_int_t i) { + if (i == 0) { + m_numberOfDigits = 0; + m_negative = false; + return; + } + m_negative = i < 0; + m_digits[0] = i < 0 ? -i : i; + m_numberOfDigits = 1; +} + +void IntegerNode::setDigits(double_native_int_t i) { + if (i == 0) { + m_numberOfDigits = 0; + m_negative = false; + return; + } + double_native_uint_t j = i < 0 ? -i : i; + native_uint_t * digits = (native_uint_t *)&j; + native_uint_t leastSignificantDigit = *digits; + native_uint_t mostSignificantDigit = *(digits+1); + m_numberOfDigits = (mostSignificantDigit == 0) ? 1 : 2; + m_digits[0] = leastSignificantDigit; + if (m_numberOfDigits > 1) { + digits[1] = mostSignificantDigit; + } + m_negative = i < 0; + +} +void IntegerNode::setDigits(const native_uint_t * digits, size_t size, bool negative) { + memcpy(m_digits, digits, size*sizeof(native_uint_t)); + m_numberOfDigits = size; + m_negative = negative; +} + +ExpressionReference IntegerNode::shallowReduce(Context & context, Preferences::AngleUnit angleUnit) { + return RationalReference(IntegerReference((NaturalIntegerAbstract *)this), IntegerReference(1)); +} + +template +T IntegerNode::templatedApproximate() const { + T a = NaturalIntegerAbstract::approximate(); + return m_negative ? -a : a; +} + +// Layout + +LayoutRef IntegerNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + LayoutRef naturalLayout = NaturalIntegerAbstract::createLayout(); + if (m_negative) { + naturalLayout.addChildAtIndex(CharLayoutRef('-'), 0, naturalLayout.numberOfChildren(), nullptr); + } + return naturalLayout; +} + +int IntegerNode::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { if (bufferSize == 0) { return -1; } buffer[bufferSize-1] = 0; - /* If the integer is too long, this method may be too slow. - * Experimentally, we can display at most integer whose number of digits is - * around 25. */ - if (m_numberOfDigits > 25) { - return strlcpy(buffer, "undef", bufferSize); + int numberOfChar = 0; + if (m_negative) { + buffer[numberOfChar++] = '-'; } + if (numberOfChar >= bufferSize-1) { + return bufferSize-1; + } + numberOfChar += NaturalIntegerAbstract::writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + return numberOfChar; +} - Integer base = Integer(10); - Integer abs = *this; - abs.setNegative(false); - IntegerDivision d = udiv(abs, base); +size_t IntegerNode::size() const { + return m_numberOfDigits*sizeof(native_uint_t)+sizeof(IntegerNode); +} + +ExpressionReference IntegerNode::setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit) { + setNegative(s == Sign::Negative); + return IntegerReference((NaturalIntegerAbstract *)this); +} + +void IntegerNode::setNegative(bool negative) { + if (isZero()) { // Zero cannot be negative + return; + } + m_negative = negative; +} + +int IntegerNode::NaturalOrder(const IntegerNode * i, const IntegerNode * j) { + if (i->sign() == Sign::Negative && j->sign() == Sign::Positive) { + return -1; + } + if (i->sign() == Sign::Positive && j->sign() == Sign::Negative) { + return 1; + } + return ::Poincare::sign(i->sign() == Sign::Negative)*ucmp(i, j); +} + +/* IntegerReference */ + +IntegerReference::IntegerReference(const native_uint_t * digits, size_t numberOfDigits, bool negative) : + IntegerReference(numberOfDigits*sizeof(native_uint_t)+sizeof(IntegerNode)) +{ + if (node()->isAllocationFailure()) { + return; + } + if (numberOfDigits == 1 && digits[0] == 0) { + negative = false; + } + typedNode()->setDigits(digits, numberOfDigits, negative); +} + +IntegerReference::IntegerReference(const char * digits, size_t length, bool negative) { + if (digits != nullptr && digits[0] == '-') { + negative = true; + digits++; + } + native_uint_t buffer[IntegerNode::k_maxNumberOfDigits]; + double_native_uint_t d = 0; int size = 0; - if (bufferSize == 1) { + if (digits != nullptr) { + for (size_t s = 0; s < length; s++) { + if (d*10+(*digits-'0') > 0xFFFFFFFF) { + buffer[size++] = d; + d = 0; + } + d = 10*d+(*digits-'0'); + digits++; + } + } + buffer[size++] = d; + *this = IntegerReference(buffer, size, negative); +} + +IntegerReference::IntegerReference(const NaturalIntegerAbstract * naturalInteger) : + IntegerReference(naturalInteger->numberOfDigits()*sizeof(native_uint_t)+sizeof(IntegerNode)) +{ + if (!node()->isAllocationFailure()) { + typedNode()->setDigits(naturalInteger->digits(), naturalInteger->numberOfDigits(), false); + } +} + +IntegerReference::IntegerReference(native_int_t i) : + IntegerReference(i == 0 ? sizeof(IntegerNode) : sizeof(IntegerNode)+sizeof(native_uint_t)) +{ + if (!node()->isAllocationFailure()) { + typedNode()->setDigits(i); + } +} + +IntegerReference::IntegerReference(double_native_int_t i) +{ + double_native_uint_t j = i; + if (i == 0) { + *this = IntegerReference(sizeof(IntegerNode)); + } else if (j <= 0xFFFFFFFF) { + *this = IntegerReference(sizeof(IntegerNode)+sizeof(native_uint_t)); + } else { + *this = IntegerReference(sizeof(IntegerNode)+2*sizeof(native_uint_t)); + } + if (!node()->isAllocationFailure()) { + typedNode()->setDigits(i); + } +} + +int IntegerReference::extractedInt() const { + if (isAllocationFailure()) { return 0; } - if (isEqualTo(Integer(0))) { - buffer[size++] = '0'; - } else if (isNegative()) { - buffer[size++] = '-'; + assert(numberOfDigits() == 1 && digit(0) <= k_maxExtractableInteger); + return node()->sign() == ExpressionNode::Sign::Negative ? -digit(0) : digit(0); +} + +int IntegerReference::NaturalOrder(const IntegerReference i, const IntegerReference j) { + if (i.isAllocationFailure() || j.isAllocationFailure()) { + return 0; } - while (!(d.remainder.isEqualTo(Integer(0)) && - d.quotient.isEqualTo(Integer(0)))) { - char c = char_from_digit(d.remainder.digit(0)); - if (size >= bufferSize-1) { - return strlcpy(buffer, "undef", bufferSize); + return IntegerNode::NaturalOrder(i.typedNode(), j.typedNode()); +} + +bool IntegerReference::isZero() const { + if (isAllocationFailure()) { + return false; + } + return typedNode()->isZero(); +} + +bool IntegerReference::isOne() const { + if (isAllocationFailure()) { + return false; + } + return typedNode()->isOne(); +} + +bool IntegerReference::isInfinity() const { + if (isAllocationFailure()) { + return false; + } + return typedNode()->isInfinity(); +} + +bool IntegerReference::isEven() const { + if (isAllocationFailure()) { + return false; + } + return typedNode()->isEven(); +} + +void IntegerReference::setNegative(bool negative) { + if (!isAllocationFailure()) { + return typedNode()->setNegative(negative); + } +} + +// Arithmetic + +IntegerReference IntegerReference::Addition(const IntegerReference a, const IntegerReference b) { + return addition(a, b, false); +} + +IntegerReference IntegerReference::Subtraction(const IntegerReference a, const IntegerReference b) { + return addition(a, b, true); +} + +IntegerReference IntegerReference::Multiplication(const IntegerReference a, const IntegerReference b) { + if (a.isAllocationFailure() || b.isAllocationFailure()) { + return IntegerReference(ExpressionNode::FailedAllocationStaticNode()); + } + IntegerReference um = IntegerNode::umult(a.typedNode(), b.typedNode()); + um.setNegative(a.sign() != b.sign()); + return um; +} + +IntegerDivisionReference IntegerReference::Division(const IntegerReference numerator, const IntegerReference denominator) { + if (numerator.isAllocationFailure() || denominator.isAllocationFailure()) { + return {.quotient = IntegerReference(ExpressionNode::FailedAllocationStaticNode()), .remainder = IntegerReference(ExpressionNode::FailedAllocationStaticNode())}; + } + IntegerDivisionReference ud = IntegerNode::udiv(numerator.typedNode(), denominator.typedNode()); + if (numerator.sign() == ExpressionNode::Sign::Positive && denominator.sign() == ExpressionNode::Sign::Positive) { + return ud; + } + if (NaturalOrder(ud.remainder, IntegerReference(0)) == 0) { + if (numerator.sign() == ExpressionNode::Sign::Positive || denominator.sign() == ExpressionNode::Sign::Positive) { + ud.quotient.setNegative(true); } - buffer[size++] = c; - d = Division(d.quotient, base); + return ud; } - buffer[size] = 0; - - // Flip the string - for (int i=m_negative, j=size-1 ; i < j ; i++, j--) { - char c = buffer[i]; - buffer[i] = buffer[j]; - buffer[j] = c; + if (numerator.sign() == ExpressionNode::Sign::Negative) { + if (denominator.sign() == ExpressionNode::Sign::Negative) { + ud.remainder.setNegative(true); + ud.quotient = Addition(ud.quotient, IntegerReference(1)); + ud.remainder = Subtraction(ud.remainder, denominator); + } else { + ud.quotient.setNegative(true); + ud.quotient = Subtraction(ud.quotient, IntegerReference(1)); + ud.remainder = Subtraction(denominator, ud.remainder); + } + } else { + assert(denominator.sign() == ExpressionNode::Sign::Negative); + ud.quotient.setNegative(true); } - return size; + return ud; } -LayoutRef Integer::createLayout() const { - char buffer[255]; - int numberOfChars = writeTextInBuffer(buffer, 255); - return LayoutEngine::createStringLayout(buffer, numberOfChars); +IntegerReference IntegerReference::Power(const IntegerReference i, const IntegerReference j) { + if (i.isAllocationFailure() || j.isAllocationFailure()) { + return IntegerReference(ExpressionNode::FailedAllocationStaticNode()); + } + assert(j.sign() == ExpressionNode::Sign::Positive); + IntegerReference upow = IntegerNode::upow(i.typedNode(), j.typedNode()); + upow.setNegative(i.sign() == ExpressionNode::Sign::Negative && !j.isEven()); + return upow; } -template float Poincare::Integer::approximate() const; -template double Poincare::Integer::approximate() const; +IntegerReference IntegerReference::Factorial(const IntegerReference i) { + if (i.isAllocationFailure()) { + return IntegerReference(ExpressionNode::FailedAllocationStaticNode()); + } + assert(i.sign() == ExpressionNode::Sign::Positive); + return IntegerNode::ufact(i.typedNode()); +} + +IntegerReference IntegerReference::addition(const IntegerReference a, const IntegerReference b, bool inverseBNegative) { + if (a.isAllocationFailure() || b.isAllocationFailure()) { + return IntegerReference(ExpressionNode::FailedAllocationStaticNode()); + } + bool bNegative = (inverseBNegative ? b.sign() == ExpressionNode::Sign::Positive : b.sign() == ExpressionNode::Sign::Negative); + if ((a.sign() == ExpressionNode::Sign::Negative) == bNegative) { + IntegerReference us = IntegerNode::usum(a.typedNode(), b.typedNode(), false); + us.setNegative(a.sign() == ExpressionNode::Sign::Negative); + return us; + } else { + /* The signs are different, this is in fact a subtraction + * s = a+b = (abs(a)-abs(b) OR abs(b)-abs(a)) + * 1/abs(a)>abs(b) : s = sign*udiff(a, b) + * 2/abs(b)>abs(a) : s = sign*udiff(b, a) + * sign? sign of the greater! */ + if (IntegerNode::ucmp(a.typedNode(), b.typedNode()) >= 0) { + IntegerReference us = IntegerNode::usum(a.typedNode(), b.typedNode(), true); + us.setNegative(a.sign() == ExpressionNode::Sign::Negative); + return us; + } else { + IntegerReference us = IntegerNode::usum(a.typedNode(), b.typedNode(), true); + us.setNegative(bNegative); + return us; + } + } +} } diff --git a/poincare/src/integral.cpp b/poincare/src/integral.cpp index f258dd783..3e421979a 100644 --- a/poincare/src/integral.cpp +++ b/poincare/src/integral.cpp @@ -31,7 +31,7 @@ int Integral::polynomialDegree(char symbolName) const { return Expression::polynomialDegree(symbolName); } -Expression * Integral::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Integral::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/layout_engine.cpp b/poincare/src/layout_engine.cpp index 5a8270905..1d36670ba 100644 --- a/poincare/src/layout_engine.cpp +++ b/poincare/src/layout_engine.cpp @@ -70,96 +70,6 @@ LayoutRef LayoutEngine::createLogLayout(LayoutRef argument, LayoutRef index) { return resultLayout; } -int LayoutEngine::writeInfixExpressionTextInBuffer(const Expression * expression, char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfDigits, const char * operatorName) { - return writeInfixExpressionOrExpressionLayoutTextInBuffer(expression, nullptr, buffer, bufferSize,floatDisplayMode, numberOfDigits, operatorName, 0, -1); -} - -int LayoutEngine::writePrefixExpressionTextInBuffer(const Expression * expression, char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfDigits, const char * operatorName) { - return writePrefixExpressionOrExpressionLayoutTextInBuffer(expression, nullptr, buffer, bufferSize, floatDisplayMode, numberOfDigits, operatorName); -} - -int LayoutEngine::writeInfixExpressionOrExpressionLayoutTextInBuffer(const Expression * expression, void * expressionLayout, char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfDigits, const char * operatorName, int firstChildIndex, int lastChildIndex) { - assert(expression != nullptr && expressionLayout == nullptr); - if (bufferSize == 0) { - return -1; - } - buffer[bufferSize-1] = 0; - int numberOfChar = 0; - int numberOfOperands = expression->numberOfOperands(); - assert(numberOfOperands > 0); - if (numberOfChar >= bufferSize-1) { - return bufferSize-1; - } - - if (expression->operand(firstChildIndex)->needParenthesisWithParent(expression)) { - buffer[numberOfChar++] = '('; - if (numberOfChar >= bufferSize-1) { - return bufferSize-1; - } - } - - numberOfChar += expression->operand(firstChildIndex)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfDigits); - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - if (expression->operand(firstChildIndex)->needParenthesisWithParent(expression)) { - buffer[numberOfChar++] = ')'; - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - } - int lastIndex = lastChildIndex < 0 ? numberOfOperands - 1 : lastChildIndex; - for (int i = firstChildIndex + 1; i < lastIndex+1; i++) { - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - numberOfChar += strlcpy(buffer+numberOfChar, operatorName, bufferSize-numberOfChar); - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - if (expression->operand(i)->needParenthesisWithParent(expression)) { - buffer[numberOfChar++] = '('; - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - } - numberOfChar += expression->operand(i)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfDigits); - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - if (expression->operand(i)->needParenthesisWithParent(expression)) { - buffer[numberOfChar++] = ')'; - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - } - } - buffer[numberOfChar] = 0; - return numberOfChar; -} - -int LayoutEngine::writePrefixExpressionOrExpressionLayoutTextInBuffer(const Expression * expression, void * expressionLayout, char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfDigits, const char * operatorName, bool writeFirstChild) { - assert(expression != nullptr && expressionLayout == nullptr); - if (bufferSize == 0) { - return -1; - } - buffer[bufferSize-1] = 0; - int numberOfChar = strlcpy(buffer, operatorName, bufferSize); - if (numberOfChar >= bufferSize-1) { - return bufferSize-1; - } - - buffer[numberOfChar++] = '('; - if (numberOfChar >= bufferSize-1) { - return bufferSize-1; - } - - int numberOfOperands = expression->numberOfOperands(); - if (numberOfOperands > 0) { - if (!writeFirstChild) { - assert(numberOfOperands > 1); - } - int firstOperandIndex = writeFirstChild ? 0 : 1; - numberOfChar += expression->operand(firstOperandIndex)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfDigits); - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - for (int i = firstOperandIndex + 1; i < numberOfOperands; i++) { - buffer[numberOfChar++] = ','; - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - numberOfChar += expression->operand(i)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfDigits); - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - } - } - buffer[numberOfChar++] = ')'; - buffer[numberOfChar] = 0; - return numberOfChar; -} - /* SerializableReference to Text */ int LayoutEngine::writeInfixSerializableRefTextInBuffer( const SerializableRef serializableRef, diff --git a/poincare/src/least_common_multiple.cpp b/poincare/src/least_common_multiple.cpp index acd805e98..2b281bd3b 100644 --- a/poincare/src/least_common_multiple.cpp +++ b/poincare/src/least_common_multiple.cpp @@ -19,7 +19,7 @@ Expression * LeastCommonMultiple::clone() const { return a; } -Expression * LeastCommonMultiple::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference LeastCommonMultiple::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/logarithm.cpp b/poincare/src/logarithm.cpp index a1fbb763e..f9b54e35a 100644 --- a/poincare/src/logarithm.cpp +++ b/poincare/src/logarithm.cpp @@ -39,7 +39,7 @@ Expression * Logarithm::simpleShallowReduce(Context & context, Preferences::Angl Expression * op = editableOperand(0); // log(x,x)->1 if (numberOfOperands() == 2 && op->isIdenticalTo(operand(1))) { - return replaceWith(new Rational(1), true); + return replaceWith(RationalReference(1), true); } if (op->type() == Type::Rational) { const Rational * r = static_cast(operand(0)); @@ -49,17 +49,17 @@ Expression * Logarithm::simpleShallowReduce(Context & context, Preferences::Angl } // log(1) = 0; if (r->isOne()) { - return replaceWith(new Rational(0), true); + return replaceWith(RationalReference(0), true); } // log(10) ->1 if (numberOfOperands() == 1 && r->isTen()) { - return replaceWith(new Rational(1), true); + return replaceWith(RationalReference(1), true); } } return this; } -Expression * Logarithm::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Logarithm::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; @@ -162,7 +162,7 @@ Expression * Logarithm::splitInteger(Integer i, bool isDenominator, Context & co assert(!i.isZero()); assert(!i.isNegative()); if (i.isOne()) { - return new Rational(0); + return RationalReference(0); } assert(!i.isOne()); Integer factors[Arithmetic::k_maxNumberOfPrimeFactors]; @@ -209,7 +209,7 @@ Expression * Logarithm::shallowBeautify(Context & context, Preferences::AngleUni } template -Evaluation * Logarithm::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { +EvaluationReference Logarithm::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { if (numberOfOperands() == 1) { return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } diff --git a/poincare/src/matrix.cpp b/poincare/src/matrix.cpp index cae9c20ed..951fb1d67 100644 --- a/poincare/src/matrix.cpp +++ b/poincare/src/matrix.cpp @@ -2,14 +2,7 @@ extern "C" { #include #include } -#include #include -#include -#include -#include -#include -#include -#include #include #include #include @@ -17,41 +10,28 @@ extern "C" { namespace Poincare { -Matrix::Matrix(MatrixData * matrixData) : - DynamicHierarchy() -{ - assert(matrixData != nullptr); - m_numberOfOperands = matrixData->numberOfRows()*matrixData->numberOfColumns(); - m_numberOfRows = matrixData->numberOfRows(); - matrixData->pilferOperands(&m_operands); - for (int i = 0; i < m_numberOfOperands; i++) { - const_cast(m_operands[i])->setParent(this); +int MatrixNode::polynomialDegree(char symbolName) const { + return -1; +} + +LayoutRef MatrixNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + MatrixLayoutRef layout; + /* To keep track of the number of children, number of columns is set to 1 and + * number of rows is incremented with each child addition. The real number of + * rows and columns is properly set once all children are added. */ + layout.setNumberOfRows(0); + layout.setNumberOfColumns(1); + LayoutRef castedLayout(layout.node()); + for (int i = 0; i < numberOfChildren(); i++) { + castedLayout.addChildAtIndex(childAtIndex(i)->createLayout(floatDisplayMode, numberOfSignificantDigits), i, i, nullptr); + layout.setNumberOfRows(i+1); } + layout.setNumberOfRows(m_numberOfRows); + layout.setNumberOfColumns(m_numberOfColumns); + return layout; } -Matrix::Matrix(const Expression * const * operands, int numberOfRows, int numberOfColumns, bool cloneOperands) : - DynamicHierarchy(operands, numberOfRows*numberOfColumns, cloneOperands), - m_numberOfRows(numberOfRows) -{ -} - -int Matrix::numberOfRows() const { - return m_numberOfRows; -} - -int Matrix::numberOfColumns() const { - return numberOfOperands()/m_numberOfRows; -} - -Expression::Type Matrix::type() const { - return Type::Matrix; -} - -Expression * Matrix::clone() const { - return new Matrix(m_operands, numberOfRows(), numberOfColumns(), true); -} - -int Matrix::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { +int MatrixNode::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { if (bufferSize == 0) { return -1; } @@ -64,21 +44,21 @@ int Matrix::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintF if (currentChar >= bufferSize-1) { return currentChar; } - for (int i = 0; i < numberOfRows(); i++) { + for (int i = 0; i < m_numberOfRows; i++) { buffer[currentChar++] = '['; if (currentChar >= bufferSize-1) { return currentChar; } - currentChar += operand(i*numberOfColumns())->writeTextInBuffer(buffer+currentChar, bufferSize-currentChar, floatDisplayMode, numberOfSignificantDigits); + currentChar += childAtIndex(i*m_numberOfColumns)->writeTextInBuffer(buffer+currentChar, bufferSize-currentChar, floatDisplayMode, numberOfSignificantDigits); if (currentChar >= bufferSize-1) { return currentChar; } - for (int j = 1; j < numberOfColumns(); j++) { + for (int j = 1; j < m_numberOfColumns; j++) { buffer[currentChar++] = ','; if (currentChar >= bufferSize-1) { return currentChar; } - currentChar += operand(i*numberOfColumns()+j)->writeTextInBuffer(buffer+currentChar, bufferSize-currentChar, floatDisplayMode, numberOfSignificantDigits); + currentChar += childAtIndex(i*m_numberOfColumns+j)->writeTextInBuffer(buffer+currentChar, bufferSize-currentChar, floatDisplayMode, numberOfSignificantDigits); if (currentChar >= bufferSize-1) { return currentChar; } @@ -97,15 +77,39 @@ int Matrix::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintF return currentChar; } -int Matrix::polynomialDegree(char symbolName) const { - return -1; +template +EvaluationReference MatrixNode::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { + MatrixComplexReference matrix(m.numberOfRows(), m.numberOfColumns()); + for (int i = 0; i < numberOfChildren(); i++) { + EvaluationReference operandEvaluation = childAtIndex(i)->approximate(T(), context, angleUnit); + if (operandEvaluation.node()->type() != Evaluation::Type::Complex) { + result.addChildTreeAtIndex(ComplexReference::Undefined(), i, i); + } else { + result.addChildTreeAtIndex(compute(*child, angleUnit), i, i); + } + } + return matrix; } -void Matrix::rowCanonize(Context & context, Preferences::AngleUnit angleUnit, Multiplication * determinant) { - // The matrix has to be reduced to be able to spot 0 inside it - for (int i = 0; i < numberOfOperands(); i++) { - editableOperand(i)->deepReduce(context, angleUnit); +int MatrixReference::numberOfRows() const { + if (isAllocationFailure()) { + return 0; } + return typedNode()->numberOfRows(); +} + +int MatrixReference::numberOfColumns() const { + if (isAllocationFailure()) { + return 0; + } + return typedNode()->numberOfColumns(); +} + +void MatrixReference::rowCanonize(Context & context, Preferences::AngleUnit angleUnit, MultiplicationReference determinant) { + // The matrix has to be reduced to be able to spot 0 inside it + ExpressionReference reduced = deepReduce(context, angleUnit); + assert(reduced == *this); + int m = numberOfRows(); int n = numberOfColumns(); @@ -115,47 +119,47 @@ void Matrix::rowCanonize(Context & context, Preferences::AngleUnit angleUnit, Mu while (h < m && k < n) { // Find the first non-null pivot int iPivot = h; - while (iPivot < m && matrixOperand(iPivot, k)->isRationalZero()) { + while (iPivot < m && matrixChild(iPivot, k)->isRationalZero()) { iPivot++; } if (iPivot == m) { // No non-null coefficient in this column, skip k++; // Update determinant: det *= 0 - if (determinant) { determinant->addOperand(new Rational(0)); } + if (determinant) { determinant.addChildTreeAtIndex(RationalReference(0), 0, determinant.numberOfChildren()); } } else { // Swap row h and iPivot if (iPivot != h) { for (int col = h; col < n; col++) { - swapOperands(iPivot*n+col, h*n+col); + swapChildren(iPivot*n+col, h*n+col); } // Update determinant: det *= -1 - if (determinant) { determinant->addOperand(new Rational(-1)); } + if (determinant) { determinant.addChildTreeAtIndex(RationalReference(-1), 0, determinant.numberOfChildren()); } } /* Set to 1 M[h][k] by linear combination */ - Expression * divisor = matrixOperand(h, k); + ExpressionReference divisor = matrixChild(h, k); // Update determinant: det *= divisor - if (determinant) { determinant->addOperand(divisor->clone()); } + if (determinant) { determinant.addChildTreeAtIndex(divisor.clone()); } for (int j = k+1; j < n; j++) { - Expression * opHJ = matrixOperand(h, j); - Expression * newOpHJ = new Division(opHJ, divisor->clone(), false); + ExpressionReference opHJ = matrixChild(h, j); + ExpressionReference newOpHJ = DivisionReference(opHJ, divisor.clone()); replaceOperand(opHJ, newOpHJ, false); newOpHJ->shallowReduce(context, angleUnit); } - matrixOperand(h, k)->replaceWith(new Rational(1), true); + matrixChild(h, k)->replaceWith(RationalReference(1), true); /* Set to 0 all M[i][j] i != h, j > k by linear combination */ for (int i = 0; i < m; i++) { if (i == h) { continue; } - Expression * factor = matrixOperand(i, k); + Expression * factor = matrixChild(i, k); for (int j = k+1; j < n; j++) { - Expression * opIJ = matrixOperand(i, j); - Expression * newOpIJ = new Subtraction(opIJ, new Multiplication(matrixOperand(h, j), factor, true), false); + Expression * opIJ = matrixChild(i, j); + Expression * newOpIJ = new Subtraction(opIJ, new Multiplication(matrixChild(h, j), factor, true), false); replaceOperand(opIJ, newOpIJ, false); newOpIJ->editableOperand(1)->shallowReduce(context, angleUnit); newOpIJ->shallowReduce(context, angleUnit); } - matrixOperand(i, k)->replaceWith(new Rational(0), true); + matrixChild(i, k)->replaceWith(RationalReference(0), true); } h++; k++; @@ -164,7 +168,7 @@ void Matrix::rowCanonize(Context & context, Preferences::AngleUnit angleUnit, Mu } template -void Matrix::ArrayRowCanonize(T * array, int numberOfRows, int numberOfColumns, T * determinant) { +void MatrixReference::ArrayRowCanonize(T * array, int numberOfRows, int numberOfColumns, T * determinant) { int h = 0; // row pivot int k = 0; // column pivot @@ -215,31 +219,15 @@ void Matrix::ArrayRowCanonize(T * array, int numberOfRows, int numberOfColumns, } } -LayoutRef Matrix::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - MatrixLayoutRef layout; - /* To keep track of the number of children, number of columns is set to 1 and - * number of rows is incremented with each child addition. The real number of - * rows and columns is properly set once all children are added. */ - layout.setNumberOfRows(0); - layout.setNumberOfColumns(1); - LayoutRef castedLayout(layout.node()); - for (int i = 0; i < numberOfOperands(); i++) { - castedLayout.addChildAtIndex(operand(i)->createLayout(floatDisplayMode, numberOfSignificantDigits), i, i, nullptr); - layout.setNumberOfRows(i+1); - } - layout.setNumberOfRows(numberOfRows()); - layout.setNumberOfColumns(numberOfColumns()); - return layout; -} -int Matrix::rank(Context & context, Preferences::AngleUnit angleUnit, bool inPlace) { +int MatrixReference::rank(Context & context, Preferences::AngleUnit angleUnit, bool inPlace) { Matrix * m = inPlace ? this : static_cast(clone()); m->rowCanonize(context, angleUnit); - int rank = m->numberOfRows(); + int rank = m->m_numberOfRows; int i = rank-1; while (i >= 0) { - int j = m->numberOfColumns()-1; - while (j >= i && matrixOperand(i,j)->isRationalZero()) { + int j = m->m_numberOfColumns-1; + while (j >= i && matrixChild(i,j)->isRationalZero()) { j--; } if (j == i-1) { @@ -256,7 +244,7 @@ int Matrix::rank(Context & context, Preferences::AngleUnit angleUnit, bool inPla } template -int Matrix::ArrayInverse(T * array, int numberOfRows, int numberOfColumns) { +int MatrixReference::ArrayInverse(T * array, int numberOfRows, int numberOfColumns) { if (numberOfRows != numberOfColumns) { return -1; } @@ -289,27 +277,27 @@ int Matrix::ArrayInverse(T * array, int numberOfRows, int numberOfColumns) { } #if MATRIX_EXACT_REDUCING -Matrix * Matrix::createTranspose() const { - const Expression ** operands = new const Expression * [numberOfOperands()]; - for (int i = 0; i < numberOfRows(); i++) { - for (int j = 0; j < numberOfColumns(); j++) { - operands[j*numberOfRows()+i] = operand(i*numberOfColumns()+j); +Matrix * MatrixReference::createTranspose() const { + const Expression ** operands = new const Expression * [numberOfChildren()]; + for (int i = 0; i < m_numberOfRows; i++) { + for (int j = 0; j < m_numberOfColumns; j++) { + operands[j*m_numberOfRows+i] = childAtIndex(i*m_numberOfColumns+j); } } // Intentionally swapping dimensions for transpose - Matrix * matrix = new Matrix(operands, numberOfColumns(), numberOfRows(), true); + Matrix * matrix = new Matrix(operands, m_numberOfColumns, m_numberOfRows, true); delete[] operands; return matrix; } -Matrix * Matrix::createIdentity(int dim) { +Matrix * MatrixReference::createIdentity(int dim) { Expression ** operands = new Expression * [dim*dim]; for (int i = 0; i < dim; i++) { for (int j = 0; j < dim; j++) { if (i == j) { - operands[i*dim+j] = new Rational(1); + operands[i*dim+j] = RationalReference(1); } else { - operands[i*dim+j] = new Rational(0); + operands[i*dim+j] = RationalReference(0); } } } @@ -318,19 +306,19 @@ Matrix * Matrix::createIdentity(int dim) { return matrix; } -Expression * Matrix::createInverse(Context & context, Preferences::AngleUnit angleUnit) const { - if (numberOfRows() != numberOfColumns()) { +Expression * MatrixReference::createInverse(Context & context, Preferences::AngleUnit angleUnit) const { + if (m_numberOfRows != m_numberOfColumns) { return new Undefined(); } - int dim = numberOfRows(); + int dim = m_numberOfRows; /* Create the matrix inv = (A|I) with A the input matrix and I the dim identity matrix */ const Expression ** operands = new const Expression * [dim*dim*2]; for (int i = 0; i < dim; i++) { for (int j = 0; j < dim; j++) { - operands[i*2*dim+j] = operand(i*dim+j)->clone(); + operands[i*2*dim+j] = childAtIndex(i*dim+j)->clone(); } for (int j = dim; j < 2*dim; j++) { - operands[i*2*dim+j] = j-dim == i ? new Rational(1) : new Rational(0); + operands[i*2*dim+j] = j-dim == i ? RationalReference(1) : RationalReference(0); } } Matrix * AI = new Matrix(operands, dim, 2*dim, false); @@ -338,7 +326,7 @@ Expression * Matrix::createInverse(Context & context, Preferences::AngleUnit ang AI->rowCanonize(context, angleUnit); // Check inversibility for (int i = 0; i < dim; i++) { - if (AI->matrixOperand(i, i)->type() != Type::Rational || !static_cast(AI->matrixOperand(i, i))->isOne()) { + if (AI->matrixChild(i, i)->type() != Type::Rational || !static_cast(AI->matrixChild(i, i))->isOne()) { delete AI; return new Undefined; } @@ -346,7 +334,7 @@ Expression * Matrix::createInverse(Context & context, Preferences::AngleUnit ang const Expression ** invOperands = new const Expression * [dim*dim]; for (int i = 0; i < dim; i++) { for (int j = 0; j < dim; j++) { - invOperands[i*dim+j] = AI->matrixOperand(i, j+dim); + invOperands[i*dim+j] = AI->matrixChild(i, j+dim); AI->detachOperandAtIndex(i*2*dim+j+dim); } } @@ -358,29 +346,11 @@ Expression * Matrix::createInverse(Context & context, Preferences::AngleUnit ang #endif -template -Evaluation * Matrix::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { - std::complex * operands = new std::complex [numberOfOperands()]; - for (int i = 0; i < numberOfOperands(); i++) { - Evaluation * operandEvaluation = operand(i)->privateApproximate(T(), context, angleUnit); - if (operandEvaluation->type() != Evaluation::Type::Complex) { - operands[i] = Complex::Undefined(); - } else { - std::complex * c = static_cast *>(operandEvaluation); - operands[i] = *c; - } - delete operandEvaluation; - } - MatrixComplex * matrix = new MatrixComplex(operands, numberOfRows(), numberOfColumns()); - delete[] operands; - return matrix; -} - -template int Matrix::ArrayInverse(float *, int, int); -template int Matrix::ArrayInverse(double *, int, int); -template int Matrix::ArrayInverse>(std::complex *, int, int); -template int Matrix::ArrayInverse>(std::complex *, int, int); -template void Matrix::ArrayRowCanonize >(std::complex*, int, int, std::complex*); -template void Matrix::ArrayRowCanonize >(std::complex*, int, int, std::complex*); +template int MatrixReference::ArrayInverse(float *, int, int); +template int MatrixReference::ArrayInverse(double *, int, int); +template int MatrixReference::ArrayInverse>(std::complex *, int, int); +template int MatrixReference::ArrayInverse>(std::complex *, int, int); +template void MatrixReference::ArrayRowCanonize >(std::complex*, int, int, std::complex*); +template void MatrixReference::ArrayRowCanonize >(std::complex*, int, int, std::complex*); } diff --git a/poincare/src/matrix_complex.cpp b/poincare/src/matrix_complex.cpp new file mode 100644 index 000000000..cce53ca08 --- /dev/null +++ b/poincare/src/matrix_complex.cpp @@ -0,0 +1,181 @@ +extern "C" { +#include +#include +#include +} +#include +//#include +#include +#include +#include +#include + +namespace Poincare { + +template +void MatrixComplexNode::setMatrixComplexDimension(int numberOfRows, int numberOfColumns) { + m_numberOfRows = numberOfRows; + m_numberOfColumns = numberOfColumns; +} + +template +ComplexNode * childAtIndex(int index) { + EvaluationNode child = EvaluationNode::childAtIndex(index); + if (child->type() == EvaluationNode::Type::Complex) { + return static_cast *>(child); + } + return nullptr; +} + +template +bool MatrixComplexNode::isUndefined() const { + if (numberOfRows() != 1 || numberOfColumns() != 1) { + return false; + } + ComplexNode * child = childAtIndex(0); + if (child && std::isnan((child->real()) && std::isnan(child->imag()))) { + return true; + } + return false; +} + +template +ExpressionReference MatrixComplexNode::complexToExpression(Preferences::ComplexFormat complexFormat) const { + MatrixReference matrix(numberOfRows(), numberOfColumns()); + for (int i = 0; i < numberOfComplexOperands(); i++) { + ComplexNode * child = childAtIndex(i); + if (child) { + matrix.addChildTreeAtIndex(child->complexToExpression(complexFormat), i, i); + } else { + matrix.addChildTreeAtIndex(UndefinedReference(), i, i); + } + } + return matrix; +} + +template +std::complex MatrixComplexNode::trace() const { + if (numberOfRows() != numberOfColumns()) { + return std::complex(NAN, NAN); + } + int dim = numberOfRows(); + std::complex c = std::complex(0); + for (int i = 0; i < dim; i++) { + ComplexNode * child = childAtIndex(i*dim+i); + if (child == nullptr) { + c = std::complex(NAN, NAN); + break; + } + c += *child; + } + return c; +} + +template +std::complex MatrixComplexNode::determinant() const { + if (numberOfRows() != numberOfColumns() || numberOfComplexOperands() > k_maxNumberOfCoefficients) { + return std::complex(NAN, NAN); + } + std::complex operandsCopy[k_maxNumberOfCoefficients]; + for (int i=0; i * child = childAtIndex(i); + if (child == nullptr) { + return std::complex(NAN, NAN); + } + operandsCopy[i] = *child; + } + std::complex determinant = std::complex(1); + MatrixReference::ArrayRowCanonize(operandsCopy, m_numberOfRows, m_numberOfColumns, &determinant); + return determinant; +} + +template +EvaluationReference MatrixComplexNode::inverse() const { + if (numberOfRows() != numberOfColumns() || numberOfComplexOperands() > k_maxNumberOfCoefficients) { + return MatrixComplexReference::Undefined(); + } + std::complex operandsCopy[k_maxNumberOfCoefficients]; + for (int i=0; i * child = childAtIndex(i); + if (child == nullptr) { + return EvaluationReference(EvaluationNode::FailedAllocationStaticNode()); + } + operandsCopy[i] = *child; + } + int result = MatrixReference::ArrayInverse(operandsCopy, m_numberOfRows, m_numberOfColumns); + if (result == 0) { + // Intentionally swapping dimensions for inverse, although it doesn't make a difference because it is square + return MatrixComplexReference(operandsCopy, m_numberOfColumns, m_numberOfRows); + } + return MatrixComplexReference::Undefined(); +} + +template +EvaluationReference MatrixComplexNode::transpose() const { + // Intentionally swapping dimensions for transpose + MatrixComplexReference result(numberOfColumns(), numberOfRows()); + for (int i = 0; i < numberOfRows(); i++) { + for (int j = 0; j < numberOfColumns(); j++) { + ComplexNode * child = childAtIndex(i*numberOfColumns()+i); + if (child) { + result.addChildTreeAtIndex(child, j*numberOfRows()+i, j*numberOfRows()+i); + } else { + result.addChildTreeAtIndex(ComplexReference::Undefined(), j*numberOfRows()+i, j*numberOfRows()+i); + } + } + } + return result; +} + +template +MatrixComplexReference::MatrixComplexReference(int numberOfRows, int numberOfColumns) : + EvaluationReference() +{ + TreeNode * node = TreePool::sharedPool()->createTreeNode>(); + this->m_identifier = node->identifier(); + if (!(node->isAllocationFailure())) { + static_cast *>(node)->setMatrixComplexDimension(numberOfRows, numberOfColumns); + } +} + +template +MatrixComplexReference::MatrixComplexReference(std::complex * operands, int numberOfRows, int numberOfColumns) : + MatrixComplexReference(numberOfRows, numberOfColumns) +{ + for (int i=0; iaddChildTreeAtIndex(ComplexReference(operands[i]), i, i); + } +} + +template +MatrixComplexReference MatrixComplexReference::createIdentity(int dim) { + MatrixComplexReference result(dim, dim); + for (int i = 0; i < dim; i++) { + for (int j = 0; j < dim; j++) { + ComplexReference c = i == j ? ComplexReference(1.0) : ComplexReference(0.0); + result.addChildTreeAtIndex(c, i*dim+j, i*dim+j); + } + } + return result; +} + +template +int MatrixComplexReference::numberOfRows() const { + if (this->node()->isAllocationFailure()) { + return 0; + } + return this->node()->numberOfRows(); +} + +template +int MatrixComplexReference::numberOfColumns() const { + if (this->node()->isAllocationFailure()) { + return 0; + } + return this->node()->numberOfColumns(); +} + +template class MatrixComplexReference; +template class MatrixComplexReference; + +} diff --git a/poincare/src/matrix_dimension.cpp b/poincare/src/matrix_dimension.cpp index e059bd738..46c3eefef 100644 --- a/poincare/src/matrix_dimension.cpp +++ b/poincare/src/matrix_dimension.cpp @@ -16,7 +16,7 @@ Expression * MatrixDimension::clone() const { return a; } -Expression * MatrixDimension::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference MatrixDimension::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; @@ -29,18 +29,18 @@ Expression * MatrixDimension::shallowReduce(Context& context, Preferences::Angle return replaceWith(new Matrix(newOperands, 1, 2, false), true); } if (!op->recursivelyMatches(Expression::IsMatrix)) { - const Expression * newOperands[2] = {new Rational(1), new Rational(1)}; + const Expression * newOperands[2] = {RationalReference(1), RationalReference(1)}; return replaceWith(new Matrix(newOperands, 1, 2, false), true); } return this; #else - const Expression * newOperands[2] = {new Rational(1), new Rational(1)}; + const Expression * newOperands[2] = {RationalReference(1), RationalReference(1)}; return replaceWith(new Matrix(newOperands, 1, 2, false), true); #endif } template -Evaluation * MatrixDimension::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { +EvaluationReference MatrixDimension::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { Evaluation * input = operand(0)->privateApproximate(T(), context, angleUnit); std::complex operands[2]; if (input->type() == Evaluation::Type::MatrixComplex) { diff --git a/poincare/src/matrix_inverse.cpp b/poincare/src/matrix_inverse.cpp index f02469f8c..c06fb021a 100644 --- a/poincare/src/matrix_inverse.cpp +++ b/poincare/src/matrix_inverse.cpp @@ -19,7 +19,7 @@ Expression * MatrixInverse::clone() const { return a; } -Expression * MatrixInverse::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference MatrixInverse::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; @@ -45,7 +45,7 @@ Expression * MatrixInverse::shallowReduce(Context& context, Preferences::AngleUn // TODO: handle this exactly in shallowReduce for small dimensions. template -Evaluation * MatrixInverse::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { +EvaluationReference MatrixInverse::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { Evaluation * input = operand(0)->privateApproximate(T(), context, angleUnit); Evaluation * inverse = input->createInverse(); if (inverse == nullptr) { diff --git a/poincare/src/matrix_trace.cpp b/poincare/src/matrix_trace.cpp index 23e75eac2..905ef5657 100644 --- a/poincare/src/matrix_trace.cpp +++ b/poincare/src/matrix_trace.cpp @@ -18,7 +18,7 @@ Expression * MatrixTrace::clone() const { return a; } -Expression * MatrixTrace::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference MatrixTrace::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/matrix_transpose.cpp b/poincare/src/matrix_transpose.cpp index 5d0f8faa6..fb30c7a73 100644 --- a/poincare/src/matrix_transpose.cpp +++ b/poincare/src/matrix_transpose.cpp @@ -17,7 +17,7 @@ Expression * MatrixTranspose::clone() const { return a; } -Expression * MatrixTranspose::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference MatrixTranspose::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; @@ -38,7 +38,7 @@ Expression * MatrixTranspose::shallowReduce(Context& context, Preferences::Angle } template -Evaluation * MatrixTranspose::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { +EvaluationReference MatrixTranspose::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { Evaluation * input = operand(0)->privateApproximate(T(), context, angleUnit); Evaluation * transpose = input->createTranspose(); assert(transpose != nullptr); diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index eda3e7b08..6b266ab6a 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -43,16 +43,16 @@ int Multiplication::polynomialDegree(char symbolName) const { return degree; } -int Multiplication::privateGetPolynomialCoefficients(char symbolName, Expression * coefficients[]) const { +int Multiplication::getPolynomialCoefficients(char symbolName, ExpressionReference coefficients[]) const { int deg = polynomialDegree(symbolName); if (deg < 0 || deg > k_maxPolynomialDegree) { return -1; } // Initialization of coefficients for (int i = 1; i <= deg; i++) { - coefficients[i] = new Rational(0); + coefficients[i] = RationalReference(0); } - coefficients[0] = new Rational(1); + coefficients[0] = RationalReference(1); Expression * intermediateCoefficients[k_maxNumberOfPolynomialCoefficients]; // Let's note result = a(0)+a(1)*X+a(2)*X^2+a(3)*x^3+.. @@ -174,7 +174,7 @@ static inline const Expression * Base(const Expression * e) { return e; } -Expression * Multiplication::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Multiplication::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { return privateShallowReduce(context, angleUnit, true, true); } @@ -191,7 +191,7 @@ Expression * Multiplication::privateShallowReduce(Context & context, Preferences for (int i = 0; i < numberOfOperands(); i++) { const Expression * o = operand(i); if (o->type() == Type::Rational && static_cast(o)->isZero()) { - return replaceWith(new Rational(0), true); + return replaceWith(RationalReference(0), true); } } @@ -521,7 +521,7 @@ Expression * Multiplication::distributeOnOperandAtIndex(int i, Context & context } const Expression * Multiplication::CreateExponent(Expression * e) { - return e->type() == Type::Power ? e->operand(1)->clone() : new Rational(1); + return e->type() == Type::Power ? e->operand(1)->clone() : RationalReference(1); } bool Multiplication::TermsHaveIdenticalBase(const Expression * e1, const Expression * e2) { diff --git a/poincare/src/n_ary_expression_node.cpp b/poincare/src/n_ary_expression_node.cpp new file mode 100644 index 000000000..42ccf4ea9 --- /dev/null +++ b/poincare/src/n_ary_expression_node.cpp @@ -0,0 +1,80 @@ +#include +extern "C" { +#include +#include +} + +namespace Poincare { + +void NAryExpressionNode::sortOperands(ExpressionOrder order, bool canBeInterrupted) { + ExpressionReference reference(this); + for (int i = reference.numberOfChildren()-1; i > 0; i--) { + bool isSorted = true; + for (int j = 0; j < reference.numberOfChildren()-1; j++) { + /* Warning: Matrix operations are not always commutative (ie, + * multiplication) so we never swap 2 matrices. */ +#if MATRIX_EXACT_REDUCING + if (order(childAtIndex(j), childAtIndex(j+1), canBeInterrupted) > 0 && (!childAtIndex(j)->recursivelyMatches(Expression::IsMatrix) || !childAtIndex(j+1)->recursivelyMatches(Expression::IsMatrix))) { +#else + if (order(childAtIndex(j), childAtIndex(j+1), canBeInterrupted) > 0) { +#endif + reference.swapChildren(j, j+1); + isSorted = false; + } + } + if (isSorted) { + return; + } + } +} + +ExpressionReference NAryExpressionNode::squashUnaryHierarchy() { + ExpressionReference reference(this); + if (reference.numberOfChildren() == 1) { + assert(parent() != nullptr); + ExpressionReference o = reference.childAtIndex(0); + reference.replaceWith(o); + return o; + } + return reference; +} + +// Private + +int NAryExpressionNode::simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const { + int m = this->numberOfChildren(); + int n = e->numberOfChildren(); + for (int i = 1; i <= m; i++) { + // The NULL node is the least node type. + if (n < i) { + return 1; + } + int order = SimplificationOrder(childAtIndex(m-i), e->childAtIndex(n-i), canBeInterrupted); + if (order != 0) { + return order; + } + } + // The NULL node is the least node type. + if (n > m) { + return -1; + } + return 0; +} + +int NAryExpressionNode::simplificationOrderGreaterType(const ExpressionNode * e, bool canBeInterrupted) const { + int m = numberOfChildren(); + if (m == 0) { + return -1; + } + /* Compare e to last term of hierarchy. */ + int order = SimplificationOrder(childAtIndex(m-1), e, canBeInterrupted); + if (order != 0) { + return order; + } + if (m > 1) { + return 1; + } + return 0; +} + +} diff --git a/poincare/src/naperian_logarithm.cpp b/poincare/src/naperian_logarithm.cpp index ad02b8b03..10ad148d2 100644 --- a/poincare/src/naperian_logarithm.cpp +++ b/poincare/src/naperian_logarithm.cpp @@ -20,7 +20,7 @@ Expression * NaperianLogarithm::clone() const { return a; } -Expression * NaperianLogarithm::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference NaperianLogarithm::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/nth_root.cpp b/poincare/src/nth_root.cpp index 27e68832a..f81604bf7 100644 --- a/poincare/src/nth_root.cpp +++ b/poincare/src/nth_root.cpp @@ -19,7 +19,7 @@ Expression * NthRoot::clone() const { NthRoot * a = new NthRoot(m_operands, true); return a; } -Expression * NthRoot::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference NthRoot::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; @@ -42,7 +42,7 @@ LayoutRef NthRoot::createLayout(Preferences::PrintFloatMode floatDisplayMode, in } template -Evaluation * NthRoot::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { +EvaluationReference NthRoot::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { Evaluation * base = operand(0)->privateApproximate(T(), context, angleUnit); Evaluation * index = operand(1)->privateApproximate(T(), context, angleUnit); Complex result = Complex::Undefined(); diff --git a/poincare/src/number.cpp b/poincare/src/number.cpp new file mode 100644 index 000000000..5fff5d946 --- /dev/null +++ b/poincare/src/number.cpp @@ -0,0 +1,121 @@ +#include +#include +#include +#include +#include +#include + +extern "C" { +#include +#include +} +#include + +namespace Poincare { + +double NumberNode::doubleApproximation() const { + switch (type()) { + case Type::Undefined: + return NAN; + case Type::Infinity: + return sign() == Sign::Negative ? -INFINITY : INFINITY; + case Type::Float: + if (sizeof(*this) == sizeof(FloatNode)) { + return static_cast *>(this)->value(); + } else { + assert(sizeof(*this) == sizeof(FloatNode)); + return static_cast *>(this)->value(); + } + case Type::Rational: + return static_cast(this)->templatedApproximate(); + case Type::Integer: + return static_cast(this)->templatedApproximate(); + default: + assert(false); + return 0.0; + } +} + +NumberReference createReference(double d) { + if (std::isnan(d)) { + return UndefinedReference(); + } else if (std::isinf(d)) { + return InfinityReference(d < 0.0); + } else { + return FloatReference(d); + } +} + +NumberReference NumberReference::Integer(const char * digits, size_t length, bool negative) { + IntegerReference i(digits, length, negative); + if (!i.isInfinity()) { + return i; + } + if (digits != nullptr && digits[0] == '-') { + negative = true; + digits++; + } + /*if (length > Decimal::k_maxExponentLength) { + return InfinityReference(negative); + } + int exponent = Decimal::Exponent(digits, length, nullptr, 0, nullptr, 0, negative); + return DecimalReference(digits, length, nullptr, 0, negative, exponent);*/ +} + +NumberReference NumberReference::BinaryOperation(const NumberReference i, const NumberReference j, IntegerBinaryOperation integerOp, RationalBinaryOperation rationalOp, DoubleBinaryOperation doubleOp) { + if (i.isAllocationFailure() || j.isAllocationFailure()) { + return NumberReference(ExpressionNode::FailedAllocationStaticNode()); + } + if (i.node()->type() == ExpressionNode::Type::Integer && j.node()->type() == ExpressionNode::Type::Integer) { + // Integer + Integer + IntegerReference k = integerOp(IntegerReference(i.node()), IntegerReference(j.node())); + if (!k.isInfinity()) { + return k; + } + } else if (i.node()->type() == ExpressionNode::Type::Integer && j.node()->type() == ExpressionNode::Type::Rational) { + // Integer + Rational + RationalReference r = rationalOp(RationalReference(IntegerReference(i.node())), RationalReference(j.node())); + if (!r.numeratorOrDenominatorIsInfinity()) { + return r; + } + } else if (i.node()->type() == ExpressionNode::Type::Rational && j.node()->type() == ExpressionNode::Type::Integer) { + // Rational + Integer + return NumberReference::BinaryOperation(j, i, integerOp, rationalOp, doubleOp); + } else if (i.node()->type() == ExpressionNode::Type::Rational && j.node()->type() == ExpressionNode::Type::Rational) { + // Rational + Rational + RationalReference a = rationalOp(RationalReference(i.node()), RationalReference(j.node())); + if (!a.numeratorOrDenominatorIsInfinity()) { + return a; + } + } + // one of the operand is Undefined/Infinity/Float or the Integer/Rational addition overflowed + double a = doubleOp(i.numberNode()->doubleApproximation(), j.numberNode()->doubleApproximation()); + return createReference(a); +} + +NumberReference NumberReference::Addition(const NumberReference i, const NumberReference j) { + return BinaryOperation(i, j, IntegerReference::Addition, RationalReference::Addition, [](double a, double b) { return a+b; }); +} + +NumberReference NumberReference::Multiplication(const NumberReference i, const NumberReference j) { + return BinaryOperation(i, j, IntegerReference::Multiplication, RationalReference::Multiplication, [](double a, double b) { return a*b; }); +} + +NumberReference NumberReference::Power(const NumberReference i, const NumberReference j) { + return BinaryOperation(i, j, IntegerReference::Power, + // Special case for Rational^Rational: we escape to Float if the index is not an Integer + [](const RationalReference i, const RationalReference j) { + if (!j.isAllocationFailure() && j.typedNode()->denominator().isOne()) { + return RationalReference::IntegerPower(i, j); + } else { + // We return an overflown result to reach the escape case Float+Float + return RationalReference(IntegerReference::Overflow()); + } + }, + [](double a, double b) { + return std::pow(a, b); + } + ); +} + +} diff --git a/poincare/src/opposite.cpp b/poincare/src/opposite.cpp index cbd4863ce..435fab861 100644 --- a/poincare/src/opposite.cpp +++ b/poincare/src/opposite.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +//#include #include #include extern "C" { @@ -13,24 +13,15 @@ extern "C" { namespace Poincare { -Expression::Type Opposite::type() const { - return Type::Opposite; +int OppositeNode::polynomialDegree(char symbolName) const { + return childAtIndex(0)->polynomialDegree(symbolName); } -Expression * Opposite::clone() const { - Opposite * o = new Opposite(m_operands, true); - return o; -} - -int Opposite::polynomialDegree(char symbolName) const { - return operand(0)->polynomialDegree(symbolName); -} - -Expression::Sign Opposite::sign() const { - if (operand(0)->sign() == Sign::Positive) { +ExpressionNode::Sign OppositeNode::sign() const { + if (childAtIndex(0)->sign() == Sign::Positive) { return Sign::Negative; } - if (operand(0)->sign() == Sign::Negative) { + if (childAtIndex(0)->sign() == Sign::Negative) { return Sign::Positive; } return Sign::Unknown; @@ -38,44 +29,22 @@ Expression::Sign Opposite::sign() const { /* Layout */ -bool Opposite::needParenthesisWithParent(const Expression * e) const { +bool OppositeNode::needsParenthesisWithParent(SerializableNode * e) const { Type types[] = {Type::Addition, Type::Subtraction, Type::Opposite, Type::Multiplication, Type::Division, Type::Power, Type::Factorial}; - return e->isOfType(types, 7); + return static_cast(e)->isOfType(types, 7); } -template -std::complex Opposite::compute(const std::complex c, Preferences::AngleUnit angleUnit) { - return -c; -} - -Expression * Opposite::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { - Expression * e = Expression::shallowReduce(context, angleUnit); - if (e != this) { - return e; - } - const Expression * op = operand(0); -#if MATRIX_EXACT_REDUCING - if (op->type() == Type::Matrix) { - return SimplificationEngine::map(this, context, angleUnit); - } -#endif - detachOperand(op); - Multiplication * m = new Multiplication(new Rational(-1), op, false); - replaceWith(m, true); - return m->shallowReduce(context, angleUnit); -} - -LayoutRef Opposite::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { +LayoutRef OppositeNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { HorizontalLayoutRef result = HorizontalLayoutRef(CharLayoutRef('-')); - if (operand(0)->type() == Type::Opposite) { - result.addOrMergeChildAtIndex(LayoutEngine::createParenthesedLayout(operand(0)->createLayout(floatDisplayMode, numberOfSignificantDigits), false), 1, false); + if (childAtIndex(0)->type() == Type::Opposite) { + result.addOrMergeChildAtIndex(LayoutEngine::createParenthesedLayout(childAtIndex(0)->createLayout(floatDisplayMode, numberOfSignificantDigits), false), 1, false); } else { - result.addOrMergeChildAtIndex(operand(0)->createLayout(floatDisplayMode, numberOfSignificantDigits), 1, false); + result.addOrMergeChildAtIndex(childAtIndex(0)->createLayout(floatDisplayMode, numberOfSignificantDigits), 1, false); } return result; } -int Opposite::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { +int OppositeNode::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { if (bufferSize == 0) { return -1; } @@ -83,12 +52,26 @@ int Opposite::writeTextInBuffer(char * buffer, int bufferSize, Preferences::Prin int numberOfChar = 0; if (bufferSize == 1) { return 0; } buffer[numberOfChar++] = '-'; - numberOfChar += operand(0)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfSignificantDigits); + numberOfChar += childAtIndex(0)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfSignificantDigits); buffer[numberOfChar] = 0; return numberOfChar; } +/* Simplification */ + +ExpressionReference OppositeNode::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { + ExpressionReference e = ExpressionNode::shallowReduce(context, angleUnit); + if (e.node() != this) { + return e; + } + const ExpressionReference child = ExpressionReference(childAtIndex(0)); +#if MATRIX_EXACT_REDUCING + if (op->type() == Type::Matrix) { + return SimplificationEngine::map(this, context, angleUnit); + } +#endif + MultiplicationReference m = MultiplicationReference(RationalReference(-1), child); + return m->node()->shallowReduce(context, angleUnit); } -template std::complex Poincare::Opposite::compute(const std::complex, Preferences::AngleUnit angleUnit); -template std::complex Poincare::Opposite::compute(const std::complex, Preferences::AngleUnit angleUnit); +} diff --git a/poincare/src/parenthesis.cpp b/poincare/src/parenthesis.cpp index 2d0c04a45..7facbf2a9 100644 --- a/poincare/src/parenthesis.cpp +++ b/poincare/src/parenthesis.cpp @@ -6,35 +6,25 @@ extern "C" { namespace Poincare { - -Expression::Type Parenthesis::type() const { - return Type::Parenthesis; +int ParenthesisNode::polynomialDegree(char symbolName) const { + return childAtIndex(0)->polynomialDegree(symbolName); } -Expression * Parenthesis::clone() const { - Parenthesis * o = new Parenthesis(m_operands, true); - return o; +LayoutRef ParenthesisNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + return LayoutEngine::createParenthesedLayout(childAtIndex(0)->createLayout(floatDisplayMode, numberOfSignificantDigits), false); } -int Parenthesis::polynomialDegree(char symbolName) const { - return operand(0)->polynomialDegree(symbolName); -} - -LayoutRef Parenthesis::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - return LayoutEngine::createParenthesedLayout(operand(0)->createLayout(floatDisplayMode, numberOfSignificantDigits), false); -} - -Expression * Parenthesis::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { - Expression * e = Expression::shallowReduce(context, angleUnit); - if (e != this) { +ExpressionReference ParenthesisNode::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { + ExpressionReference e = ExpressionNode::shallowReduce(context, angleUnit); + if (e.node() != this) { return e; } - return replaceWith(editableOperand(0), true); + return ExpressionReference(childAtIndex(0)); } template -Evaluation * Parenthesis::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { - return operand(0)->privateApproximate(T(), context, angleUnit); +EvaluationReference ParenthesisNode::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { + return childAtIndex(0)->approximate(T(), context, angleUnit); } } diff --git a/poincare/src/permute_coefficient.cpp b/poincare/src/permute_coefficient.cpp index 1baacc45b..509ed6ca8 100644 --- a/poincare/src/permute_coefficient.cpp +++ b/poincare/src/permute_coefficient.cpp @@ -18,7 +18,7 @@ Expression * PermuteCoefficient::clone() const { return b; } -Expression * PermuteCoefficient::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference PermuteCoefficient::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; @@ -51,7 +51,7 @@ Expression * PermuteCoefficient::shallowReduce(Context& context, Preferences::An Integer n = r0->numerator(); Integer k = r1->numerator(); if (n.isLowerThan(k)) { - return replaceWith(new Rational(0), true); + return replaceWith(RationalReference(0), true); } /* if n is too big, we do not reduce to avoid too long computation. * The permute coefficient will be evaluate approximatively later */ diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index 3d3d496bc..5c8fc56d6 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -83,7 +83,7 @@ int Power::polynomialDegree(char symbolName) const { return -1; } -int Power::privateGetPolynomialCoefficients(char symbolName, Expression * coefficients[]) const { +int Power::getPolynomialCoefficients(char symbolName, ExpressionReference coefficients[]) const { int deg = polynomialDegree(symbolName); if (deg <= 0) { return Expression::privateGetPolynomialCoefficients(symbolName, coefficients); @@ -101,9 +101,9 @@ int Power::privateGetPolynomialCoefficients(char symbolName, Expression * coeffi int n = r->numerator().extractedInt(); if (n <= k_maxPolynomialDegree) { for (int i = 0; i < n; i++) { - coefficients[i] = new Rational(0); + coefficients[i] = RationalReference(0); } - coefficients[n] = new Rational(1); + coefficients[n] = RationalReference(1); return n; } } @@ -188,7 +188,7 @@ LayoutRef Power::createLayout(Preferences::PrintFloatMode floatDisplayMode, int return result; } -int Power::simplificationOrderSameType(const Expression * e, bool canBeInterrupted) const { +int Power::simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const { int baseComparison = SimplificationOrder(operand(0), e->operand(0), canBeInterrupted); if (baseComparison != 0) { return baseComparison; @@ -205,7 +205,7 @@ int Power::simplificationOrderGreaterType(const Expression * e, bool canBeInterr return SimplificationOrder(operand(1), &one, canBeInterrupted); } -Expression * Power::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Power::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; @@ -277,7 +277,7 @@ Expression * Power::shallowReduce(Context& context, Preferences::AngleUnit angle /* Warning: in all other case but 0^0, we replace x^0 by one. This is * almost always true except when x = 0. However, not substituting x^0 by * one would prevent from simplifying many expressions like x/x->1. */ - return replaceWith(new Rational(1), true); + return replaceWith(RationalReference(1), true); } // x^1 if (b->isOne()) { @@ -289,7 +289,7 @@ Expression * Power::shallowReduce(Context& context, Preferences::AngleUnit angle // 0^x if (a->isZero()) { if (operand(1)->sign() == Sign::Positive) { - return replaceWith(new Rational(0), true); + return replaceWith(RationalReference(0), true); } if (operand(1)->sign() == Sign::Negative) { return replaceWith(new Undefined(), true); @@ -297,7 +297,7 @@ Expression * Power::shallowReduce(Context& context, Preferences::AngleUnit angle } // 1^x if (a->isOne()) { - return replaceWith(new Rational(1), true); + return replaceWith(RationalReference(1), true); } } @@ -595,7 +595,7 @@ Expression * Power::CreateSimplifiedIntegerRationalPower(Integer i, Rational * r assert(!i.isZero()); assert(r->sign() == Sign::Positive); if (i.isOne()) { - return new Rational(1); + return RationalReference(1); } Integer absI = i; absI.setNegative(false); @@ -665,11 +665,11 @@ Expression * Power::CreateNthRootOfUnity(const Rational r) { #endif } -Expression * Power::shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Power::shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) { // X^-y -> 1/(X->shallowBeautify)^y if (operand(1)->sign() == Sign::Negative) { Expression * p = cloneDenominator(context, angleUnit); - Division * d = new Division(new Rational(1), p, false); + Division * d = new Division(RationalReference(1), p, false); p->shallowReduce(context, angleUnit); replaceWith(d, true); return d->shallowBeautify(context, angleUnit); diff --git a/poincare/src/prediction_interval.cpp b/poincare/src/prediction_interval.cpp index 78a3624a4..550776fde 100644 --- a/poincare/src/prediction_interval.cpp +++ b/poincare/src/prediction_interval.cpp @@ -25,7 +25,7 @@ int PredictionInterval::polynomialDegree(char symbolName) const { return -1; } -Expression * PredictionInterval::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference PredictionInterval::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; @@ -71,7 +71,7 @@ Expression * PredictionInterval::shallowReduce(Context& context, Preferences::An } template -Evaluation * PredictionInterval::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { +EvaluationReference PredictionInterval::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { Evaluation * pInput = operand(0)->privateApproximate(T(), context, angleUnit); Evaluation * nInput = operand(1)->privateApproximate(T(), context, angleUnit); T p = static_cast *>(pInput)->toScalar(); diff --git a/poincare/src/print_float.cpp b/poincare/src/print_float.cpp index ece53bed0..30fa64729 100644 --- a/poincare/src/print_float.cpp +++ b/poincare/src/print_float.cpp @@ -65,7 +65,7 @@ int PrintFloat::convertFloatToText(T f, char * buffer, int bufferSize, template int PrintFloat::convertFloatToTextPrivate(T f, char * buffer, int numberOfSignificantDigits, Preferences::PrintFloatMode mode) { assert(numberOfSignificantDigits > 0); - /*if (std::isinf(f)) { + if (std::isinf(f)) { int currentChar = 0; if (f < 0) { buffer[currentChar++] = '-'; @@ -75,7 +75,7 @@ int PrintFloat::convertFloatToTextPrivate(T f, char * buffer, int numberOfSignif buffer[currentChar++] = 'f'; buffer[currentChar] = 0; return currentChar; - }*/ + } if (std::isinf(f) || std::isnan(f)) { int currentChar = 0; diff --git a/poincare/src/rational.cpp b/poincare/src/rational.cpp index 1e15b438b..fca5c59a6 100644 --- a/poincare/src/rational.cpp +++ b/poincare/src/rational.cpp @@ -8,171 +8,265 @@ extern "C" { #include #include #include +#include namespace Poincare { -// Constructors +/* Rational Node */ -Rational::Rational(const Integer numerator, const Integer denominator) { - assert(!denominator.isZero()); - if (numerator.isOne() || denominator.isOne()) { - // Avoid computing GCD if possible - m_numerator = numerator; - m_denominator = denominator; - } else { - Integer gcd = Arithmetic::GCD(&numerator, &denominator); - m_numerator = Integer::Division(numerator, gcd).quotient; - m_denominator = Integer::Division(denominator, gcd).quotient; - } - if (m_numerator.isNegative() && m_denominator.isNegative()) { - m_numerator.setNegative(false); - m_denominator.setNegative(false); - } else if (m_denominator.isNegative()) { - m_numerator.setNegative(true); - m_denominator.setNegative(false); - } +void RationalNode::setDigits(native_uint_t * numeratorDigits, size_t numeratorSize, native_uint_t * denominatorDigits, size_t denominatorSize, bool negative) { + m_negative = negative; + m_numberOfDigitsNumerator = numeratorSize; + m_numberOfDigitsDenominator = denominatorSize; + memcpy(m_digits, numeratorDigits, numeratorSize*sizeof(native_uint_t)); + memcpy(m_digits + m_numberOfDigitsNumerator, denominatorDigits, denominatorSize*sizeof(native_uint_t)); } -Rational::Rational(const Integer numerator) { - m_numerator = numerator; - m_denominator = Integer(1); +NaturalIntegerPointer RationalNode::numerator() const { + return NaturalIntegerPointer((native_uint_t *)m_digits, m_numberOfDigitsNumerator); } -Rational::Rational(const Rational & other) { - m_numerator = other.m_numerator; - m_denominator = other.m_denominator; +NaturalIntegerPointer RationalNode::denominator() const { + return NaturalIntegerPointer(((native_uint_t *)m_digits+m_numberOfDigitsNumerator), m_numberOfDigitsDenominator); } -Rational & Rational::operator=(const Rational & other) { - m_numerator = other.m_numerator; - m_numerator = other.m_numerator; - m_denominator = other.m_denominator; - return *this; +// Tree Node + +size_t RationalNode::size() const { + return sizeof(RationalNode)+sizeof(native_uint_t)*(m_numberOfDigitsNumerator+m_numberOfDigitsDenominator); } -// Getter -const Integer Rational::numerator() const { - return m_numerator; -} +// Serialization Node -const Integer Rational::denominator() const { - return m_denominator; -} -// Expression subclassing - -Expression::Type Rational::type() const { - return Type::Rational; -} - -Expression * Rational::clone() const { - return new Rational(m_numerator, m_denominator); -} - -Expression::Sign Rational::sign() const { - if (m_numerator.isNegative()) { - return Sign::Negative; - } - return Sign::Positive; -} - -Expression * Rational::setSign(Sign s) { - assert(s != Sign::Unknown); - bool negative = s == Sign::Negative ? true : false; - m_numerator.setNegative(negative); - return this; -} - -Expression * Rational::shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) { - if (m_numerator.isNegative()) { - m_numerator.setNegative(false); - Opposite * o = new Opposite(this, true); - return replaceWith(o, true); - } - return this; -} - -Expression * Rational::cloneDenominator(Context & context, Preferences::AngleUnit angleUnit) const { - if (m_denominator.isOne()) { - return nullptr; - } - return new Rational(m_denominator); -} - -// Basic operations - -Rational Rational::Addition(const Rational & i, const Rational & j) { - Integer newNumerator = Integer::Addition(Integer::Multiplication(i.numerator(), j.denominator()), Integer::Multiplication(j.numerator(), i.denominator())); - Integer newDenominator = Integer::Multiplication(i.denominator(), j.denominator()); - return Rational(newNumerator, newDenominator); -} - -Rational Rational::Multiplication(const Rational & i, const Rational & j) { - Integer newNumerator = Integer::Multiplication(i.numerator(), j.numerator()); - Integer newDenominator = Integer::Multiplication(i.denominator(), j.denominator()); - return Rational(newNumerator, newDenominator); -} - -Rational Rational::Power(const Rational & i, const Integer & j) { - Integer absJ = j; - absJ.setNegative(false); - Integer newNumerator = Integer::Power(i.numerator(), absJ); - Integer newDenominator = Integer::Power(i.denominator(), absJ); - if (j.isNegative()) { - return Rational(newDenominator, newNumerator); - } - return Rational(newNumerator, newDenominator); -} - -int Rational::NaturalOrder(const Rational & i, const Rational & j) { - Integer i1 = Integer::Multiplication(i.numerator(), j.denominator()); - Integer i2 = Integer::Multiplication(i.denominator(), j.numerator()); - return Integer::NaturalOrder(i1, i2); -} - -// Comparison - -int Rational::simplificationOrderSameType(const Expression * e, bool canBeInterrupted) const { - assert(e->type() == Expression::Type::Rational); - const Rational * other = static_cast(e); - return NaturalOrder(*this, *other); -} - -template Complex * Rational::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { - T n = m_numerator.approximate(); - T d = m_denominator.approximate(); - return new Complex(n/d); -} - -bool Rational::needParenthesisWithParent(const Expression * e) const { - if (m_denominator.isOne()) { +bool RationalNode::needsParenthesisWithParent(SerializableNode * e) const { + if (denominator().isOne()) { return false; } Type types[] = {Type::Division, Type::Power, Type::Factorial}; - return e->isOfType(types, 3); + return static_cast(e)->isOfType(types, 3); } -LayoutRef Rational::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - LayoutRef numeratorLayout = m_numerator.createLayout(); - if (m_denominator.isOne()) { - return numeratorLayout; +int RationalNode::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + if (bufferSize == 0) { + return -1; } - LayoutRef denominatorLayout = m_denominator.createLayout(); - return FractionLayoutRef(numeratorLayout, denominatorLayout); -} - -int Rational::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { buffer[bufferSize-1] = 0; - int numberOfChar = m_numerator.writeTextInBuffer(buffer, bufferSize); - if (m_denominator.isOne()) { + int numberOfChar = 0; + if (m_negative) { + buffer[numberOfChar++] = '-'; + } + if (numberOfChar >= bufferSize-1) { + return bufferSize-1; + } + numberOfChar += numerator().writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + if (denominator().isOne()) { return numberOfChar; } if (numberOfChar >= bufferSize-1) { return numberOfChar; } buffer[numberOfChar++] = '/'; - numberOfChar += m_denominator.writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + numberOfChar += denominator().writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); return numberOfChar; } +// Expression subclassing + +ExpressionNode::Sign RationalNode::sign() const { + if (m_negative) { + return Sign::Negative; + } + return Sign::Positive; } +void RationalNode::setSign(Sign s) { + assert(s != Sign::Unknown); + m_negative = s == Sign::Negative ? true : false; +} + +// Layout + +LayoutRef RationalNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + LayoutRef numeratorLayout = numerator().createLayout(); + if (m_negative) { + numeratorLayout.addChildAtIndex(CharLayoutRef('-'), 0, numeratorLayout.numberOfChildren(), nullptr); + } + if (denominator().isOne()) { + return numeratorLayout; + } + LayoutRef denominatorLayout = denominator().createLayout(); + return FractionLayoutRef(numeratorLayout, denominatorLayout); +} + +// Approximation + +template T RationalNode::templatedApproximate() const { + T n = numerator().approximate(); + T d = denominator().approximate(); + return m_negative ? -n/d : n/d; +} + +// Comparison + +int RationalNode::NaturalOrder(const RationalNode i, const RationalNode j) { + NaturalIntegerPointer in = i.numerator(); + NaturalIntegerPointer id = i.denominator(); + NaturalIntegerPointer jn = j.numerator(); + NaturalIntegerPointer jd = j.denominator(); + IntegerReference i1 = NaturalIntegerAbstract::umult(&in, &jd); + IntegerReference i2 = NaturalIntegerAbstract::umult(&id, &jn); + return IntegerReference::NaturalOrder(i1, i2); +} + +int RationalNode::simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const { + assert(e->type() == ExpressionNode::Type::Rational); + const RationalNode * other = static_cast(e); + return NaturalOrder(*this, *other); +} + +// Simplification + +ExpressionReference RationalNode::shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) { + if (m_negative) { + m_negative = false; + return OppositeReference(ExpressionReference(this)); + } + return ExpressionReference(this); +} + +ExpressionReference RationalNode::cloneDenominator(Context & context, Preferences::AngleUnit angleUnit) const { + if (denominator().isOne()) { + return ExpressionReference(nullptr); + } + NaturalIntegerPointer d = denominator(); + assert(!d.isInfinity()); + return RationalReference(&d, false); +} + +/* Rational Reference */ + +// Constructors + +RationalReference::RationalReference(IntegerReference numerator, IntegerReference denominator) { + assert(!denominator.isZero()); + if (!numerator.isOne() && !denominator.isOne()) { + // Avoid computing GCD if possible + IntegerReference gcd = Arithmetic::GCD(numerator, denominator); + numerator = IntegerReference::Division(numerator, gcd).quotient; + denominator = IntegerReference::Division(denominator, gcd).quotient; + } + if (numerator.isAllocationFailure() || denominator.isAllocationFailure()) { + *this = RationalReference(ExpressionNode::FailedAllocationStaticNode()); + } + *this = RationalReference(sizeof(RationalNode)+sizeof(native_uint_t)*(numerator.typedNode()->numberOfDigits()+denominator.typedNode()->numberOfDigits())); + if (isAllocationFailure()) { + return; + } + bool negative = (numerator.sign() == ExpressionNode::Sign::Positive && denominator.sign() == ExpressionNode::Sign::Negative) || (denominator.sign() == ExpressionNode::Sign::Positive && numerator.sign() == ExpressionNode::Sign::Negative); + typedNode()->setDigits(numerator.typedNode()->digits(), numerator.typedNode()->numberOfDigits(), denominator.typedNode()->digits(), denominator.typedNode()->numberOfDigits(), negative); + return; +} + +RationalReference::RationalReference(const IntegerReference numerator) { + if (numerator.isAllocationFailure()) { + *this = RationalReference(ExpressionNode::FailedAllocationStaticNode()); + } + *this = RationalReference(numerator.typedNode(), numerator.sign() == ExpressionNode::Sign::Negative); +} + +RationalReference::RationalReference(const NaturalIntegerAbstract * numerator, bool negative) { + *this = RationalReference(sizeof(RationalNode)+sizeof(native_uint_t)*(numerator->numberOfDigits()+1)); + if (isAllocationFailure()) { + return; + } + native_uint_t one = 1; + typedNode()->setDigits(numerator->digits(), numerator->numberOfDigits(), &one, 1, negative); + return; +} + +RationalReference::RationalReference(native_int_t i) { + *this = RationalReference(sizeof(RationalNode)+sizeof(native_uint_t)*2); + if (isAllocationFailure()) { + return; + } + native_uint_t absI = i < 0 ? -i : i; + native_uint_t one = 1; + typedNode()->setDigits(&absI, 1, &one, 1, i < 0); + return; +} + +RationalReference::RationalReference(native_int_t i, native_int_t j) { + assert(j != 0); + *this = RationalReference(sizeof(RationalNode)+sizeof(native_uint_t)*2); + if (isAllocationFailure()) { + return; + } + native_uint_t absI = i < 0 ? -i : i; + native_uint_t absJ = j < 0 ? -j : j; + typedNode()->setDigits(&absI, 1, &absJ, 1, (i < 0 && j > 0) || (i > 0 && j < 0)); + return; +} + +bool RationalReference::isOne() const { + if (isAllocationFailure()) { + return false; + } + return typedNode()->isOne(); +} + +bool RationalReference::numeratorOrDenominatorIsInfinity() const { + if (isAllocationFailure()) { + return false; + } + return typedNode()->numerator().isInfinity() || typedNode()->denominator().isInfinity(); +} + +// Basic operations + +RationalReference RationalReference::Addition(const RationalReference i, const RationalReference j) { + if (i.isAllocationFailure() || j.isAllocationFailure()) { + return RationalReference(ExpressionNode::FailedAllocationStaticNode()); + } + NaturalIntegerPointer in = i.typedNode()->numerator(); + NaturalIntegerPointer id = i.typedNode()->denominator(); + NaturalIntegerPointer jn = j.typedNode()->numerator(); + NaturalIntegerPointer jd = j.typedNode()->denominator(); + IntegerReference newDenominator = NaturalIntegerAbstract::umult(&id, &jd); + IntegerReference newNumeratorPart1 = NaturalIntegerAbstract::umult(&in, &jd); + IntegerReference newNumeratorPart2 = NaturalIntegerAbstract::umult(&jn, &id); + newNumeratorPart1.setNegative(i.sign() == ExpressionNode::Sign::Negative); + newNumeratorPart2.setNegative(j.sign() == ExpressionNode::Sign::Negative); + IntegerReference newNumerator = IntegerReference::Addition(newNumeratorPart1, newNumeratorPart2); + return RationalReference(newNumerator, newDenominator); +} + +RationalReference RationalReference::Multiplication(const RationalReference i, const RationalReference j) { + if (i.isAllocationFailure() || j.isAllocationFailure()) { + return RationalReference(ExpressionNode::FailedAllocationStaticNode()); + } + NaturalIntegerPointer in = i.typedNode()->numerator(); + NaturalIntegerPointer id = i.typedNode()->denominator(); + NaturalIntegerPointer jn = j.typedNode()->numerator(); + NaturalIntegerPointer jd = j.typedNode()->denominator(); + IntegerReference newNumerator = NaturalIntegerAbstract::umult(&in, &jn); + IntegerReference newDenominator = NaturalIntegerAbstract::umult(&id, &jd); + newNumerator.setNegative(i.sign() != j.sign()); + return RationalReference(newNumerator, newDenominator); +} + +RationalReference RationalReference::IntegerPower(const RationalReference i, const RationalReference j) { + if (i.isAllocationFailure() || j.isAllocationFailure()) { + return RationalReference(ExpressionNode::FailedAllocationStaticNode()); + } + NaturalIntegerPointer in = i.typedNode()->numerator(); + NaturalIntegerPointer id = i.typedNode()->denominator(); + NaturalIntegerPointer jn = j.typedNode()->numerator(); + IntegerReference newNumerator = NaturalIntegerPointer::upow(&in, &jn); + IntegerReference newDenominator = NaturalIntegerPointer::upow(&id, &jn); + if (j.sign() == ExpressionNode::Sign::Negative) { + return RationalReference(newDenominator, newNumerator); + } + return RationalReference(newNumerator, newDenominator); +} + +} diff --git a/poincare/src/real_part.cpp b/poincare/src/real_part.cpp index d780845c0..0df595f41 100644 --- a/poincare/src/real_part.cpp +++ b/poincare/src/real_part.cpp @@ -16,7 +16,7 @@ Expression * RealPart::clone() const { return a; } -Expression * RealPart::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference RealPart::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/round.cpp b/poincare/src/round.cpp index cbfdd5209..919bd1dc8 100644 --- a/poincare/src/round.cpp +++ b/poincare/src/round.cpp @@ -19,7 +19,7 @@ Expression * Round::clone() const { return c; } -Expression * Round::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Round::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/sequence.cpp b/poincare/src/sequence.cpp index b65b2be8e..93cfac855 100644 --- a/poincare/src/sequence.cpp +++ b/poincare/src/sequence.cpp @@ -16,7 +16,7 @@ LayoutRef Sequence::createLayout(Preferences::PrintFloatMode floatDisplayMode, i } template -Evaluation * Sequence::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { +EvaluationReference Sequence::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { Evaluation * aInput = operand(1)->privateApproximate(T(), context, angleUnit); Evaluation * bInput = operand(2)->privateApproximate(T(), context, angleUnit); T start = aInput->toScalar(); diff --git a/poincare/src/sine.cpp b/poincare/src/sine.cpp index 92cb34036..d6aad46d9 100644 --- a/poincare/src/sine.cpp +++ b/poincare/src/sine.cpp @@ -32,7 +32,7 @@ std::complex Sine::computeOnComplex(const std::complex c, Preferences::Ang return Trigonometry::RoundToMeaningfulDigits(res); } -Expression * Sine::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Sine::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/square_root.cpp b/poincare/src/square_root.cpp index 7839a84b6..879cabfca 100644 --- a/poincare/src/square_root.cpp +++ b/poincare/src/square_root.cpp @@ -36,7 +36,7 @@ std::complex SquareRoot::computeOnComplex(const std::complex c, Preference return ApproximationEngine::truncateRealOrImaginaryPartAccordingToArgument(result); } -Expression * SquareRoot::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference SquareRoot::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/store.cpp b/poincare/src/store.cpp index 096b0370d..57dafda38 100644 --- a/poincare/src/store.cpp +++ b/poincare/src/store.cpp @@ -28,7 +28,7 @@ int Store::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFl return LayoutEngine::writeInfixExpressionTextInBuffer(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, "\x90"); } -Expression * Store::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Store::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { context.setExpressionForSymbolName(value(), symbol(), context); return replaceWith(editableOperand(1), true)->shallowReduce(context, angleUnit); } @@ -42,7 +42,7 @@ LayoutRef Store::createLayout(Preferences::PrintFloatMode floatDisplayMode, int } template -Evaluation * Store::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { +EvaluationReference Store::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { context.setExpressionForSymbolName(value(), symbol(), context); if (context.expressionForSymbol(symbol()) != nullptr) { return context.expressionForSymbol(symbol())->privateApproximate(T(), context, angleUnit); diff --git a/poincare/src/subtraction.cpp b/poincare/src/subtraction.cpp index e633edb2c..82fe299d9 100644 --- a/poincare/src/subtraction.cpp +++ b/poincare/src/subtraction.cpp @@ -54,7 +54,7 @@ template MatrixComplex Subtraction::computeOnComplexAndMatrix(con return result; } -Expression * Subtraction::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Subtraction::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 4fbe306d3..b3a521243 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -1,10 +1,8 @@ #include #include -#include -#include +#include #include -#include #include #include @@ -20,7 +18,172 @@ extern "C" { namespace Poincare { -const char * Symbol::textForSpecialSymbols(char name) { +ExpressionNode::Sign SymbolNode::sign() const { + /* TODO: Maybe, we will want to know that from a context given in parameter: + if (context.expressionForSymbol(this) != nullptr) { + return context.expressionForSymbol(this)->sign(context); + }*/ + if (m_name == Ion::Charset::SmallPi) { + return Sign::Positive; + } + if (m_name == Ion::Charset::Exponential) { + return Sign::Positive; + } + return Sign::Unknown; +} + +ExpressionReference SymbolNode::replaceSymbolWithExpression(char symbol, ExpressionReference expression) { + if (m_name == symbol) { + ExpressionReference value = expression.clone(); + if (parent() && value.needsParenthesisWithParent(parent())) { + value = ParenthesisReference(value); + } + return value; + } + return ExpressionReference(this); +} + +int SymbolNode::polynomialDegree(char symbol) const { + if (m_name == symbol) { + return 1; + } + return 0; +} + +int SymbolNode::getPolynomialCoefficients(char symbolName, ExpressionReference coefficients[]) const { + if (m_name == symbolName) { + coefficients[0] = RationalReference(0); + coefficients[1] = RationalReference(1); + return 1; + } + coefficients[0] = SymbolReference(m_name); + return 0; +} + +int SymbolNode::getVariables(isVariableTest isVariable, char * variables) const { + size_t variablesLength = strlen(variables); + if (isVariable(m_name)) { + char * currentChar = variables; + while (*currentChar != 0) { + if (*currentChar == m_name) { + return variablesLength; + } + currentChar++; + } + if (variablesLength < ExpressionReference::k_maxNumberOfVariables) { + variables[variablesLength] = m_name; + variables[variablesLength+1] = 0; + return variablesLength+1; + } + return -1; + } + return variablesLength; +} + +float SymbolNode::characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const { + if (m_name == 'x') { + return NAN; + } + return 0.0; +} + +int SymbolNode::simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const { + assert(e->type() == Type::Symbol); + if ((uint8_t)m_name == ((uint8_t)static_cast(e)->name())) { + return 0; + } + if ((uint8_t)m_name > ((uint8_t)static_cast(e)->name())) { + return 1; + } + return -1; +} + +LayoutRef SymbolNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + if (m_name == SymbolReference::SpecialSymbols::Ans) { + return LayoutEngine::createStringLayout("ans", 3); + } + if (m_name == SymbolReference::SpecialSymbols::un) { + return HorizontalLayoutRef( + CharLayoutRef('u'), + VerticalOffsetLayoutRef( + CharLayoutRef('n'), + VerticalOffsetLayoutNode::Type::Subscript)); + } + if (m_name == SymbolReference::SpecialSymbols::un1) { + return HorizontalLayoutRef( + CharLayoutRef('u'), + VerticalOffsetLayoutRef( + LayoutEngine::createStringLayout("n+1", 3), + VerticalOffsetLayoutNode::Type::Subscript)); + } + if (m_name == SymbolReference::SpecialSymbols::vn) { + return HorizontalLayoutRef( + CharLayoutRef('v'), + VerticalOffsetLayoutRef( + CharLayoutRef('n'), + VerticalOffsetLayoutNode::Type::Subscript)); + } + if (m_name == SymbolReference::SpecialSymbols::vn1) { + return HorizontalLayoutRef( + CharLayoutRef('v'), + VerticalOffsetLayoutRef( + LayoutEngine::createStringLayout("n+1", 3), + VerticalOffsetLayoutNode::Type::Subscript)); + } + if (SymbolReference::isMatrixSymbol(m_name) || SymbolReference::isSeriesSymbol(m_name) || SymbolReference::isRegressionSymbol(m_name)) { + return LayoutEngine::createStringLayout(SymbolReference::textForSpecialSymbols(m_name), 2); + } + return LayoutEngine::createStringLayout(&m_name, 1); +} + +int SymbolNode::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + if (bufferSize == 0) { + return -1; + } + if (bufferSize == 1) { + buffer[bufferSize-1] = 0; + return 0; + } + /* Special cases for all special symbols */ + if (m_name >0 && m_name < 32) { + return strlcpy(buffer, SymbolReference::textForSpecialSymbols(m_name), bufferSize); + } + buffer[0] = m_name; + buffer[1] = 0; + return 1; +} + +ExpressionReference SymbolNode::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { + // Do not replace symbols in expression of type: 3->A + if (parent() && parent()->type() == Type::Store && parent()->childAtIndex(1) == this) { + return this; + } + const ExpressionReference e = context.expressionForSymbol(SymbolReference(m_name)); + if (e.isDefined() && hasAnExactRepresentation(context)) { // TODO: later AZ should be replaced. + /* The stored expression had been beautified which forces to call deepReduce. */ + return e.clone().deepReduce(context, angleUnit); + } + return ExpressionReference(this); +} + +bool SymbolNode::hasAnExactRepresentation(Context & context) const { + // TODO: so far, no symbols can be exact but A, ..Z should be able to hold exact values later. + return false; +} + +template +EvaluationReference SymbolNode::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { + if (m_name == Ion::Charset::IComplex) { + return ComplexReference(0.0, 1.0); + } + const ExpressionReference e = context.expressionForSymbol(SymbolReference(m_name)); + if (e.isDefined()) { + return e.node()->approximate(T(), context, angleUnit); + } + return ComplexReference::Undefined(); +} + +const char * SymbolReference::textForSpecialSymbols(char name) { switch (name) { case SpecialSymbols::Ans: return "ans"; @@ -82,27 +245,7 @@ const char * Symbol::textForSpecialSymbols(char name) { } } -int Symbol::getVariables(isVariableTest isVariable, char * variables) const { - size_t variablesLength = strlen(variables); - if (isVariable(m_name)) { - char * currentChar = variables; - while (*currentChar != 0) { - if (*currentChar == m_name) { - return variablesLength; - } - currentChar++; - } - if (variablesLength < k_maxNumberOfVariables) { - variables[variablesLength] = m_name; - variables[variablesLength+1] = 0; - return variablesLength+1; - } - return -1; - } - return variablesLength; -} - -Symbol::SpecialSymbols Symbol::matrixSymbol(char index) { +SymbolReference::SpecialSymbols SymbolReference::matrixSymbol(char index) { switch (index - '0') { case 0: return SpecialSymbols::M0; @@ -130,218 +273,47 @@ Symbol::SpecialSymbols Symbol::matrixSymbol(char index) { } } -Symbol::Symbol(char name) : - m_name(name) -{ -} - -Symbol::Symbol(Symbol&& other) : - m_name(other.m_name) -{ -} - -Symbol::Symbol(const Symbol& other) : - m_name(other.m_name) -{ -} - -Expression * Symbol::clone() const { - return new Symbol(m_name); -} - -int Symbol::polynomialDegree(char symbol) const { - if (m_name == symbol) { - return 1; - } - return 0; -} - -int Symbol::privateGetPolynomialCoefficients(char symbolName, Expression * coefficients[]) const { - if (m_name == symbolName) { - coefficients[0] = new Rational(0); - coefficients[1] = new Rational(1); - return 1; - } - coefficients[0] = clone(); - return 0; -} - -Expression * Symbol::replaceSymbolWithExpression(char symbol, Expression * expression) { - if (m_name == symbol) { - Expression * value = expression->clone(); - if (parent() && value->needParenthesisWithParent(parent())) { - value = new Parenthesis(value, false); - } - return replaceWith(value, true); - } - return this; -} - -Expression::Sign Symbol::sign() const { - /* TODO: Maybe, we will want to know that from a context given in parameter: - if (context.expressionForSymbol(this) != nullptr) { - return context.expressionForSymbol(this)->sign(context); - }*/ - if (m_name == Ion::Charset::SmallPi) { - return Sign::Positive; - } - if (m_name == Ion::Charset::Exponential) { - return Sign::Positive; - } - return Sign::Unknown; -} - -bool Symbol::isApproximate(Context & context) const { - // TODO: so far, all symbols A to Z, M0->M9 hold an approximate values. But they should be able to hold exact values later. - if (isScalarSymbol() || isMatrixSymbol()) { +bool SymbolReference::isMatrixSymbol(char c) { + if (c >= (char)SpecialSymbols::M0 && c <= (char)SpecialSymbols::M9) { return true; } return false; } -float Symbol::characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const { - if (m_name == 'x') { - return NAN; - } - return 0.0; -} - -bool Symbol::hasAnExactRepresentation(Context & context) const { - // TODO: so far, no symbols can be exact but A, ..Z should be able to hold exact values later. - return false; -} - -Expression * Symbol::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { - // Do not replace symbols in expression of type: 3->A - if (parent()->type() == Type::Store && parent()->operand(1) == this) { - return this; - } - const Expression * e = context.expressionForSymbol(this); - if (e != nullptr && hasAnExactRepresentation(context)) { // TODO: later A...Z should be replaced. - /* The stored expression had been beautified which forces to call deepReduce. */ - return replaceWith(e->clone(), true)->deepReduce(context, angleUnit); - } - return this; -} - -template -Evaluation * Symbol::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { - if (m_name == Ion::Charset::IComplex) { - return new Complex(0.0, 1.0); - } - if (context.expressionForSymbol(this) != nullptr) { - return context.expressionForSymbol(this)->privateApproximate(T(), context, angleUnit); - } - return new Complex(Complex::Undefined()); -} - -Expression::Type Symbol::type() const { - return Expression::Type::Symbol; -} - -char Symbol::name() const { - return m_name; -} - -LayoutRef Symbol::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - if (m_name == SpecialSymbols::Ans) { - return LayoutEngine::createStringLayout("ans", 3); - } - if (m_name == SpecialSymbols::un) { - return HorizontalLayoutRef( - CharLayoutRef('u'), - VerticalOffsetLayoutRef( - CharLayoutRef('n'), - VerticalOffsetLayoutNode::Type::Subscript)); - } - if (m_name == SpecialSymbols::un1) { - return HorizontalLayoutRef( - CharLayoutRef('u'), - VerticalOffsetLayoutRef( - LayoutEngine::createStringLayout("n+1", 3), - VerticalOffsetLayoutNode::Type::Subscript)); - } - if (m_name == SpecialSymbols::vn) { - return HorizontalLayoutRef( - CharLayoutRef('v'), - VerticalOffsetLayoutRef( - CharLayoutRef('n'), - VerticalOffsetLayoutNode::Type::Subscript)); - } - if (m_name == SpecialSymbols::vn1) { - return HorizontalLayoutRef( - CharLayoutRef('v'), - VerticalOffsetLayoutRef( - LayoutEngine::createStringLayout("n+1", 3), - VerticalOffsetLayoutNode::Type::Subscript)); - } - if (isMatrixSymbol() || isSeriesSymbol(m_name) || isRegressionSymbol(m_name)) { - return LayoutEngine::createStringLayout(textForSpecialSymbols(m_name), 2); - } - return LayoutEngine::createStringLayout(&m_name, 1); -} - -int Symbol::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - if (bufferSize == 0) { - return -1; - } - if (bufferSize == 1) { - buffer[bufferSize-1] = 0; - return 0; - } - /* Special cases for all special symbols */ - if (m_name >0 && m_name < 32) { - return strlcpy(buffer, textForSpecialSymbols(m_name), bufferSize); - } - buffer[0] = m_name; - buffer[1] = 0; - return 1; -} - -bool Symbol::isMatrixSymbol() const { - if (m_name >= (char)SpecialSymbols::M0 && m_name <= (char)SpecialSymbols::M9) { +bool SymbolReference::isScalarSymbol(char c) { + if (c >= 'A' && c <= 'Z') { return true; } return false; } -bool Symbol::isScalarSymbol() const { - if (m_name >= 'A' && m_name <= 'Z') { - return true; - } - return false; -} - -bool Symbol::isVariableSymbol(char c) { +bool SymbolReference::isVariableSymbol(char c) { if (c >= 'a' && c <= 'z') { return true; } return false; } -bool Symbol::isSeriesSymbol(char c) { +bool SymbolReference::isSeriesSymbol(char c) { if (c >= (char)SpecialSymbols::V1 && c <= (char)SpecialSymbols::N3) { return true; } return false; } -bool Symbol::isRegressionSymbol(char c) { +bool SymbolReference::isRegressionSymbol(char c) { if (c >= (char)SpecialSymbols::X1 && c <= (char)SpecialSymbols::Y3) { return true; } return false; } -int Symbol::simplificationOrderSameType(const Expression * e, bool canBeInterrupted) const { - assert(e->type() == Expression::Type::Symbol); - if ((uint8_t)m_name == ((uint8_t)static_cast(e)->name())) { - return 0; +bool SymbolReference::isApproximate(char c, Context & context) { + // TODO: so far, all symbols A to Z, M0->M9 hold an approximate values. But they should be able to hold exact values later. + if (SymbolReference::isScalarSymbol(c) || SymbolReference::isMatrixSymbol(c)) { + return true; } - if ((uint8_t)m_name > ((uint8_t)static_cast(e)->name())) { - return 1; - } - return -1; + return false; } } diff --git a/poincare/src/tangent.cpp b/poincare/src/tangent.cpp index 60cc04af2..cd09c99b3 100644 --- a/poincare/src/tangent.cpp +++ b/poincare/src/tangent.cpp @@ -33,7 +33,7 @@ std::complex Tangent::computeOnComplex(const std::complex c, Preferences:: return Trigonometry::RoundToMeaningfulDigits(res); } -Expression * Tangent::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +ExpressionReference Tangent::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { Expression * e = Expression::shallowReduce(context, angleUnit); if (e != this) { return e; diff --git a/poincare/src/tree_reference.cpp b/poincare/src/tree_reference.cpp index 1411babab..506c0754d 100644 --- a/poincare/src/tree_reference.cpp +++ b/poincare/src/tree_reference.cpp @@ -135,6 +135,21 @@ void TreeReference::replaceTreeChild(TreeReference oldChild, TreeReference newCh oldChild.node()->release(oldChild.numberOfChildren()); } +void TreeReference::swapChildren(int i, int j) { + assert(isDefined()); + assert(i >= 0 && i < numberOfChildren()); + assert(j >= 0 && j < numberOfChildren()); + if (i == j) { + return; + } + int firstChildIndex = i < j ? i : j; + int secondChildIndex = i > j ? i : j; + TreeReference firstChild = treeChildAtIndex(firstChildIndex); + TreeReference secondChild = treeChildAtIndex(secondChildIndex); + TreePool::sharedPool()->move(firstChild.node()->nextSibling(), secondChild.node(), secondChild.numberOfChildren()); + TreePool::sharedPool()->move(treeChildAtIndex(secondChildIndex).node()->nextSibling(), firstChild.node(), firstChild.numberOfChildren()); +} + void TreeReference::replaceWithAllocationFailure(int currentNumberOfChildren) { if (isAllocationFailure()) { return; diff --git a/poincare/src/undefined.cpp b/poincare/src/undefined.cpp index 79c59ccea..8fdf9e3ff 100644 --- a/poincare/src/undefined.cpp +++ b/poincare/src/undefined.cpp @@ -1,4 +1,5 @@ #include +#include #include extern "C" { @@ -8,33 +9,25 @@ extern "C" { namespace Poincare { -Expression::Type Undefined::type() const { - return Type::Undefined; -} - -Expression * Undefined::clone() const { - return new Undefined(); -} - -int Undefined::polynomialDegree(char symbolName) const { +int UndefinedNode::polynomialDegree(char symbolName) const { return -1; } -template Complex * Undefined::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { - return new Complex(Complex::Undefined()); -} - -LayoutRef Undefined::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - char buffer[16]; - int numberOfChars = PrintFloat::convertFloatToText(NAN, buffer, 16, 1, floatDisplayMode); +LayoutRef UndefinedNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + char buffer[6]; + int numberOfChars = PrintFloat::convertFloatToText(NAN, buffer, 6, numberOfSignificantDigits, floatDisplayMode); return LayoutEngine::createStringLayout(buffer, numberOfChars); } -int Undefined::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { +int UndefinedNode::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { if (bufferSize == 0) { return -1; } - return strlcpy(buffer, "undef", bufferSize); + return PrintFloat::convertFloatToText(NAN, buffer, bufferSize, numberOfSignificantDigits, floatDisplayMode); +} + +template EvaluationReference UndefinedNode::templatedApproximate() const { + return ComplexReference::Undefined(); } }