From fd25b678ce120d5060da89716bf5a3c989740a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 23 Jul 2019 17:14:18 +0200 Subject: [PATCH] [poincare] Split Multiplication into MultiplicationExplicite and MultiplicationImplicite --- apps/regression/model/cubic_model.cpp | 8 +- apps/regression/model/quadratic_model.cpp | 6 +- apps/regression/model/quartic_model.cpp | 10 +- apps/regression/model/trigonometric_model.cpp | 6 +- apps/solver/equation_store.cpp | 32 +- poincare/Makefile | 2 + poincare/include/poincare/complex_cartesian.h | 4 +- poincare/include/poincare/expression.h | 3 + poincare/include/poincare/expression_node.h | 3 +- poincare/include/poincare/factor.h | 4 +- poincare/include/poincare/matrix.h | 3 - poincare/include/poincare/multiplication.h | 63 +- .../poincare/multiplication_explicite.h | 85 +++ .../poincare/multiplication_implicite.h | 48 ++ poincare/include/poincare_nodes.h | 3 +- poincare/src/absolute_value.cpp | 4 +- poincare/src/addition.cpp | 22 +- poincare/src/complex_cartesian.cpp | 47 +- poincare/src/confidence_interval.cpp | 4 +- poincare/src/conjugate.cpp | 4 +- poincare/src/determinant.cpp | 17 +- poincare/src/division.cpp | 9 +- poincare/src/expression.cpp | 14 +- poincare/src/expression_debug.cpp | 7 +- poincare/src/factor.cpp | 8 +- poincare/src/factorial.cpp | 6 +- poincare/src/logarithm.cpp | 12 +- poincare/src/matrix.cpp | 3 +- poincare/src/matrix_dimension.cpp | 1 + poincare/src/multiplication.cpp | 702 +---------------- poincare/src/multiplication_explicite.cpp | 718 ++++++++++++++++++ poincare/src/multiplication_implicite.cpp | 53 ++ poincare/src/opposite.cpp | 4 +- poincare/src/parsing/parser.cpp | 4 +- poincare/src/power.cpp | 60 +- poincare/src/prediction_interval.cpp | 6 +- poincare/src/sign_function.cpp | 2 +- poincare/src/subtraction.cpp | 4 +- poincare/src/tree_handle.cpp | 3 +- poincare/src/trigonometry.cpp | 20 +- poincare/src/trigonometry_cheat_table.cpp | 4 +- poincare/test/expression_order.cpp | 38 +- poincare/test/layouts.cpp | 6 +- poincare/test/parser.cpp | 64 +- poincare/test/properties.cpp | 8 +- 45 files changed, 1148 insertions(+), 986 deletions(-) create mode 100644 poincare/include/poincare/multiplication_explicite.h create mode 100644 poincare/include/poincare/multiplication_implicite.h create mode 100644 poincare/src/multiplication_explicite.cpp create mode 100644 poincare/src/multiplication_implicite.cpp diff --git a/apps/regression/model/cubic_model.cpp b/apps/regression/model/cubic_model.cpp index 1c5899e81..1c0a67747 100644 --- a/apps/regression/model/cubic_model.cpp +++ b/apps/regression/model/cubic_model.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include using namespace Poincare; @@ -83,17 +83,17 @@ Expression CubicModel::expression(double * modelCoefficients) { double c = modelCoefficients[2]; double d = modelCoefficients[3]; Expression addChildren[] = { - Multiplication::Builder( + MultiplicationExplicite::Builder( Number::DecimalNumber(a), Power::Builder( Symbol::Builder('x'), Decimal::Builder(3.0))), - Multiplication::Builder( + MultiplicationExplicite::Builder( Number::DecimalNumber(b), Power::Builder( Symbol::Builder('x'), Decimal::Builder(2.0))), - Multiplication::Builder( + MultiplicationExplicite::Builder( Number::DecimalNumber(c), Symbol::Builder('x')), Number::DecimalNumber(d) diff --git a/apps/regression/model/quadratic_model.cpp b/apps/regression/model/quadratic_model.cpp index 67305337f..8d4709ba9 100644 --- a/apps/regression/model/quadratic_model.cpp +++ b/apps/regression/model/quadratic_model.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include using namespace Poincare; @@ -70,12 +70,12 @@ Expression QuadraticModel::expression(double * modelCoefficients) { double c = modelCoefficients[2]; // a*x^2+b*x+c Expression addChildren[] = { - Multiplication::Builder( + MultiplicationExplicite::Builder( Number::DecimalNumber(a), Power::Builder( Symbol::Builder('x'), Decimal::Builder(2.0))), - Multiplication::Builder( + MultiplicationExplicite::Builder( Number::DecimalNumber(b), Symbol::Builder('x')), Number::DecimalNumber(c) diff --git a/apps/regression/model/quartic_model.cpp b/apps/regression/model/quartic_model.cpp index 32a2323a8..9289631d0 100644 --- a/apps/regression/model/quartic_model.cpp +++ b/apps/regression/model/quartic_model.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include using namespace Poincare; @@ -98,25 +98,25 @@ Expression QuarticModel::expression(double * modelCoefficients) { double e = modelCoefficients[4]; Expression addChildren[] = { // a*x^4 - Multiplication::Builder( + MultiplicationExplicite::Builder( Number::DecimalNumber(a), Power::Builder( Symbol::Builder('x'), Decimal::Builder(4.0))), // b*x^3 - Multiplication::Builder( + MultiplicationExplicite::Builder( Number::DecimalNumber(b), Power::Builder( Symbol::Builder('x'), Decimal::Builder(3.0))), // c*x^2 - Multiplication::Builder( + MultiplicationExplicite::Builder( Number::DecimalNumber(c), Power::Builder( Symbol::Builder('x'), Decimal::Builder(2.0))), // d*x - Multiplication::Builder( + MultiplicationExplicite::Builder( Number::DecimalNumber(d), Symbol::Builder('x')), // e diff --git a/apps/regression/model/trigonometric_model.cpp b/apps/regression/model/trigonometric_model.cpp index 2475f61e0..f08dfd927 100644 --- a/apps/regression/model/trigonometric_model.cpp +++ b/apps/regression/model/trigonometric_model.cpp @@ -2,7 +2,7 @@ #include "../../shared/poincare_helpers.h" #include #include -#include +#include #include #include #include @@ -66,11 +66,11 @@ Expression TrigonometricModel::expression(double * modelCoefficients) { // a*sin(bx+c)+d Expression result = Addition::Builder( - Multiplication::Builder( + MultiplicationExplicite::Builder( Number::DecimalNumber(a), Sine::Builder( Addition::Builder( - Multiplication::Builder( + MultiplicationExplicite::Builder( Number::DecimalNumber(b), Symbol::Builder('x')), Number::DecimalNumber(c)))), diff --git a/apps/solver/equation_store.cpp b/apps/solver/equation_store.cpp index 9f2b75480..31af8f7be 100644 --- a/apps/solver/equation_store.cpp +++ b/apps/solver/equation_store.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -274,20 +274,20 @@ EquationStore::Error EquationStore::oneDimensialPolynomialSolve(Expression exact /* Equation ax^2+bx+c = 0 */ assert(degree == 2); // Compute delta = b*b-4ac - Expression delta = Subtraction::Builder(Power::Builder(coefficients[1].clone(), Rational::Builder(2)), Multiplication::Builder(Rational::Builder(4), coefficients[0].clone(), coefficients[2].clone())); + Expression delta = Subtraction::Builder(Power::Builder(coefficients[1].clone(), Rational::Builder(2)), MultiplicationExplicite::Builder(Rational::Builder(4), coefficients[0].clone(), coefficients[2].clone())); delta = delta.simplify(context, updatedComplexFormat(context), Poincare::Preferences::sharedPreferences()->angleUnit()); if (delta.isUninitialized()) { delta = Poincare::Undefined::Builder(); } if (delta.isRationalZero()) { // if delta = 0, x0=x1= -b/(2a) - exactSolutions[0] = Division::Builder(Opposite::Builder(coefficients[1]), Multiplication::Builder(Rational::Builder(2), coefficients[2])); + exactSolutions[0] = Division::Builder(Opposite::Builder(coefficients[1]), MultiplicationExplicite::Builder(Rational::Builder(2), coefficients[2])); m_numberOfSolutions = 2; } else { // x0 = (-b-sqrt(delta))/(2a) - exactSolutions[0] = Division::Builder(Subtraction::Builder(Opposite::Builder(coefficients[1].clone()), SquareRoot::Builder(delta.clone())), Multiplication::Builder(Rational::Builder(2), coefficients[2].clone())); + exactSolutions[0] = Division::Builder(Subtraction::Builder(Opposite::Builder(coefficients[1].clone()), SquareRoot::Builder(delta.clone())), MultiplicationExplicite::Builder(Rational::Builder(2), coefficients[2].clone())); // x1 = (-b+sqrt(delta))/(2a) - exactSolutions[1] = Division::Builder(Addition::Builder(Opposite::Builder(coefficients[1]), SquareRoot::Builder(delta.clone())), Multiplication::Builder(Rational::Builder(2), coefficients[2])); + exactSolutions[1] = Division::Builder(Addition::Builder(Opposite::Builder(coefficients[1]), SquareRoot::Builder(delta.clone())), MultiplicationExplicite::Builder(Rational::Builder(2), coefficients[2])); m_numberOfSolutions = 3; } exactSolutions[m_numberOfSolutions-1] = delta; @@ -307,18 +307,18 @@ EquationStore::Error EquationStore::oneDimensialPolynomialSolve(Expression exact Expression * mult2Operands[3] = {new Rational::Builder(-27), new Power::Builder(a->clone(), new Rational::Builder(2), false), new Power::Builder(d->clone(), new Rational::Builder(2), false)}; Expression * mult3Operands[3] = {new Rational::Builder(-4), a->clone(), new Power::Builder(c->clone(), new Rational::Builder(3), false)}; Expression * mult4Operands[3] = {new Rational::Builder(-4), d->clone(), new Power::Builder(b->clone(), new Rational::Builder(3), false)}; - Expression * add0Operands[5] = {new Multiplication::Builder(mult0Operands, 2, false), new Multiplication::Builder(mult1Operands, 5, false), new Multiplication::Builder(mult2Operands, 3, false), new Multiplication::Builder(mult3Operands, 3, false), new Multiplication::Builder(mult4Operands, 3, false)}; + Expression * add0Operands[5] = {new MultiplicationExplicite::Builder(mult0Operands, 2, false), new MultiplicationExplicite::Builder(mult1Operands, 5, false), new MultiplicationExplicite::Builder(mult2Operands, 3, false), new MultiplicationExplicite::Builder(mult3Operands, 3, false), new MultiplicationExplicite::Builder(mult4Operands, 3, false)}; Expression * delta = new Addition(add0Operands, 5, false); PoincareHelpers::Simplify(&delta, *context); // Delta0 = b^2-3ac Expression * mult5Operands[3] = {new Rational::Builder(3), a->clone(), c->clone()}; - Expression * delta0 = new Subtraction::Builder(new Power::Builder(b->clone(), new Rational::Builder(2), false), new Multiplication::Builder(mult5Operands, 3, false), false); + Expression * delta0 = new Subtraction::Builder(new Power::Builder(b->clone(), new Rational::Builder(2), false), new MultiplicationExplicite::Builder(mult5Operands, 3, false), false); Reduce(&delta0, *context); if (delta->isRationalZero()) { if (delta0->isRationalZero()) { // delta0 = 0 && delta = 0 --> x0 = -b/(3a) delete delta0; - m_exactSolutions[0] = new Opposite::Builder(new Division::Builder(b, new Multiplication::Builder(new Rational::Builder(3), a, false), false), false); + m_exactSolutions[0] = new Opposite::Builder(new Division::Builder(b, new MultiplicationExplicite::Builder(new Rational::Builder(3), a, false), false), false); m_numberOfSolutions = 1; delete c; delete d; @@ -326,33 +326,33 @@ EquationStore::Error EquationStore::oneDimensialPolynomialSolve(Expression exact // delta = 0 --> x0 = (9ad-bc)/(2delta0) // --> x1 = (4abc-9a^2d-b^3)/(a*delta0) Expression * mult6Operands[3] = {new Rational::Builder(9), a, d}; - m_exactSolutions[0] = new Division::Builder(new Subtraction::Builder(new Multiplication::Builder(mult6Operands, 3, false), new Multiplication::Builder(b, c, false), false), new Multiplication::Builder(new Rational::Builder(2), delta0, false), false); + m_exactSolutions[0] = new Division::Builder(new Subtraction::Builder(new MultiplicationExplicite::Builder(mult6Operands, 3, false), new MultiplicationExplicite::Builder(b, c, false), false), new MultiplicationExplicite::Builder(new Rational::Builder(2), delta0, false), false); Expression * mult7Operands[4] = {new Rational::Builder(4), a->clone(), b->clone(), c->clone()}; Expression * mult8Operands[3] = {new Rational::Builder(-9), new Power::Builder(a->clone(), new Rational::Builder(2), false), d->clone()}; - Expression * add1Operands[3] = {new Multiplication::Builder(mult7Operands, 4, false), new Multiplication::Builder(mult8Operands,3, false), new Opposite::Builder(new Power::Builder(b->clone(), new Rational::Builder(3), false), false)}; - m_exactSolutions[1] = new Division::Builder(new Addition(add1Operands, 3, false), new Multiplication::Builder(a->clone(), delta0, false), false); + Expression * add1Operands[3] = {new MultiplicationExplicite::Builder(mult7Operands, 4, false), new MultiplicationExplicite::Builder(mult8Operands,3, false), new Opposite::Builder(new Power::Builder(b->clone(), new Rational::Builder(3), false), false)}; + m_exactSolutions[1] = new Division::Builder(new Addition(add1Operands, 3, false), new MultiplicationExplicite::Builder(a->clone(), delta0, false), false); m_numberOfSolutions = 2; } } else { // delta1 = 2b^3-9abc+27a^2*d Expression * mult9Operands[4] = {new Rational::Builder(-9), a, b, c}; Expression * mult10Operands[3] = {new Rational::Builder(27), new Power::Builder(a->clone(), new Rational::Builder(2), false), d}; - Expression * add2Operands[3] = {new Multiplication::Builder(new Rational::Builder(2), new Power::Builder(b->clone(), new Rational::Builder(3), false), false), new Multiplication::Builder(mult9Operands, 4, false), new Multiplication::Builder(mult10Operands, 3, false)}; + Expression * add2Operands[3] = {new MultiplicationExplicite::Builder(new Rational::Builder(2), new Power::Builder(b->clone(), new Rational::Builder(3), false), false), new MultiplicationExplicite::Builder(mult9Operands, 4, false), new MultiplicationExplicite::Builder(mult10Operands, 3, false)}; Expression * delta1 = new Addition(add2Operands, 3, false); // C = Root((delta1+sqrt(-27a^2*delta))/2, 3) Expression * mult11Operands[3] = {new Rational::Builder(-27), new Power::Builder(a->clone(), new Rational::Builder(2), false), (*delta)->clone()}; - Expression * c = new Power::Builder(new Division::Builder(new Addition(delta1, new SquareRoot(new Multiplication::Builder(mult11Operands, 3, false), false), false), new Rational::Builder(2), false), new Rational::Builder(1,3), false); - Expression * unary3roots[2] = {new Addition(new Rational::Builder(-1,2), new Division::Builder(new Multiplication::Builder(new SquareRoot(new Rational::Builder(3), false), new Constant::Builder(UCodePointMathematicalBoldSmallI), false), new Rational::Builder(2), false), false), new Subtraction::Builder(new Rational::Builder(-1,2), new Division::Builder(new Multiplication::Builder(new SquareRoot(new Rational::Builder(3), false), new Constant::Builder(UCodePointMathematicalBoldSmallI), false), new Rational::Builder(2), false), false)}; + Expression * c = new Power::Builder(new Division::Builder(new Addition(delta1, new SquareRoot(new MultiplicationExplicite::Builder(mult11Operands, 3, false), false), false), new Rational::Builder(2), false), new Rational::Builder(1,3), false); + Expression * unary3roots[2] = {new Addition(new Rational::Builder(-1,2), new Division::Builder(new MultiplicationExplicite::Builder(new SquareRoot(new Rational::Builder(3), false), new Constant::Builder(UCodePointMathematicalBoldSmallI), false), new Rational::Builder(2), false), false), new Subtraction::Builder(new Rational::Builder(-1,2), new Division::Builder(new MultiplicationExplicite::Builder(new SquareRoot(new Rational::Builder(3), false), new Constant::Builder(UCodePointMathematicalBoldSmallI), false), new Rational::Builder(2), false), false)}; // x_k = -1/(3a)*(b+C*z+delta0/(zC)) with z = unary cube root for (int k = 0; k < 3; k++) { Expression * ccopy = c; Expression * delta0copy = delta0; if (k < 2) { - ccopy = new Multiplication::Builder(c->clone(), unary3roots[k], false); + ccopy = new MultiplicationExplicite::Builder(c->clone(), unary3roots[k], false); delta0copy = delta0->clone(); } Expression * add3Operands[3] = {b->clone(), ccopy, new Division::Builder(delta0copy, ccopy->clone(), false)}; - m_exactSolutions[k] = new Multiplication::Builder(new Division::Builder(new Rational::Builder(-1), new Multiplication::Builder(new Rational::Builder(3), a->clone(), false), false), new Addition(add3Operands, 3, false), false); + m_exactSolutions[k] = new MultiplicationExplicite::Builder(new Division::Builder(new Rational::Builder(-1), new MultiplicationExplicite::Builder(new Rational::Builder(3), a->clone(), false), false), new Addition(add3Operands, 3, false), false); } m_numberOfSolutions = 3; } diff --git a/poincare/Makefile b/poincare/Makefile index caa5a6088..71fb80111 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -91,6 +91,8 @@ poincare_src += $(addprefix poincare/src/,\ matrix_trace.cpp \ matrix_transpose.cpp \ multiplication.cpp \ + multiplication_explicite.cpp \ + multiplication_implicite.cpp \ n_ary_expression.cpp \ naperian_logarithm.cpp \ nth_root.cpp \ diff --git a/poincare/include/poincare/complex_cartesian.h b/poincare/include/poincare/complex_cartesian.h index 6137befdc..99b3a6f88 100644 --- a/poincare/include/poincare/complex_cartesian.h +++ b/poincare/include/poincare/complex_cartesian.h @@ -2,7 +2,7 @@ #define POINCARE_COMPLEX_CARTESIAN_H #include -#include +#include namespace Poincare { @@ -62,7 +62,7 @@ private: static constexpr int k_maxNumberOfNodesBeforeInterrupting = 50; void factorAndArgumentOfFunction(Expression e, ExpressionNode::Type searchedType, Expression * factor, Expression * argument, ExpressionNode::ReductionContext reductionContext); ComplexCartesian interruptComputationIfManyNodes(); - static Multiplication squareRootHelper(Expression e, ExpressionNode::ReductionContext reductionContext); + static MultiplicationExplicite squareRootHelper(Expression e, ExpressionNode::ReductionContext reductionContext); static Expression powerHelper(Expression norm, Expression trigo, ExpressionNode::ReductionContext reductionContext); }; diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 142b8966a..f7763d614 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -61,6 +61,8 @@ class Expression : public TreeHandle { friend class MatrixTrace; friend class MatrixTranspose; friend class Multiplication; + friend class MultiplicationExplicite; + friend class MultiplicationImplicite; friend class NaperianLogarithm; friend class NthRoot; friend class Number; @@ -126,6 +128,7 @@ public: ExpressionNode::Type type() const { return node()->type(); } ExpressionNode::Sign sign(Context * context) const { return node()->sign(context); } bool isUndefined() const { return node()->type() == ExpressionNode::Type::Undefined || node()->type() == ExpressionNode::Type::Unreal; } + bool isMultiplication() const { return node()->type() == ExpressionNode::Type::MultiplicationExplicite || node()->type() == ExpressionNode::Type::MultiplicationImplicite; } bool isNumber() const { return node()->isNumber(); } bool isRationalZero() const; bool isRationalOne() const; diff --git a/poincare/include/poincare/expression_node.h b/poincare/include/poincare/expression_node.h index 52812efe6..d2935b925 100644 --- a/poincare/include/poincare/expression_node.h +++ b/poincare/include/poincare/expression_node.h @@ -32,7 +32,8 @@ public: Decimal, Float, Infinity, - Multiplication, + MultiplicationExplicite, + MultiplicationImplicite, Power, Addition, Factorial, diff --git a/poincare/include/poincare/factor.h b/poincare/include/poincare/factor.h index 850afdb18..e2be32f03 100644 --- a/poincare/include/poincare/factor.h +++ b/poincare/include/poincare/factor.h @@ -3,7 +3,7 @@ #include #include -#include +#include #include namespace Poincare { @@ -42,7 +42,7 @@ public: static constexpr Expression::FunctionHelper s_functionHelper = Expression::FunctionHelper("factor", 1, &UntypedBuilderOneChild); - Multiplication createMultiplicationOfIntegerPrimeDecomposition(Integer i, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; + MultiplicationExplicite createMultiplicationOfIntegerPrimeDecomposition(Integer i, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; // Expression Expression shallowReduce(Context * context); diff --git a/poincare/include/poincare/matrix.h b/poincare/include/poincare/matrix.h index bd7213c2a..87b87fb28 100644 --- a/poincare/include/poincare/matrix.h +++ b/poincare/include/poincare/matrix.h @@ -2,12 +2,9 @@ #define POINCARE_MATRIX_H #include -#include namespace Poincare { -class Multiplication; - class MatrixNode /*final*/ : public ExpressionNode { public: MatrixNode() : diff --git a/poincare/include/poincare/multiplication.h b/poincare/include/poincare/multiplication.h index d933e590b..2099d2823 100644 --- a/poincare/include/poincare/multiplication.h +++ b/poincare/include/poincare/multiplication.h @@ -7,20 +7,10 @@ namespace Poincare { class MultiplicationNode /*final*/ : public NAryExpressionNode { - friend class Addition; public: using NAryExpressionNode::NAryExpressionNode; - // Tree - size_t size() const override { return sizeof(MultiplicationNode); } -#if POINCARE_TREE_LOG - virtual void logNodeName(std::ostream & stream) const override { - stream << "Multiplication"; - } -#endif - // Properties - Type type() const override { return Type::Multiplication; } Sign sign(Context * context) const override; int polynomialDegree(Context * context, const char * symbolName) const override; int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const override; @@ -32,22 +22,11 @@ public: } template static MatrixComplex computeOnMatrices(const MatrixComplex m, const MatrixComplex n, Preferences::ComplexFormat complexFormat); -private: - // Property - Expression setSign(Sign s, ReductionContext reductionContext) override; - +protected: // Layout bool childNeedsParenthesis(const TreeNode * child) const override; - Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - - // Serialize - int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - - // Simplification - Expression shallowReduce(ReductionContext reductionContext) override; - Expression shallowBeautify(ReductionContext reductionContext) override; - Expression denominator(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override; +private: /* Approximation */ template static MatrixComplex computeOnMatrixAndComplex(const MatrixComplex m, const std::complex c, Preferences::ComplexFormat complexFormat) { return ApproximationHelper::ElementWiseOnMatrixComplexAndComplex(m, c, complexFormat, compute); @@ -60,49 +39,13 @@ private: } }; -class Multiplication final : public NAryExpression { - friend class AdditionNode; - friend class Addition; - friend class Power; +class Multiplication : public NAryExpression { public: Multiplication(const MultiplicationNode * n) : NAryExpression(n) {} - static Multiplication Builder() { return TreeHandle::NAryBuilder(); } - static Multiplication Builder(Expression e1) { return Multiplication::Builder(&e1, 1); } - static Multiplication Builder(Expression e1, Expression e2) { return Multiplication::Builder(ArrayBuilder(e1, e2).array(), 2); } - static Multiplication Builder(Expression e1, Expression e2, Expression e3) { return Multiplication::Builder(ArrayBuilder(e1, e2, e3).array(), 3); } - static Multiplication Builder(Expression e1, Expression e2, Expression e3, Expression e4) { return Multiplication::Builder(ArrayBuilder(e1, e2, e3, e4).array(), 4); } - static Multiplication Builder(Expression * children, size_t numberOfChildren) { return TreeHandle::NAryBuilder(children, numberOfChildren); } template static void computeOnArrays(T * m, T * n, T * result, int mNumberOfColumns, int mNumberOfRows, int nNumberOfColumns); // Expression - Expression setSign(ExpressionNode::Sign s, ExpressionNode::ReductionContext reductionContext); - Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); - Expression shallowBeautify(ExpressionNode::ReductionContext reductionContext); int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const; - Expression denominator(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; - void sortChildrenInPlace(ExpressionOrder order, Context * context, bool canBeInterrupted) { - NAryExpression::sortChildrenInPlace(order, context, false, canBeInterrupted); - } -private: - // Simplification - Expression privateShallowReduce(ExpressionNode::ReductionContext reductionContext, bool expand, bool canBeInterrupted); - void mergeMultiplicationChildrenInPlace(); - void factorizeBase(int i, int j, ExpressionNode::ReductionContext reductionContext); - void mergeInChildByFactorizingBase(int i, Expression e, ExpressionNode::ReductionContext reductionContext); - void factorizeExponent(int i, int j, ExpressionNode::ReductionContext reductionContext); - Expression distributeOnOperandAtIndex(int index, ExpressionNode::ReductionContext reductionContext); - void addMissingFactors(Expression factor, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); - void factorizeSineAndCosine(int i, int j, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); - static bool HaveSameNonNumeralFactors(const Expression & e1, const Expression & e2); - static bool TermsHaveIdenticalBase(const Expression & e1, const Expression & e2); - static bool TermsHaveIdenticalExponent(const Expression & e1, const Expression & e2); - static bool TermHasNumeralBase(const Expression & e); - static bool TermHasNumeralExponent(const Expression & e); - static const Expression CreateExponent(Expression e); - /* Warning: mergeNegativePower doesnot always return a multiplication: - * *(b^-1,c^-1) -> (bc)^-1 */ - Expression mergeNegativePower(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); - static inline const Expression Base(const Expression e); }; } diff --git a/poincare/include/poincare/multiplication_explicite.h b/poincare/include/poincare/multiplication_explicite.h new file mode 100644 index 000000000..e248db8ef --- /dev/null +++ b/poincare/include/poincare/multiplication_explicite.h @@ -0,0 +1,85 @@ +#ifndef POINCARE_MULTIPLICATION_EXPLICITE_H +#define POINCARE_MULTIPLICATION_EXPLICITE_H + +#include +#include + +namespace Poincare { + +class MultiplicationExpliciteNode /*final*/ : public MultiplicationNode { + friend class Addition; +public: + using MultiplicationNode::MultiplicationNode; + // Tree + size_t size() const override { return sizeof(MultiplicationExpliciteNode); } +#if POINCARE_TREE_LOG + virtual void logNodeName(std::ostream & stream) const override { + stream << "Multiplication Explicite"; + } +#endif + + // Properties + Type type() const override { return Type::MultiplicationExplicite; } + +private: + // Property + Expression setSign(Sign s, ReductionContext reductionContext) override; + + // Layout + Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + + // Serialize + int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + + // Simplification + Expression shallowReduce(ReductionContext reductionContext) override; + Expression shallowBeautify(ReductionContext reductionContext) override; + Expression denominator(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override; + +}; + +class MultiplicationExplicite : public Multiplication { + friend class AdditionNode; + friend class Addition; + friend class Power; +public: + MultiplicationExplicite(const MultiplicationExpliciteNode * n) : Multiplication(n) {} + static MultiplicationExplicite Builder() { return TreeHandle::NAryBuilder(); } + static MultiplicationExplicite Builder(Expression e1) { return MultiplicationExplicite::Builder(&e1, 1); } + static MultiplicationExplicite Builder(Expression e1, Expression e2) { return MultiplicationExplicite::Builder(ArrayBuilder(e1, e2).array(), 2); } + static MultiplicationExplicite Builder(Expression e1, Expression e2, Expression e3) { return MultiplicationExplicite::Builder(ArrayBuilder(e1, e2, e3).array(), 3); } + static MultiplicationExplicite Builder(Expression e1, Expression e2, Expression e3, Expression e4) { return MultiplicationExplicite::Builder(ArrayBuilder(e1, e2, e3, e4).array(), 4); } + static MultiplicationExplicite Builder(Expression * children, size_t numberOfChildren) { return TreeHandle::NAryBuilder(children, numberOfChildren); } + + Expression setSign(ExpressionNode::Sign s, ExpressionNode::ReductionContext reductionContext); + Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); + Expression shallowBeautify(ExpressionNode::ReductionContext reductionContext); + Expression denominator(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; + void sortChildrenInPlace(ExpressionOrder order, Context * context, bool canBeInterrupted) { + NAryExpression::sortChildrenInPlace(order, context, false, canBeInterrupted); + } +private: + // Simplification + Expression privateShallowReduce(ExpressionNode::ReductionContext reductionContext, bool expand, bool canBeInterrupted); + void mergeMultiplicationChildrenInPlace(); + void factorizeBase(int i, int j, ExpressionNode::ReductionContext reductionContext); + void mergeInChildByFactorizingBase(int i, Expression e, ExpressionNode::ReductionContext reductionContext); + void factorizeExponent(int i, int j, ExpressionNode::ReductionContext reductionContext); + Expression distributeOnOperandAtIndex(int index, ExpressionNode::ReductionContext reductionContext); + void addMissingFactors(Expression factor, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); + void factorizeSineAndCosine(int i, int j, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); + static bool HaveSameNonNumeralFactors(const Expression & e1, const Expression & e2); + static bool TermsHaveIdenticalBase(const Expression & e1, const Expression & e2); + static bool TermsHaveIdenticalExponent(const Expression & e1, const Expression & e2); + static bool TermHasNumeralBase(const Expression & e); + static bool TermHasNumeralExponent(const Expression & e); + static const Expression CreateExponent(Expression e); + /* Warning: mergeNegativePower doesnot always return a multiplication: + * *(b^-1,c^-1) -> (bc)^-1 */ + Expression mergeNegativePower(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); + static inline const Expression Base(const Expression e); +}; + +} + +#endif diff --git a/poincare/include/poincare/multiplication_implicite.h b/poincare/include/poincare/multiplication_implicite.h new file mode 100644 index 000000000..42fc23338 --- /dev/null +++ b/poincare/include/poincare/multiplication_implicite.h @@ -0,0 +1,48 @@ +#ifndef POINCARE_MULTIPLICATION_IMPLICITE_H +#define POINCARE_MULTIPLICATION_IMPLICITE_H + +#include + +namespace Poincare { + +class MultiplicationImplicite; + +class MultiplicationImpliciteNode /*final*/ : public MultiplicationNode { +public: + using MultiplicationNode::MultiplicationNode; + + // Tree + size_t size() const override { return sizeof(MultiplicationImpliciteNode); } +#if POINCARE_TREE_LOG + virtual void logNodeName(std::ostream & stream) const override { + stream << "Multiplication Implicite"; + } +#endif + + // Properties + Type type() const override { return Type::MultiplicationImplicite; } + +private: + // Layout + bool childNeedsParenthesis(const TreeNode * child) const override; + Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + + // Serialize + int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + + // Simplification + Expression shallowReduce(ReductionContext reductionContext) override; +}; + +class MultiplicationImplicite : public Multiplication { +public: + MultiplicationImplicite(const MultiplicationImpliciteNode * n) : Multiplication(n) {} + static MultiplicationImplicite Builder(Expression e1, Expression e2) { return MultiplicationImplicite::Builder(ArrayBuilder(e1, e2).array(), 2); } + static MultiplicationImplicite Builder(Expression * children, size_t numberOfChildren) { return TreeHandle::NAryBuilder(children, numberOfChildren); } + // Simplification + Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); +}; + +} + +#endif diff --git a/poincare/include/poincare_nodes.h b/poincare/include/poincare_nodes.h index d468d43f5..8e00126c7 100644 --- a/poincare/include/poincare_nodes.h +++ b/poincare/include/poincare_nodes.h @@ -49,7 +49,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/poincare/src/absolute_value.cpp b/poincare/src/absolute_value.cpp index 19c3267cb..7f33488bb 100644 --- a/poincare/src/absolute_value.cpp +++ b/poincare/src/absolute_value.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include @@ -55,7 +55,7 @@ Expression AbsoluteValue::shallowReduce(ExpressionNode::ReductionContext reducti } else if (!std::isnan(app) && ((c.isNumber() && app < 0.0f) || app <= -Expression::Epsilon())) { // abs(a) = -a with a < 0 (same comment as above to check that a < 0) - Multiplication m = Multiplication::Builder(Rational::Builder(-1), c); + MultiplicationExplicite m = MultiplicationExplicite::Builder(Rational::Builder(-1), c); replaceWithInPlace(m); return m.shallowReduce(reductionContext); } diff --git a/poincare/src/addition.cpp b/poincare/src/addition.cpp index 935abe759..c96a2b1ea 100644 --- a/poincare/src/addition.cpp +++ b/poincare/src/addition.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include @@ -61,7 +61,7 @@ Expression AdditionNode::shallowBeautify(ReductionContext reductionContext) { // Addition const Number Addition::NumeralFactor(const Expression & e) { - if (e.type() == ExpressionNode::Type::Multiplication && e.childAtIndex(0).isNumber()) { + if (e.type() == ExpressionNode::Type::MultiplicationExplicite && e.childAtIndex(0).isNumber()) { Number result = e.childAtIndex(0).convert(); return result; } @@ -305,7 +305,7 @@ Expression Addition::shallowReduce(ExpressionNode::ReductionContext reductionCon } int Addition::NumberOfNonNumeralFactors(const Expression & e) { - if (e.type() != ExpressionNode::Type::Multiplication) { + if (e.type() != ExpressionNode::Type::MultiplicationExplicite) { return 1; // Or (e->type() != Type::Rational); } int result = e.numberOfChildren(); @@ -316,7 +316,7 @@ int Addition::NumberOfNonNumeralFactors(const Expression & e) { } const Expression Addition::FirstNonNumeralFactor(const Expression & e) { - if (e.type() != ExpressionNode::Type::Multiplication) { + if (e.type() != ExpressionNode::Type::MultiplicationExplicite) { return e; } if (e.childAtIndex(0).isNumber()) { @@ -346,7 +346,7 @@ bool Addition::TermsHaveIdenticalNonNumeralFactors(const Expression & e1, const return FirstNonNumeralFactor(e1).isIdenticalTo(FirstNonNumeralFactor(e2)); } else { assert(numberOfNonNumeralFactors > 1); - return Multiplication::HaveSameNonNumeralFactors(e1, e2); + return MultiplicationExplicite::HaveSameNonNumeralFactors(e1, e2); } } @@ -360,7 +360,7 @@ Expression Addition::factorizeOnCommonDenominator(ExpressionNode::ReductionConte Addition a = Addition::Builder(); // Step 1: We want to compute the common denominator, b*d - Multiplication commonDenominator = Multiplication::Builder(); + MultiplicationExplicite commonDenominator = MultiplicationExplicite::Builder(); for (int i = 0; i < numberOfChildren(); i++) { Expression childI = childAtIndex(i); Expression currentDenominator = childI.denominator(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); @@ -390,14 +390,14 @@ Expression Addition::factorizeOnCommonDenominator(ExpressionNode::ReductionConte assert(reductionContext.target() == ExpressionNode::ReductionTarget::User); // Else, before, the algorithm used User target -> put back ? Addition numerator = Addition::Builder(); for (int i = 0; i < numberOfChildren(); i++) { - Multiplication m = Multiplication::Builder(childAtIndex(i), commonDenominator.clone()); + MultiplicationExplicite m = MultiplicationExplicite::Builder(childAtIndex(i), commonDenominator.clone()); numerator.addChildAtIndexInPlace(m, numerator.numberOfChildren(), numerator.numberOfChildren()); m.privateShallowReduce(reductionContext, true, false); } // Step 3: Add the denominator Power inverseDenominator = Power::Builder(commonDenominator, Rational::Builder(-1)); - Multiplication result = Multiplication::Builder(numerator, inverseDenominator); + MultiplicationExplicite result = MultiplicationExplicite::Builder(numerator, inverseDenominator); // Step 4: Simplify the numerator numerator.shallowReduce(reductionContext); @@ -436,9 +436,9 @@ void Addition::factorizeChildrenAtIndexesInPlace(int index1, int index2, Express removeChildAtIndexInPlace(index2); // Step 3: Create a multiplication - Multiplication m = Multiplication::Builder(); - if (e1.type() == ExpressionNode::Type::Multiplication) { - m = static_cast(e1); + MultiplicationExplicite m = MultiplicationExplicite::Builder(); + if (e1.type() == ExpressionNode::Type::MultiplicationExplicite) { + m = static_cast(e1); } else { replaceChildAtIndexInPlace(index1, m); m.addChildAtIndexInPlace(e1, 0, 0); diff --git a/poincare/src/complex_cartesian.cpp b/poincare/src/complex_cartesian.cpp index 75ce09f47..0d7261b61 100644 --- a/poincare/src/complex_cartesian.cpp +++ b/poincare/src/complex_cartesian.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -84,12 +83,12 @@ void ComplexCartesian::factorAndArgumentOfFunction(Expression e, ExpressionNode: *argument = e.childAtIndex(0); return; } - if (e.type() == ExpressionNode::Type::Multiplication) { + if (e.type() == ExpressionNode::Type::MultiplicationExplicite) { for (int i = 0; i < e.numberOfChildren(); i++) { if (e.childAtIndex(i).type() == searchedType) { *argument = e.childAtIndex(i).childAtIndex(0); *factor = e.clone(); - static_cast(factor)->removeChildAtIndexInPlace(i); + static_cast(factor)->removeChildAtIndexInPlace(i); *factor = factor->shallowReduce(reductionContext); Expression positiveFactor = factor->makePositiveAnyNegativeNumeralFactor(reductionContext); *factor = positiveFactor.isUninitialized() ? *factor : positiveFactor; @@ -158,7 +157,7 @@ Expression ComplexCartesian::argument(ExpressionNode::ReductionContext reduction } // Then, compute sign(b) * π/2 - atan(a/b) Expression signb = SignFunction::Builder(b); - Expression signbPi2 = Multiplication::Builder(Rational::Builder(1,2), signb, Constant::Builder(UCodePointGreekSmallLetterPi)); + Expression signbPi2 = MultiplicationExplicite::Builder(Rational::Builder(1,2), signb, Constant::Builder(UCodePointGreekSmallLetterPi)); signb.shallowReduce(reductionContext); Expression sub = Subtraction::Builder(signbPi2, arcTangent); signbPi2.shallowReduce(reductionContext); @@ -169,7 +168,7 @@ Expression ComplexCartesian::argument(ExpressionNode::ReductionContext reduction Expression signa = SignFunction::Builder(a).shallowReduce(reductionContext); Subtraction sub = Subtraction::Builder(Rational::Builder(1), signa); signa.shallowReduce(reductionContext); - Multiplication mul = Multiplication::Builder(Rational::Builder(1,2), Constant::Builder(UCodePointGreekSmallLetterPi), sub); + MultiplicationExplicite mul = MultiplicationExplicite::Builder(Rational::Builder(1,2), Constant::Builder(UCodePointGreekSmallLetterPi), sub); sub.shallowReduce(reductionContext); return mul; } @@ -185,10 +184,10 @@ ComplexCartesian ComplexCartesian::inverse(ExpressionNode::ReductionContext redu denominatorReal.shallowReduce(reductionContext); Expression denominatorImagInv = Power::Builder(denominatorImag, Rational::Builder(-1)); denominatorImag.shallowReduce(reductionContext); - Multiplication A = Multiplication::Builder(a, denominatorRealInv); + MultiplicationExplicite A = MultiplicationExplicite::Builder(a, denominatorRealInv); denominatorRealInv.shallowReduce(reductionContext); - Expression numeratorImag = Multiplication::Builder(Rational::Builder(-1), b); - Multiplication B = Multiplication::Builder(numeratorImag, denominatorImagInv); + Expression numeratorImag = MultiplicationExplicite::Builder(Rational::Builder(-1), b); + MultiplicationExplicite B = MultiplicationExplicite::Builder(numeratorImag, denominatorImagInv); numeratorImag.shallowReduce(reductionContext); denominatorImagInv.shallowReduce(reductionContext); ComplexCartesian result = ComplexCartesian::Builder(A,B); @@ -197,13 +196,13 @@ ComplexCartesian ComplexCartesian::inverse(ExpressionNode::ReductionContext redu return result.interruptComputationIfManyNodes(); } -Multiplication ComplexCartesian::squareRootHelper(Expression e, ExpressionNode::ReductionContext reductionContext) { +MultiplicationExplicite ComplexCartesian::squareRootHelper(Expression e, ExpressionNode::ReductionContext reductionContext) { //(1/2)*sqrt(2*e) - Multiplication doubleE = Multiplication::Builder(Rational::Builder(2), e); + MultiplicationExplicite doubleE = MultiplicationExplicite::Builder(Rational::Builder(2), e); e.shallowReduce(reductionContext); Expression sqrt = SquareRoot::Builder(doubleE); doubleE.shallowReduce(reductionContext); - Multiplication result = Multiplication::Builder(Rational::Builder(1,2), sqrt); + MultiplicationExplicite result = MultiplicationExplicite::Builder(Rational::Builder(1,2), sqrt); sqrt.shallowReduce(reductionContext); return result; } @@ -218,11 +217,11 @@ ComplexCartesian ComplexCartesian::squareRoot(ExpressionNode::ReductionContext r // A = (1/2)*sqrt(2*(sqrt(a^2+b^2)+a)) Addition normAdda = Addition::Builder(normA, a.clone()); normA.shallowReduce(reductionContext); - Multiplication A = squareRootHelper(normAdda, reductionContext); + MultiplicationExplicite A = squareRootHelper(normAdda, reductionContext); // B = B: (1/2)*sqrt(2*(sqrt(a^2+b^2)-a)) Subtraction normSuba = Subtraction::Builder(normB, a); normB.shallowReduce(reductionContext); - Multiplication B = squareRootHelper(normSuba, reductionContext); + MultiplicationExplicite B = squareRootHelper(normSuba, reductionContext); // B = B: (1/2)*sqrt(2*(sqrt(a^2+b^2)-a))*sign(b) Expression signb = SignFunction::Builder(b); B.addChildAtIndexInPlace(signb, B.numberOfChildren(), B.numberOfChildren()); @@ -246,7 +245,7 @@ ComplexCartesian ComplexCartesian::powerInteger(int n, ExpressionNode::Reduction ComplexCartesian result; Expression bpow = Power::Builder(b, Rational::Builder(n)); if (n/2%2 == 1) { - Expression temp = Multiplication::Builder(Rational::Builder(-1), bpow); + Expression temp = MultiplicationExplicite::Builder(Rational::Builder(-1), bpow); bpow.shallowReduce(reductionContext); bpow = temp; } @@ -270,7 +269,7 @@ ComplexCartesian ComplexCartesian::powerInteger(int n, ExpressionNode::Reduction Expression bclone = i == n ? b : b.clone(); Power apow = Power::Builder(aclone, Rational::Builder(n-i)); Power bpow = Power::Builder(bclone, Rational::Builder(i)); - Multiplication m = Multiplication::Builder(binom, apow, bpow); + MultiplicationExplicite m = MultiplicationExplicite::Builder(binom, apow, bpow); binom.shallowReduce(reductionContext.context()); apow.shallowReduce(reductionContext); bpow.shallowReduce(reductionContext); @@ -300,14 +299,14 @@ ComplexCartesian ComplexCartesian::multiply(ComplexCartesian & other, Expression Expression d = other.imag(); // (a+ib) * (c+id) = (ac-bd)+i*(ad+bc) // Compute ac-bd - Expression ac = Multiplication::Builder(a.clone(), c.clone()); - Expression bd = Multiplication::Builder(b.clone(), d.clone()); + Expression ac = MultiplicationExplicite::Builder(a.clone(), c.clone()); + Expression bd = MultiplicationExplicite::Builder(b.clone(), d.clone()); Subtraction A = Subtraction::Builder(ac, bd); ac.shallowReduce(reductionContext); bd.shallowReduce(reductionContext); // Compute ad+bc - Expression ad = Multiplication::Builder(a, d); - Expression bc = Multiplication::Builder(b, c); + Expression ad = MultiplicationExplicite::Builder(a, d); + Expression bc = MultiplicationExplicite::Builder(b, c); Addition B = Addition::Builder(ad, bc); ad.shallowReduce(reductionContext); bc.shallowReduce(reductionContext); @@ -318,7 +317,7 @@ ComplexCartesian ComplexCartesian::multiply(ComplexCartesian & other, Expression } Expression ComplexCartesian::powerHelper(Expression norm, Expression trigo, ExpressionNode::ReductionContext reductionContext) { - Multiplication m = Multiplication::Builder(norm, trigo); + MultiplicationExplicite m = MultiplicationExplicite::Builder(norm, trigo); norm.shallowReduce(reductionContext); trigo.shallowReduce(reductionContext); return m; @@ -334,20 +333,20 @@ ComplexCartesian ComplexCartesian::power(ComplexCartesian & other, ExpressionNod // R = r^c*e^(-th*d) Expression rpowc = Power::Builder(rclone, c.clone()); rclone.shallowReduce(reductionContext); - Expression thmuld = Multiplication::Builder(Rational::Builder(-1), thclone, d.clone()); + Expression thmuld = MultiplicationExplicite::Builder(Rational::Builder(-1), thclone, d.clone()); thclone.shallowReduce(reductionContext); Expression exp = Power::Builder(Constant::Builder(UCodePointScriptSmallE), thmuld); thmuld.shallowReduce(reductionContext); - Multiplication norm = Multiplication::Builder(rpowc, exp); + MultiplicationExplicite norm = MultiplicationExplicite::Builder(rpowc, exp); rpowc.shallowReduce(reductionContext); exp.shallowReduce(reductionContext); // TH = d*ln(r)+c*th Expression lnr = NaperianLogarithm::Builder(r); r.shallowReduce(reductionContext); - Multiplication dlnr = Multiplication::Builder(d, lnr); + MultiplicationExplicite dlnr = MultiplicationExplicite::Builder(d, lnr); lnr.shallowReduce(reductionContext); - Multiplication thc = Multiplication::Builder(th, c); + MultiplicationExplicite thc = MultiplicationExplicite::Builder(th, c); th.shallowReduce(reductionContext); Expression argument = Addition::Builder(thc, dlnr); thc.shallowReduce(reductionContext); diff --git a/poincare/src/confidence_interval.cpp b/poincare/src/confidence_interval.cpp index a0439125c..444d6ff9a 100644 --- a/poincare/src/confidence_interval.cpp +++ b/poincare/src/confidence_interval.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include #include @@ -84,7 +84,7 @@ Expression ConfidenceInterval::shallowReduce(ExpressionNode::ReductionContext re // Compute [r0-1/sqr(r1), r0+1/sqr(r1)] Expression sqr = Power::Builder(r1, Rational::Builder(-1, 2)); Matrix matrix = Matrix::Builder(); - matrix.addChildAtIndexInPlace(Addition::Builder(r0.clone(), Multiplication::Builder(Rational::Builder(-1), sqr.clone())), 0, 0); + matrix.addChildAtIndexInPlace(Addition::Builder(r0.clone(), MultiplicationExplicite::Builder(Rational::Builder(-1), sqr.clone())), 0, 0); matrix.addChildAtIndexInPlace(Addition::Builder(r0, sqr), 1, 1); matrix.setDimensions(1, 2); replaceWithInPlace(matrix); diff --git a/poincare/src/conjugate.cpp b/poincare/src/conjugate.cpp index b7c40c3ed..231bf862f 100644 --- a/poincare/src/conjugate.cpp +++ b/poincare/src/conjugate.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include @@ -49,7 +49,7 @@ Expression Conjugate::shallowReduce(ExpressionNode::ReductionContext reductionCo } if (c.type() == ExpressionNode::Type::ComplexCartesian) { ComplexCartesian complexChild = static_cast(c); - Multiplication m = Multiplication::Builder(Rational::Builder(-1), complexChild.imag()); + MultiplicationExplicite m = MultiplicationExplicite::Builder(Rational::Builder(-1), complexChild.imag()); complexChild.replaceChildAtIndexInPlace(1, m); m.shallowReduce(reductionContext); replaceWithInPlace(complexChild); diff --git a/poincare/src/determinant.cpp b/poincare/src/determinant.cpp index dbe616a16..50cdf2939 100644 --- a/poincare/src/determinant.cpp +++ b/poincare/src/determinant.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -61,8 +62,8 @@ Expression Determinant::shallowReduce(ExpressionNode::ReductionContext reduction } else if (dim == 2) { /* |a b| * Determinant of |c d| is ad-bc */ - Multiplication ad = Multiplication::Builder(m0.matrixChild(0,0), m0.matrixChild(1,1)); - Multiplication bc = Multiplication::Builder(m0.matrixChild(0,1), m0.matrixChild(1,0)); + MultiplicationExplicite ad = MultiplicationExplicite::Builder(m0.matrixChild(0,0), m0.matrixChild(1,1)); + MultiplicationExplicite bc = MultiplicationExplicite::Builder(m0.matrixChild(0,1), m0.matrixChild(1,0)); result = Subtraction::Builder(ad, bc); ad.shallowReduce(reductionContext); bc.shallowReduce(reductionContext); @@ -81,12 +82,12 @@ Expression Determinant::shallowReduce(ExpressionNode::ReductionContext reduction Expression i = m0.matrixChild(2,2); constexpr int additionChildrenCount = 6; Expression additionChildren[additionChildrenCount] = { - Multiplication::Builder(a.clone(), e.clone(), i.clone()), - Multiplication::Builder(b.clone(), f.clone(), g.clone()), - Multiplication::Builder(c.clone(), d.clone(), h.clone()), - Multiplication::Builder(Rational::Builder(-1), c, e, g), - Multiplication::Builder(Rational::Builder(-1), b, d, i), - Multiplication::Builder(Rational::Builder(-1), a, f, h)}; + MultiplicationExplicite::Builder(a.clone(), e.clone(), i.clone()), + MultiplicationExplicite::Builder(b.clone(), f.clone(), g.clone()), + MultiplicationExplicite::Builder(c.clone(), d.clone(), h.clone()), + MultiplicationExplicite::Builder(Rational::Builder(-1), c, e, g), + MultiplicationExplicite::Builder(Rational::Builder(-1), b, d, i), + MultiplicationExplicite::Builder(Rational::Builder(-1), a, f, h)}; result = Addition::Builder(additionChildren, additionChildrenCount); for (int i = 0; i < additionChildrenCount; i++) { additionChildren[i].shallowReduce(reductionContext); diff --git a/poincare/src/division.cpp b/poincare/src/division.cpp index 0f699d8a3..e301fe067 100644 --- a/poincare/src/division.cpp +++ b/poincare/src/division.cpp @@ -1,6 +1,7 @@ #include #include -#include +#include +#include #include #include #include @@ -28,8 +29,8 @@ bool DivisionNode::childNeedsParenthesis(const TreeNode * child) const { if (static_cast(child)->type() == Type::Rational && !static_cast(child)->denominator().isOne()) { return true; } - Type types[] = {Type::Subtraction, Type::Opposite, Type::Multiplication, Type::Division, Type::Addition}; - return static_cast(child)->isOfType(types, 5); + Type types[] = {Type::Subtraction, Type::Opposite, Type::MultiplicationExplicite, Type::MultiplicationImplicite, Type::Division, Type::Addition}; + return static_cast(child)->isOfType(types, 6); } Layout DivisionNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { @@ -80,7 +81,7 @@ Expression Division::shallowReduce(ExpressionNode::ReductionContext reductionCon /* For matrices: we decided that A/B is computed as A = A/B * B so A/B = AB^-1 * (it could have been A = B * A/B so A/B = B^-1*A). */ Expression p = Power::Builder(childAtIndex(1), Rational::Builder(-1)); - Multiplication m = Multiplication::Builder(childAtIndex(0), p); + MultiplicationExplicite m = MultiplicationExplicite::Builder(childAtIndex(0), p); p.shallowReduce(reductionContext); // For instance: Division::Builder(2,1). p would be 1^(-1) which can be simplified replaceWithInPlace(m); return m.shallowReduce(reductionContext); diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index c66f95bcb..daf787d6a 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -108,7 +108,7 @@ bool Expression::IsRandom(const Expression e, Context * context) { } bool Expression::IsNAry(const Expression e, Context * context) { - return e.type() == ExpressionNode::Type::Addition || e.type() == ExpressionNode::Type::Multiplication; + return e.type() == ExpressionNode::Type::Addition || e.type() == ExpressionNode::Type::MultiplicationExplicite || e.type() == ExpressionNode::Type::MultiplicationImplicite; } bool Expression::IsMatrix(const Expression e, Context * context) { @@ -278,7 +278,7 @@ Expression Expression::makePositiveAnyNegativeNumeralFactor(ExpressionNode::Redu return setSign(ExpressionNode::Sign::Positive, reductionContext); } // The expression is a multiplication whose numeral factor is negative - if (type() == ExpressionNode::Type::Multiplication && numberOfChildren() > 0 && childAtIndex(0).isNumber() && childAtIndex(0).sign(reductionContext.context()) == ExpressionNode::Sign::Negative) { + if (isMultiplication() && numberOfChildren() > 0 && childAtIndex(0).isNumber() && childAtIndex(0).sign(reductionContext.context()) == ExpressionNode::Sign::Negative) { Multiplication m = convert(); if (m.childAtIndex(0).type() == ExpressionNode::Type::Rational && m.childAtIndex(0).convert().isMinusOne()) { // The negative numeral factor is -1, we just remove it @@ -559,12 +559,12 @@ Expression Expression::mapOnMatrixFirstChild(ExpressionNode::ReductionContext re Expression Expression::radianToDegree() { // e*180/Pi - return Multiplication::Builder(*this, Rational::Builder(180), Power::Builder(Constant::Builder(UCodePointGreekSmallLetterPi), Rational::Builder(-1))); + return MultiplicationExplicite::Builder(*this, Rational::Builder(180), Power::Builder(Constant::Builder(UCodePointGreekSmallLetterPi), Rational::Builder(-1))); } Expression Expression::degreeToRadian() { // e*Pi/180 - return Multiplication::Builder(*this, Rational::Builder(1, 180), Constant::Builder(UCodePointGreekSmallLetterPi)); + return MultiplicationExplicite::Builder(*this, Rational::Builder(1, 180), Constant::Builder(UCodePointGreekSmallLetterPi)); } Expression Expression::reduce(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) { @@ -660,7 +660,7 @@ Expression Expression::CreateComplexExpression(Expression ra, Expression tb, Pre if (isOneTb) { imag = Constant::Builder(UCodePointMathematicalBoldSmallI); } else { - imag = Multiplication::Builder(tb , Constant::Builder(UCodePointMathematicalBoldSmallI)); + imag = MultiplicationImplicite::Builder(tb , Constant::Builder(UCodePointMathematicalBoldSmallI)); } } if (imag.isUninitialized()) { @@ -691,7 +691,7 @@ Expression Expression::CreateComplexExpression(Expression ra, Expression tb, Pre if (isOneTb) { arg = Constant::Builder(UCodePointMathematicalBoldSmallI); } else { - arg = Multiplication::Builder(tb, Constant::Builder(UCodePointMathematicalBoldSmallI)); + arg = MultiplicationImplicite::Builder(tb, Constant::Builder(UCodePointMathematicalBoldSmallI)); } if (isNegativeTb) { arg = Opposite::Builder(arg); @@ -703,7 +703,7 @@ Expression Expression::CreateComplexExpression(Expression ra, Expression tb, Pre } else if (norm.isUninitialized()) { return exp; } else { - return Multiplication::Builder(norm, exp); + return MultiplicationImplicite::Builder(norm, exp); } } } diff --git a/poincare/src/expression_debug.cpp b/poincare/src/expression_debug.cpp index cf56a96c8..55b92e4f0 100644 --- a/poincare/src/expression_debug.cpp +++ b/poincare/src/expression_debug.cpp @@ -150,8 +150,11 @@ void print_expression(const Expression e, int indentationLevel) { case ExpressionNode::Type::MatrixTranspose: std::cout << "MatrixTranspose"; break; - case ExpressionNode::Type::Multiplication: - std::cout << "Multiplication"; + case ExpressionNode::Type::MultiplicationExplicite: + std::cout << "Multiplication Explicite"; + break; + case ExpressionNode::Type::MultiplicationImplicite: + std::cout << "Multiplication Implicite"; break; case ExpressionNode::Type::NaperianLogarithm: std::cout << "NaperianLogarithm"; diff --git a/poincare/src/factor.cpp b/poincare/src/factor.cpp index 224d755e7..a66aba309 100644 --- a/poincare/src/factor.cpp +++ b/poincare/src/factor.cpp @@ -34,10 +34,10 @@ Expression FactorNode::shallowBeautify(ReductionContext reductionContext) { return Factor(this).shallowBeautify(reductionContext); } -Multiplication Factor::createMultiplicationOfIntegerPrimeDecomposition(Integer i, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { +MultiplicationExplicite Factor::createMultiplicationOfIntegerPrimeDecomposition(Integer i, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { assert(!i.isZero()); assert(!i.isNegative()); - Multiplication m = Multiplication::Builder(); + MultiplicationExplicite m = MultiplicationExplicite::Builder(); Integer factors[Arithmetic::k_maxNumberOfPrimeFactors]; Integer coefficients[Arithmetic::k_maxNumberOfPrimeFactors]; int numberOfPrimeFactors = Arithmetic::PrimeFactorization(i, factors, coefficients, Arithmetic::k_maxNumberOfPrimeFactors); @@ -82,13 +82,13 @@ Expression Factor::shallowBeautify(ExpressionNode::ReductionContext reductionCon replaceWithInPlace(r); return r; } - Multiplication numeratorDecomp = createMultiplicationOfIntegerPrimeDecomposition(r.unsignedIntegerNumerator(), reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); + MultiplicationExplicite numeratorDecomp = createMultiplicationOfIntegerPrimeDecomposition(r.unsignedIntegerNumerator(), reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); if (numeratorDecomp.numberOfChildren() == 0) { return replaceWithUndefinedInPlace(); } Expression result = numeratorDecomp.squashUnaryHierarchyInPlace(); if (!r.integerDenominator().isOne()) { - Multiplication denominatorDecomp = createMultiplicationOfIntegerPrimeDecomposition(r.integerDenominator(), reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); + MultiplicationExplicite denominatorDecomp = createMultiplicationOfIntegerPrimeDecomposition(r.integerDenominator(), reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); if (denominatorDecomp.numberOfChildren() == 0) { return replaceWithUndefinedInPlace(); } diff --git a/poincare/src/factorial.cpp b/poincare/src/factorial.cpp index 5e12fa7cb..11f5b561d 100644 --- a/poincare/src/factorial.cpp +++ b/poincare/src/factorial.cpp @@ -28,8 +28,8 @@ bool FactorialNode::childNeedsParenthesis(const TreeNode * child) const { if (static_cast(child)->type() == Type::Rational && !static_cast(child)->denominator().isOne()) { return true; } - Type types[] = {Type::Subtraction, Type::Opposite, Type::Multiplication, Type::Division, Type::Addition, Type::Power}; - return static_cast(child)->isOfType(types, 6); + Type types[] = {Type::Subtraction, Type::Opposite, Type::MultiplicationExplicite, Type::MultiplicationImplicite, Type::Division, Type::Addition, Type::Power}; + return static_cast(child)->isOfType(types, 7); } // Simplification @@ -111,7 +111,7 @@ Expression Factorial::shallowReduce(ExpressionNode::ReductionContext reductionCo Expression Factorial::shallowBeautify() { // +(a,b)! ->(+(a,b))! if (childAtIndex(0).type() == ExpressionNode::Type::Addition - || childAtIndex(0).type() == ExpressionNode::Type::Multiplication + || childAtIndex(0).isMultiplication() || childAtIndex(0).type() == ExpressionNode::Type::Power) { Expression result = Factorial::Builder(Parenthesis::Builder(childAtIndex(0))); diff --git a/poincare/src/logarithm.cpp b/poincare/src/logarithm.cpp index 4d621ca6f..2ad55b28f 100644 --- a/poincare/src/logarithm.cpp +++ b/poincare/src/logarithm.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include @@ -164,20 +164,20 @@ Expression Logarithm::shallowReduce(ExpressionNode::ReductionContext reductionCo Expression x = p.childAtIndex(0); Expression y = p.childAtIndex(1); replaceChildInPlace(p, x); - Multiplication mult = Multiplication::Builder(y); + MultiplicationExplicite mult = MultiplicationExplicite::Builder(y); replaceWithInPlace(mult); mult.addChildAtIndexInPlace(*this, 1, 1); // --> y*log(x,b) shallowReduce(reductionContext); // reduce log (ie log(e, e) = 1) return mult.shallowReduce(reductionContext); } // log(x*y, b)->log(x,b)+log(y, b) if x,y>0 - if (c.type() == ExpressionNode::Type::Multiplication) { + if (c.type() == ExpressionNode::Type::MultiplicationExplicite) { Addition a = Addition::Builder(); for (int i = 0; i < c.numberOfChildren()-1; i++) { Expression factor = c.childAtIndex(i); if (factor.sign(reductionContext.context()) == ExpressionNode::Sign::Positive) { Expression newLog = clone(); - static_cast(c).removeChildInPlace(factor, factor.numberOfChildren()); + static_cast(c).removeChildInPlace(factor, factor.numberOfChildren()); newLog.replaceChildAtIndexInPlace(0, factor); a.addChildAtIndexInPlace(newLog, a.numberOfChildren(), a.numberOfChildren()); newLog.shallowReduce(reductionContext); @@ -324,7 +324,7 @@ Expression Logarithm::splitLogarithmInteger(Integer i, bool isDenominator, Expre if (!isDenominator) { return e; } - Multiplication m = Multiplication::Builder(Rational::Builder(-1), e); + MultiplicationExplicite m = MultiplicationExplicite::Builder(Rational::Builder(-1), e); return m; } Addition a = Addition::Builder(); @@ -334,7 +334,7 @@ Expression Logarithm::splitLogarithmInteger(Integer i, bool isDenominator, Expre } Logarithm e = clone().convert(); e.replaceChildAtIndexInPlace(0, Rational::Builder(factors[index])); - Multiplication m = Multiplication::Builder(Rational::Builder(coefficients[index]), e); + MultiplicationExplicite m = MultiplicationExplicite::Builder(Rational::Builder(coefficients[index]), e); e.simpleShallowReduce(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); a.addChildAtIndexInPlace(m, a.numberOfChildren(), a.numberOfChildren()); m.shallowReduce(reductionContext); diff --git a/poincare/src/matrix.cpp b/poincare/src/matrix.cpp index c0c148494..4cdfc3cb8 100644 --- a/poincare/src/matrix.cpp +++ b/poincare/src/matrix.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -210,7 +211,7 @@ Matrix Matrix::rowCanonize(ExpressionNode::ReductionContext reductionContext) { Expression factor = matrixChild(i, k); for (int j = k+1; j < n; j++) { Expression opIJ = matrixChild(i, j); - Expression newOpIJ = Subtraction::Builder(opIJ, Multiplication::Builder(matrixChild(h, j).clone(), factor.clone())); + Expression newOpIJ = Subtraction::Builder(opIJ, MultiplicationExplicite::Builder(matrixChild(h, j).clone(), factor.clone())); replaceChildAtIndexInPlace(i*n+j, newOpIJ); newOpIJ.childAtIndex(1).shallowReduce(reductionContext); newOpIJ = newOpIJ.shallowReduce(reductionContext); diff --git a/poincare/src/matrix_dimension.cpp b/poincare/src/matrix_dimension.cpp index 3584afd92..027651c4c 100644 --- a/poincare/src/matrix_dimension.cpp +++ b/poincare/src/matrix_dimension.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 5e420db30..a66267223 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -1,14 +1,13 @@ #include +#include #include #include #include -#include #include #include #include #include #include -#include #include #include #include @@ -67,11 +66,6 @@ MatrixComplex MultiplicationNode::computeOnMatrices(const MatrixComplex m, return result; } -Expression MultiplicationNode::setSign(Sign s, ReductionContext reductionContext) { - assert(s == ExpressionNode::Sign::Positive); - return Multiplication(this).setSign(s, reductionContext); -} - bool MultiplicationNode::childNeedsParenthesis(const TreeNode * child) const { if ((static_cast(child)->isNumber() && Number(static_cast(child)).sign() == Sign::Negative) || static_cast(child)->type() == ExpressionNode::Type::Opposite) @@ -85,32 +79,6 @@ bool MultiplicationNode::childNeedsParenthesis(const TreeNode * child) const { return static_cast(child)->isOfType(types, 2); } -Layout MultiplicationNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - constexpr int stringMaxSize = CodePoint::MaxCodePointCharLength + 1; - char string[stringMaxSize]; - SerializationHelper::CodePoint(string, stringMaxSize, UCodePointMiddleDot); - return LayoutHelper::Infix(Multiplication(this), floatDisplayMode, numberOfSignificantDigits, string); -} - -int MultiplicationNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - constexpr int stringMaxSize = CodePoint::MaxCodePointCharLength + 1; - char string[stringMaxSize]; - SerializationHelper::CodePoint(string, stringMaxSize, UCodePointMultiplicationSign); - return SerializationHelper::Infix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, string); -} - -Expression MultiplicationNode::shallowReduce(ReductionContext reductionContext) { - return Multiplication(this).shallowReduce(reductionContext); -} - -Expression MultiplicationNode::shallowBeautify(ReductionContext reductionContext) { - return Multiplication(this).shallowBeautify(reductionContext); -} - -Expression MultiplicationNode::denominator(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { - return Multiplication(this).denominator(context, complexFormat, angleUnit); -} - /* Multiplication */ template @@ -126,82 +94,6 @@ void Multiplication::computeOnArrays(T * m, T * n, T * result, int mNumberOfColu } } -Expression Multiplication::setSign(ExpressionNode::Sign s, ExpressionNode::ReductionContext reductionContext) { - assert(s == ExpressionNode::Sign::Positive); - for (int i = 0; i < numberOfChildren(); i++) { - if (childAtIndex(i).sign(reductionContext.context()) == ExpressionNode::Sign::Negative) { - replaceChildAtIndexInPlace(i, childAtIndex(i).setSign(s, reductionContext)); - } - } - return shallowReduce(reductionContext); -} - -Expression Multiplication::shallowReduce(ExpressionNode::ReductionContext reductionContext) { - return privateShallowReduce(reductionContext, true, true); -} - -Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext reductionContext) { - /* Beautifying a Multiplication consists in several possible operations: - * - Add Opposite ((-3)*x -> -(3*x), useful when printing fractions) - * - Adding parenthesis if needed (a*(b+c) is not a*b+c) - * - Creating a Division if there's either a term with a power of -1 (a.b^(-1) - * shall become a/b) or a non-integer rational term (3/2*a -> (3*a)/2). */ - - // Step 1: Turn -n*A into -(n*A) - Expression noNegativeNumeral = makePositiveAnyNegativeNumeralFactor(reductionContext); - // If one negative numeral factor was made positive, we turn the expression in an Opposite - if (!noNegativeNumeral.isUninitialized()) { - Opposite o = Opposite::Builder(); - noNegativeNumeral.replaceWithInPlace(o); - o.replaceChildAtIndexInPlace(0, noNegativeNumeral); - return o; - } - - /* Step 2: Merge negative powers: a*b^(-1)*c^(-pi)*d = a*(b*c^pi)^(-1) - * This also turns 2/3*a into 2*a*3^(-1) */ - Expression thisExp = mergeNegativePower(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); - if (thisExp.type() == ExpressionNode::Type::Power) { - return thisExp.shallowBeautify(reductionContext); - } - assert(thisExp.type() == ExpressionNode::Type::Multiplication); - - // Step 3: Add Parenthesis if needed - for (int i = 0; i < thisExp.numberOfChildren(); i++) { - const Expression o = thisExp.childAtIndex(i); - if (o.type() == ExpressionNode::Type::Addition) { - Parenthesis p = Parenthesis::Builder(o); - thisExp.replaceChildAtIndexInPlace(i, p); - } - } - - // Step 4: Create a Division if needed - for (int i = 0; i < numberOfChildren(); i++) { - Expression childI = thisExp.childAtIndex(i); - if (!(childI.type() == ExpressionNode::Type::Power && childI.childAtIndex(1).type() == ExpressionNode::Type::Rational && childI.childAtIndex(1).convert().isMinusOne())) { - continue; - } - - // Let's remove the denominator-to-be from this - Expression denominatorOperand = childI.childAtIndex(0); - removeChildInPlace(childI, childI.numberOfChildren()); - - Expression numeratorOperand = shallowReduce(reductionContext); - // Delete unnecessary parentheses on numerator - if (numeratorOperand.type() == ExpressionNode::Type::Parenthesis) { - Expression numeratorChild0 = numeratorOperand.childAtIndex(0); - numeratorOperand.replaceWithInPlace(numeratorChild0); - numeratorOperand = numeratorChild0; - } - Expression originalParent = numeratorOperand.parent(); - Division d = Division::Builder(); - numeratorOperand.replaceWithInPlace(d); - d.replaceChildAtIndexInPlace(0, numeratorOperand); - d.replaceChildAtIndexInPlace(1, denominatorOperand); - return d.shallowBeautify(reductionContext); - } - return thisExp; -} - int Multiplication::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const { int deg = polynomialDegree(context, symbolName); if (deg < 0 || deg > Expression::k_maxPolynomialDegree) { @@ -225,606 +117,18 @@ int Multiplication::getPolynomialCoefficients(Context * context, const char * sy int jbis = j > degI ? degI : j; for (int l = 0; l <= jbis ; l++) { // Always copy the a and b coefficients are they are used multiple times - a.addChildAtIndexInPlace(Multiplication::Builder(intermediateCoefficients[l].clone(), coefficients[j-l].clone()), a.numberOfChildren(), a.numberOfChildren()); + a.addChildAtIndexInPlace(MultiplicationExplicite::Builder(intermediateCoefficients[l].clone(), coefficients[j-l].clone()), a.numberOfChildren(), a.numberOfChildren()); } /* a(j) and b(j) are used only to compute coefficient at rank >= j, we * can delete them as we compute new coefficient by decreasing ranks. */ coefficients[j] = a; } // new coefficients[0] = a(0)*b(0) - coefficients[0] = Multiplication::Builder(coefficients[0], intermediateCoefficients[0]); + coefficients[0] = MultiplicationExplicite::Builder(coefficients[0], intermediateCoefficients[0]); } return deg; } -Expression Multiplication::denominator(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { - // Merge negative power: a*b^-1*c^(-Pi)*d = a*(b*c^Pi)^-1 - // WARNING: we do not want to change the expression but to create a new one. - Multiplication thisClone = clone().convert(); - Expression e = thisClone.mergeNegativePower(context, complexFormat, angleUnit); - if (e.type() == ExpressionNode::Type::Power) { - return e.denominator(context, complexFormat, angleUnit); - } else { - assert(e.type() == ExpressionNode::Type::Multiplication); - for (int i = 0; i < e.numberOfChildren(); i++) { - // a*b^(-1)*... -> a*.../b - if (e.childAtIndex(i).type() == ExpressionNode::Type::Power - && e.childAtIndex(i).childAtIndex(1).type() == ExpressionNode::Type::Rational - && e.childAtIndex(i).childAtIndex(1).convert().isMinusOne()) - { - return e.childAtIndex(i).childAtIndex(0); - } - } - } - return Expression(); -} - -Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext reductionContext, bool shouldExpand, bool canBeInterrupted) { - { - Expression e = Expression::defaultShallowReduce(); - if (e.isUndefined()) { - return e; - } - } - - /* Step 1: MultiplicationNode is associative, so let's start by merging children - * which also are multiplications themselves. */ - mergeMultiplicationChildrenInPlace(); - - // Step 2: Sort the children - sortChildrenInPlace([](const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { return ExpressionNode::SimplificationOrder(e1, e2, true, canBeInterrupted); }, reductionContext.context(), true); - - // Step 3: Handle matrices - /* Thanks to the simplification order, all matrix children (if any) are the - * last children. */ - Expression lastChild = childAtIndex(numberOfChildren()-1); - if (lastChild.type() == ExpressionNode::Type::Matrix) { - Matrix resultMatrix = static_cast(lastChild); - // Use the last matrix child as the final matrix - int n = resultMatrix.numberOfRows(); - int m = resultMatrix.numberOfColumns(); - /* Scan accross the children to find other matrices. The last child is the - * result matrix so we start at numberOfChildren()-2. */ - int multiplicationChildIndex = numberOfChildren()-2; - while (multiplicationChildIndex >= 0) { - Expression currentChild = childAtIndex(multiplicationChildIndex); - if (currentChild.type() != ExpressionNode::Type::Matrix) { - break; - } - Matrix currentMatrix = static_cast(currentChild); - int currentN = currentMatrix.numberOfRows(); - int currentM = currentMatrix.numberOfColumns(); - if (currentM != n) { - // Matrices dimensions do not match for multiplication - return replaceWithUndefinedInPlace(); - } - /* Create the matrix resulting of the multiplication of the current matrix - * and the result matrix - * resultMatrix - * i2= 0..m - * +-+-+-+-+-+ - * | | | | | | - * +-+-+-+-+-+ - * j=0..n | | | | | | - * +-+-+-+-+-+ - * | | | | | | - * +-+-+-+-+-+ - * currentMatrix - * j=0..currentM - * +---+---+---+ +-+-+-+-+-+ - * |  |   |  | | | | | | | - * +---+---+---+ +-+-+-+-+-+ - * i1=0..currentN |  |   |  | | |e| | | | - * +---+---+---+ +-+-+-+-+-+ - * |   |   | | | | | | | | - * +---+---+---+ +-+-+-+-+-+ - * */ - int newResultN = currentN; - int newResultM = m; - Matrix newResult = Matrix::Builder(); - for (int i = 0; i < newResultN; i++) { - for (int j = 0; j < newResultM; j++) { - Addition a = Addition::Builder(); - for (int k = 0; k < n; k++) { - Expression e = Multiplication::Builder(currentMatrix.matrixChild(i, k).clone(), resultMatrix.matrixChild(k, j).clone()); - a.addChildAtIndexInPlace(e, a.numberOfChildren(), a.numberOfChildren()); - e.shallowReduce(reductionContext); - } - newResult.addChildAtIndexInPlace(a, newResult.numberOfChildren(), newResult.numberOfChildren()); - a.shallowReduce(reductionContext); - } - } - newResult.setDimensions(newResultN, newResultM); - n = newResultN; - m = newResultM; - removeChildInPlace(currentMatrix, currentMatrix.numberOfChildren()); - replaceChildInPlace(resultMatrix, newResult); - resultMatrix = newResult; - multiplicationChildIndex--; - } - /* Distribute the remaining multiplication children on the matrix children, - * if there are no oether matrices (such as a non reduced confidence - * interval). */ - - if (multiplicationChildIndex >= 0) { - if (SortedIsMatrix(childAtIndex(multiplicationChildIndex), reductionContext.context())) { - return *this; - } - removeChildInPlace(resultMatrix, resultMatrix.numberOfChildren()); - for (int i = 0; i < n*m; i++) { - Multiplication m = clone().convert(); - Expression entryI = resultMatrix.childAtIndex(i); - resultMatrix.replaceChildInPlace(entryI, m); - m.addChildAtIndexInPlace(entryI, m.numberOfChildren(), m.numberOfChildren()); - m.shallowReduce(reductionContext); - } - } - replaceWithInPlace(resultMatrix); - return resultMatrix.shallowReduce(reductionContext); - } - - /* Step 4: Gather like terms. For example, turn pi^2*pi^3 into pi^5. Thanks to - * the simplification order, such terms are guaranteed to be next to each - * other. */ - int i = 0; - while (i < numberOfChildren()-1) { - Expression oi = childAtIndex(i); - Expression oi1 = childAtIndex(i+1); - if (oi.recursivelyMatches(Expression::IsRandom, reductionContext.context(), true)) { - // Do not factorize random or randint - i++; - continue; - } - if (TermsHaveIdenticalBase(oi, oi1)) { - bool shouldFactorizeBase = true; - if (TermHasNumeralBase(oi)) { - /* Combining powers of a given rational isn't straightforward. Indeed, - * there are two cases we want to deal with: - * - 2*2^(1/2) or 2*2^pi, we want to keep as-is - * - 2^(1/2)*2^(3/2) we want to combine. */ - shouldFactorizeBase = oi.type() == ExpressionNode::Type::Power && oi1.type() == ExpressionNode::Type::Power; - } - if (shouldFactorizeBase) { - factorizeBase(i, i+1, reductionContext); - continue; - } - } else if (TermHasNumeralBase(oi) && TermHasNumeralBase(oi1) && TermsHaveIdenticalExponent(oi, oi1)) { - factorizeExponent(i, i+1, reductionContext); - continue; - } - i++; - } - - /* Step 5: We look for terms of form sin(x)^p*cos(x)^q with p, q rational of - * opposite signs. We replace them by either: - * - tan(x)^p*cos(x)^(p+q) if |p|<|q| - * - tan(x)^(-q)*sin(x)^(p+q) otherwise */ - if (reductionContext.target() == ExpressionNode::ReductionTarget::User) { - for (int i = 0; i < numberOfChildren(); i++) { - Expression o1 = childAtIndex(i); - if (Base(o1).type() == ExpressionNode::Type::Sine && TermHasNumeralExponent(o1)) { - const Expression x = Base(o1).childAtIndex(0); - /* Thanks to the SimplificationOrder, Cosine-base factors are after - * Sine-base factors */ - for (int j = i+1; j < numberOfChildren(); j++) { - Expression o2 = childAtIndex(j); - if (Base(o2).type() == ExpressionNode::Type::Cosine && TermHasNumeralExponent(o2) && Base(o2).childAtIndex(0).isIdenticalTo(x)) { - factorizeSineAndCosine(i, j, reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); - break; - } - } - } - } - /* Replacing sin/cos by tan factors may have mixed factors and factors are - * guaranteed to be sorted (according ot SimplificationOrder) at the end of - * shallowReduce */ - sortChildrenInPlace([](const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { return ExpressionNode::SimplificationOrder(e1, e2, true, canBeInterrupted); }, reductionContext.context(), true); - } - - /* Step 6: We remove rational children that appeared in the middle of sorted - * children. It's important to do this after having factorized because - * factorization can lead to new ones. Indeed: - * pi^(-1)*pi-> 1 - * i*i -> -1 - * 2^(1/2)*2^(1/2) -> 2 - * sin(x)*cos(x) -> 1*tan(x) - * Last, we remove the only rational child if it is one and not the only - * child. */ - i = 1; - while (i < numberOfChildren()) { - Expression o = childAtIndex(i); - if (o.type() == ExpressionNode::Type::Rational && static_cast(o).isOne()) { - removeChildAtIndexInPlace(i); - continue; - } - if (o.isNumber()) { - if (childAtIndex(0).isNumber()) { - Number o0 = childAtIndex(0).convert(); - Number m = Number::Multiplication(o0, static_cast(o)); - replaceChildAtIndexInPlace(0, m); - removeChildAtIndexInPlace(i); - } else { - // Number child has to be first - removeChildAtIndexInPlace(i); - addChildAtIndexInPlace(o, 0, numberOfChildren()); - } - continue; - } - i++; - } - - /* Step 7: If the first child is zero, the multiplication result is zero. We - * do this after merging the rational children, because the merge takes care - * of turning 0*inf into undef. We still have to check that no other child - * involves an inifity expression to avoid reducing 0*e^(inf) to 0. - * If the first child is 1, we remove it if there are other children. */ - { - const Expression c = childAtIndex(0); - if (c.type() == ExpressionNode::Type::Rational && static_cast(c).isZero()) { - // Check that other children don't match inf - bool infiniteFactor = false; - for (int i = 1; i < numberOfChildren(); i++) { - infiniteFactor = childAtIndex(i).recursivelyMatches(Expression::IsInfinity, reductionContext.context()); - if (infiniteFactor) { - break; - } - } - if (!infiniteFactor) { - replaceWithInPlace(c); - return c; - } - } - if (c.type() == ExpressionNode::Type::Rational && static_cast(c).isOne() && numberOfChildren() > 1) { - removeChildAtIndexInPlace(0); - } - } - - /* Step 8: Expand multiplication over addition children if any. For example, - * turn (a+b)*c into a*c + b*c. We do not want to do this step right now if - * the parent is a multiplication or if the reduction is done bottom up to - * avoid missing factorization such as (x+y)^(-1)*((a+b)*(x+y)). - * Note: This step must be done after Step 4, otherwise we wouldn't be able to - * reduce expressions such as (x+y)^(-1)*(x+y)(a+b). - * If there is a random somewhere, do not expand. */ - Expression p = parent(); - bool hasRandom = recursivelyMatches(Expression::IsRandom, reductionContext.context(), true); - if (shouldExpand - && (p.isUninitialized() || p.type() != ExpressionNode::Type::Multiplication) - && !hasRandom) - { - for (int i = 0; i < numberOfChildren(); i++) { - if (childAtIndex(i).type() == ExpressionNode::Type::Addition) { - return distributeOnOperandAtIndex(i, reductionContext); - } - } - } - - // Step 9: Let's remove the multiplication altogether if it has one child - Expression result = squashUnaryHierarchyInPlace(); - if (result != *this) { - return result; - } - - /* Step 10: Let's bubble up the complex operator if possible - * 3 cases: - * - All children are real, we do nothing (allChildrenAreReal == 1) - * - One of the child is non-real and not a ComplexCartesian: it means a - * complex expression could not be resolved as a ComplexCartesian, we cannot - * do anything about it now (allChildrenAreReal == -1) - * - All children are either real or ComplexCartesian (allChildrenAreReal == 0) - * We can bubble up ComplexCartesian nodes. - * Do not simplify if there are randoms !*/ - if (!hasRandom && allChildrenAreReal(reductionContext.context()) == 0) { - int nbChildren = numberOfChildren(); - int i = nbChildren-1; - // Children are sorted so ComplexCartesian nodes are at the end - assert(childAtIndex(i).type() == ExpressionNode::Type::ComplexCartesian); - // First, we merge all ComplexCartesian children into one - ComplexCartesian child = childAtIndex(i).convert(); - removeChildAtIndexInPlace(i); - i--; - while (i >= 0) { - Expression e = childAtIndex(i); - if (e.type() != ExpressionNode::Type::ComplexCartesian) { - // the Multiplication is sorted so ComplexCartesian nodes are the last ones - break; - } - child = child.multiply(static_cast(e), reductionContext); - removeChildAtIndexInPlace(i); - i--; - } - // The real children are both factors of the real and the imaginary multiplication - Multiplication real = *this; - Multiplication imag = clone().convert(); - real.addChildAtIndexInPlace(child.real(), real.numberOfChildren(), real.numberOfChildren()); - imag.addChildAtIndexInPlace(child.imag(), real.numberOfChildren(), real.numberOfChildren()); - ComplexCartesian newComplexCartesian = ComplexCartesian::Builder(); - replaceWithInPlace(newComplexCartesian); - newComplexCartesian.replaceChildAtIndexInPlace(0, real); - newComplexCartesian.replaceChildAtIndexInPlace(1, imag); - real.shallowReduce(reductionContext); - imag.shallowReduce(reductionContext); - return newComplexCartesian.shallowReduce(); - } - - return result; -} - -void Multiplication::mergeMultiplicationChildrenInPlace() { - // Multiplication is associative: a*(b*c)->a*b*c - int i = 0; - while (i < numberOfChildren()) { - Expression c = childAtIndex(i); - if (c.type() == ExpressionNode::Type::Multiplication) { - mergeChildrenAtIndexInPlace(c, i); // TODO: ensure that matrix children are not swapped to implement MATRIX_EXACT_REDUCING - continue; - } - i++; - } -} - -void Multiplication::factorizeBase(int i, int j, ExpressionNode::ReductionContext reductionContext) { - /* This function factorizes two children which have a common base. For example - * if this is Multiplication::Builder(pi^2, pi^3), then pi^2 and pi^3 could be merged - * and this turned into Multiplication::Builder(pi^5). */ - - Expression e = childAtIndex(j); - // Step 1: Get rid of the child j - removeChildAtIndexInPlace(j); - // Step 2: Merge child j in child i by factorizing base - mergeInChildByFactorizingBase(i, e, reductionContext); -} - -void Multiplication::mergeInChildByFactorizingBase(int i, Expression e, ExpressionNode::ReductionContext reductionContext) { - /* This function replace the child at index i by its factorization with e. e - * and childAtIndex(i) are supposed to have a common base. */ - - // Step 1: Find the new exponent - Expression s = Addition::Builder(CreateExponent(childAtIndex(i)), CreateExponent(e)); // pi^2*pi^3 -> pi^(2+3) -> pi^5 - // Step 2: Create the new Power - Expression p = Power::Builder(Base(childAtIndex(i)), s); // pi^2*pi^-2 -> pi^0 -> 1 - s.shallowReduce(reductionContext); - // Step 3: Replace one of the child - replaceChildAtIndexInPlace(i, p); - p = p.shallowReduce(reductionContext); - /* Step 4: Reducing the new power might have turned it into a multiplication, - * ie: 12^(1/2) -> 2*3^(1/2). In that case, we need to merge the multiplication - * node with this. */ - if (p.type() == ExpressionNode::Type::Multiplication) { - mergeMultiplicationChildrenInPlace(); - } -} - -void Multiplication::factorizeExponent(int i, int j, ExpressionNode::ReductionContext reductionContext) { - /* This function factorizes children which share a common exponent. For - * example, it turns Multiplication::Builder(2^x,3^x) into Multiplication::Builder(6^x). */ - - // Step 1: Find the new base - Expression m = Multiplication::Builder(Base(childAtIndex(i)), Base(childAtIndex(j))); // 2^x*3^x -> (2*3)^x -> 6^x - // Step 2: Get rid of one of the children - removeChildAtIndexInPlace(j); - // Step 3: Replace the other child - childAtIndex(i).replaceChildAtIndexInPlace(0, m); - // Step 4: Reduce expressions - m.shallowReduce(reductionContext); - Expression p = childAtIndex(i).shallowReduce(reductionContext); // 2^x*(1/2)^x -> (2*1/2)^x -> 1 - /* Step 5: Reducing the new power might have turned it into a multiplication, - * ie: 12^(1/2) -> 2*3^(1/2). In that case, we need to merge the multiplication - * node with this. */ - if (p.type() == ExpressionNode::Type::Multiplication) { - mergeMultiplicationChildrenInPlace(); - } -} - -Expression Multiplication::distributeOnOperandAtIndex(int i, ExpressionNode::ReductionContext reductionContext) { - /* This method creates a*...*b*y... + a*...*c*y... + ... from - * a*...*(b+c+...)*y... */ - assert(i >= 0 && i < numberOfChildren()); - assert(childAtIndex(i).type() == ExpressionNode::Type::Addition); - - Addition a = Addition::Builder(); - Expression childI = childAtIndex(i); - int numberOfAdditionTerms = childI.numberOfChildren(); - for (int j = 0; j < numberOfAdditionTerms; j++) { - Multiplication m = clone().convert(); - m.replaceChildAtIndexInPlace(i, childI.childAtIndex(j)); - // Reduce m: pi^(-1)*(pi + x) -> pi^(-1)*pi + pi^(-1)*x -> 1 + pi^(-1)*x - a.addChildAtIndexInPlace(m, a.numberOfChildren(), a.numberOfChildren()); - m.shallowReduce(reductionContext); - } - replaceWithInPlace(a); - return a.shallowReduce(reductionContext); // Order terms, put under a common denominator if needed -} - -void Multiplication::addMissingFactors(Expression factor, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) { - if (factor.type() == ExpressionNode::Type::Multiplication) { - for (int j = 0; j < factor.numberOfChildren(); j++) { - addMissingFactors(factor.childAtIndex(j), context, complexFormat, angleUnit); - } - return; - } - /* Special case when factor is a Rational: if 'this' has already a rational - * child, we replace it by its LCM with factor ; otherwise, we simply add - * factor as a child. */ - if (numberOfChildren() > 0 && childAtIndex(0).type() == ExpressionNode::Type::Rational && factor.type() == ExpressionNode::Type::Rational) { - assert(static_cast(factor).integerDenominator().isOne()); - assert(childAtIndex(0).convert().integerDenominator().isOne()); - Integer lcm = Arithmetic::LCM(static_cast(factor).unsignedIntegerNumerator(), childAtIndex(0).convert().unsignedIntegerNumerator()); - if (lcm.isOverflow()) { - addChildAtIndexInPlace(Rational::Builder(static_cast(factor).unsignedIntegerNumerator()), 1, numberOfChildren()); - return; - } - replaceChildAtIndexInPlace(0, Rational::Builder(lcm)); - return; - } - if (factor.type() != ExpressionNode::Type::Rational) { - /* If factor is not a rational, we merge it with the child of identical - * base if any. Otherwise, we add it as an new child. */ - ExpressionNode::ReductionContext reductionContext = ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User); - for (int i = 0; i < numberOfChildren(); i++) { - if (TermsHaveIdenticalBase(childAtIndex(i), factor)) { - Expression sub = Subtraction::Builder(CreateExponent(childAtIndex(i)), CreateExponent(factor)).deepReduce(reductionContext); - if (sub.sign(reductionContext.context()) == ExpressionNode::Sign::Negative) { // index[0] < index[1] - sub = Opposite::Builder(sub); - if (factor.type() == ExpressionNode::Type::Power) { - factor.replaceChildAtIndexInPlace(1, sub); - } else { - factor = Power::Builder(factor, sub); - } - sub.shallowReduce(reductionContext); - mergeInChildByFactorizingBase(i, factor, reductionContext); - } else if (sub.sign(reductionContext.context()) == ExpressionNode::Sign::Unknown) { - mergeInChildByFactorizingBase(i, factor, reductionContext); - } - return; - } - } - } - addChildAtIndexInPlace(factor.clone(), 0, numberOfChildren()); - sortChildrenInPlace([](const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { return ExpressionNode::SimplificationOrder(e1, e2, true, canBeInterrupted); }, context, true); -} - -void Multiplication::factorizeSineAndCosine(int i, int j, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) { - /* This function turn sin(x)^p * cos(x)^q into either: - * - tan(x)^p*cos(x)^(p+q) if |p|<|q| - * - tan(x)^(-q)*sin(x)^(p+q) otherwise */ - const Expression x = Base(childAtIndex(i)).childAtIndex(0); - // We check before that p and q were numbers - Number p = CreateExponent(childAtIndex(i)).convert(); - Number q = CreateExponent(childAtIndex(j)).convert(); - // If p and q have the same sign, we cannot replace them by a tangent - if ((int)p.sign()*(int)q.sign() > 0) { - return; - } - Number sumPQ = Number::Addition(p, q); - Number absP = p.clone().convert().setSign(ExpressionNode::Sign::Positive); - Number absQ = q.clone().convert().setSign(ExpressionNode::Sign::Positive); - Expression tan = Tangent::Builder(x.clone()); - ExpressionNode::ReductionContext userReductionContext = ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User); - if (Number::NaturalOrder(absP, absQ) < 0) { - // Replace sin(x) by tan(x) or sin(x)^p by tan(x)^p - if (p.isRationalOne()) { - replaceChildAtIndexInPlace(i, tan); - } else { - replaceChildAtIndexInPlace(i, Power::Builder(tan, p)); - } - childAtIndex(i).shallowReduce(userReductionContext); - // Replace cos(x)^q by cos(x)^(p+q) - replaceChildAtIndexInPlace(j, Power::Builder(Base(childAtIndex(j)), sumPQ)); - childAtIndex(j).shallowReduce(userReductionContext); - } else { - // Replace cos(x)^q by tan(x)^(-q) - Expression newPower = Power::Builder(tan, Number::Multiplication(q, Rational::Builder(-1))); - newPower.childAtIndex(1).shallowReduce(userReductionContext); - replaceChildAtIndexInPlace(j, newPower); - newPower.shallowReduce(userReductionContext); - // Replace sin(x)^p by sin(x)^(p+q) - replaceChildAtIndexInPlace(i, Power::Builder(Base(childAtIndex(i)), sumPQ)); - childAtIndex(i).shallowReduce(userReductionContext); - } -} - -bool Multiplication::HaveSameNonNumeralFactors(const Expression & e1, const Expression & e2) { - assert(e1.numberOfChildren() > 0); - assert(e2.numberOfChildren() > 0); - int numberOfNonNumeralFactors1 = e1.childAtIndex(0).isNumber() ? e1.numberOfChildren()-1 : e1.numberOfChildren(); - int numberOfNonNumeralFactors2 = e2.childAtIndex(0).isNumber() ? e2.numberOfChildren()-1 : e2.numberOfChildren(); - if (numberOfNonNumeralFactors1 != numberOfNonNumeralFactors2) { - return false; - } - int firstNonNumeralOperand1 = e1.childAtIndex(0).isNumber() ? 1 : 0; - int firstNonNumeralOperand2 = e2.childAtIndex(0).isNumber() ? 1 : 0; - for (int i = 0; i < numberOfNonNumeralFactors1; i++) { - Expression currentChild1 = e1.childAtIndex(firstNonNumeralOperand1+i); - if (currentChild1.isRandom() - || !(currentChild1.isIdenticalTo(e2.childAtIndex(firstNonNumeralOperand2+i)))) - { - return false; - } - } - return true; -} - -const Expression Multiplication::CreateExponent(Expression e) { - Expression result = e.type() == ExpressionNode::Type::Power ? e.childAtIndex(1).clone() : Rational::Builder(1); - return result; -} - -bool Multiplication::TermsHaveIdenticalBase(const Expression & e1, const Expression & e2) { - return Base(e1).isIdenticalTo(Base(e2)); -} - -bool Multiplication::TermsHaveIdenticalExponent(const Expression & e1, const Expression & e2) { - /* Note: We will return false for e1=2 and e2=Pi, even though one could argue - * that these have the same exponent whose value is 1. */ - return e1.type() == ExpressionNode::Type::Power && e2.type() == ExpressionNode::Type::Power && (e1.childAtIndex(1).isIdenticalTo(e2.childAtIndex(1))); -} - -bool Multiplication::TermHasNumeralBase(const Expression & e) { - return Base(e).isNumber(); -} - -bool Multiplication::TermHasNumeralExponent(const Expression & e) { - if (e.type() != ExpressionNode::Type::Power) { - return true; - } - if (e.childAtIndex(1).isNumber()) { - return true; - } - return false; -} - -Expression Multiplication::mergeNegativePower(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) { - /* mergeNegativePower groups all factors that are power of form a^(-b) together - * for instance, a^(-1)*b^(-c)*c = c*(a*b^c)^(-1) */ - Multiplication m = Multiplication::Builder(); - // Special case for rational p/q: if q != 1, q should be at denominator - if (childAtIndex(0).type() == ExpressionNode::Type::Rational && !childAtIndex(0).convert().integerDenominator().isOne()) { - Rational r = childAtIndex(0).convert(); - m.addChildAtIndexInPlace(Rational::Builder(r.integerDenominator()), 0, m.numberOfChildren()); - if (r.signedIntegerNumerator().isOne()) { - removeChildAtIndexInPlace(0); - } else { - replaceChildAtIndexInPlace(0, Rational::Builder(r.signedIntegerNumerator())); - } - } - int i = 0; - // Look for power of form a^(-b) - while (i < numberOfChildren()) { - if (childAtIndex(i).type() == ExpressionNode::Type::Power) { - Expression p = childAtIndex(i); - Expression positivePIndex = p.childAtIndex(1).makePositiveAnyNegativeNumeralFactor( ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User)); - if (!positivePIndex.isUninitialized()) { - // Remove a^(-b) from the Multiplication - removeChildAtIndexInPlace(i); - // Add a^b to m - m.addChildAtIndexInPlace(p, m.numberOfChildren(), m.numberOfChildren()); - if (p.childAtIndex(1).isRationalOne()) { - p.replaceWithInPlace(p.childAtIndex(0)); - } - // We do not increment i because we removed one child from the Multiplication - continue; - } - } - i++; - } - if (m.numberOfChildren() == 0) { - return *this; - } - m.sortChildrenInPlace([](const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { return ExpressionNode::SimplificationOrder(e1, e2, true, canBeInterrupted); }, context, true); - Power p = Power::Builder(m.squashUnaryHierarchyInPlace(), Rational::Builder(-1)); - addChildAtIndexInPlace(p, 0, numberOfChildren()); - sortChildrenInPlace([](const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { return ExpressionNode::SimplificationOrder(e1, e2, true, canBeInterrupted); }, context, true); - return squashUnaryHierarchyInPlace(); -} - -const Expression Multiplication::Base(const Expression e) { - if (e.type() == ExpressionNode::Type::Power) { - return e.childAtIndex(0); - } - return e; -} - template MatrixComplex MultiplicationNode::computeOnComplexAndMatrix(std::complex const, const MatrixComplex, Preferences::ComplexFormat); template MatrixComplex MultiplicationNode::computeOnComplexAndMatrix(std::complex const, const MatrixComplex, Preferences::ComplexFormat); template Complex MultiplicationNode::compute(const std::complex, const std::complex, Preferences::ComplexFormat); diff --git a/poincare/src/multiplication_explicite.cpp b/poincare/src/multiplication_explicite.cpp new file mode 100644 index 000000000..26122e8ca --- /dev/null +++ b/poincare/src/multiplication_explicite.cpp @@ -0,0 +1,718 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Poincare { + +Expression MultiplicationExpliciteNode::setSign(Sign s, ReductionContext reductionContext) { + assert(s == ExpressionNode::Sign::Positive); + return MultiplicationExplicite(this).setSign(s, reductionContext); +} + +Layout MultiplicationExpliciteNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + constexpr int stringMaxSize = CodePoint::MaxCodePointCharLength + 1; + char string[stringMaxSize]; + SerializationHelper::CodePoint(string, stringMaxSize, UCodePointMultiplicationSign); + return LayoutHelper::Infix(MultiplicationExplicite(this), floatDisplayMode, numberOfSignificantDigits, string); +} + +int MultiplicationExpliciteNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + constexpr int stringMaxSize = CodePoint::MaxCodePointCharLength + 1; + char string[stringMaxSize]; + SerializationHelper::CodePoint(string, stringMaxSize, UCodePointMultiplicationSign); + return SerializationHelper::Infix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, string); +} + +Expression MultiplicationExpliciteNode::shallowReduce(ReductionContext reductionContext) { + return MultiplicationExplicite(this).shallowReduce(reductionContext); +} + +Expression MultiplicationExpliciteNode::shallowBeautify(ReductionContext reductionContext) { + return MultiplicationExplicite(this).shallowBeautify(reductionContext); +} + +Expression MultiplicationExpliciteNode::denominator(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { + return MultiplicationExplicite(this).denominator(context, complexFormat, angleUnit); +} + +/* MultiplicationExplicite */ + +Expression MultiplicationExplicite::setSign(ExpressionNode::Sign s, ExpressionNode::ReductionContext reductionContext) { + assert(s == ExpressionNode::Sign::Positive); + for (int i = 0; i < numberOfChildren(); i++) { + if (childAtIndex(i).sign(reductionContext.context()) == ExpressionNode::Sign::Negative) { + replaceChildAtIndexInPlace(i, childAtIndex(i).setSign(s, reductionContext)); + } + } + return shallowReduce(reductionContext); +} + +Expression MultiplicationExplicite::shallowReduce(ExpressionNode::ReductionContext reductionContext) { + return privateShallowReduce(reductionContext, true, true); +} + +Expression MultiplicationExplicite::shallowBeautify(ExpressionNode::ReductionContext reductionContext) { + /* Beautifying a Multiplication consists in several possible operations: + * - Add Opposite ((-3)*x -> -(3*x), useful when printing fractions) + * - Adding parenthesis if needed (a*(b+c) is not a*b+c) + * - Creating a Division if there's either a term with a power of -1 (a.b^(-1) + * shall become a/b) or a non-integer rational term (3/2*a -> (3*a)/2). */ + + // Step 1: Turn -n*A into -(n*A) + Expression noNegativeNumeral = makePositiveAnyNegativeNumeralFactor(reductionContext); + // If one negative numeral factor was made positive, we turn the expression in an Opposite + if (!noNegativeNumeral.isUninitialized()) { + Opposite o = Opposite::Builder(); + noNegativeNumeral.replaceWithInPlace(o); + o.replaceChildAtIndexInPlace(0, noNegativeNumeral); + return o; + } + + /* Step 2: Merge negative powers: a*b^(-1)*c^(-pi)*d = a*(b*c^pi)^(-1) + * This also turns 2/3*a into 2*a*3^(-1) */ + Expression thisExp = mergeNegativePower(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); + if (thisExp.type() == ExpressionNode::Type::Power) { + return thisExp.shallowBeautify(reductionContext); + } + assert(thisExp.type() == ExpressionNode::Type::MultiplicationExplicite); + + // Step 3: Add Parenthesis if needed + for (int i = 0; i < thisExp.numberOfChildren(); i++) { + const Expression o = thisExp.childAtIndex(i); + if (o.type() == ExpressionNode::Type::Addition) { + Parenthesis p = Parenthesis::Builder(o); + thisExp.replaceChildAtIndexInPlace(i, p); + } + } + + // Step 4: Create a Division if needed + for (int i = 0; i < numberOfChildren(); i++) { + Expression childI = thisExp.childAtIndex(i); + if (!(childI.type() == ExpressionNode::Type::Power && childI.childAtIndex(1).type() == ExpressionNode::Type::Rational && childI.childAtIndex(1).convert().isMinusOne())) { + continue; + } + + // Let's remove the denominator-to-be from this + Expression denominatorOperand = childI.childAtIndex(0); + removeChildInPlace(childI, childI.numberOfChildren()); + + Expression numeratorOperand = shallowReduce(reductionContext); + // Delete unnecessary parentheses on numerator + if (numeratorOperand.type() == ExpressionNode::Type::Parenthesis) { + Expression numeratorChild0 = numeratorOperand.childAtIndex(0); + numeratorOperand.replaceWithInPlace(numeratorChild0); + numeratorOperand = numeratorChild0; + } + Expression originalParent = numeratorOperand.parent(); + Division d = Division::Builder(); + numeratorOperand.replaceWithInPlace(d); + d.replaceChildAtIndexInPlace(0, numeratorOperand); + d.replaceChildAtIndexInPlace(1, denominatorOperand); + return d.shallowBeautify(reductionContext); + } + return thisExp; +} + +Expression MultiplicationExplicite::denominator(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { + // Merge negative power: a*b^-1*c^(-Pi)*d = a*(b*c^Pi)^-1 + // WARNING: we do not want to change the expression but to create a new one. + MultiplicationExplicite thisClone = clone().convert(); + Expression e = thisClone.mergeNegativePower(context, complexFormat, angleUnit); + if (e.type() == ExpressionNode::Type::Power) { + return e.denominator(context, complexFormat, angleUnit); + } else { + assert(e.type() == ExpressionNode::Type::MultiplicationExplicite); + for (int i = 0; i < e.numberOfChildren(); i++) { + // a*b^(-1)*... -> a*.../b + if (e.childAtIndex(i).type() == ExpressionNode::Type::Power + && e.childAtIndex(i).childAtIndex(1).type() == ExpressionNode::Type::Rational + && e.childAtIndex(i).childAtIndex(1).convert().isMinusOne()) + { + return e.childAtIndex(i).childAtIndex(0); + } + } + } + return Expression(); +} + +Expression MultiplicationExplicite::privateShallowReduce(ExpressionNode::ReductionContext reductionContext, bool shouldExpand, bool canBeInterrupted) { + { + Expression e = Expression::defaultShallowReduce(); + if (e.isUndefined()) { + return e; + } + } + + /* Step 1: MultiplicationExpliciteNode is associative, so let's start by merging children + * which also are multiplications themselves. */ + mergeMultiplicationChildrenInPlace(); + + // Step 2: Sort the children + sortChildrenInPlace([](const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { return ExpressionNode::SimplificationOrder(e1, e2, true, canBeInterrupted); }, reductionContext.context(), true); + + // Step 3: Handle matrices + /* Thanks to the simplification order, all matrix children (if any) are the + * last children. */ + Expression lastChild = childAtIndex(numberOfChildren()-1); + if (lastChild.type() == ExpressionNode::Type::Matrix) { + Matrix resultMatrix = static_cast(lastChild); + // Use the last matrix child as the final matrix + int n = resultMatrix.numberOfRows(); + int m = resultMatrix.numberOfColumns(); + /* Scan accross the children to find other matrices. The last child is the + * result matrix so we start at numberOfChildren()-2. */ + int multiplicationChildIndex = numberOfChildren()-2; + while (multiplicationChildIndex >= 0) { + Expression currentChild = childAtIndex(multiplicationChildIndex); + if (currentChild.type() != ExpressionNode::Type::Matrix) { + break; + } + Matrix currentMatrix = static_cast(currentChild); + int currentN = currentMatrix.numberOfRows(); + int currentM = currentMatrix.numberOfColumns(); + if (currentM != n) { + // Matrices dimensions do not match for multiplication + return replaceWithUndefinedInPlace(); + } + /* Create the matrix resulting of the multiplication of the current matrix + * and the result matrix + * resultMatrix + * i2= 0..m + * +-+-+-+-+-+ + * | | | | | | + * +-+-+-+-+-+ + * j=0..n | | | | | | + * +-+-+-+-+-+ + * | | | | | | + * +-+-+-+-+-+ + * currentMatrix + * j=0..currentM + * +---+---+---+ +-+-+-+-+-+ + * |  |   |  | | | | | | | + * +---+---+---+ +-+-+-+-+-+ + * i1=0..currentN |  |   |  | | |e| | | | + * +---+---+---+ +-+-+-+-+-+ + * |   |   | | | | | | | | + * +---+---+---+ +-+-+-+-+-+ + * */ + int newResultN = currentN; + int newResultM = m; + Matrix newResult = Matrix::Builder(); + for (int i = 0; i < newResultN; i++) { + for (int j = 0; j < newResultM; j++) { + Addition a = Addition::Builder(); + for (int k = 0; k < n; k++) { + Expression e = MultiplicationExplicite::Builder(currentMatrix.matrixChild(i, k).clone(), resultMatrix.matrixChild(k, j).clone()); + a.addChildAtIndexInPlace(e, a.numberOfChildren(), a.numberOfChildren()); + e.shallowReduce(reductionContext); + } + newResult.addChildAtIndexInPlace(a, newResult.numberOfChildren(), newResult.numberOfChildren()); + a.shallowReduce(reductionContext); + } + } + newResult.setDimensions(newResultN, newResultM); + n = newResultN; + m = newResultM; + removeChildInPlace(currentMatrix, currentMatrix.numberOfChildren()); + replaceChildInPlace(resultMatrix, newResult); + resultMatrix = newResult; + multiplicationChildIndex--; + } + /* Distribute the remaining multiplication children on the matrix children, + * if there are no oether matrices (such as a non reduced confidence + * interval). */ + + if (multiplicationChildIndex >= 0) { + if (SortedIsMatrix(childAtIndex(multiplicationChildIndex), reductionContext.context())) { + return *this; + } + removeChildInPlace(resultMatrix, resultMatrix.numberOfChildren()); + for (int i = 0; i < n*m; i++) { + MultiplicationExplicite m = clone().convert(); + Expression entryI = resultMatrix.childAtIndex(i); + resultMatrix.replaceChildInPlace(entryI, m); + m.addChildAtIndexInPlace(entryI, m.numberOfChildren(), m.numberOfChildren()); + m.shallowReduce(reductionContext); + } + } + replaceWithInPlace(resultMatrix); + return resultMatrix.shallowReduce(reductionContext); + } + + /* Step 4: Gather like terms. For example, turn pi^2*pi^3 into pi^5. Thanks to + * the simplification order, such terms are guaranteed to be next to each + * other. */ + int i = 0; + while (i < numberOfChildren()-1) { + Expression oi = childAtIndex(i); + Expression oi1 = childAtIndex(i+1); + if (oi.recursivelyMatches(Expression::IsRandom, reductionContext.context(), true)) { + // Do not factorize random or randint + i++; + continue; + } + if (TermsHaveIdenticalBase(oi, oi1)) { + bool shouldFactorizeBase = true; + if (TermHasNumeralBase(oi)) { + /* Combining powers of a given rational isn't straightforward. Indeed, + * there are two cases we want to deal with: + * - 2*2^(1/2) or 2*2^pi, we want to keep as-is + * - 2^(1/2)*2^(3/2) we want to combine. */ + shouldFactorizeBase = oi.type() == ExpressionNode::Type::Power && oi1.type() == ExpressionNode::Type::Power; + } + if (shouldFactorizeBase) { + factorizeBase(i, i+1, reductionContext); + continue; + } + } else if (TermHasNumeralBase(oi) && TermHasNumeralBase(oi1) && TermsHaveIdenticalExponent(oi, oi1)) { + factorizeExponent(i, i+1, reductionContext); + continue; + } + i++; + } + + /* Step 5: We look for terms of form sin(x)^p*cos(x)^q with p, q rational of + * opposite signs. We replace them by either: + * - tan(x)^p*cos(x)^(p+q) if |p|<|q| + * - tan(x)^(-q)*sin(x)^(p+q) otherwise */ + if (reductionContext.target() == ExpressionNode::ReductionTarget::User) { + for (int i = 0; i < numberOfChildren(); i++) { + Expression o1 = childAtIndex(i); + if (Base(o1).type() == ExpressionNode::Type::Sine && TermHasNumeralExponent(o1)) { + const Expression x = Base(o1).childAtIndex(0); + /* Thanks to the SimplificationOrder, Cosine-base factors are after + * Sine-base factors */ + for (int j = i+1; j < numberOfChildren(); j++) { + Expression o2 = childAtIndex(j); + if (Base(o2).type() == ExpressionNode::Type::Cosine && TermHasNumeralExponent(o2) && Base(o2).childAtIndex(0).isIdenticalTo(x)) { + factorizeSineAndCosine(i, j, reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); + break; + } + } + } + } + /* Replacing sin/cos by tan factors may have mixed factors and factors are + * guaranteed to be sorted (according ot SimplificationOrder) at the end of + * shallowReduce */ + sortChildrenInPlace([](const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { return ExpressionNode::SimplificationOrder(e1, e2, true, canBeInterrupted); }, reductionContext.context(), true); + } + + /* Step 6: We remove rational children that appeared in the middle of sorted + * children. It's important to do this after having factorized because + * factorization can lead to new ones. Indeed: + * pi^(-1)*pi-> 1 + * i*i -> -1 + * 2^(1/2)*2^(1/2) -> 2 + * sin(x)*cos(x) -> 1*tan(x) + * Last, we remove the only rational child if it is one and not the only + * child. */ + i = 1; + while (i < numberOfChildren()) { + Expression o = childAtIndex(i); + if (o.type() == ExpressionNode::Type::Rational && static_cast(o).isOne()) { + removeChildAtIndexInPlace(i); + continue; + } + if (o.isNumber()) { + if (childAtIndex(0).isNumber()) { + Number o0 = childAtIndex(0).convert(); + Number m = Number::Multiplication(o0, static_cast(o)); + replaceChildAtIndexInPlace(0, m); + removeChildAtIndexInPlace(i); + } else { + // Number child has to be first + removeChildAtIndexInPlace(i); + addChildAtIndexInPlace(o, 0, numberOfChildren()); + } + continue; + } + i++; + } + + /* Step 7: If the first child is zero, the multiplication result is zero. We + * do this after merging the rational children, because the merge takes care + * of turning 0*inf into undef. We still have to check that no other child + * involves an inifity expression to avoid reducing 0*e^(inf) to 0. + * If the first child is 1, we remove it if there are other children. */ + { + const Expression c = childAtIndex(0); + if (c.type() == ExpressionNode::Type::Rational && static_cast(c).isZero()) { + // Check that other children don't match inf + bool infiniteFactor = false; + for (int i = 1; i < numberOfChildren(); i++) { + infiniteFactor = childAtIndex(i).recursivelyMatches(Expression::IsInfinity, reductionContext.context()); + if (infiniteFactor) { + break; + } + } + if (!infiniteFactor) { + replaceWithInPlace(c); + return c; + } + } + if (c.type() == ExpressionNode::Type::Rational && static_cast(c).isOne() && numberOfChildren() > 1) { + removeChildAtIndexInPlace(0); + } + } + + /* Step 8: Expand multiplication over addition children if any. For example, + * turn (a+b)*c into a*c + b*c. We do not want to do this step right now if + * the parent is a multiplication or if the reduction is done bottom up to + * avoid missing factorization such as (x+y)^(-1)*((a+b)*(x+y)). + * Note: This step must be done after Step 4, otherwise we wouldn't be able to + * reduce expressions such as (x+y)^(-1)*(x+y)(a+b). + * If there is a random somewhere, do not expand. */ + Expression p = parent(); + bool hasRandom = recursivelyMatches(Expression::IsRandom, reductionContext.context(), true); + if (shouldExpand + && (p.isUninitialized() || p.type() != ExpressionNode::Type::MultiplicationExplicite) + && !hasRandom) + { + for (int i = 0; i < numberOfChildren(); i++) { + if (childAtIndex(i).type() == ExpressionNode::Type::Addition) { + return distributeOnOperandAtIndex(i, reductionContext); + } + } + } + + // Step 9: Let's remove the multiplication altogether if it has one child + Expression result = squashUnaryHierarchyInPlace(); + if (result != *this) { + return result; + } + + /* Step 10: Let's bubble up the complex operator if possible + * 3 cases: + * - All children are real, we do nothing (allChildrenAreReal == 1) + * - One of the child is non-real and not a ComplexCartesian: it means a + * complex expression could not be resolved as a ComplexCartesian, we cannot + * do anything about it now (allChildrenAreReal == -1) + * - All children are either real or ComplexCartesian (allChildrenAreReal == 0) + * We can bubble up ComplexCartesian nodes. + * Do not simplify if there are randoms !*/ + if (!hasRandom && allChildrenAreReal(reductionContext.context()) == 0) { + int nbChildren = numberOfChildren(); + int i = nbChildren-1; + // Children are sorted so ComplexCartesian nodes are at the end + assert(childAtIndex(i).type() == ExpressionNode::Type::ComplexCartesian); + // First, we merge all ComplexCartesian children into one + ComplexCartesian child = childAtIndex(i).convert(); + removeChildAtIndexInPlace(i); + i--; + while (i >= 0) { + Expression e = childAtIndex(i); + if (e.type() != ExpressionNode::Type::ComplexCartesian) { + // the Multiplication is sorted so ComplexCartesian nodes are the last ones + break; + } + child = child.multiply(static_cast(e), reductionContext); + removeChildAtIndexInPlace(i); + i--; + } + // The real children are both factors of the real and the imaginary multiplication + MultiplicationExplicite real = *this; + MultiplicationExplicite imag = clone().convert(); + real.addChildAtIndexInPlace(child.real(), real.numberOfChildren(), real.numberOfChildren()); + imag.addChildAtIndexInPlace(child.imag(), real.numberOfChildren(), real.numberOfChildren()); + ComplexCartesian newComplexCartesian = ComplexCartesian::Builder(); + replaceWithInPlace(newComplexCartesian); + newComplexCartesian.replaceChildAtIndexInPlace(0, real); + newComplexCartesian.replaceChildAtIndexInPlace(1, imag); + real.shallowReduce(reductionContext); + imag.shallowReduce(reductionContext); + return newComplexCartesian.shallowReduce(); + } + + return result; +} + +void MultiplicationExplicite::mergeMultiplicationChildrenInPlace() { + // Multiplication is associative: a*(b*c)->a*b*c + int i = 0; + while (i < numberOfChildren()) { + Expression c = childAtIndex(i); + if (c.type() == ExpressionNode::Type::MultiplicationExplicite) { + mergeChildrenAtIndexInPlace(c, i); // TODO: ensure that matrix children are not swapped to implement MATRIX_EXACT_REDUCING + continue; + } + i++; + } +} + +void MultiplicationExplicite::factorizeBase(int i, int j, ExpressionNode::ReductionContext reductionContext) { + /* This function factorizes two children which have a common base. For example + * if this is MultiplicationExplicite::Builder(pi^2, pi^3), then pi^2 and pi^3 could be merged + * and this turned into MultiplicationExplicite::Builder(pi^5). */ + + Expression e = childAtIndex(j); + // Step 1: Get rid of the child j + removeChildAtIndexInPlace(j); + // Step 2: Merge child j in child i by factorizing base + mergeInChildByFactorizingBase(i, e, reductionContext); +} + +void MultiplicationExplicite::mergeInChildByFactorizingBase(int i, Expression e, ExpressionNode::ReductionContext reductionContext) { + /* This function replace the child at index i by its factorization with e. e + * and childAtIndex(i) are supposed to have a common base. */ + + // Step 1: Find the new exponent + Expression s = Addition::Builder(CreateExponent(childAtIndex(i)), CreateExponent(e)); // pi^2*pi^3 -> pi^(2+3) -> pi^5 + // Step 2: Create the new Power + Expression p = Power::Builder(Base(childAtIndex(i)), s); // pi^2*pi^-2 -> pi^0 -> 1 + s.shallowReduce(reductionContext); + // Step 3: Replace one of the child + replaceChildAtIndexInPlace(i, p); + p = p.shallowReduce(reductionContext); + /* Step 4: Reducing the new power might have turned it into a multiplication, + * ie: 12^(1/2) -> 2*3^(1/2). In that case, we need to merge the multiplication + * node with this. */ + if (p.type() == ExpressionNode::Type::MultiplicationExplicite) { + mergeMultiplicationChildrenInPlace(); + } +} + +void MultiplicationExplicite::factorizeExponent(int i, int j, ExpressionNode::ReductionContext reductionContext) { + /* This function factorizes children which share a common exponent. For + * example, it turns MultiplicationExplicite::Builder(2^x,3^x) into MultiplicationExplicite::Builder(6^x). */ + + // Step 1: Find the new base + Expression m = MultiplicationExplicite::Builder(Base(childAtIndex(i)), Base(childAtIndex(j))); // 2^x*3^x -> (2*3)^x -> 6^x + // Step 2: Get rid of one of the children + removeChildAtIndexInPlace(j); + // Step 3: Replace the other child + childAtIndex(i).replaceChildAtIndexInPlace(0, m); + // Step 4: Reduce expressions + m.shallowReduce(reductionContext); + Expression p = childAtIndex(i).shallowReduce(reductionContext); // 2^x*(1/2)^x -> (2*1/2)^x -> 1 + /* Step 5: Reducing the new power might have turned it into a multiplication, + * ie: 12^(1/2) -> 2*3^(1/2). In that case, we need to merge the multiplication + * node with this. */ + if (p.type() == ExpressionNode::Type::MultiplicationExplicite) { + mergeMultiplicationChildrenInPlace(); + } +} + +Expression MultiplicationExplicite::distributeOnOperandAtIndex(int i, ExpressionNode::ReductionContext reductionContext) { + /* This method creates a*...*b*y... + a*...*c*y... + ... from + * a*...*(b+c+...)*y... */ + assert(i >= 0 && i < numberOfChildren()); + assert(childAtIndex(i).type() == ExpressionNode::Type::Addition); + + Addition a = Addition::Builder(); + Expression childI = childAtIndex(i); + int numberOfAdditionTerms = childI.numberOfChildren(); + for (int j = 0; j < numberOfAdditionTerms; j++) { + MultiplicationExplicite m = clone().convert(); + m.replaceChildAtIndexInPlace(i, childI.childAtIndex(j)); + // Reduce m: pi^(-1)*(pi + x) -> pi^(-1)*pi + pi^(-1)*x -> 1 + pi^(-1)*x + a.addChildAtIndexInPlace(m, a.numberOfChildren(), a.numberOfChildren()); + m.shallowReduce(reductionContext); + } + replaceWithInPlace(a); + return a.shallowReduce(reductionContext); // Order terms, put under a common denominator if needed +} + +void MultiplicationExplicite::addMissingFactors(Expression factor, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) { + if (factor.type() == ExpressionNode::Type::MultiplicationExplicite) { + for (int j = 0; j < factor.numberOfChildren(); j++) { + addMissingFactors(factor.childAtIndex(j), context, complexFormat, angleUnit); + } + return; + } + /* Special case when factor is a Rational: if 'this' has already a rational + * child, we replace it by its LCM with factor ; otherwise, we simply add + * factor as a child. */ + if (numberOfChildren() > 0 && childAtIndex(0).type() == ExpressionNode::Type::Rational && factor.type() == ExpressionNode::Type::Rational) { + assert(static_cast(factor).integerDenominator().isOne()); + assert(childAtIndex(0).convert().integerDenominator().isOne()); + Integer lcm = Arithmetic::LCM(static_cast(factor).unsignedIntegerNumerator(), childAtIndex(0).convert().unsignedIntegerNumerator()); + if (lcm.isOverflow()) { + addChildAtIndexInPlace(Rational::Builder(static_cast(factor).unsignedIntegerNumerator()), 1, numberOfChildren()); + return; + } + replaceChildAtIndexInPlace(0, Rational::Builder(lcm)); + return; + } + if (factor.type() != ExpressionNode::Type::Rational) { + /* If factor is not a rational, we merge it with the child of identical + * base if any. Otherwise, we add it as an new child. */ + ExpressionNode::ReductionContext reductionContext = ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User); + for (int i = 0; i < numberOfChildren(); i++) { + if (TermsHaveIdenticalBase(childAtIndex(i), factor)) { + Expression sub = Subtraction::Builder(CreateExponent(childAtIndex(i)), CreateExponent(factor)).deepReduce(reductionContext); + if (sub.sign(reductionContext.context()) == ExpressionNode::Sign::Negative) { // index[0] < index[1] + sub = Opposite::Builder(sub); + if (factor.type() == ExpressionNode::Type::Power) { + factor.replaceChildAtIndexInPlace(1, sub); + } else { + factor = Power::Builder(factor, sub); + } + sub.shallowReduce(reductionContext); + mergeInChildByFactorizingBase(i, factor, reductionContext); + } else if (sub.sign(reductionContext.context()) == ExpressionNode::Sign::Unknown) { + mergeInChildByFactorizingBase(i, factor, reductionContext); + } + return; + } + } + } + addChildAtIndexInPlace(factor.clone(), 0, numberOfChildren()); + sortChildrenInPlace([](const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { return ExpressionNode::SimplificationOrder(e1, e2, true, canBeInterrupted); }, context, true); +} + +void MultiplicationExplicite::factorizeSineAndCosine(int i, int j, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) { + /* This function turn sin(x)^p * cos(x)^q into either: + * - tan(x)^p*cos(x)^(p+q) if |p|<|q| + * - tan(x)^(-q)*sin(x)^(p+q) otherwise */ + const Expression x = Base(childAtIndex(i)).childAtIndex(0); + // We check before that p and q were numbers + Number p = CreateExponent(childAtIndex(i)).convert(); + Number q = CreateExponent(childAtIndex(j)).convert(); + // If p and q have the same sign, we cannot replace them by a tangent + if ((int)p.sign()*(int)q.sign() > 0) { + return; + } + Number sumPQ = Number::Addition(p, q); + Number absP = p.clone().convert().setSign(ExpressionNode::Sign::Positive); + Number absQ = q.clone().convert().setSign(ExpressionNode::Sign::Positive); + Expression tan = Tangent::Builder(x.clone()); + ExpressionNode::ReductionContext userReductionContext = ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User); + if (Number::NaturalOrder(absP, absQ) < 0) { + // Replace sin(x) by tan(x) or sin(x)^p by tan(x)^p + if (p.isRationalOne()) { + replaceChildAtIndexInPlace(i, tan); + } else { + replaceChildAtIndexInPlace(i, Power::Builder(tan, p)); + } + childAtIndex(i).shallowReduce(userReductionContext); + // Replace cos(x)^q by cos(x)^(p+q) + replaceChildAtIndexInPlace(j, Power::Builder(Base(childAtIndex(j)), sumPQ)); + childAtIndex(j).shallowReduce(userReductionContext); + } else { + // Replace cos(x)^q by tan(x)^(-q) + Expression newPower = Power::Builder(tan, Number::Multiplication(q, Rational::Builder(-1))); + newPower.childAtIndex(1).shallowReduce(userReductionContext); + replaceChildAtIndexInPlace(j, newPower); + newPower.shallowReduce(userReductionContext); + // Replace sin(x)^p by sin(x)^(p+q) + replaceChildAtIndexInPlace(i, Power::Builder(Base(childAtIndex(i)), sumPQ)); + childAtIndex(i).shallowReduce(userReductionContext); + } +} + +bool MultiplicationExplicite::HaveSameNonNumeralFactors(const Expression & e1, const Expression & e2) { + assert(e1.numberOfChildren() > 0); + assert(e2.numberOfChildren() > 0); + int numberOfNonNumeralFactors1 = e1.childAtIndex(0).isNumber() ? e1.numberOfChildren()-1 : e1.numberOfChildren(); + int numberOfNonNumeralFactors2 = e2.childAtIndex(0).isNumber() ? e2.numberOfChildren()-1 : e2.numberOfChildren(); + if (numberOfNonNumeralFactors1 != numberOfNonNumeralFactors2) { + return false; + } + int firstNonNumeralOperand1 = e1.childAtIndex(0).isNumber() ? 1 : 0; + int firstNonNumeralOperand2 = e2.childAtIndex(0).isNumber() ? 1 : 0; + for (int i = 0; i < numberOfNonNumeralFactors1; i++) { + Expression currentChild1 = e1.childAtIndex(firstNonNumeralOperand1+i); + if (currentChild1.isRandom() + || !(currentChild1.isIdenticalTo(e2.childAtIndex(firstNonNumeralOperand2+i)))) + { + return false; + } + } + return true; +} + +const Expression MultiplicationExplicite::CreateExponent(Expression e) { + Expression result = e.type() == ExpressionNode::Type::Power ? e.childAtIndex(1).clone() : Rational::Builder(1); + return result; +} + +bool MultiplicationExplicite::TermsHaveIdenticalBase(const Expression & e1, const Expression & e2) { + return Base(e1).isIdenticalTo(Base(e2)); +} + +bool MultiplicationExplicite::TermsHaveIdenticalExponent(const Expression & e1, const Expression & e2) { + /* Note: We will return false for e1=2 and e2=Pi, even though one could argue + * that these have the same exponent whose value is 1. */ + return e1.type() == ExpressionNode::Type::Power && e2.type() == ExpressionNode::Type::Power && (e1.childAtIndex(1).isIdenticalTo(e2.childAtIndex(1))); +} + +bool MultiplicationExplicite::TermHasNumeralBase(const Expression & e) { + return Base(e).isNumber(); +} + +bool MultiplicationExplicite::TermHasNumeralExponent(const Expression & e) { + if (e.type() != ExpressionNode::Type::Power) { + return true; + } + if (e.childAtIndex(1).isNumber()) { + return true; + } + return false; +} + +Expression MultiplicationExplicite::mergeNegativePower(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) { + /* mergeNegativePower groups all factors that are power of form a^(-b) together + * for instance, a^(-1)*b^(-c)*c = c*(a*b^c)^(-1) */ + MultiplicationExplicite m = MultiplicationExplicite::Builder(); + // Special case for rational p/q: if q != 1, q should be at denominator + if (childAtIndex(0).type() == ExpressionNode::Type::Rational && !childAtIndex(0).convert().integerDenominator().isOne()) { + Rational r = childAtIndex(0).convert(); + m.addChildAtIndexInPlace(Rational::Builder(r.integerDenominator()), 0, m.numberOfChildren()); + if (r.signedIntegerNumerator().isOne()) { + removeChildAtIndexInPlace(0); + } else { + replaceChildAtIndexInPlace(0, Rational::Builder(r.signedIntegerNumerator())); + } + } + int i = 0; + // Look for power of form a^(-b) + while (i < numberOfChildren()) { + if (childAtIndex(i).type() == ExpressionNode::Type::Power) { + Expression p = childAtIndex(i); + Expression positivePIndex = p.childAtIndex(1).makePositiveAnyNegativeNumeralFactor( ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User)); + if (!positivePIndex.isUninitialized()) { + // Remove a^(-b) from the Multiplication + removeChildAtIndexInPlace(i); + // Add a^b to m + m.addChildAtIndexInPlace(p, m.numberOfChildren(), m.numberOfChildren()); + if (p.childAtIndex(1).isRationalOne()) { + p.replaceWithInPlace(p.childAtIndex(0)); + } + // We do not increment i because we removed one child from the Multiplication + continue; + } + } + i++; + } + if (m.numberOfChildren() == 0) { + return *this; + } + m.sortChildrenInPlace([](const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { return ExpressionNode::SimplificationOrder(e1, e2, true, canBeInterrupted); }, context, true); + Power p = Power::Builder(m.squashUnaryHierarchyInPlace(), Rational::Builder(-1)); + addChildAtIndexInPlace(p, 0, numberOfChildren()); + sortChildrenInPlace([](const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { return ExpressionNode::SimplificationOrder(e1, e2, true, canBeInterrupted); }, context, true); + return squashUnaryHierarchyInPlace(); +} + +const Expression MultiplicationExplicite::Base(const Expression e) { + if (e.type() == ExpressionNode::Type::Power) { + return e.childAtIndex(0); + } + return e; +} + +} diff --git a/poincare/src/multiplication_implicite.cpp b/poincare/src/multiplication_implicite.cpp new file mode 100644 index 000000000..5369fadc7 --- /dev/null +++ b/poincare/src/multiplication_implicite.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Poincare { + +Layout MultiplicationImpliciteNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + return LayoutHelper::Infix(MultiplicationImplicite(this), floatDisplayMode, numberOfSignificantDigits, ""); +} + +int MultiplicationImpliciteNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + return SerializationHelper::Infix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, ""); +} + +Expression MultiplicationImpliciteNode::shallowReduce(ReductionContext reductionContext) { + return MultiplicationImplicite(this).shallowReduce(reductionContext); +} + +bool MultiplicationImpliciteNode::childNeedsParenthesis(const TreeNode * child) const { + if (MultiplicationNode::childNeedsParenthesis(child)) { + return true; + } + if (static_cast(child)->type() == Type::Rational && !static_cast(child)->denominator().isOne()) { + return true; + } + Type types[] = {Type::Power, Type::Opposite, Type::MultiplicationExplicite, Type::Division, Type::Factorial}; + return static_cast(child)->isOfType(types, 5); +} + +/* Multiplication */ + +Expression MultiplicationImplicite::shallowReduce(ExpressionNode::ReductionContext reductionContext) { + { + Expression e = Expression::defaultShallowReduce(); + if (e.isUndefined()) { + return e; + } + } + assert(numberOfChildren() == 2); + MultiplicationExplicite m = MultiplicationExplicite::Builder(); + for (int i = 0; i < numberOfChildren(); i++) { + m.addChildAtIndexInPlace(childAtIndex(i), i, i); + } + replaceWithInPlace(m); + return m.shallowReduce(reductionContext); +} + +} diff --git a/poincare/src/opposite.cpp b/poincare/src/opposite.cpp index 0ad9d5b3b..a12fc51f8 100644 --- a/poincare/src/opposite.cpp +++ b/poincare/src/opposite.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include @@ -79,7 +79,7 @@ Expression Opposite::shallowReduce(ExpressionNode::ReductionContext reductionCon return result; } Expression child = result.childAtIndex(0); - result = Multiplication::Builder(Rational::Builder(-1), child); + result = MultiplicationExplicite::Builder(Rational::Builder(-1), child); replaceWithInPlace(result); return result.shallowReduce(reductionContext); } diff --git a/poincare/src/parsing/parser.cpp b/poincare/src/parsing/parser.cpp index 85d0183b8..93f599c79 100644 --- a/poincare/src/parsing/parser.cpp +++ b/poincare/src/parsing/parser.cpp @@ -191,7 +191,7 @@ void Parser::parseMinus(Expression & leftHandSide, Token::Type stoppingType) { void Parser::parseTimes(Expression & leftHandSide, Token::Type stoppingType) { Expression rightHandSide; if (parseBinaryOperator(leftHandSide, rightHandSide, Token::Times)) { - leftHandSide = Multiplication::Builder(leftHandSide, rightHandSide); + leftHandSide = MultiplicationExplicite::Builder(leftHandSide, rightHandSide); } } @@ -205,7 +205,7 @@ void Parser::parseSlash(Expression & leftHandSide, Token::Type stoppingType) { void Parser::parseImplicitTimes(Expression & leftHandSide, Token::Type stoppingType) { Expression rightHandSide; if (parseBinaryOperator(leftHandSide, rightHandSide, Token::Slash)) { - leftHandSide = Multiplication::Builder(leftHandSide, rightHandSide); + leftHandSide = MultiplicationImplicite::Builder(leftHandSide, rightHandSide); } } diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index bed781c10..af478e2b8 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -157,8 +157,8 @@ bool PowerNode::childNeedsParenthesis(const TreeNode * child) const { if (static_cast(child)->type() == Type::Rational && !static_cast(child)->denominator().isOne()) { return true; } - Type types[] = {Type::Power, Type::Subtraction, Type::Opposite, Type::Multiplication, Type::Division, Type::Addition}; - return static_cast(child)->isOfType(types, 6); + Type types[] = {Type::Power, Type::Subtraction, Type::Opposite, Type::MultiplicationExplicite, Type::MultiplicationImplicite, Type::Division, Type::Addition}; + return static_cast(child)->isOfType(types, 7); } int PowerNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { @@ -333,7 +333,7 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex Expression result = matrixBase.clone(); // TODO: implement a quick exponentiation for (int k = 1; k < exp; k++) { - result = Multiplication::Builder(result, matrixBase.clone()); + result = MultiplicationExplicite::Builder(result, matrixBase.clone()); result = result.shallowReduce(reductionContext); } assert(!result.isUninitialized()); @@ -503,7 +503,7 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex if (base.sign(reductionContext.context()) == ExpressionNode::Sign::Negative) { // (-inf)^x --> (-1)^x*inf Power p = Power::Builder(Rational::Builder(-1), childAtIndex(1)); - result = Multiplication::Builder(p, result); + result = MultiplicationExplicite::Builder(p, result); p.shallowReduce(reductionContext); } } @@ -541,7 +541,7 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex replaceChildAtIndexInPlace(0, m0); /* m0 doesn't need to be shallowReduce as * makePositiveAnyNegativeNumeralFactor returns a reduced expression */ - Multiplication m1 = Multiplication::Builder(); + MultiplicationExplicite m1 = MultiplicationExplicite::Builder(); replaceWithInPlace(m1); // Multiply m1 by i complex Constant i = Constant::Builder(UCodePointMathematicalBoldSmallI); @@ -555,14 +555,14 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex // Step 8: e^(r*i*Pi) with r rational --> cos(pi*r) + i*sin(pi*r) if (!letPowerAtRoot && isNthRootOfUnity()) { Expression i = index.childAtIndex(index.numberOfChildren()-2); - static_cast(index).removeChildAtIndexInPlace(index.numberOfChildren()-2); + static_cast(index).removeChildAtIndexInPlace(index.numberOfChildren()-2); if (reductionContext.angleUnit() == Preferences::AngleUnit::Degree) { index.replaceChildAtIndexInPlace(index.numberOfChildren()-1, Rational::Builder(180)); } Expression cos = Cosine::Builder(index); index = index.shallowReduce(reductionContext); Expression sin = Sine::Builder(index.clone()); - Expression complexPart = Multiplication::Builder(sin, i); + Expression complexPart = MultiplicationExplicite::Builder(sin, i); sin.shallowReduce(reductionContext); Expression a = Addition::Builder(cos, complexPart); cos.shallowReduce(reductionContext); @@ -631,8 +631,8 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex } } // Step 11: (a*b*c*...)^r ? - if (!letPowerAtRoot && baseType == ExpressionNode::Type::Multiplication) { - Multiplication multiplicationBase = static_cast(base); + if (!letPowerAtRoot && baseType == ExpressionNode::Type::MultiplicationExplicite) { + MultiplicationExplicite multiplicationBase = static_cast(base); // Case 1: (a*b*c*...)^n = a^n*b^n*c^n*... if n integer if (indexType == ExpressionNode::Type::Rational && static_cast(index).integerDenominator().isOne()) { return simplifyPowerMultiplication(reductionContext); @@ -662,7 +662,7 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex // |a|^r*(sign(a)*b*...)^r Power thisRef = *this; - Multiplication root = Multiplication::Builder(p); + MultiplicationExplicite root = MultiplicationExplicite::Builder(p); replaceWithInPlace(root); root.addChildAtIndexInPlace(thisRef, 1, 1); p.shallowReduce(reductionContext); @@ -706,7 +706,7 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex additionIndex.removeChildAtIndexInPlace(0); // p2 = a^(c+...) // if addition had only 2 children additionIndex.squashUnaryHierarchyInPlace(); - Multiplication m = Multiplication::Builder(p1); + MultiplicationExplicite m = MultiplicationExplicite::Builder(p1); replaceWithInPlace(m); m.addChildAtIndexInPlace(thisRef, 1, 1); p1.simplifyRationalRationalPower(reductionContext); @@ -750,7 +750,7 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex // We need a 'double' distribution and newA will hold the new expanded form Expression newA = Addition::Builder(); for (int j = 0; j < a.numberOfChildren(); j++) { - Expression m = Multiplication::Builder(result.clone(), a.childAtIndex(j).clone()).distributeOnOperandAtIndex(0, reductionContext); + Expression m = MultiplicationExplicite::Builder(result.clone(), a.childAtIndex(j).clone()).distributeOnOperandAtIndex(0, reductionContext); if (newA.type() == ExpressionNode::Type::Addition) { static_cast(newA).addChildAtIndexInPlace(m, newA.numberOfChildren(), newA.numberOfChildren()); } else { @@ -762,7 +762,7 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex result = newA; } else { // Just distribute result on a - Multiplication m = Multiplication::Builder(a.clone(), result.clone()); + MultiplicationExplicite m = MultiplicationExplicite::Builder(a.clone(), result.clone()); Expression distributedM = m.distributeOnOperandAtIndex(0, reductionContext); result.replaceWithInPlace(distributedM); result = distributedM; @@ -797,7 +797,7 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex Power * p0 = new Power::Builder(x0->clone(), new Rational::Builder(i), false); Power * p1 = new Power::Builder(x1->clone(), new Rational::Builder(clippedN-i), false); const Expression * operands[3] = {r, p0, p1}; - Multiplication * m = new Multiplication::Builder(operands, 3, false); + MultiplicationExplicite * m = new MultiplicationExplicite::Builder(operands, 3, false); p0->shallowReduce(reductionContext); p1->shallowReduce(reductionContext); a->addOperand(m); @@ -855,7 +855,7 @@ Expression Power::shallowBeautify(ExpressionNode::ReductionContext reductionCont // Step 4: +(a,b)^c ->(+(a,b))^c and *(a,b)^c ->(*(a,b))^c if (childAtIndex(0).type() == ExpressionNode::Type::Addition - || childAtIndex(0).type() == ExpressionNode::Type::Multiplication) + || childAtIndex(0).isMultiplication()) { Parenthesis p = Parenthesis::Builder(childAtIndex(0)); replaceChildAtIndexInPlace(0, p); @@ -885,7 +885,7 @@ Expression Power::denominator(Context * context, Preferences::ComplexFormat comp Expression Power::simplifyPowerPower(ExpressionNode::ReductionContext reductionContext) { // this is p^e = (a^b)^e, we want a^(b*e) Expression p = childAtIndex(0); - Multiplication m = Multiplication::Builder(p.childAtIndex(1), childAtIndex(1)); + MultiplicationExplicite m = MultiplicationExplicite::Builder(p.childAtIndex(1), childAtIndex(1)); replaceChildAtIndexInPlace(0, p.childAtIndex(0)); replaceChildAtIndexInPlace(1, m); m.shallowReduce(reductionContext); @@ -927,7 +927,7 @@ Expression Power::simplifyRationalRationalPower(ExpressionNode::ReductionContext n = CreateSimplifiedIntegerRationalPower(a.signedIntegerNumerator(), b, false, reductionContext); d = CreateSimplifiedIntegerRationalPower(a.integerDenominator(), b, true, reductionContext); } - Multiplication m = Multiplication::Builder(n, d); + MultiplicationExplicite m = MultiplicationExplicite::Builder(n, d); replaceWithInPlace(m); return m.shallowReduce(reductionContext); } @@ -970,7 +970,7 @@ Expression Power::CreateSimplifiedIntegerRationalPower(Integer i, Rational r, bo } Integer one(1); Rational r3 = isDenominator ? Rational::Builder(one, r1) : Rational::Builder(r1); - Multiplication m = Multiplication::Builder(); + MultiplicationExplicite m = MultiplicationExplicite::Builder(); m.addChildAtIndexInPlace(r3, 0, 0); if (!r2.isOne()) { m.addChildAtIndexInPlace(p, 1, 1); @@ -1023,9 +1023,9 @@ Expression Power::removeSquareRootsFromDenominator(ExpressionNode::ReductionCont Power sqrt = Power::Builder(Rational::Builder(pq), Rational::Builder(1, 2)); Integer one(1); if (castedChild1.isHalf()) { - result = Multiplication::Builder(Rational::Builder(one, q), sqrt); + result = MultiplicationExplicite::Builder(Rational::Builder(one, q), sqrt); } else { - result = Multiplication::Builder(Rational::Builder(one, p), sqrt); // We use here the assertion that p != 0 + result = MultiplicationExplicite::Builder(Rational::Builder(one, p), sqrt); // We use here the assertion that p != 0 } sqrt.shallowReduce(reductionContext); } @@ -1080,11 +1080,11 @@ Expression Power::removeSquareRootsFromDenominator(ExpressionNode::ReductionCont Integer factor1 = Integer::Multiplication( Integer::Multiplication(n1, d1), Integer::Multiplication(Integer::Power(d2, Integer(2)), q2)); - Multiplication m1 = Multiplication::Builder(Rational::Builder(factor1), sqrt1); + Multiplication m1 = MultiplicationExplicite::Builder(Rational::Builder(factor1), sqrt1); Integer factor2 = Integer::Multiplication( Integer::Multiplication(n2, d2), Integer::Multiplication(Integer::Power(d1, Integer(2)), q1)); - Multiplication m2 = Multiplication::Builder(Rational::Builder(factor2), sqrt2); + Multiplication m2 = MultiplicationExplicite::Builder(Rational::Builder(factor2), sqrt2); Expression numerator; if (denominator.isNegative()) { numerator = Subtraction::Builder(m2, m1); @@ -1097,7 +1097,7 @@ Expression Power::removeSquareRootsFromDenominator(ExpressionNode::ReductionCont } numerator = numerator.deepReduce(reductionContext); Integer one(1); - result = Multiplication::Builder(numerator, Rational::Builder(one, denominator)); + result = MultiplicationExplicite::Builder(numerator, Rational::Builder(one, denominator)); } if (!result.isUninitialized()) { @@ -1140,7 +1140,7 @@ bool Power::isNthRootOfUnity() const { if (childAtIndex(0).type() != ExpressionNode::Type::Constant || !childAtIndex(0).convert().isExponential()) { return false; } - if (childAtIndex(1).type() != ExpressionNode::Type::Multiplication) { + if (childAtIndex(1).type() != ExpressionNode::Type::MultiplicationExplicite) { return false; } if (childAtIndex(1).numberOfChildren() < 2 || childAtIndex(1).numberOfChildren() > 3) { @@ -1183,7 +1183,7 @@ Expression Power::CreateComplexExponent(const Expression & r, ExpressionNode::Re const Constant exp = Constant::Builder(UCodePointScriptSmallE); Constant iComplex = Constant::Builder(UCodePointMathematicalBoldSmallI); const Constant pi = Constant::Builder(UCodePointGreekSmallLetterPi); - Multiplication mExp = Multiplication::Builder(iComplex, pi, r.clone()); + MultiplicationExplicite mExp = MultiplicationExplicite::Builder(iComplex, pi, r.clone()); iComplex.shallowReduce(reductionContext); Power p = Power::Builder(exp, mExp); mExp.shallowReduce(reductionContext); @@ -1191,10 +1191,10 @@ Expression Power::CreateComplexExponent(const Expression & r, ExpressionNode::Re #if 0 const Constant iComplex = Constant::Builder(UCodePointMathematicalBoldSmallI); const Constant pi = Constant::Builder(UCodePointGreekSmallLetterPi); - Expression op = Multiplication::Builder(pi, r).shallowReduce(context, complexFormat, angleUnit, false); + Expression op = MultiplicationExplicite::Builder(pi, r).shallowReduce(context, complexFormat, angleUnit, false); Cosine cos = Cosine(op).shallowReduce(context, complexFormat, angleUnit, false);; Sine sin = Sine(op).shallowReduce(context, complexFormat, angleUnit, false); - Expression m = Multiplication::Builder(iComplex, sin); + Expression m = MultiplicationExplicite::Builder(iComplex, sin); Expression a = Addition::Builder(cos, m); const Expression * multExpOperands[3] = {pi, r->clone()}; #endif @@ -1211,7 +1211,7 @@ bool Power::TermIsARationalSquareRootOrRational(const Expression & e) { { return true; } - if (e.type() == ExpressionNode::Type::Multiplication + if (e.type() == ExpressionNode::Type::MultiplicationExplicite && e.numberOfChildren() == 2 && e.childAtIndex(0).type() == ExpressionNode::Type::Rational && e.childAtIndex(1).type() == ExpressionNode::Type::Power @@ -1232,7 +1232,7 @@ const Rational Power::RadicandInExpression(const Expression & e) { assert(e.childAtIndex(0).type() == ExpressionNode::Type::Rational); return e.childAtIndex(0).convert(); } else { - assert(e.type() == ExpressionNode::Type::Multiplication); + assert(e.type() == ExpressionNode::Type::MultiplicationExplicite); assert(e.childAtIndex(1).type() == ExpressionNode::Type::Power); assert(e.childAtIndex(1).childAtIndex(0).type() == ExpressionNode::Type::Rational); return e.childAtIndex(1).childAtIndex(0).convert(); @@ -1245,7 +1245,7 @@ const Rational Power::RationalFactorInExpression(const Expression & e) { } else if (e.type() == ExpressionNode::Type::Power) { return Rational::Builder(1); } else { - assert(e.type() == ExpressionNode::Type::Multiplication); + assert(e.type() == ExpressionNode::Type::MultiplicationExplicite); assert(e.childAtIndex(0).type() == ExpressionNode::Type::Rational); return e.childAtIndex(0).convert(); } diff --git a/poincare/src/prediction_interval.cpp b/poincare/src/prediction_interval.cpp index 60da68b6e..2acf5027b 100644 --- a/poincare/src/prediction_interval.cpp +++ b/poincare/src/prediction_interval.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include #include @@ -89,9 +89,9 @@ Expression PredictionInterval::shallowReduce(ExpressionNode::ReductionContext re } // Compute sqr = sqrt(r0*(1-r0)/r1) Expression sqr = Power::Builder(Division::Builder(numerator, r1), Rational::Builder(1, 2)); - Expression m = Multiplication::Builder(Rational::Builder(196, 100), sqr); + Expression m = MultiplicationExplicite::Builder(Rational::Builder(196, 100), sqr); Matrix matrix = Matrix::Builder(); - matrix.addChildAtIndexInPlace(Addition::Builder(r0.clone(), Multiplication::Builder(Rational::Builder(-1), m.clone())), 0, 0); + matrix.addChildAtIndexInPlace(Addition::Builder(r0.clone(), MultiplicationExplicite::Builder(Rational::Builder(-1), m.clone())), 0, 0); matrix.addChildAtIndexInPlace(Addition::Builder(r0.clone(), m), 1, 1); matrix.setDimensions(1, 2); replaceWithInPlace(matrix); diff --git a/poincare/src/sign_function.cpp b/poincare/src/sign_function.cpp index 6381f3856..f15c11d18 100644 --- a/poincare/src/sign_function.cpp +++ b/poincare/src/sign_function.cpp @@ -84,7 +84,7 @@ Expression SignFunction::shallowReduce(ExpressionNode::ReductionContext reductio return *this; } Expression sign = *this; - Multiplication m = Multiplication::Builder(Rational::Builder(-1)); + Multiplication m = MultiplicationExplicite::Builder(Rational::Builder(-1)); replaceWithInPlace(m); m.addChildAtIndexInPlace(sign, 1, 1); // sign does not need to be shallowReduced because -x = NAN --> x = NAN return m; // m does not need to be shallowReduced, -1*sign cannot be reduced diff --git a/poincare/src/subtraction.cpp b/poincare/src/subtraction.cpp index cdb083ef1..2e820a9ca 100644 --- a/poincare/src/subtraction.cpp +++ b/poincare/src/subtraction.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include @@ -61,7 +61,7 @@ Expression Subtraction::shallowReduce(ExpressionNode::ReductionContext reduction if (e.isUndefined()) { return e; } - Expression m = Multiplication::Builder(Rational::Builder(-1), childAtIndex(1)); + Expression m = MultiplicationExplicite::Builder(Rational::Builder(-1), childAtIndex(1)); Addition a = Addition::Builder(childAtIndex(0), m); m = m.shallowReduce(reductionContext); replaceWithInPlace(a); diff --git a/poincare/src/tree_handle.cpp b/poincare/src/tree_handle.cpp index 337302cf9..0ca34a70b 100644 --- a/poincare/src/tree_handle.cpp +++ b/poincare/src/tree_handle.cpp @@ -314,7 +314,8 @@ template MatrixIdentity TreeHandle::FixedArityBuilder(TreeHandle*, size_t); template MatrixTrace TreeHandle::FixedArityBuilder(TreeHandle*, size_t); template MatrixTranspose TreeHandle::FixedArityBuilder(TreeHandle*, size_t); -template Multiplication TreeHandle::NAryBuilder(TreeHandle*, size_t); +template MultiplicationExplicite TreeHandle::NAryBuilder(TreeHandle*, size_t); +template MultiplicationImplicite TreeHandle::NAryBuilder(TreeHandle*, size_t); template NaperianLogarithm TreeHandle::FixedArityBuilder(TreeHandle*, size_t); template NthRoot TreeHandle::FixedArityBuilder(TreeHandle*, size_t); template Opposite TreeHandle::FixedArityBuilder(TreeHandle*, size_t); diff --git a/poincare/src/trigonometry.cpp b/poincare/src/trigonometry.cpp index 3b834770b..d07daf5f6 100644 --- a/poincare/src/trigonometry.cpp +++ b/poincare/src/trigonometry.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include @@ -82,7 +82,7 @@ bool Trigonometry::AreInverseFunctions(const Expression & directFunction, const bool Trigonometry::ExpressionIsEquivalentToTangent(const Expression & e) { // We look for (cos^-1 * sin) assert(ExpressionNode::Type::Power < ExpressionNode::Type::Sine); - if (e.type() == ExpressionNode::Type::Multiplication + if (e.type() == ExpressionNode::Type::MultiplicationExplicite && e.childAtIndex(1).type() == ExpressionNode::Type::Sine && e.childAtIndex(0).type() == ExpressionNode::Type::Power && e.childAtIndex(0).childAtIndex(0).type() == ExpressionNode::Type::Cosine @@ -125,7 +125,7 @@ Expression Trigonometry::shallowReduceDirectFunction(Expression & e, ExpressionN Power::Builder( Addition::Builder( Rational::Builder(1), - Multiplication::Builder( + MultiplicationExplicite::Builder( Rational::Builder(-1), Power::Builder(e.childAtIndex(0).childAtIndex(0), Rational::Builder(2)) ) @@ -166,7 +166,7 @@ Expression Trigonometry::shallowReduceDirectFunction(Expression & e, ExpressionN // reduce 1+*x^2 res.childAtIndex(0).shallowReduce(reductionContext); if (e.type() == ExpressionNode::Type::Sine) { - res = Multiplication::Builder(x, res); + res = MultiplicationExplicite::Builder(x, res); // reduce (1+x^2)^(-1/2) res.childAtIndex(0).shallowReduce(reductionContext); } @@ -184,7 +184,7 @@ Expression Trigonometry::shallowReduceDirectFunction(Expression & e, ExpressionN return e.shallowReduce(reductionContext); } else { // sin(-a) = -sin(a) or tan(-a) = -tan(a) - Multiplication m = Multiplication::Builder(Rational::Builder(-1)); + MultiplicationExplicite m = MultiplicationExplicite::Builder(Rational::Builder(-1)); e.replaceWithInPlace(m); m.addChildAtIndexInPlace(e, 1, 1); e.shallowReduce(reductionContext); @@ -197,7 +197,7 @@ Expression Trigonometry::shallowReduceDirectFunction(Expression & e, ExpressionN * multiply the cos/sin/tan by -1 if needed. * We know thanks to Step 3 that p/q > 0. */ if ((reductionContext.angleUnit() == Preferences::AngleUnit::Radian - && e.childAtIndex(0).type() == ExpressionNode::Type::Multiplication + && e.childAtIndex(0).type() == ExpressionNode::Type::MultiplicationExplicite && e.childAtIndex(0).numberOfChildren() == 2 && e.childAtIndex(0).childAtIndex(1).type() == ExpressionNode::Type::Constant && e.childAtIndex(0).childAtIndex(1).convert().isPi() @@ -250,7 +250,7 @@ Expression Trigonometry::shallowReduceDirectFunction(Expression & e, ExpressionN unaryCoefficient *= -1; } Expression simplifiedCosine = e.shallowReduce(reductionContext); // recursive - Multiplication m = Multiplication::Builder(Rational::Builder(unaryCoefficient)); + MultiplicationExplicite m = MultiplicationExplicite::Builder(Rational::Builder(unaryCoefficient)); simplifiedCosine.replaceWithInPlace(m); m.addChildAtIndexInPlace(simplifiedCosine, 1, 1); return m.shallowReduce(reductionContext); @@ -303,12 +303,12 @@ Expression Trigonometry::shallowReduceInverseFunction(Expression & e, Expressio * reduced to undef) */ if (reductionContext.target() == ExpressionNode::ReductionTarget::User || x.isNumber()) { Expression sign = SignFunction::Builder(x.clone()); - Multiplication m0 = Multiplication::Builder(Rational::Builder(1,2), sign, Constant::Builder(UCodePointGreekSmallLetterPi)); + MultiplicationExplicite m0 = MultiplicationExplicite::Builder(Rational::Builder(1,2), sign, Constant::Builder(UCodePointGreekSmallLetterPi)); sign.shallowReduce(reductionContext); e.replaceChildAtIndexInPlace(0, x); Addition a = Addition::Builder(m0); e.replaceWithInPlace(a); - Multiplication m1 = Multiplication::Builder(Rational::Builder(-1), e); + MultiplicationExplicite m1 = MultiplicationExplicite::Builder(Rational::Builder(-1), e); e.shallowReduce(reductionContext); a.addChildAtIndexInPlace(m1, 1, 1); return a.shallowReduce(reductionContext); @@ -348,7 +348,7 @@ Expression Trigonometry::shallowReduceInverseFunction(Expression & e, Expressio return s.shallowReduce(reductionContext); } else { // asin(-x) = -asin(x) or atan(-x) = -atan(x) - Multiplication m = Multiplication::Builder(Rational::Builder(-1)); + MultiplicationExplicite m = MultiplicationExplicite::Builder(Rational::Builder(-1)); e.replaceWithInPlace(m); m.addChildAtIndexInPlace(e, 1, 1); e.shallowReduce(reductionContext); diff --git a/poincare/src/trigonometry_cheat_table.cpp b/poincare/src/trigonometry_cheat_table.cpp index 0fb6e71e8..85e758cc3 100644 --- a/poincare/src/trigonometry_cheat_table.cpp +++ b/poincare/src/trigonometry_cheat_table.cpp @@ -41,11 +41,11 @@ Expression TrigonometryCheatTable::simplify(const Expression e, ExpressionNode:: && e.type() != ExpressionNode::Type::Rational) || (inputType == Type::AngleInRadians && e.type() != ExpressionNode::Type::Rational - && e.type() != ExpressionNode::Type::Multiplication + && e.type() != ExpressionNode::Type::MultiplicationExplicite && e.type() != ExpressionNode::Type::Constant) || (inputType > Type::AngleInRadians && e.type() != ExpressionNode::Type::Rational - && e.type() != ExpressionNode::Type::Multiplication + && e.type() != ExpressionNode::Type::MultiplicationExplicite && e.type() != ExpressionNode::Type::Power && e.type() != ExpressionNode::Type::Addition)) { diff --git a/poincare/test/expression_order.cpp b/poincare/test/expression_order.cpp index d6c326371..39a177765 100644 --- a/poincare/test/expression_order.cpp +++ b/poincare/test/expression_order.cpp @@ -9,8 +9,8 @@ using namespace Poincare; void assert_multiplication_or_addition_is_ordered_as(Expression e1, Expression e2) { Shared::GlobalContext globalContext; - if (e1.type() == ExpressionNode::Type::Multiplication) { - static_cast(e1).sortChildrenInPlace( + if (e1.type() == ExpressionNode::Type::MultiplicationExplicite) { + static_cast(e1).sortChildrenInPlace( [](const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted) { return ExpressionNode::SimplificationOrder(e1, e2, true, canBeInterrupted); }, &globalContext, true); @@ -27,13 +27,13 @@ void assert_multiplication_or_addition_is_ordered_as(Expression e1, Expression e QUIZ_CASE(poincare_expression_order) { { // 2 * 5 -> 2 * 5 - Expression e1 = Multiplication::Builder(Rational::Builder(2), Rational::Builder(5)); + Expression e1 = MultiplicationExplicite::Builder(Rational::Builder(2), Rational::Builder(5)); assert_multiplication_or_addition_is_ordered_as(e1, e1); } { // 5 * 2 -> 2 * 5 - Expression e1 = Multiplication::Builder(Rational::Builder(5), Rational::Builder(2)); - Expression e2 = Multiplication::Builder(Rational::Builder(2), Rational::Builder(5)); + Expression e1 = MultiplicationExplicite::Builder(Rational::Builder(5), Rational::Builder(2)); + Expression e2 = MultiplicationExplicite::Builder(Rational::Builder(2), Rational::Builder(5)); assert_multiplication_or_addition_is_ordered_as(e1, e2); } { @@ -59,8 +59,8 @@ QUIZ_CASE(poincare_expression_order) { } { // root(3) $ 2 -> 2 * root(3) - Expression e1 = Multiplication::Builder(SquareRoot::Builder(Rational::Builder(3)), Rational::Builder(2)); - Expression e2 = Multiplication::Builder(Rational::Builder(2), SquareRoot::Builder(Rational::Builder(3))); + Expression e1 = MultiplicationExplicite::Builder(SquareRoot::Builder(Rational::Builder(3)), Rational::Builder(2)); + Expression e2 = MultiplicationExplicite::Builder(Rational::Builder(2), SquareRoot::Builder(Rational::Builder(3))); assert_multiplication_or_addition_is_ordered_as(e1, e2); } { @@ -84,16 +84,16 @@ QUIZ_CASE(poincare_expression_order) { } { // 3*x^2 + 2*x^3 -> 2*x^3 + 3*x^2 - Expression child1 = Multiplication::Builder(Rational::Builder(2), Power::Builder(Symbol::Builder('x'), Rational::Builder(3))); - Expression child2 = Multiplication::Builder(Rational::Builder(3), Power::Builder(Symbol::Builder('x'), Rational::Builder(2))); + Expression child1 = MultiplicationExplicite::Builder(Rational::Builder(2), Power::Builder(Symbol::Builder('x'), Rational::Builder(3))); + Expression child2 = MultiplicationExplicite::Builder(Rational::Builder(3), Power::Builder(Symbol::Builder('x'), Rational::Builder(2))); Expression e1 = Addition::Builder(child2.clone(), child1.clone()); Expression e2 = Addition::Builder(child1, child2); assert_multiplication_or_addition_is_ordered_as(e1, e2); } { // 2*x + 3*x -> 3*x + 2*x - Expression child1 = Multiplication::Builder(Rational::Builder(3), Symbol::Builder('x')); - Expression child2 = Multiplication::Builder(Rational::Builder(2), Symbol::Builder('x')); + Expression child1 = MultiplicationExplicite::Builder(Rational::Builder(3), Symbol::Builder('x')); + Expression child2 = MultiplicationExplicite::Builder(Rational::Builder(2), Symbol::Builder('x')); Expression e1 = Addition::Builder(child2.clone(), child1.clone()); Expression e2 = Addition::Builder(child1, child2); assert_multiplication_or_addition_is_ordered_as(e1, e2); @@ -102,16 +102,16 @@ QUIZ_CASE(poincare_expression_order) { // pi^b * pi^a -> pi^a * pi^b Expression child1 = Power::Builder(Constant::Builder(UCodePointGreekSmallLetterPi), Symbol::Builder('a')); Expression child2 = Power::Builder(Constant::Builder(UCodePointGreekSmallLetterPi), Symbol::Builder('b')); - Expression e1 = Multiplication::Builder(child2.clone(), child1.clone()); - Expression e2 = Multiplication::Builder(child1, child2); + Expression e1 = MultiplicationExplicite::Builder(child2.clone(), child1.clone()); + Expression e2 = MultiplicationExplicite::Builder(child1, child2); assert_multiplication_or_addition_is_ordered_as(e1, e2); } { // pi^3 * pi^2 -> pi^2 * pi^3 Expression child1 = Power::Builder(Constant::Builder(UCodePointGreekSmallLetterPi), Rational::Builder(2)); Expression child2 = Power::Builder(Constant::Builder(UCodePointGreekSmallLetterPi), Rational::Builder(3)); - Expression e1 = Multiplication::Builder(child2.clone(), child1.clone()); - Expression e2 = Multiplication::Builder(child1, child2); + Expression e1 = MultiplicationExplicite::Builder(child2.clone(), child1.clone()); + Expression e2 = MultiplicationExplicite::Builder(child1, child2); assert_multiplication_or_addition_is_ordered_as(e1, e2); } { @@ -120,8 +120,8 @@ QUIZ_CASE(poincare_expression_order) { Expression child2 = Rational::Builder(2); Expression childMatrix = Matrix::Builder(); static_cast(childMatrix).addChildAtIndexInPlace(Rational::Builder(3), 0, 0); - Expression e1 = Multiplication::Builder(child2.clone(), childMatrix.clone(), child1.clone()); - Expression e2 = Multiplication::Builder(child1.clone(), child2.clone(), childMatrix.clone()); + Expression e1 = MultiplicationExplicite::Builder(child2.clone(), childMatrix.clone(), child1.clone()); + Expression e2 = MultiplicationExplicite::Builder(child1.clone(), child2.clone(), childMatrix.clone()); assert_multiplication_or_addition_is_ordered_as(e1, e2); } @@ -147,8 +147,8 @@ QUIZ_CASE(poincare_expression_order) { childMatrix1.clone(), childMatrix2.clone() }; - Expression e1 = Multiplication::Builder(children, numberOfChildren); - Expression e2 = Multiplication::Builder(childrenSorted, numberOfChildren); + Expression e1 = MultiplicationExplicite::Builder(children, numberOfChildren); + Expression e2 = MultiplicationExplicite::Builder(childrenSorted, numberOfChildren); assert_multiplication_or_addition_is_ordered_as(e1, e2); } diff --git a/poincare/test/layouts.cpp b/poincare/test/layouts.cpp index c54870902..d112d0556 100644 --- a/poincare/test/layouts.cpp +++ b/poincare/test/layouts.cpp @@ -234,7 +234,7 @@ QUIZ_CASE(poincare_parse_layouts) { CodePointLayout::Builder('+'), CodePointLayout::Builder('5'))), CodePointLayout::Builder('3')); - e = Multiplication::Builder( + e = MultiplicationExplicite::Builder( Rational::Builder(5), Division::Builder( Rational::Builder(6), @@ -296,8 +296,8 @@ QUIZ_CASE(poincare_parse_layouts) { VerticalOffsetLayout::Builder( CodePointLayout::Builder('3'), VerticalOffsetLayoutNode::Position::Superscript)); - e = Multiplication::Builder(Rational::Builder(2),Power::Builder(Constant::Builder(UCodePointScriptSmallE),Parenthesis::Builder(Rational::Builder(3)))); - assert_parsed_expression_is("2ℯ^(3)", Multiplication::Builder(Rational::Builder(2),Power::Builder(Constant::Builder(UCodePointScriptSmallE),Parenthesis::Builder(Rational::Builder(3))))); + e = MultiplicationExplicite::Builder(Rational::Builder(2),Power::Builder(Constant::Builder(UCodePointScriptSmallE),Parenthesis::Builder(Rational::Builder(3)))); + assert_parsed_expression_is("2ℯ^(3)", MultiplicationExplicite::Builder(Rational::Builder(2),Power::Builder(Constant::Builder(UCodePointScriptSmallE),Parenthesis::Builder(Rational::Builder(3))))); assert_parsed_layout_is(l, e); } diff --git a/poincare/test/parser.cpp b/poincare/test/parser.cpp index 7779d030a..2b8df0278 100644 --- a/poincare/test/parser.cpp +++ b/poincare/test/parser.cpp @@ -122,16 +122,16 @@ QUIZ_CASE(poincare_parser_parse) { assert_parsed_expression_is("(1+2)", Parenthesis::Builder(Addition::Builder(Rational::Builder(1),Rational::Builder(2)))); assert_parsed_expression_is("1+2+3", Addition::Builder(Addition::Builder(Rational::Builder(1),Rational::Builder(2)),Rational::Builder(3))); assert_parsed_expression_is("1+2+(3+4)", Addition::Builder(Addition::Builder(Rational::Builder(1),Rational::Builder(2)),Parenthesis::Builder(Addition::Builder(Rational::Builder(3),Rational::Builder(4))))); - assert_parsed_expression_is("1×2", Multiplication::Builder(Rational::Builder(1),Rational::Builder(2))); - assert_parsed_expression_is("1×2×3", Multiplication::Builder(Multiplication::Builder(Rational::Builder(1),Rational::Builder(2)),Rational::Builder(3))); - assert_parsed_expression_is("1+2×3", Addition::Builder(Rational::Builder(1), Multiplication::Builder(Rational::Builder(2), Rational::Builder(3)))); + assert_parsed_expression_is("1×2", MultiplicationExplicite::Builder(Rational::Builder(1),Rational::Builder(2))); + assert_parsed_expression_is("1×2×3", MultiplicationExplicite::Builder(MultiplicationExplicite::Builder(Rational::Builder(1),Rational::Builder(2)),Rational::Builder(3))); + assert_parsed_expression_is("1+2×3", Addition::Builder(Rational::Builder(1), MultiplicationExplicite::Builder(Rational::Builder(2), Rational::Builder(3)))); assert_parsed_expression_is("1/2", Division::Builder(Rational::Builder(1),Rational::Builder(2))); assert_parsed_expression_is("(1/2)", Parenthesis::Builder(Division::Builder(Rational::Builder(1),Rational::Builder(2)))); assert_parsed_expression_is("1/2/3", Division::Builder(Division::Builder(Rational::Builder(1),Rational::Builder(2)),Rational::Builder(3))); - assert_parsed_expression_is("1/2×3", Multiplication::Builder(Division::Builder(Rational::Builder(1),Rational::Builder(2)),Rational::Builder(3))); - assert_parsed_expression_is("(1/2×3)", Parenthesis::Builder(Multiplication::Builder(Division::Builder(Rational::Builder(1),Rational::Builder(2)),Rational::Builder(3)))); - assert_parsed_expression_is("1×2/3", Multiplication::Builder(Rational::Builder(1),Division::Builder(Rational::Builder(2),Rational::Builder(3)))); - assert_parsed_expression_is("(1×2/3)", Parenthesis::Builder(Multiplication::Builder(Rational::Builder(1),Division::Builder(Rational::Builder(2),Rational::Builder(3))))); + assert_parsed_expression_is("1/2×3", MultiplicationExplicite::Builder(Division::Builder(Rational::Builder(1),Rational::Builder(2)),Rational::Builder(3))); + assert_parsed_expression_is("(1/2×3)", Parenthesis::Builder(MultiplicationExplicite::Builder(Division::Builder(Rational::Builder(1),Rational::Builder(2)),Rational::Builder(3)))); + assert_parsed_expression_is("1×2/3", MultiplicationExplicite::Builder(Rational::Builder(1),Division::Builder(Rational::Builder(2),Rational::Builder(3)))); + assert_parsed_expression_is("(1×2/3)", Parenthesis::Builder(MultiplicationExplicite::Builder(Rational::Builder(1),Division::Builder(Rational::Builder(2),Rational::Builder(3))))); assert_parsed_expression_is("(1/2/3)", Parenthesis::Builder(Division::Builder(Division::Builder(Rational::Builder(1),Rational::Builder(2)),Rational::Builder(3)))); assert_parsed_expression_is("1^2", Power::Builder(Rational::Builder(1),Rational::Builder(2))); assert_parsed_expression_is("1^2^3", Power::Builder(Rational::Builder(1),Power::Builder(Rational::Builder(2),Rational::Builder(3)))); @@ -147,23 +147,23 @@ QUIZ_CASE(poincare_parser_parse) { assert_parsed_expression_is("1+-2", Addition::Builder(Rational::Builder(1),Opposite::Builder(Rational::Builder(2)))); assert_parsed_expression_is("--1", Opposite::Builder((Expression)Opposite::Builder(Rational::Builder(1)))); assert_parsed_expression_is("(1+2)-3", Subtraction::Builder(Parenthesis::Builder(Addition::Builder(Rational::Builder(1),Rational::Builder(2))),Rational::Builder(3))); - assert_parsed_expression_is("(2×-3)", Parenthesis::Builder(Multiplication::Builder(Rational::Builder(2),Opposite::Builder(Rational::Builder(3))))); + assert_parsed_expression_is("(2×-3)", Parenthesis::Builder(MultiplicationExplicite::Builder(Rational::Builder(2),Opposite::Builder(Rational::Builder(3))))); assert_parsed_expression_is("1^(2)-3", Subtraction::Builder(Power::Builder(Rational::Builder(1),Parenthesis::Builder(Rational::Builder(2))),Rational::Builder(3))); assert_parsed_expression_is("1^2-3", Subtraction::Builder(Power::Builder(Rational::Builder(1),Rational::Builder(2)),Rational::Builder(3))); assert_parsed_expression_is("2^-3", Power::Builder(Rational::Builder(2),Opposite::Builder(Rational::Builder(3)))); assert_parsed_expression_is("2--2+-1", Addition::Builder(Subtraction::Builder(Rational::Builder(2),Opposite::Builder(Rational::Builder(2))),Opposite::Builder(Rational::Builder(1)))); - assert_parsed_expression_is("2--2×-1", Subtraction::Builder(Rational::Builder(2),Opposite::Builder(Multiplication::Builder(Rational::Builder(2),Opposite::Builder(Rational::Builder(1)))))); + assert_parsed_expression_is("2--2×-1", Subtraction::Builder(Rational::Builder(2),Opposite::Builder(MultiplicationExplicite::Builder(Rational::Builder(2),Opposite::Builder(Rational::Builder(1)))))); assert_parsed_expression_is("-1^2", Opposite::Builder(Power::Builder(Rational::Builder(1),Rational::Builder(2)))); assert_parsed_expression_is("2/-3/-4", Division::Builder(Division::Builder(Rational::Builder(2),Opposite::Builder(Rational::Builder(3))),Opposite::Builder(Rational::Builder(4)))); - assert_parsed_expression_is("1×2-3×4", Subtraction::Builder(Multiplication::Builder(Rational::Builder(1),Rational::Builder(2)),Multiplication::Builder(Rational::Builder(3),Rational::Builder(4)))); - assert_parsed_expression_is("-1×2", Opposite::Builder(Multiplication::Builder(Rational::Builder(1), Rational::Builder(2)))); + assert_parsed_expression_is("1×2-3×4", Subtraction::Builder(MultiplicationExplicite::Builder(Rational::Builder(1),Rational::Builder(2)),MultiplicationExplicite::Builder(Rational::Builder(3),Rational::Builder(4)))); + assert_parsed_expression_is("-1×2", Opposite::Builder(MultiplicationExplicite::Builder(Rational::Builder(1), Rational::Builder(2)))); assert_parsed_expression_is("1!", Factorial::Builder(Rational::Builder(1))); assert_parsed_expression_is("1+2!", Addition::Builder(Rational::Builder(1),Factorial::Builder(Rational::Builder(2)))); assert_parsed_expression_is("1!+2", Addition::Builder(Factorial::Builder(Rational::Builder(1)),Rational::Builder(2))); assert_parsed_expression_is("1!+2!", Addition::Builder(Factorial::Builder(Rational::Builder(1)),Factorial::Builder(Rational::Builder(2)))); - assert_parsed_expression_is("1×2!", Multiplication::Builder(Rational::Builder(1),Factorial::Builder(Rational::Builder(2)))); - assert_parsed_expression_is("1!×2", Multiplication::Builder(Factorial::Builder(Rational::Builder(1)),Rational::Builder(2))); - assert_parsed_expression_is("1!×2!", Multiplication::Builder(Factorial::Builder(Rational::Builder(1)),Factorial::Builder(Rational::Builder(2)))); + assert_parsed_expression_is("1×2!", MultiplicationExplicite::Builder(Rational::Builder(1),Factorial::Builder(Rational::Builder(2)))); + assert_parsed_expression_is("1!×2", MultiplicationExplicite::Builder(Factorial::Builder(Rational::Builder(1)),Rational::Builder(2))); + assert_parsed_expression_is("1!×2!", MultiplicationExplicite::Builder(Factorial::Builder(Rational::Builder(1)),Factorial::Builder(Rational::Builder(2)))); assert_parsed_expression_is("1-2!", Subtraction::Builder(Rational::Builder(1),Factorial::Builder(Rational::Builder(2)))); assert_parsed_expression_is("1!-2", Subtraction::Builder(Factorial::Builder(Rational::Builder(1)),Rational::Builder(2))); assert_parsed_expression_is("1!-2!", Subtraction::Builder(Factorial::Builder(Rational::Builder(1)),Factorial::Builder(Rational::Builder(2)))); @@ -361,27 +361,27 @@ QUIZ_CASE(poincare_parser_parse_store) { QUIZ_CASE(poincare_parser_implicit_multiplication) { assert_raises_parsing_error(".1.2"); assert_raises_parsing_error("1 2"); - assert_parsed_expression_is("1x", Multiplication::Builder(Rational::Builder(1),Symbol::Builder("x", 1))); - assert_parsed_expression_is("1ans", Multiplication::Builder(Rational::Builder(1),Symbol::Builder("ans", 3))); + assert_parsed_expression_is("1x", MultiplicationExplicite::Builder(Rational::Builder(1),Symbol::Builder("x", 1))); + assert_parsed_expression_is("1ans", MultiplicationExplicite::Builder(Rational::Builder(1),Symbol::Builder("ans", 3))); assert_parsed_expression_is("x1", Symbol::Builder("x1", 2)); - assert_parsed_expression_is("1x+2", Addition::Builder(Multiplication::Builder(Rational::Builder(1),Symbol::Builder("x", 1)),Rational::Builder(2))); - assert_parsed_expression_is("1π", Multiplication::Builder(Rational::Builder(1),Constant::Builder(UCodePointGreekSmallLetterPi))); - assert_parsed_expression_is("1x-2", Subtraction::Builder(Multiplication::Builder(Rational::Builder(1),Symbol::Builder("x", 1)),Rational::Builder(2))); - assert_parsed_expression_is("-1x", Opposite::Builder(Multiplication::Builder(Rational::Builder(1),Symbol::Builder("x", 1)))); - assert_parsed_expression_is("2×1x", Multiplication::Builder(Rational::Builder(2),Multiplication::Builder(Rational::Builder(1),Symbol::Builder("x", 1)))); - assert_parsed_expression_is("2^1x", Multiplication::Builder(Power::Builder(Rational::Builder(2),Rational::Builder(1)),Symbol::Builder("x", 1))); - assert_parsed_expression_is("1x^2", Multiplication::Builder(Rational::Builder(1),Power::Builder(Symbol::Builder("x", 1),Rational::Builder(2)))); - assert_parsed_expression_is("2/1x", Division::Builder(Rational::Builder(2),Multiplication::Builder(Rational::Builder(1),Symbol::Builder("x", 1)))); - assert_parsed_expression_is("1x/2", Division::Builder(Multiplication::Builder(Rational::Builder(1),Symbol::Builder("x", 1)),Rational::Builder(2))); - assert_parsed_expression_is("(1)2", Multiplication::Builder(Parenthesis::Builder(Rational::Builder(1)),Rational::Builder(2))); - assert_parsed_expression_is("1(2)", Multiplication::Builder(Rational::Builder(1),Parenthesis::Builder(Rational::Builder(2)))); - assert_parsed_expression_is("sin(1)2", Multiplication::Builder(Sine::Builder(Rational::Builder(1)),Rational::Builder(2))); - assert_parsed_expression_is("1cos(2)", Multiplication::Builder(Rational::Builder(1),Cosine::Builder(Rational::Builder(2)))); - assert_parsed_expression_is("1!2", Multiplication::Builder(Factorial::Builder(Rational::Builder(1)),Rational::Builder(2))); - assert_parsed_expression_is("2ℯ^(3)", Multiplication::Builder(Rational::Builder(2),Power::Builder(Constant::Builder(UCodePointScriptSmallE),Parenthesis::Builder(Rational::Builder(3))))); + assert_parsed_expression_is("1x+2", Addition::Builder(MultiplicationExplicite::Builder(Rational::Builder(1),Symbol::Builder("x", 1)),Rational::Builder(2))); + assert_parsed_expression_is("1π", MultiplicationExplicite::Builder(Rational::Builder(1),Constant::Builder(UCodePointGreekSmallLetterPi))); + assert_parsed_expression_is("1x-2", Subtraction::Builder(MultiplicationExplicite::Builder(Rational::Builder(1),Symbol::Builder("x", 1)),Rational::Builder(2))); + assert_parsed_expression_is("-1x", Opposite::Builder(MultiplicationExplicite::Builder(Rational::Builder(1),Symbol::Builder("x", 1)))); + assert_parsed_expression_is("2×1x", MultiplicationExplicite::Builder(Rational::Builder(2),MultiplicationExplicite::Builder(Rational::Builder(1),Symbol::Builder("x", 1)))); + assert_parsed_expression_is("2^1x", MultiplicationExplicite::Builder(Power::Builder(Rational::Builder(2),Rational::Builder(1)),Symbol::Builder("x", 1))); + assert_parsed_expression_is("1x^2", MultiplicationExplicite::Builder(Rational::Builder(1),Power::Builder(Symbol::Builder("x", 1),Rational::Builder(2)))); + assert_parsed_expression_is("2/1x", Division::Builder(Rational::Builder(2),MultiplicationExplicite::Builder(Rational::Builder(1),Symbol::Builder("x", 1)))); + assert_parsed_expression_is("1x/2", Division::Builder(MultiplicationExplicite::Builder(Rational::Builder(1),Symbol::Builder("x", 1)),Rational::Builder(2))); + assert_parsed_expression_is("(1)2", MultiplicationExplicite::Builder(Parenthesis::Builder(Rational::Builder(1)),Rational::Builder(2))); + assert_parsed_expression_is("1(2)", MultiplicationExplicite::Builder(Rational::Builder(1),Parenthesis::Builder(Rational::Builder(2)))); + assert_parsed_expression_is("sin(1)2", MultiplicationExplicite::Builder(Sine::Builder(Rational::Builder(1)),Rational::Builder(2))); + assert_parsed_expression_is("1cos(2)", MultiplicationExplicite::Builder(Rational::Builder(1),Cosine::Builder(Rational::Builder(2)))); + assert_parsed_expression_is("1!2", MultiplicationExplicite::Builder(Factorial::Builder(Rational::Builder(1)),Rational::Builder(2))); + assert_parsed_expression_is("2ℯ^(3)", MultiplicationExplicite::Builder(Rational::Builder(2),Power::Builder(Constant::Builder(UCodePointScriptSmallE),Parenthesis::Builder(Rational::Builder(3))))); Expression m1[] = {Rational::Builder(1)}; Matrix M1 = BuildMatrix(1,1,m1); Expression m2[] = {Rational::Builder(2)}; Matrix M2 = BuildMatrix(1,1,m2); - assert_parsed_expression_is("[[1]][[2]]", Multiplication::Builder(M1,M2)); + assert_parsed_expression_is("[[1]][[2]]", MultiplicationExplicite::Builder(M1,M2)); } QUIZ_CASE(poincare_parser_expression_evaluation) { diff --git a/poincare/test/properties.cpp b/poincare/test/properties.cpp index 8fb8a7d16..831623ea6 100644 --- a/poincare/test/properties.cpp +++ b/poincare/test/properties.cpp @@ -80,12 +80,12 @@ QUIZ_CASE(poincare_characteristic_range) { assert_expression_has_characteristic_range(Cosine::Builder(Opposite::Builder(Symbol::Builder(UCodePointUnknownX))), 360.0f); assert_expression_has_characteristic_range(Cosine::Builder(Symbol::Builder(UCodePointUnknownX)), 2.0f*M_PI, Preferences::AngleUnit::Radian); assert_expression_has_characteristic_range(Cosine::Builder(Opposite::Builder(Symbol::Builder(UCodePointUnknownX))), 2.0f*M_PI, Preferences::AngleUnit::Radian); - assert_expression_has_characteristic_range(Sine::Builder(Addition::Builder(Multiplication::Builder(Rational::Builder(9),Symbol::Builder(UCodePointUnknownX)),Rational::Builder(10))), 40.0f); - assert_expression_has_characteristic_range(Addition::Builder(Sine::Builder(Addition::Builder(Multiplication::Builder(Rational::Builder(9),Symbol::Builder(UCodePointUnknownX)),Rational::Builder(10))),Cosine::Builder(Division::Builder(Symbol::Builder(UCodePointUnknownX),Rational::Builder(2)))), 720.0f); - assert_expression_has_characteristic_range(Addition::Builder(Sine::Builder(Addition::Builder(Multiplication::Builder(Rational::Builder(9),Symbol::Builder(UCodePointUnknownX)),Rational::Builder(10))),Cosine::Builder(Division::Builder(Symbol::Builder(UCodePointUnknownX),Rational::Builder(2)))), 4.0f*M_PI, Preferences::AngleUnit::Radian); + assert_expression_has_characteristic_range(Sine::Builder(Addition::Builder(MultiplicationExplicite::Builder(Rational::Builder(9),Symbol::Builder(UCodePointUnknownX)),Rational::Builder(10))), 40.0f); + assert_expression_has_characteristic_range(Addition::Builder(Sine::Builder(Addition::Builder(MultiplicationExplicite::Builder(Rational::Builder(9),Symbol::Builder(UCodePointUnknownX)),Rational::Builder(10))),Cosine::Builder(Division::Builder(Symbol::Builder(UCodePointUnknownX),Rational::Builder(2)))), 720.0f); + assert_expression_has_characteristic_range(Addition::Builder(Sine::Builder(Addition::Builder(MultiplicationExplicite::Builder(Rational::Builder(9),Symbol::Builder(UCodePointUnknownX)),Rational::Builder(10))),Cosine::Builder(Division::Builder(Symbol::Builder(UCodePointUnknownX),Rational::Builder(2)))), 4.0f*M_PI, Preferences::AngleUnit::Radian); assert_expression_has_characteristic_range(Symbol::Builder(UCodePointUnknownX), NAN); assert_expression_has_characteristic_range(Addition::Builder(Cosine::Builder(Rational::Builder(3)),Rational::Builder(2)), 0.0f); - assert_expression_has_characteristic_range(CommonLogarithm::Builder(Cosine::Builder(Multiplication::Builder(Rational::Builder(40),Symbol::Builder(UCodePointUnknownX)))), 9.0f); + assert_expression_has_characteristic_range(CommonLogarithm::Builder(Cosine::Builder(MultiplicationExplicite::Builder(Rational::Builder(40),Symbol::Builder(UCodePointUnknownX)))), 9.0f); assert_expression_has_characteristic_range(Cosine::Builder((Expression)Cosine::Builder(Symbol::Builder(UCodePointUnknownX))), 360.0f); assert_simplify("cos(x)→f(x)"); assert_expression_has_characteristic_range(Function::Builder("f",1,Symbol::Builder(UCodePointUnknownX)), 360.0f);