diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index bc706faea..05a81fb93 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -167,6 +167,7 @@ private: int getPolynomialCoefficients(char symbolName, Expression coefficients[]) const { return node()->getPolynomialCoefficients(symbolName, coefficients); } /* Simplification */ + Expression denominator(Context & context, Preferences::AngleUnit angleUnit) const { return node()->denominator(context, angleUnit); } Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit) const { return node()->shallowReduce(context, angleUnit); } Expression deepReduce(Context & context, Preferences::AngleUnit angleUnit) const; Expression shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) const { return node()->shallowBeautify(context, angleUnit); } diff --git a/poincare/include/poincare/expression_node.h b/poincare/include/poincare/expression_node.h index 2527e6709..8cf0ac559 100644 --- a/poincare/include/poincare/expression_node.h +++ b/poincare/include/poincare/expression_node.h @@ -149,6 +149,7 @@ public: /* Simplification */ /*!*/ virtual Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit) const; /*!*/ virtual Expression shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) const; + /*!*/ virtual Expression denominator(Context & context, Preferences::AngleUnit angleUnit) const; /* Hierarchy */ ExpressionNode * childAtIndex(int i) const override { return static_cast(TreeNode::childAtIndex(i)); } @@ -157,9 +158,6 @@ public: // TreeNode TreeNode * uninitializedStaticNode() const override; protected: - // Private methods used in simplification process - /*!*/ virtual Expression denominator(Context & context, Preferences::AngleUnit angleUnit) const; - /* Hierarchy */ ExpressionNode * parent() const override { return static_cast(TreeNode::parent()); } diff --git a/poincare/include/poincare/multiplication.h b/poincare/include/poincare/multiplication.h index 1a2f7d527..e3b2c1353 100644 --- a/poincare/include/poincare/multiplication.h +++ b/poincare/include/poincare/multiplication.h @@ -29,12 +29,13 @@ public: } #endif + // Properties Type type() const override { return Type::Multiplication; } Sign sign() const override; int polynomialDegree(char symbolName) const override; int getPolynomialCoefficients(char symbolName, Expression coefficients[]) const override; - // Evaluation + // Approximation template static Complex compute(const std::complex c, const std::complex d) { return Complex(c*d); } template static MatrixComplex computeOnComplexAndMatrix(const std::complex c, const MatrixComplex m) { return ApproximationHelper::ElementWiseOnMatrixComplexAndComplex(m, c, compute); @@ -49,6 +50,8 @@ private: // Layout bool needsParenthesesWithParent(const SerializationHelperInterface * parentNode) const override; LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + + // Serialize int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; // Simplification @@ -56,7 +59,7 @@ private: Expression shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) const override; Expression denominator(Context & context, Preferences::AngleUnit angleUnit) const override; - /* Evaluation */ + /* Approximation */ template static MatrixComplex computeOnMatrixAndComplex(const MatrixComplex m, const std::complex c) { return ApproximationHelper::ElementWiseOnMatrixComplexAndComplex(m, c, compute); } @@ -87,15 +90,18 @@ public: Expression setSign(ExpressionNode::Sign s, Context & context, Preferences::AngleUnit angleUnit) const; Expression shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const; Expression shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) const; + int getPolynomialCoefficients(char symbolName, Expression coefficients[]) const; + Expression denominator(Context & context, Preferences::AngleUnit angleUnit) const; private: // Simplification Expression privateShallowReduce(Context& context, Preferences::AngleUnit angleUnit, bool expand, bool canBeInterrupted) const; - void mergeMultiplicationOperands(); - void factorizeBase(Expression e1, Expression e2, Context & context, Preferences::AngleUnit angleUnit); - void factorizeExponent(Expression e1, Expression e2, Context & context, Preferences::AngleUnit angleUnit); - Expression distributeOnOperandAtIndex(int index, Context & context, Preferences::AngleUnit angleUnit); + void mergeMultiplicationChildrenInPlace(); + void factorizeBase(int i, int j, Context & context, Preferences::AngleUnit angleUnit); + void mergeInChildByFactorizingBase(int i, Expression e, Context & context, Preferences::AngleUnit angleUnit); + void factorizeExponent(int i, int j, Context & context, Preferences::AngleUnit angleUnit); + Expression distributeOnOperandAtIndex(int index, Context & context, Preferences::AngleUnit angleUnit) const; void addMissingFactors(Expression factor, Context & context, Preferences::AngleUnit angleUnit); - void factorizeSineAndCosine(Expression o1, Expression o2, Context & context, Preferences::AngleUnit angleUnit); + void factorizeSineAndCosine(int i, int j, Context & context, 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); @@ -104,7 +110,7 @@ private: static const Expression CreateExponent(Expression e); /* Warning: mergeNegativePower doesnot always return a multiplication: * *(b^-1,c^-1) -> (bc)^-1 */ - Expression mergeNegativePower(Context & context, Preferences::AngleUnit angleUnit); + Expression mergeNegativePower(Context & context, Preferences::AngleUnit angleUnit) const; }; } diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 6be4febf5..ccd3f379c 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -1,12 +1,12 @@ #include #include -//#include -//#include +#include +#include #include //#include #include #include -//#include +#include #include #include //#include @@ -19,6 +19,13 @@ namespace Poincare { +static inline const Expression Base(const Expression e) { + if (e.type() == ExpressionNode::Type::Power) { + return e.childAtIndex(0); + } + return e; +} + MultiplicationNode * MultiplicationNode::FailedAllocationStaticNode() { static AllocationFailureExpressionNode failure; TreePool::sharedPool()->registerStaticNodeIfRequired(&failure); @@ -49,39 +56,7 @@ int MultiplicationNode::polynomialDegree(char symbolName) const { } int MultiplicationNode::getPolynomialCoefficients(char symbolName, Expression coefficients[]) const { - int deg = polynomialDegree(symbolName); - if (deg < 0 || deg > Expression::k_maxPolynomialDegree) { - return -1; - } - // Initialization of coefficients - for (int i = 1; i <= deg; i++) { - coefficients[i] = Rational(0); - } - coefficients[0] = Rational(1); - - Expression intermediateCoefficients[Expression::k_maxNumberOfPolynomialCoefficients]; - // Let's note result = a(0)+a(1)*X+a(2)*X^2+a(3)*x^3+.. - for (int i = 0; i < numberOfChildren(); i++) { - // childAtIndex(i) = b(0)+b(1)*X+b(2)*X^2+b(3)*x^3+... - int degI = childAtIndex(i)->getPolynomialCoefficients(symbolName, intermediateCoefficients); - assert(degI <= Expression::k_maxPolynomialDegree); - for (int j = deg; j > 0; j--) { - // new coefficients[j] = b(0)*a(j)+b(1)*a(j-1)+b(2)*a(j-2)+... - Addition a; - 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(intermediateCoefficients[l], coefficients[j-l]), 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. */ - // TODO remove if (j <= degI) { delete intermediateCoefficients[j]; }; - coefficients[j] = a; - } - // new coefficients[0] = a(0)*b(0) - coefficients[0] = Multiplication(coefficients[0], intermediateCoefficients[0]); - } - return deg; + Multiplication(this).getPolynomialCoefficients(symbolName, coefficients); } template @@ -116,7 +91,7 @@ MatrixComplex MultiplicationNode::computeOnMatrices(const MatrixComplex m, return result; } -Expression MultiplicationNode::setSign(ExpressionNode::Sign s, Context & context, Preferences::AngleUnit angleUnit) const { +Expression MultiplicationNode::setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit) const { return Multiplication(this).setSign(s, context, angleUnit); } @@ -144,40 +119,15 @@ Expression MultiplicationNode::shallowBeautify(Context& context, Preferences::An } Expression MultiplicationNode::denominator(Context & context, Preferences::AngleUnit angleUnit) const { - Expression e = Multiplication(this); - return e; - //TODO -#if 0 - // 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. - SimplificationRoot root(clone()); - Expression * e = ((Multiplication *)root.childAtIndex(0))->mergeNegativePower(context, angleUnit); - Expression * result = nullptr; - if (e->type() == Type::Power) { - result = static_cast(e)->denominator(context, angleUnit); - } else { - assert(e->type() == Type::Multiplication); - for (int i = 0; i < e->numberOfChildren(); i++) { - // a*b^(-1)*... -> a*.../b - if (e->childAtIndex(i)->type() == Type::Power && e->childAtIndex(i)->childAtIndex(1)->type() == Type::Rational && static_cast(e->childAtIndex(i)->childAtIndex(1))->isMinusOne()) { - Power * p = static_cast(e->editableOperand(i)); - result = p->editableOperand(0); - p->detachOperand((result)); - } - } - } - root.detachOperand(e); - delete e; - return result; -#endif + return Multiplication(this).denominator(context, angleUnit); } -// MULTIPLICATION +/* Multiplication */ Expression Multiplication::setSign(ExpressionNode::Sign s, Context & context, Preferences::AngleUnit angleUnit) const { assert(s == ExpressionNode::Sign::Positive); Expression result = *this; - for (int i = 0; i < numberOfChildren(); i++) { + for (int i = 0; i < result.numberOfChildren(); i++) { if (childAtIndex(i).sign() == ExpressionNode::Sign::Negative) { result.replaceChildAtIndexInPlace(i, childAtIndex(i).setSign(s, context, angleUnit)); } @@ -189,48 +139,159 @@ Expression Multiplication::shallowReduce(Context& context, Preferences::AngleUni return privateShallowReduce(context, angleUnit, true, true); } -Expression Multiplication::privateShallowReduce(Context & context, Preferences::AngleUnit angleUnit, bool shouldExpand, bool canBeInterrupted) const { - return Expression::defaultShallowReduce(context, angleUnit);; - //TODO -#if 0 - Expression * e = Expression::defaultShallowReduce(context, angleUnit); - if (e != this) { - return e; - } - /* Step 1: MultiplicationNode is associative, so let's start by merging children - * which also are multiplications themselves. */ - mergeMultiplicationOperands(); +Expression Multiplication::shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) const { + /* 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 2: If any of the operand is zero, the multiplication result is zero */ - for (int i = 0; i < numberOfChildren(); i++) { - const Expression * o = childAtIndex(i); - if (o->type() == Type::Rational && static_cast(o)->isZero()) { - return replaceWith(RationalReference(0), true); + Expression thisCopy = *this; + // Step 1: Turn -n*A into -(n*A) + if (thisCopy.childAtIndex(0).isNumber() && thisCopy.childAtIndex(0).sign() == ExpressionNode::Sign::Negative) { + if (thisCopy.childAtIndex(0).type() == ExpressionNode::Type::Rational && static_cast(thisCopy.childAtIndex(0)).isMinusOne()) { + thisCopy.removeChildAtIndexInPlace(0); + } else { + thisCopy.childAtIndex(0).setSign(ExpressionNode::Sign::Positive, context, angleUnit); + } + return Opposite(static_cast(thisCopy).squashUnaryHierarchy().shallowBeautify(context, angleUnit)); + } + + /* 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) */ + thisCopy = static_cast(thisCopy).mergeNegativePower(context, angleUnit); + if (thisCopy.type() == ExpressionNode::Type::Power) { + return thisCopy.shallowBeautify(context, angleUnit); + } + assert(thisCopy.type() == ExpressionNode::Type::Multiplication); + + // Step 3: Add Parenthesis if needed + for (int i = 0; i < thisCopy.numberOfChildren(); i++) { + const Expression o = thisCopy.childAtIndex(i); + if (thisCopy.type() == ExpressionNode::Type::Addition ) { + Parenthesis p(o); + thisCopy.replaceChildAtIndexInPlace(i, p); } } - // Step 3: Sort the operands - sortOperands(SimplificationOrder, canBeInterrupted); + // Step 4: Create a Division if needed + for (int i = 0; i < thisCopy.numberOfChildren(); i++) { + if (!(thisCopy.childAtIndex(i).type() == ExpressionNode::Type::Power && thisCopy.childAtIndex(i).childAtIndex(1).type() == ExpressionNode::Type::Rational && static_cast(thisCopy.childAtIndex(i).childAtIndex(1)).isMinusOne())) { + continue; + } + + // Let's remove the denominator-to-be from this + Expression denominatorOperand = thisCopy.childAtIndex(i).childAtIndex(0); + thisCopy.removeChildAtIndexInPlace(i); + Expression numeratorOperand = thisCopy.shallowReduce(context, angleUnit); + // Delete parenthesis unnecessary on numerator + if (numeratorOperand.type() == ExpressionNode::Type::Parenthesis) { + numeratorOperand = numeratorOperand.childAtIndex(0); + } + return Division(numeratorOperand, denominatorOperand).shallowBeautify(context, angleUnit); + } + return thisCopy; +} + +int Multiplication::getPolynomialCoefficients(char symbolName, Expression coefficients[]) const { + int deg = polynomialDegree(symbolName); + if (deg < 0 || deg > Expression::k_maxPolynomialDegree) { + return -1; + } + // Initialization of coefficients + for (int i = 1; i <= deg; i++) { + coefficients[i] = Rational(0); + } + coefficients[0] = Rational(1); + + Expression intermediateCoefficients[Expression::k_maxNumberOfPolynomialCoefficients]; + // Let's note result = a(0)+a(1)*X+a(2)*X^2+a(3)*x^3+.. + for (int i = 0; i < numberOfChildren(); i++) { + // childAtIndex(i) = b(0)+b(1)*X+b(2)*X^2+b(3)*x^3+... + int degI = childAtIndex(i).getPolynomialCoefficients(symbolName, intermediateCoefficients); + assert(degI <= Expression::k_maxPolynomialDegree); + for (int j = deg; j > 0; j--) { + // new coefficients[j] = b(0)*a(j)+b(1)*a(j-1)+b(2)*a(j-2)+... + Addition a; + 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(intermediateCoefficients[l], coefficients[j-l]), 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. */ + // TODO remove if (j <= degI) { delete intermediateCoefficients[j]; }; + coefficients[j] = a; + } + // new coefficients[0] = a(0)*b(0) + coefficients[0] = Multiplication(coefficients[0], intermediateCoefficients[0]); + } + return deg; +} + +Expression Multiplication::denominator(Context & context, 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. + Expression e = mergeNegativePower(context, angleUnit); + if (e.type() == ExpressionNode::Type::Power) { + return e.denominator(context, 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 && static_cast(e.childAtIndex(i).childAtIndex(1)).isMinusOne()) { + return e.childAtIndex(i).childAtIndex(0); + } + } + } + return Expression(); +} + +Expression Multiplication::privateShallowReduce(Context & context, Preferences::AngleUnit angleUnit, bool shouldExpand, bool canBeInterrupted) const { + { + Expression e = Expression::defaultShallowReduce(context, angleUnit);; + if (e.isUndefinedOrAllocationFailure()) { + return e; + } + } + + Multiplication thisCopy = *this; + + /* Step 1: MultiplicationNode is associative, so let's start by merging children + * which also are multiplications themselves. */ + thisCopy.mergeMultiplicationChildrenInPlace(); + + /* Step 2: If any of the child is zero, the multiplication result is zero */ + for (int i = 0; i < thisCopy.numberOfChildren(); i++) { + const Expression o = thisCopy.childAtIndex(i); + if (o.type() == ExpressionNode::Type::Rational && static_cast(o).isZero()) { + return Rational(0); + } + } + + // Step 3: Sort the children + thisCopy.sortChildrenInPlace(ExpressionNode::SimplificationOrder, canBeInterrupted); #if MATRIX_EXACT_REDUCING +#if 0 // OLD CODE /* Step 3bis: get rid of matrix */ int n = 1; int m = 1; - /* All operands have been simplified so if any operand contains a matrix, it - * is at the root node of the operand. Moreover, thanks to the simplification - * order, all matrix operands (if any) are the last operands. */ - Expression * lastOperand = editableOperand(numberOfChildren()-1); - if (lastOperand->type() == Type::Matrix) { + /* All children have been simplified so if any child contains a matrix, it + * is at the root node of the child. Moreover, thanks to the simplification + * order, all matrix children (if any) are the last children. */ + Expression * lastOperand = childAtIndex(numberOfChildren()-1); + if (lastOperand->type() == ExpressionNode::Type::Matrix) { Matrix * resultMatrix = static_cast(lastOperand); - // Use the last matrix operand as the final matrix + // Use the last matrix child as the final matrix n = resultMatrix->numberOfRows(); m = resultMatrix->numberOfColumns(); - /* Scan accross the multiplication operands to find any other matrix: - * (the last operand is the result matrix so we start at + /* Scan accross the multiplication children to find any other matrix: + * (the last child is the result matrix so we start at * numberOfChildren()-2)*/ int k = numberOfChildren()-2; - while (k >= 0 && childAtIndex(k)->type() == Type::Matrix) { - Matrix * currentMatrix = static_cast(editableOperand(k)); + while (k >= 0 && childAtIndex(k)->type() == ExpressionNode::Type::Matrix) { + Matrix * currentMatrix = static_cast(childAtIndex(k)); int on = currentMatrix->numberOfRows(); int om = currentMatrix->numberOfColumns(); if (om != n) { @@ -262,7 +323,7 @@ Expression Multiplication::privateShallowReduce(Context & context, Preferences:: int i2 = e%m; int i1 = e/m; for (int j = 0; j < n; j++) { - Expression * mult = new Multiplication(currentMatrix->editableOperand(j+om*i1), resultMatrix->editableOperand(j*m+i2), true); + Expression * mult = new Multiplication(currentMatrix->childAtIndex(j+om*i1), resultMatrix->childAtIndex(j*m+i2), true); static_cast(newMatrixOperands[e])->addOperand(mult); mult->shallowReduce(context, angleUnit); } @@ -274,25 +335,26 @@ Expression Multiplication::privateShallowReduce(Context & context, Preferences:: k--; } removeOperand(resultMatrix, false); - // Distribute the remaining multiplication on matrix operands + // Distribute the remaining multiplication on matrix children for (int i = 0; i < n*m; i++) { Multiplication * m = static_cast(clone()); - Expression * entryI = resultMatrix->editableOperand(i); + Expression * entryI = resultMatrix->childAtIndex(i); resultMatrix->replaceOperand(entryI, m, false); m->addOperand(entryI); m->shallowReduce(context, angleUnit); } return replaceWith(resultMatrix, true)->shallowReduce(context, angleUnit); } +#endif #endif /* 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 = editableOperand(i); - Expression * oi1 = editableOperand(i+1); + while (i < thisCopy.numberOfChildren()-1) { + Expression oi = thisCopy.childAtIndex(i); + Expression oi1 = thisCopy.childAtIndex(i+1); if (TermsHaveIdenticalBase(oi, oi1)) { bool shouldFactorizeBase = true; if (TermHasNumeralBase(oi)) { @@ -300,14 +362,14 @@ Expression Multiplication::privateShallowReduce(Context & context, Preferences:: * 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() == Type::Power && oi1->type() == Type::Power; + shouldFactorizeBase = oi.type() == ExpressionNode::Type::Power && oi1.type() == ExpressionNode::Type::Power; } if (shouldFactorizeBase) { - factorizeBase(oi, oi1, context, angleUnit); + thisCopy.factorizeBase(i, i+1, context, angleUnit); continue; } } else if (TermHasNumeralBase(oi) && TermHasNumeralBase(oi1) && TermsHaveIdenticalExponent(oi, oi1)) { - factorizeExponent(oi, oi1, context, angleUnit); + thisCopy.factorizeExponent(i, i+1, context, angleUnit); continue; } i++; @@ -317,16 +379,16 @@ Expression Multiplication::privateShallowReduce(Context & context, Preferences:: *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 */ - for (int i = 0; i < numberOfChildren(); i++) { - Expression * o1 = editableOperand(i); - if (Base(o1)->type() == Type::Sine && TermHasNumeralExponent(o1)) { - const Expression * x = Base(o1)->childAtIndex(0); + for (int i = 0; i < thisCopy.numberOfChildren(); i++) { + Expression o1 = thisCopy.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 = editableOperand(j); - if (Base(o2)->type() == Type::Cosine && TermHasNumeralExponent(o2) && Base(o2)->childAtIndex(0)->isIdenticalTo(x)) { - factorizeSineAndCosine(o1, o2, context, angleUnit); + for (int j = i+1; j < thisCopy.numberOfChildren(); j++) { + Expression o2 = thisCopy.childAtIndex(j); + if (Base(o2).type() == ExpressionNode::Type::Cosine && TermHasNumeralExponent(o2) && Base(o2).childAtIndex(0).isIdenticalTo(x)) { + thisCopy.factorizeSineAndCosine(i, j, context, angleUnit); break; } } @@ -335,223 +397,128 @@ Expression Multiplication::privateShallowReduce(Context & context, Preferences:: /* 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 */ - sortOperands(SimplificationOrder, true); + thisCopy.sortChildrenInPlace(ExpressionNode::SimplificationOrder, canBeInterrupted); - /* Step 6: We remove rational operands that appeared in the middle of sorted - * operands. It's important to do this after having factorized because + /* 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 operand if it is one and not the only - * operand. */ + * Last, we remove the only rational child if it is one and not the only + * child. */ i = 1; - while (i < numberOfChildren()) { - Expression * o = editableOperand(i); - if (o->type() == Type::Rational && static_cast(o)->isOne()) { - removeOperand(o, true); + while (i < thisCopy.numberOfChildren()) { + Expression o = thisCopy.childAtIndex(i); + if (o.type() == ExpressionNode::Type::Rational && static_cast(o).isOne()) { + thisCopy.removeChildAtIndexInPlace(i); continue; } - if (o->type() == Type::Rational) { - if (childAtIndex(0)->type() == Type::Rational) { - Rational * o0 = static_cast(editableOperand(0)); - Rational m = Rational::Multiplication(*o0, *(static_cast(o))); - replaceOperand(o0, new Rational(m), true); - removeOperand(o, true); + if (o.isNumber()) { + if (thisCopy.childAtIndex(0).isNumber()) { + Number o0 = static_cast(thisCopy.childAtIndex(0)); + Number m = Number::Multiplication(o0, static_cast(o)); + thisCopy.replaceChildAtIndexInPlace(0, m); + thisCopy.removeChildAtIndexInPlace(i); } else { - removeOperand(o, false); - addOperandAtIndex(o, 0); + // Number child has to be first + thisCopy.removeChildAtIndexInPlace(i); + thisCopy.addChildAtIndexInPlace(o, 0, thisCopy.numberOfChildren()); } continue; } i++; } - if (childAtIndex(0)->type() == Type::Rational && static_cast(editableOperand(0))->isOne() && numberOfChildren() > 1) { - removeOperand(editableOperand(0), true); + if (thisCopy.childAtIndex(0).type() == ExpressionNode::Type::Rational && static_cast(thisCopy.childAtIndex(0)).isOne() && numberOfChildren() > 1) { + thisCopy.removeChildAtIndexInPlace(0); } - - /* Step 7: Expand multiplication over addition operands if any. For example, + /* Step 7: 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 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 (shouldExpand && parent()->type() != Type::Multiplication) { - for (int i=0; itype() == Type::Addition) { - return distributeOnOperandAtIndex(i, context, angleUnit); + if (shouldExpand) { // && parent()->type() != ExpressionNode::Type::Multiplication) { // TODO: Handle this top dow in deepReduce? + for (int i=0; i 0); - assert(e2.numberOfChildren() > 0); - int numberOfNonNumeralFactors1 = e1.childAtIndex(0).type() == ExpressionNode::Type::Rational ? e1.numberOfChildren()-1 : e1.numberOfChildren(); - int numberOfNonNumeralFactors2 = e2.childAtIndex(0).type() == ExpressionNode::Type::Rational ? e2.numberOfChildren()-1 : e2.numberOfChildren(); - if (numberOfNonNumeralFactors1 != numberOfNonNumeralFactors2) { - return false; - } - int firstNonNumeralOperand1 = e1.childAtIndex(0).type() == ExpressionNode::Type::Rational ? 1 : 0; - int firstNonNumeralOperand2 = e2.childAtIndex(0).type() == ExpressionNode::Type::Rational ? 1 : 0; - for (int i = 0; i < numberOfNonNumeralFactors1; i++) { - if (!(e1.childAtIndex(firstNonNumeralOperand1+i).isIdenticalTo(e2.childAtIndex(firstNonNumeralOperand2+i)))) { - return false; - } - } - return true; -} - -static inline const Expression Base(const Expression e) { - if (e.type() == ExpressionNode::Type::Power) { - return e.childAtIndex(0); - } - return e; -} - -void Multiplication::mergeMultiplicationOperands() { +void Multiplication::mergeMultiplicationChildrenInPlace() { // Multiplication is associative: a*(b*c)->a*b*c int i = 0; int initialNumberOfChildren = numberOfChildren(); while (i < initialNumberOfChildren) { Expression c = childAtIndex(i); if (c.type() == ExpressionNode::Type::Multiplication) { - mergeChildrenAtIndexInPlace(c, numberOfChildren()); // TODO: ensure that matrix operands are not swapped to implement MATRIX_EXACT_REDUCING + mergeChildrenAtIndexInPlace(c, numberOfChildren()); // TODO: ensure that matrix children are not swapped to implement MATRIX_EXACT_REDUCING continue; } i++; } } -void Multiplication::factorizeSineAndCosine(Expression e1, Expression e2, Context & context, Preferences::AngleUnit angleUnit) { - // TODO Warning!! e1 and e2 are copies, so their parent is not this !! -#if 0 - assert(e1->parent() == this && o2->parent() == this); - /* 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(o1)->childAtIndex(0); - Rational p = o1->type() == Type::Power ? *(static_cast(o1->editableOperand(1))) : Rational(1); - Rational q = o2->type() == Type::Power ? *(static_cast(o2->editableOperand(1))) : Rational(1); - /* If p and q have the same sign, we cannot replace them by a tangent */ - if ((int)p.sign()*(int)q.sign() > 0) { - return; - } - Rational sumPQ = Rational::Addition(p, q); - Rational absP = p; - absP.setSign(Sign::Positive); - Rational absQ = q; - absQ.setSign(Sign::Positive); - Expression * tan = new Tangent(x, true); - if (Rational::NaturalOrder(absP, absQ) < 0) { - if (o1->type() == Type::Power) { - o1->replaceOperand(o1->childAtIndex(0), tan, true); - } else { - replaceOperand(o1, tan, true); - o1 = tan; - } - o1->shallowReduce(context, angleUnit); - if (o2->type() == Type::Power) { - o2->replaceOperand(o2->childAtIndex(1), new Rational(sumPQ), true); - } else { - Expression * newO2 = new Power(o2, new Rational(sumPQ), false); - replaceOperand(o2, newO2, false); - o2 = newO2; - } - o2->shallowReduce(context, angleUnit); - } else { - if (o2->type() == Type::Power) { - o2->replaceOperand(o2->childAtIndex(1), new Rational(Rational::Multiplication(q, Rational(-1))), true); - o2->replaceOperand(o2->childAtIndex(0), tan, true); - } else { - Expression * newO2 = new Power(tan, new Rational(-1), false); - replaceOperand(o2, newO2, true); - o2 = newO2; - } - o2->shallowReduce(context, angleUnit); - if (o1->type() == Type::Power) { - o1->replaceOperand(o1->childAtIndex(1), new Rational(sumPQ), true); - } else { - Expression * newO1 = new Power(o1, new Rational(sumPQ), false); - replaceOperand(o1, newO1, false); - o1 = newO1; - } - o1->shallowReduce(context, angleUnit); - } -#endif -} - -void Multiplication::factorizeBase(Expression e1, Expression e2, Context & context, Preferences::AngleUnit angleUnit) { -#if 0 - /* This function factorizes two operands which have a common base. For example +void Multiplication::factorizeBase(int i, int j, Context & context, Preferences::AngleUnit angleUnit) { + /* This function factorizes two children which have a common base. For example * if this is Multiplication(pi^2, pi^3), then pi^2 and pi^3 could be merged * and this turned into Multiplication(pi^5). */ - assert(TermsHaveIdenticalBase(e1, e2)); + + 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, context, angleUnit); +} + +void Multiplication::mergeInChildByFactorizingBase(int i, Expression e, Context & context, Preferences::AngleUnit angleUnit) { + /* This function replace the child at index i by its factorization with e. + * e and childAtIndex(i) are supposed to have a command base. */ // Step 1: Find the new exponent - Expression * s = new Addition(CreateExponent(e1), CreateExponent(e2), false); - - // Step 2: Get rid of one of the operands - removeOperand(e2, true); - - // Step 3: Use the new exponent - Power * p = nullptr; - if (e1->type() == Type::Power) { - // If e1 is a power, replace the initial exponent with the new one - e1->replaceOperand(e1->childAtIndex(1), s, true); - p = static_cast(e1); - } else { - // Otherwise, create a new Power node - p = new Power(e1, s, false); - replaceOperand(e1, p, false); - } - - // Step 4: Reduce the new power - s->shallowReduce(context, angleUnit); // pi^2*pi^3 -> pi^(2+3) -> pi^5 - Expression * reducedP = p->shallowReduce(context, angleUnit); // pi^2*pi^-2 -> pi^0 -> 1 - /* Step 5: Reducing the new power might have turned it into a multiplication, + Expression s = Addition(CreateExponent(childAtIndex(i)), CreateExponent(e)).shallowReduce(context, angleUnit); // pi^2*pi^3 -> pi^(2+3) -> pi^5 + // Step 2: Create the new Power + Expression p = Power(Base(childAtIndex(i)), s).shallowReduce(context, angleUnit); // pi^2*pi^-2 -> pi^0 -> 1 + // Step 3: Replace one of the child + replaceChildAtIndexInPlace(i, p); + /* 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 (reducedP->type() == Type::Multiplication) { - mergeMultiplicationOperands(); + if (p.type() == ExpressionNode::Type::Multiplication) { + mergeMultiplicationChildrenInPlace(); } -#endif } -void Multiplication::factorizeExponent(Expression e1, Expression e2, Context & context, Preferences::AngleUnit angleUnit) { -#if 0 - /* This function factorizes operands which share a common exponent. For +void Multiplication::factorizeExponent(int i, int j, Context & context, Preferences::AngleUnit angleUnit) { + /* This function factorizes children which share a common exponent. For * example, it turns Multiplication(2^x,3^x) into Multiplication(6^x). */ - assert(e1->parent() == this && e2->parent() == this); - const Expression * base1 = e1->childAtIndex(0)->clone(); - const Expression * base2 = e2->childAtIndex(0); - e2->detachOperand(base2); - Expression * m = new Multiplication(base1, base2, false); - removeOperand(e2, true); - e1->replaceOperand(e1->childAtIndex(0), m, true); - - m->shallowReduce(context, angleUnit); // 2^x*3^x -> (2*3)^x -> 6^x - Expression * reducedE1 = e1->shallowReduce(context, angleUnit); // 2^x*(1/2)^x -> (2*1/2)^x -> 1 - /* Reducing the new power might have turned it into a multiplication, + // Step 1: find the new base + Expression s = Multiplication(childAtIndex(i), childAtIndex(j)).shallowReduce(context, angleUnit); // 2^x*3^x -> (2*3)^x -> 6^x + // Step 2: create the new power + Expression p = Power(childAtIndex(i).childAtIndex(0), s).shallowReduce(context, angleUnit); // 2^x*(1/2)^x -> (2*1/2)^x -> 1 + // Step 3: Replace one of the child + replaceChildAtIndexInPlace(i, p); + // Step 4: Get rid of the other child + removeChildAtIndexInPlace(j); + /* 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 (reducedE1->type() == Type::Multiplication) { - mergeMultiplicationOperands(); + if (p.type() == ExpressionNode::Type::Multiplication) { + mergeMultiplicationChildrenInPlace(); } -#endif } -Expression Multiplication::distributeOnOperandAtIndex(int i, Context & context, Preferences::AngleUnit angleUnit) { +Expression Multiplication::distributeOnOperandAtIndex(int i, Context & context, Preferences::AngleUnit angleUnit) const { /* This method creates a*...*b*y... + a*...*c*y... + ... from * a*...*(b+c+...)*y... */ assert(i >= 0 && i < numberOfChildren()); @@ -569,6 +536,104 @@ Expression Multiplication::distributeOnOperandAtIndex(int i, Context & context, return a.shallowReduce(context, angleUnit); // Order terms, put under a common denominator if needed } +void Multiplication::addMissingFactors(Expression factor, Context & context, Preferences::AngleUnit angleUnit) { + if (factor.type() == ExpressionNode::Type::Multiplication) { + for (int j = 0; j < factor.numberOfChildren(); j++) { + addMissingFactors(factor.childAtIndex(j), context, 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 an child. */ + if (numberOfChildren() > 0 && childAtIndex(0).type() == ExpressionNode::Type::Rational && factor.type() == ExpressionNode::Type::Rational) { + assert(static_cast(factor).integerDenominator().isOne()); + assert(static_cast(childAtIndex(0)).integerDenominator().isOne()); + replaceChildAtIndexInPlace(0, Rational(Arithmetic::LCM(static_cast(factor).unsignedIntegerNumerator(), static_cast(childAtIndex(0)).unsignedIntegerNumerator()))); + 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. */ + for (int i = 0; i < numberOfChildren(); i++) { + if (TermsHaveIdenticalBase(childAtIndex(i), factor)) { + Expression sub = Subtraction(CreateExponent(childAtIndex(i)), CreateExponent(factor)).deepReduce(context, angleUnit); + if (sub.sign() == ExpressionNode::Sign::Negative) { // index[0] < index[1] + sub = Opposite(sub).shallowReduce(context, angleUnit); + if (factor.type() == ExpressionNode::Type::Power) { + factor.replaceChildAtIndexInPlace(1, sub); + } else { + factor = Power(factor, sub); + } + factor = factor.shallowReduce(context, angleUnit); + mergeInChildByFactorizingBase(i, factor, context, angleUnit); + // TODO: we use to shallowReduce childAtIndex(i) here? Needed ? + } else if (sub.sign() == ExpressionNode::Sign::Unknown) { + // TODO: we use to shallowReduce childAtIndex(i) here? Needed ? + mergeInChildByFactorizingBase(i, factor, context, angleUnit); + } else {} + /* Reducing the new child i can lead to creating a new multiplication + * (ie 2^(1+2*3^(1/2)) -> 2*2^(2*3^(1/2)). We thus have to get rid of + * nested multiplication: */ + //mergeMultiplicationOperands(); // TODO: required ??? + return; + } + } + } + addChildAtIndexInPlace(factor, 0, numberOfChildren()); + sortChildrenInPlace(ExpressionNode::SimplificationOrder, false); +} + +void Multiplication::factorizeSineAndCosine(int i, int j, Context & context, 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 = static_cast(CreateExponent(childAtIndex(i))); + Number q = static_cast(CreateExponent(childAtIndex(j))); + /* 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; + absP.setSign(ExpressionNode::Sign::Positive, context, angleUnit); + Number absQ = q; + absQ.setSign(ExpressionNode::Sign::Positive, context, angleUnit); + // TODO: uncomment once Tangent is implemented + /*Expression tan = Tangent(x); + if (Number::NaturalOrder(absP, absQ) < 0) { + // replace sin(x)^p by tan(x)^p + replaceChildAtIndexInPlace(i, Power(tan, p).shallowReduce(context, angleUnit)); + // replace cos(x)^q by cos(x)^(p+q) + replaceChildAtIndexInPlace(j, Power(Base(childAtIndex(j)), sumPQ).shallowReduce(context, angleUnit)); + } else { + // replace cos(x)^q by tan(x)^(-q) + replaceChildAtIndexInPlace(j, Power(tan, Number::Multiplication(q, Rational(-1)).shallowReduce(context, angleUnit)).shallowReduce(context, angleUnit)); + // replace sin(x)^p by sin(x)^(p+q) + replaceChildAtIndexInPlace(i, Power(Base(childAtIndex(i)), sumPQ).shallowReduce(context, angleUnit)); + }*/ +} + +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++) { + if (!(e1.childAtIndex(firstNonNumeralOperand1+i).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) : Rational(1); return result; @@ -585,182 +650,51 @@ bool Multiplication::TermsHaveIdenticalExponent(const Expression e1, const Expre } bool Multiplication::TermHasNumeralBase(const Expression e) { - return Base(e).type() == ExpressionNode::Type::Rational; + return Base(e).isNumber(); } bool Multiplication::TermHasNumeralExponent(const Expression e) { if (e.type() != ExpressionNode::Type::Power) { return true; } - if (e.childAtIndex(1).type() == ExpressionNode::Type::Rational) { + if (e.childAtIndex(1).isNumber()) { return true; } return false; } -Expression Multiplication::shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) const { - return *this; - // TODO -#if 0 - /* 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) - if (childAtIndex(0)->type() == Type::Rational && childAtIndex(0)->sign() == Sign::Negative) { - if (static_cast(childAtIndex(0))->isMinusOne()) { - removeOperand(editableOperand(0), true); - } else { - editableOperand(0)->setSign(Sign::Positive, context, angleUnit); - } - Expression * e = squashUnaryHierarchy(); - Opposite * o = new Opposite(e, true); - e->replaceWith(o, true); - o->editableOperand(0)->shallowBeautify(context, angleUnit); - 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 * e = mergeNegativePower(context, angleUnit); - if (e->type() == Type::Power) { - return e->shallowBeautify(context, angleUnit); - } - assert(e == this); - - // Step 3: Add Parenthesis if needed - for (int i = 0; i < numberOfChildren(); i++) { - const Expression * o = childAtIndex(i); - if (o->type() == Type::Addition ) { - Parenthesis * p = new Parenthesis(o, false); - replaceOperand(o, p, false); - } - } - - // Step 4: Create a Division if needed - for (int i = 0; i < numberOfChildren(); i++) { - if (!(childAtIndex(i)->type() == Type::Power && childAtIndex(i)->childAtIndex(1)->type() == Type::Rational && static_cast(childAtIndex(i)->childAtIndex(1))->isMinusOne())) { - continue; - } - - // Let's remove the denominator-to-be from this - Power * p = static_cast(editableOperand(i)); - Expression * denominatorOperand = p->editableOperand(0); - p->detachOperand(denominatorOperand); - removeOperand(p, true); - - Expression * numeratorOperand = shallowReduce(context, angleUnit); - // Delete parenthesis unnecessary on numerator - if (numeratorOperand->type() == Type::Parenthesis) { - numeratorOperand = numeratorOperand->replaceWith(numeratorOperand->editableOperand(0), true); - } - Expression * originalParent = numeratorOperand->parent(); - Division * d = new Division(numeratorOperand, denominatorOperand, false); - originalParent->replaceOperand(numeratorOperand, d, false); - return d->shallowBeautify(context, angleUnit); - } - - return this; -#endif -} - -Expression Multiplication::mergeNegativePower(Context & context, Preferences::AngleUnit angleUnit) { - Expression e = *this; - return e; - //TODO -#if 0 - Multiplication * m = new Multiplication(); +Expression Multiplication::mergeNegativePower(Context & context, Preferences::AngleUnit angleUnit) const { + Multiplication thisCopy = *this; + Multiplication m; // Special case for rational p/q: if q != 1, q should be at denominator - if (childAtIndex(0)->type() == Type::Rational && !static_cast(childAtIndex(0))->denominator().isOne()) { - Rational * r = static_cast(editableOperand(0)); - m->addOperand(new Rational(r->denominator())); - if (r->numerator().isOne()) { - removeOperand(r, true); + if (childAtIndex(0).type() == ExpressionNode::Type::Rational && !static_cast(childAtIndex(0)).integerDenominator().isOne()) { + Rational r = static_cast(childAtIndex(0)); + m.addChildAtIndexInPlace(Rational(r.integerDenominator()), 0, m.numberOfChildren()); + if (r.signedIntegerNumerator().isOne()) { + thisCopy.removeChildAtIndexInPlace(0); } else { - replaceOperand(r, new Rational(r->numerator()), true); + thisCopy.replaceChildAtIndexInPlace(0, Rational(r.signedIntegerNumerator())); } } int i = 0; - while (i < numberOfChildren()) { - if (childAtIndex(i)->type() == Type::Power && childAtIndex(i)->childAtIndex(1)->sign() == Sign::Negative) { - Expression * e = editableOperand(i); - e->editableOperand(1)->setSign(Sign::Positive, context, angleUnit); - removeOperand(e, false); - m->addOperand(e); - e->shallowReduce(context, angleUnit); + while (i < thisCopy.numberOfChildren()) { + if (thisCopy.childAtIndex(i).type() == ExpressionNode::Type::Power && thisCopy.childAtIndex(i).childAtIndex(1).sign() == ExpressionNode::Sign::Negative) { + Expression e = thisCopy.childAtIndex(i); + e.replaceChildAtIndexInPlace(1, e.childAtIndex(1).setSign(ExpressionNode::Sign::Positive, context, angleUnit)); + m.addChildAtIndexInPlace(e.shallowReduce(context, angleUnit), m.numberOfChildren(), m.numberOfChildren()); + thisCopy.removeChildAtIndexInPlace(i); } else { i++; } } - if (m->numberOfChildren() == 0) { - delete m; - return this; + if (m.numberOfChildren() == 0) { + return thisCopy; } - Power * p = new Power(m, new Rational(-1), false); - m->sortOperands(SimplificationOrder, true); - m->squashUnaryHierarchy(); - addOperand(p); - sortOperands(SimplificationOrder, true); - return squashUnaryHierarchy(); -#endif -} - -void Multiplication::addMissingFactors(Expression factor, Context & context, Preferences::AngleUnit angleUnit) { - return; - //TODO -#if 0 - if (factor->type() == Type::Multiplication) { - for (int j = 0; j < factor->numberOfChildren(); j++) { - addMissingFactors(factor->editableOperand(j), context, angleUnit); - } - return; - } - /* Special case when factor is a Rational: if 'this' has already a rational - * operand, we replace it by its LCM with factor ; otherwise, we simply add - * factor as an operand. */ - if (numberOfChildren() > 0 && childAtIndex(0)->type() == Type::Rational && factor->type() == Type::Rational) { - Rational * f = static_cast(factor); - Rational * o = static_cast(editableOperand(0)); - assert(f->denominator().isOne()); - assert(o->denominator().isOne()); - Integer i = f->numerator(); - Integer j = o->numerator(); - return replaceOperand(o, new Rational(Arithmetic::LCM(&i, &j))); - } - if (factor->type() != Type::Rational) { - /* If factor is not a rational, we merge it with the operand of identical - * base if any. Otherwise, we add it as an new operand. */ - for (int i = 0; i < numberOfChildren(); i++) { - if (TermsHaveIdenticalBase(childAtIndex(i), factor)) { - Expression * sub = new Subtraction(CreateExponent(editableOperand(i)), CreateExponent(factor), false); - Reduce((Expression **)&sub, context, angleUnit); - if (sub->sign() == Sign::Negative) { // index[0] < index[1] - if (factor->type() == Type::Power) { - factor->replaceOperand(factor->editableOperand(1), new Opposite(sub, true), true); - } else { - factor = new Power(factor, new Opposite(sub, true), false); - } - factor->editableOperand(1)->shallowReduce(context, angleUnit); - factorizeBase(editableOperand(i), factor, context, angleUnit); - editableOperand(i)->shallowReduce(context, angleUnit); - } else if (sub->sign() == Sign::Unknown) { - factorizeBase(editableOperand(i), factor, context, angleUnit); - editableOperand(i)->shallowReduce(context, angleUnit); - } else {} - delete sub; - /* Reducing the new operand i can lead to creating a new multiplication - * (ie 2^(1+2*3^(1/2)) -> 2*2^(2*3^(1/2)). We thus have to get rid of - * nested multiplication: */ - mergeMultiplicationOperands(); - return; - } - } - } - addOperand(factor->clone()); - sortOperands(SimplificationOrder, false); -#endif + m.sortChildrenInPlace(ExpressionNode::SimplificationOrder, true); + Power p(m.squashUnaryHierarchy(), Rational(-1)); + thisCopy.addChildAtIndexInPlace(p, 0, thisCopy.numberOfChildren()); + thisCopy.sortChildrenInPlace(ExpressionNode::SimplificationOrder, true); + return thisCopy.squashUnaryHierarchy(); } template MatrixComplex MultiplicationNode::computeOnComplexAndMatrix(std::complex const, const MatrixComplex);