mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-22 15:20:39 +01:00
[poincare] Implement missing simplification methods of Multiplication
This commit is contained in:
@@ -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); }
|
||||
|
||||
@@ -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<ExpressionNode *>(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<ExpressionNode *>(TreeNode::parent()); }
|
||||
|
||||
|
||||
@@ -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<typename T> static Complex<T> compute(const std::complex<T> c, const std::complex<T> d) { return Complex<T>(c*d); }
|
||||
template<typename T> static MatrixComplex<T> computeOnComplexAndMatrix(const std::complex<T> c, const MatrixComplex<T> m) {
|
||||
return ApproximationHelper::ElementWiseOnMatrixComplexAndComplex(m, c, compute<T>);
|
||||
@@ -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<typename T> static MatrixComplex<T> computeOnMatrixAndComplex(const MatrixComplex<T> m, const std::complex<T> c) {
|
||||
return ApproximationHelper::ElementWiseOnMatrixComplexAndComplex(m, c, compute<T>);
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#include <poincare/multiplication.h>
|
||||
#include <poincare/addition.h>
|
||||
//#include <poincare/arithmetic.h>
|
||||
//#include <poincare/division.h>
|
||||
#include <poincare/arithmetic.h>
|
||||
#include <poincare/division.h>
|
||||
#include <poincare/layout_helper.h>
|
||||
//#include <poincare/matrix.h>
|
||||
#include <poincare/opposite.h>
|
||||
#include <poincare/parenthesis.h>
|
||||
//#include <poincare/power.h>
|
||||
#include <poincare/power.h>
|
||||
#include <poincare/rational.h>
|
||||
#include <poincare/serialization_helper.h>
|
||||
//#include <poincare/simplification_root.h>
|
||||
@@ -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<MultiplicationNode> 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<typename T>
|
||||
@@ -116,7 +91,7 @@ MatrixComplex<T> MultiplicationNode::computeOnMatrices(const MatrixComplex<T> 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<Power *>(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<const Rational *>(e->childAtIndex(i)->childAtIndex(1))->isMinusOne()) {
|
||||
Power * p = static_cast<Power *>(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<const Rational *>(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<Rational>(thisCopy.childAtIndex(0)).isMinusOne()) {
|
||||
thisCopy.removeChildAtIndexInPlace(0);
|
||||
} else {
|
||||
thisCopy.childAtIndex(0).setSign(ExpressionNode::Sign::Positive, context, angleUnit);
|
||||
}
|
||||
return Opposite(static_cast<Multiplication>(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<Multiplication>(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<Rational>(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<Rational>(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<Rational>(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<Matrix *>(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<Matrix *>(editableOperand(k));
|
||||
while (k >= 0 && childAtIndex(k)->type() == ExpressionNode::Type::Matrix) {
|
||||
Matrix * currentMatrix = static_cast<Matrix *>(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<Addition *>(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<Multiplication *>(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<Rational *>(o)->isOne()) {
|
||||
removeOperand(o, true);
|
||||
while (i < thisCopy.numberOfChildren()) {
|
||||
Expression o = thisCopy.childAtIndex(i);
|
||||
if (o.type() == ExpressionNode::Type::Rational && static_cast<Rational>(o).isOne()) {
|
||||
thisCopy.removeChildAtIndexInPlace(i);
|
||||
continue;
|
||||
}
|
||||
if (o->type() == Type::Rational) {
|
||||
if (childAtIndex(0)->type() == Type::Rational) {
|
||||
Rational * o0 = static_cast<Rational *>(editableOperand(0));
|
||||
Rational m = Rational::Multiplication(*o0, *(static_cast<Rational *>(o)));
|
||||
replaceOperand(o0, new Rational(m), true);
|
||||
removeOperand(o, true);
|
||||
if (o.isNumber()) {
|
||||
if (thisCopy.childAtIndex(0).isNumber()) {
|
||||
Number o0 = static_cast<Rational>(thisCopy.childAtIndex(0));
|
||||
Number m = Number::Multiplication(o0, static_cast<Number>(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<Rational *>(editableOperand(0))->isOne() && numberOfChildren() > 1) {
|
||||
removeOperand(editableOperand(0), true);
|
||||
if (thisCopy.childAtIndex(0).type() == ExpressionNode::Type::Rational && static_cast<Rational>(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; i<numberOfChildren(); i++) {
|
||||
if (childAtIndex(i)->type() == 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<thisCopy.numberOfChildren(); i++) {
|
||||
if (thisCopy.childAtIndex(i).type() == ExpressionNode::Type::Addition) {
|
||||
return thisCopy.distributeOnOperandAtIndex(i, context, angleUnit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 8: Let's remove the multiplication altogether if it has one operand
|
||||
Expression * result = squashUnaryHierarchy();
|
||||
// Step 8: Let's remove the multiplication altogether if it has one child
|
||||
Expression result = thisCopy.squashUnaryHierarchy();
|
||||
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Multiplication::HaveSameNonNumeralFactors(const Expression e1, const Expression e2) {
|
||||
assert(e1.numberOfChildren() > 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<Rational *>(o1->editableOperand(1))) : Rational(1);
|
||||
Rational q = o2->type() == Type::Power ? *(static_cast<Rational *>(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<Power *>(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<Rational>(factor).integerDenominator().isOne());
|
||||
assert(static_cast<Rational>(childAtIndex(0)).integerDenominator().isOne());
|
||||
replaceChildAtIndexInPlace(0, Rational(Arithmetic::LCM(static_cast<Rational>(factor).unsignedIntegerNumerator(), static_cast<Rational>(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<Number>(CreateExponent(childAtIndex(i)));
|
||||
Number q = static_cast<Number>(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<const Rational *>(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<const Rational *>(childAtIndex(i)->childAtIndex(1))->isMinusOne())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Let's remove the denominator-to-be from this
|
||||
Power * p = static_cast<Power *>(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<const Rational *>(childAtIndex(0))->denominator().isOne()) {
|
||||
Rational * r = static_cast<Rational *>(editableOperand(0));
|
||||
m->addOperand(new Rational(r->denominator()));
|
||||
if (r->numerator().isOne()) {
|
||||
removeOperand(r, true);
|
||||
if (childAtIndex(0).type() == ExpressionNode::Type::Rational && !static_cast<const Rational>(childAtIndex(0)).integerDenominator().isOne()) {
|
||||
Rational r = static_cast<Rational>(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<Rational *>(factor);
|
||||
Rational * o = static_cast<Rational *>(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<float> MultiplicationNode::computeOnComplexAndMatrix<float>(std::complex<float> const, const MatrixComplex<float>);
|
||||
|
||||
Reference in New Issue
Block a user