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