mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-23 15:50:49 +01:00
[poincare] Sketch of complex reduction as part of the reduce routine
This commit is contained in:
@@ -49,6 +49,7 @@ objs += $(addprefix poincare/src/,\
|
||||
ceiling.o\
|
||||
complex.o\
|
||||
complex_argument.o\
|
||||
complex_cartesian.o\
|
||||
complex_helper.o\
|
||||
confidence_interval.o\
|
||||
conjugate.o\
|
||||
|
||||
@@ -26,6 +26,7 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
// Approximation
|
||||
template<typename T> static Complex<T> computeOnComplex(const std::complex<T> c, Preferences::AngleUnit angleUnit) {
|
||||
|
||||
@@ -25,6 +25,7 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianComplexFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return childAtIndex(0)->isReal(context, angleUnit); }
|
||||
|
||||
private:
|
||||
// Layout
|
||||
|
||||
@@ -21,6 +21,7 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
// Properties
|
||||
Type type() const override{ return Type::BinomialCoefficient; }
|
||||
|
||||
@@ -21,6 +21,7 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
// Properties
|
||||
Type type() const override { return Type::Ceiling; }
|
||||
|
||||
@@ -20,6 +20,7 @@ public:
|
||||
#endif
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
// Properties
|
||||
Type type() const override { return Type::ComplexArgument; }
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define POINCARE_COMPLEX_CARTESIAN_H
|
||||
|
||||
#include <poincare/expression.h>
|
||||
#include <poincare/complex_helper.h>
|
||||
#include <poincare/multiplication.h>
|
||||
|
||||
namespace Poincare {
|
||||
|
||||
@@ -26,19 +26,42 @@ private:
|
||||
// Evaluation
|
||||
Evaluation<float> approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { assert(false); return Evaluation<float>(); }
|
||||
Evaluation<double> approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { assert(false); return Evaluation<double>(); }
|
||||
// Simplification
|
||||
Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit, ReductionTarget target) override;
|
||||
Expression shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) override;
|
||||
};
|
||||
|
||||
class ComplexCartesian final : public Expression {
|
||||
public:
|
||||
ComplexCartesian() : Expression() {}
|
||||
ComplexCartesian(const ComplexCartesianNode * node) : Expression(node) {}
|
||||
static ComplexCartesian Builder() { ComplexCartesianNode * node = TreePool::sharedPool()->createTreeNode<ComplexCartesianNode>(); return ComplexCartesian(node); }
|
||||
static ComplexCartesian Builder(Expression child0, Expression child1) { return ComplexCartesian(child0, child1); }
|
||||
|
||||
// Getters
|
||||
Expression real() { return childAtIndex(0); }
|
||||
Expression imag() { return childAtIndex(1); }
|
||||
|
||||
// Simplification
|
||||
Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit);
|
||||
Expression shallowBeautify(Context & context, Preferences::AngleUnit angleUnit);
|
||||
|
||||
// Common operations (done in-place)
|
||||
Expression squareNorm(Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target);
|
||||
Expression norm(Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target);
|
||||
Expression argument(Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target);
|
||||
ComplexCartesian inverse(Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target);
|
||||
ComplexCartesian squareRoot(Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target);
|
||||
ComplexCartesian powerInteger(int n, Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target);
|
||||
ComplexCartesian multiply(ComplexCartesian & other, Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target);
|
||||
ComplexCartesian power(ComplexCartesian & other, Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target);
|
||||
private:
|
||||
ComplexCartesian(Expression child0, Expression child1) : Expression(TreePool::sharedPool()->createTreeNode<ComplexCartesianNode>()) {
|
||||
replaceChildAtIndexInPlace(0, child0);
|
||||
replaceChildAtIndexInPlace(1, child1);
|
||||
}
|
||||
static Multiplication squareRootHelper(Expression e, Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target);
|
||||
static Expression powerHelper(Expression norm, Expression trigo, Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ public:
|
||||
#endif
|
||||
|
||||
// Complex
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override;
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override;
|
||||
|
||||
// Expression Properties
|
||||
@@ -36,6 +37,9 @@ public:
|
||||
bool isPi() const { return isConstantChar(Ion::Charset::SmallPi); }
|
||||
bool isExponential() const { return isConstantChar(Ion::Charset::Exponential); }
|
||||
bool isIComplex() const { return isConstantChar(Ion::Charset::IComplex); }
|
||||
|
||||
// Simplification
|
||||
Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit, ReductionTarget target) override;
|
||||
private:
|
||||
char m_name[0]; // MUST be the last member variable
|
||||
|
||||
@@ -54,6 +58,9 @@ public:
|
||||
bool isExponential() const { return node()->isExponential(); }
|
||||
bool isIComplex() const { return node()->isIComplex(); }
|
||||
|
||||
// Simplification
|
||||
Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit);
|
||||
|
||||
private:
|
||||
ConstantNode * node() const { return static_cast<ConstantNode *>(Expression::node()); }
|
||||
};
|
||||
|
||||
@@ -22,6 +22,7 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianComplexFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return childAtIndex(0)->isReal(context, angleUnit); }
|
||||
|
||||
// Properties
|
||||
Type type() const override { return Type::Cosine; }
|
||||
|
||||
@@ -22,6 +22,7 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
// Properties
|
||||
Type type() const override { return Type::Derivative; }
|
||||
|
||||
@@ -23,6 +23,8 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
private:
|
||||
// Layout
|
||||
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||
|
||||
@@ -24,6 +24,8 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
private:
|
||||
// Layout
|
||||
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||
|
||||
@@ -29,6 +29,7 @@ class Expression : public TreeHandle {
|
||||
template<typename T>
|
||||
friend class ComplexNode;
|
||||
friend class ComplexArgument;
|
||||
friend class ComplexCartesian;
|
||||
friend class ComplexHelper;
|
||||
friend class ConfidenceInterval;
|
||||
friend class Conjugate;
|
||||
@@ -166,6 +167,7 @@ public:
|
||||
Expression defaultReplaceUnknown(const Symbol & symbol);
|
||||
|
||||
/* Complex */
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const { return node()->isReal(context, angleUnit); }
|
||||
bool isPureReal(Context & context, Preferences::AngleUnit angleUnit) const;
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const;
|
||||
ComplexPolar complexPolar(Context & context, Preferences::AngleUnit angleUnit) const;
|
||||
@@ -186,8 +188,8 @@ public:
|
||||
Expression simplify(Context & context, Preferences::AngleUnit angleUnit);
|
||||
Expression reduce(Context & context, Preferences::AngleUnit angleUnit);
|
||||
static Expression ExpressionWithoutSymbols(Expression expressionWithSymbols, Context & context);
|
||||
Expression radianToDegree(Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target);
|
||||
Expression degreeToRadian(Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target);
|
||||
Expression radianToDegree();
|
||||
Expression degreeToRadian();
|
||||
|
||||
/* Approximation Helper */
|
||||
template<typename U> static U epsilon();
|
||||
|
||||
@@ -48,7 +48,6 @@ public:
|
||||
BinomialCoefficient,
|
||||
Ceiling,
|
||||
ComplexArgument,
|
||||
ComplexCartesian,
|
||||
ComplexPolar,
|
||||
Conjugate,
|
||||
Derivative,
|
||||
@@ -88,6 +87,8 @@ public:
|
||||
Symbol,
|
||||
Constant,
|
||||
|
||||
ComplexCartesian,
|
||||
|
||||
Matrix,
|
||||
ConfidenceInterval,
|
||||
MatrixDimension,
|
||||
@@ -128,6 +129,7 @@ public:
|
||||
* ComplexCartesian::shallowBeautify. This would enable us to do only one
|
||||
* scan of the tree in ParseAndSimplifyForComplexFormat instead of Simplifying
|
||||
* and then extracting ComplexCartesian. */
|
||||
virtual bool isReal(Context & context, Preferences::AngleUnit angleUnit) const { return false; }
|
||||
virtual ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const;
|
||||
virtual ComplexPolar complexPolar(Context & context, Preferences::AngleUnit angleUnit) const;
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
private:
|
||||
// Layout
|
||||
bool childNeedsParenthesis(const TreeNode * child) const override;
|
||||
|
||||
@@ -25,6 +25,8 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
private:
|
||||
// Layout
|
||||
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||
|
||||
@@ -25,6 +25,8 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
private:
|
||||
// Layout
|
||||
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||
|
||||
@@ -22,6 +22,8 @@ public:
|
||||
Type type() const override { return Type::GreatCommonDivisor; }
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
private:
|
||||
// Layout
|
||||
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||
|
||||
@@ -24,6 +24,8 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
private:
|
||||
// Layout
|
||||
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||
|
||||
@@ -26,6 +26,8 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
private:
|
||||
// Layout
|
||||
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||
|
||||
@@ -22,6 +22,8 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
private:
|
||||
/* Layout */
|
||||
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
|
||||
private:
|
||||
// Layout
|
||||
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||
|
||||
@@ -18,6 +18,9 @@ public:
|
||||
}
|
||||
void eraseNumberOfChildren() override { m_numberOfChildren = 0; }
|
||||
|
||||
// Complex
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override;
|
||||
|
||||
// Comparison
|
||||
typedef int (*ExpressionOrder)(const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted);
|
||||
|
||||
@@ -48,6 +51,11 @@ public:
|
||||
Expression squashUnaryHierarchyInPlace() {
|
||||
return node()->squashUnaryHierarchyInPlace();
|
||||
}
|
||||
/* allChildrenAreReal returns:
|
||||
* - 1 if all children are real
|
||||
* - 0 if all non real children are ComplexCartesian
|
||||
* - -1 if some chidren are non-real and non ComplexCartesian */
|
||||
int allChildrenAreReal(Context & context, Preferences::AngleUnit angleUnit) const;
|
||||
protected:
|
||||
NAryExpressionNode * node() const { return static_cast<NAryExpressionNode *>(Expression::node()); }
|
||||
};
|
||||
|
||||
@@ -25,6 +25,7 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
};
|
||||
|
||||
class Number : public Expression {
|
||||
|
||||
@@ -27,6 +27,8 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
private:
|
||||
// Layout
|
||||
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||
|
||||
@@ -22,6 +22,7 @@ public:
|
||||
#endif
|
||||
|
||||
// Complex
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override;
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override;
|
||||
ComplexPolar complexPolar(Context & context, Preferences::AngleUnit angleUnit) const override;
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
private:
|
||||
// Layout
|
||||
|
||||
@@ -21,6 +21,7 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
// Properties
|
||||
Type type() const override { return Type::Random; }
|
||||
|
||||
@@ -24,6 +24,7 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
private:
|
||||
// Layout
|
||||
|
||||
@@ -21,6 +21,7 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
// Properties
|
||||
Type type() const override { return Type::Round; }
|
||||
|
||||
@@ -26,6 +26,7 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianRealFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return true; }
|
||||
|
||||
private:
|
||||
// Layout
|
||||
|
||||
@@ -22,6 +22,7 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianComplexFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return childAtIndex(0)->isReal(context, angleUnit); }
|
||||
|
||||
// Properties
|
||||
Type type() const override { return Type::Sine; }
|
||||
|
||||
@@ -25,6 +25,8 @@ public:
|
||||
|
||||
// Complex
|
||||
ComplexCartesian complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const override { return ComplexHelper::complexCartesianComplexFunction(this, context, angleUnit); }
|
||||
bool isReal(Context & context, Preferences::AngleUnit angleUnit) const override { return childAtIndex(0)->isReal(context, angleUnit); }
|
||||
|
||||
private:
|
||||
// Layout
|
||||
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||
|
||||
@@ -266,8 +266,43 @@ Expression Addition::shallowReduce(Context & context, Preferences::AngleUnit ang
|
||||
|
||||
// Step 5: Let's remove the addition altogether if it has a single child
|
||||
Expression result = squashUnaryHierarchyInPlace();
|
||||
if (result != *this) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Step 6: Let's put everything under a common denominator.
|
||||
/* Step 6: 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. */
|
||||
if (allChildrenAreReal(context, angleUnit) == 0) {
|
||||
Addition imag;
|
||||
Addition real = *this;
|
||||
i = numberOfChildren() - 1;
|
||||
while (i >= 0) {
|
||||
Expression c = childAtIndex(i);
|
||||
if (c.type() == ExpressionNode::Type::ComplexCartesian) {
|
||||
real.replaceChildAtIndexInPlace(i, c.childAtIndex(0));
|
||||
imag.addChildAtIndexInPlace(c.childAtIndex(1), imag.numberOfChildren(), imag.numberOfChildren());
|
||||
} else {
|
||||
// the Addition is sorted so ComplexCartesian nodes are the last ones
|
||||
break;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
ComplexCartesian newComplexCartesian = ComplexCartesian::Builder();
|
||||
replaceWithInPlace(newComplexCartesian);
|
||||
newComplexCartesian.replaceChildAtIndexInPlace(0, real);
|
||||
newComplexCartesian.replaceChildAtIndexInPlace(1, imag);
|
||||
real.shallowReduce(context, angleUnit, target);
|
||||
imag.shallowReduce(context, angleUnit, target);
|
||||
return newComplexCartesian.shallowReduce(context, angleUnit);
|
||||
}
|
||||
|
||||
/* Step 7: Let's put everything under a common denominator.
|
||||
* This step is done only for ReductionTarget::User if the parent expression
|
||||
* is not an addition. */
|
||||
Expression p = result.parent();
|
||||
|
||||
259
poincare/src/complex_cartesian.cpp
Normal file
259
poincare/src/complex_cartesian.cpp
Normal file
@@ -0,0 +1,259 @@
|
||||
#include <poincare/complex_cartesian.h>
|
||||
#include <poincare/addition.h>
|
||||
#include <poincare/arc_tangent.h>
|
||||
#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>
|
||||
#include <poincare/sine.h>
|
||||
#include <poincare/sign_function.h>
|
||||
#include <poincare/subtraction.h>
|
||||
#include <poincare/power.h>
|
||||
#include <assert.h>
|
||||
#include <cmath>
|
||||
|
||||
namespace Poincare {
|
||||
|
||||
Expression ComplexCartesianNode::shallowReduce(Context & context, Preferences::AngleUnit angleUnit, ReductionTarget target) {
|
||||
return ComplexCartesian(this).shallowReduce(context, angleUnit);
|
||||
}
|
||||
|
||||
Expression ComplexCartesianNode::shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) {
|
||||
return ComplexCartesian(this).shallowBeautify(context, angleUnit);
|
||||
}
|
||||
|
||||
|
||||
bool isZero(const Expression e) {
|
||||
return e.type() == ExpressionNode::Type::Rational && static_cast<const Rational &>(e).isZero();
|
||||
}
|
||||
bool isOne(const Expression e) {
|
||||
return e.type() == ExpressionNode::Type::Rational && static_cast<const Rational &>(e).isOne();
|
||||
}
|
||||
bool isMinusOne(const Expression e) {
|
||||
return e.type() == ExpressionNode::Type::Rational && static_cast<const Rational &>(e).isMinusOne();
|
||||
}
|
||||
|
||||
Expression ComplexCartesian::shallowReduce(Context & context, Preferences::AngleUnit angleUnit) {
|
||||
if (imag().isRationalZero()) {
|
||||
Expression r = real();
|
||||
replaceWithInPlace(r);
|
||||
return r;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Expression ComplexCartesian::shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) {
|
||||
Expression a = real();
|
||||
Expression b = imag();
|
||||
Expression oppositeA = a.makePositiveAnyNegativeNumeralFactor(context, angleUnit);
|
||||
Expression oppositeB = b.makePositiveAnyNegativeNumeralFactor(context, angleUnit);
|
||||
a = oppositeA.isUninitialized() ? a : oppositeA;
|
||||
b = oppositeB.isUninitialized() ? b : oppositeB;
|
||||
Expression e = Expression::CreateComplexExpression(a, b, Preferences::ComplexFormat::Cartesian,
|
||||
a.type() == ExpressionNode::Type::Undefined || b.type() == ExpressionNode::Type::Undefined,
|
||||
isZero(a), isOne(a), isZero(b), isOne(b), isMinusOne(b),
|
||||
!oppositeA.isUninitialized(),
|
||||
!oppositeB.isUninitialized()
|
||||
);
|
||||
replaceWithInPlace(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
Expression ComplexCartesian::squareNorm(Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target) {
|
||||
Expression a = real();
|
||||
Expression b = imag();
|
||||
Expression a2 = Power(a, Rational(2));
|
||||
Expression b2 = Power(b, Rational(2));
|
||||
Addition add(a2, b2);
|
||||
a2.shallowReduce(context, angleUnit, target);
|
||||
b2.shallowReduce(context, angleUnit, target);
|
||||
return add;
|
||||
}
|
||||
|
||||
Expression ComplexCartesian::norm(Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target) {
|
||||
Expression n2 = squareNorm(context, angleUnit, target);
|
||||
Expression n = SquareRoot::Builder(n2);
|
||||
n2.shallowReduce(context, angleUnit, target);
|
||||
return n;
|
||||
}
|
||||
|
||||
Expression ComplexCartesian::argument(Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target) {
|
||||
Expression a = real();
|
||||
Expression b = imag();
|
||||
if (!b.isRationalZero()) {
|
||||
// if b != 0, argument = sign(b) * Pi/2 - arctan(a/b)
|
||||
// First, compute arctan(a/b) or (Pi/180)*arctan(a/b)
|
||||
Expression divab = Division(a, b.clone());
|
||||
Expression arcTangent = ArcTangent::Builder(divab);
|
||||
divab.shallowReduce(context, angleUnit, target);
|
||||
if (angleUnit == Preferences::AngleUnit::Degree) {
|
||||
Expression temp = arcTangent.degreeToRadian();
|
||||
arcTangent.shallowReduce(context, angleUnit, target);
|
||||
arcTangent = temp;
|
||||
}
|
||||
// Then, compute sign(b) * Pi/2 - arctan(a/b)
|
||||
Expression signb = SignFunction::Builder(b);
|
||||
Expression signbPi2 = Multiplication(Rational(1,2), signb, Constant(Ion::Charset::SmallPi));
|
||||
signb.shallowReduce(context, angleUnit, target);
|
||||
Expression sub = Subtraction(signbPi2, arcTangent);
|
||||
signbPi2.shallowReduce(context, angleUnit, target);
|
||||
arcTangent.shallowReduce(context, angleUnit, target);
|
||||
return sub;
|
||||
} else {
|
||||
// if b == 0, argument = (1-sign(a))*Pi/2
|
||||
Expression signa = SignFunction::Builder(a).shallowReduce(context, angleUnit);
|
||||
Subtraction sub(Rational(1), signa);
|
||||
signa.shallowReduce(context, angleUnit, target);
|
||||
Multiplication mul(Rational(1,2), Constant(Ion::Charset::SmallPi), sub);
|
||||
sub.shallowReduce(context, angleUnit, target);
|
||||
return mul;
|
||||
}
|
||||
}
|
||||
|
||||
ComplexCartesian ComplexCartesian::inverse(Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target) {
|
||||
Expression a = real();
|
||||
Expression b = imag();
|
||||
// 1/(a+ib) = a/(a^2+b^2)+i*(-b/(a^2+b^2))
|
||||
Expression denominatorReal = clone().convert<ComplexCartesian>().squareNorm(context, angleUnit, target);
|
||||
Expression denominatorImag = denominatorReal.clone();
|
||||
Expression denominatorRealInv = Power(denominatorReal, Rational(-1));
|
||||
denominatorReal.shallowReduce(context, angleUnit, target);
|
||||
Expression denominatorImagInv = Power(denominatorImag, Rational(-1));
|
||||
denominatorImag.shallowReduce(context, angleUnit, target);
|
||||
Multiplication A(a, denominatorRealInv);
|
||||
denominatorRealInv.shallowReduce(context, angleUnit, target);
|
||||
Expression numeratorImag = Multiplication(Rational(-1), b);
|
||||
Multiplication B(numeratorImag, denominatorImagInv);
|
||||
numeratorImag.shallowReduce(context, angleUnit, target);
|
||||
denominatorImagInv.shallowReduce(context, angleUnit, target);
|
||||
ComplexCartesian result(A,B);
|
||||
A.shallowReduce(context, angleUnit, target);
|
||||
B.shallowReduce(context, angleUnit, target);
|
||||
return result;
|
||||
}
|
||||
|
||||
Multiplication ComplexCartesian::squareRootHelper(Expression e, Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target) {
|
||||
//(1/2)*sqrt(2*e)
|
||||
Multiplication doubleE(Rational(2), e);
|
||||
e.shallowReduce(context, angleUnit, target);
|
||||
Expression sqrt = SquareRoot::Builder(doubleE);
|
||||
doubleE.shallowReduce(context, angleUnit, target);
|
||||
Multiplication result(Rational(1,2), sqrt);
|
||||
sqrt.shallowReduce(context, angleUnit, target);
|
||||
return result;
|
||||
}
|
||||
|
||||
ComplexCartesian ComplexCartesian::squareRoot(Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target) {
|
||||
Expression a = real();
|
||||
Expression b = imag();
|
||||
// A: (1/2)*sqrt(2*(sqrt(a^2+b^2)+a))
|
||||
// B: (1/2)*sqrt(2*(sqrt(a^2+b^2)-a))*sign(b)
|
||||
Expression normA = clone().convert<ComplexCartesian>().norm(context, angleUnit, target);
|
||||
Expression normB = normA.clone();
|
||||
// A = (1/2)*sqrt(2*(sqrt(a^2+b^2)+a))
|
||||
Addition normAdda(normA, a.clone());
|
||||
normA.shallowReduce(context, angleUnit, target);
|
||||
Multiplication A = squareRootHelper(normAdda, context, angleUnit, target);
|
||||
// B = B: (1/2)*sqrt(2*(sqrt(a^2+b^2)-a))
|
||||
Subtraction normSuba(normB, a);
|
||||
normB.shallowReduce(context, angleUnit, target);
|
||||
Multiplication B = squareRootHelper(normSuba, context, angleUnit, target);
|
||||
// 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());
|
||||
signb.shallowReduce(context, angleUnit, target);
|
||||
ComplexCartesian result = ComplexCartesian::Builder(A, B);
|
||||
A.shallowReduce(context, angleUnit, target);
|
||||
B.shallowReduce(context, angleUnit, target);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
ComplexCartesian ComplexCartesian::powerInteger(int n, Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target) {
|
||||
return ComplexCartesian();
|
||||
}
|
||||
|
||||
ComplexCartesian ComplexCartesian::multiply(ComplexCartesian & other, Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target) {
|
||||
Expression a = real();
|
||||
Expression b = imag();
|
||||
Expression c = other.real();
|
||||
Expression d = other.imag();
|
||||
// (a+ib) * (c+id) = (ac-bd)+i*(ad+bc)
|
||||
// Compute ac-bd
|
||||
Expression ac = Multiplication(a.clone(), c.clone());
|
||||
Expression bd = Multiplication(b.clone(), d.clone());
|
||||
Subtraction A(ac, bd);
|
||||
ac.shallowReduce(context, angleUnit, target);
|
||||
bd.shallowReduce(context, angleUnit, target);
|
||||
// Compute ad+bc
|
||||
Expression ad = Multiplication(a, d);
|
||||
Expression bc = Multiplication(b, c);
|
||||
Addition B(ad, bc);
|
||||
ad.shallowReduce(context, angleUnit, target);
|
||||
bc.shallowReduce(context, angleUnit, target);
|
||||
ComplexCartesian result = ComplexCartesian::Builder(A, B);
|
||||
A.shallowReduce(context, angleUnit, target);
|
||||
B.shallowReduce(context, angleUnit, target);
|
||||
return result;
|
||||
}
|
||||
|
||||
Expression ComplexCartesian::powerHelper(Expression norm, Expression trigo, Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target) {
|
||||
Multiplication m(norm, trigo);
|
||||
norm.shallowReduce(context, angleUnit, target);
|
||||
trigo.shallowReduce(context, angleUnit, target);
|
||||
return m;
|
||||
}
|
||||
|
||||
ComplexCartesian ComplexCartesian::power(ComplexCartesian & other, Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target) {
|
||||
Expression r = clone().convert<ComplexCartesian>().norm(context, angleUnit, target);
|
||||
Expression rclone = r.clone();
|
||||
Expression th = argument(context, angleUnit, target);
|
||||
Expression thclone = th.clone();
|
||||
Expression c = other.real();
|
||||
Expression d = other.imag();
|
||||
// R = r^c*e^(-th*d)
|
||||
Expression rpowc = Power(rclone, c);
|
||||
rclone.shallowReduce(context, angleUnit, target);
|
||||
Expression thmuld = Multiplication(Rational(-1), thclone, d.clone());
|
||||
thclone.shallowReduce(context, angleUnit, target);
|
||||
Expression exp = Power(Constant(Ion::Charset::Exponential), thmuld);
|
||||
thmuld.shallowReduce(context, angleUnit, target);
|
||||
Multiplication norm(rpowc, exp);
|
||||
rpowc.shallowReduce(context, angleUnit, target);
|
||||
exp.shallowReduce(context, angleUnit, target);
|
||||
|
||||
// TH = d*ln(r)+c*th
|
||||
Expression lnr = NaperianLogarithm::Builder(r);
|
||||
r.shallowReduce(context, angleUnit, target);
|
||||
Multiplication dlnr(d, lnr);
|
||||
lnr.shallowReduce(context, angleUnit, target);
|
||||
Multiplication thc(th, c);
|
||||
th.shallowReduce(context, angleUnit, target);
|
||||
Expression argument = Addition(thc, dlnr);
|
||||
thc.shallowReduce(context, angleUnit, target);
|
||||
dlnr.shallowReduce(context, angleUnit, target);
|
||||
|
||||
if (angleUnit == Preferences::AngleUnit::Degree) {
|
||||
Expression temp = argument.radianToDegree();
|
||||
argument.shallowReduce(context, angleUnit, target);
|
||||
argument = temp;
|
||||
}
|
||||
// Result = (norm*cos(argument), norm*sin(argument))
|
||||
Expression normClone = norm.clone();
|
||||
Expression argClone = argument.clone();
|
||||
Expression cos = Cosine::Builder(argClone);
|
||||
argClone.shallowReduce(context, angleUnit, target);
|
||||
Expression normcosarg = powerHelper(normClone, cos, context, angleUnit, target);
|
||||
Expression sin = Sine::Builder(argument);
|
||||
argument.shallowReduce(context, angleUnit, target);
|
||||
Expression normsinarg = powerHelper(norm, sin, context, angleUnit, target);
|
||||
ComplexCartesian result = ComplexCartesian::Builder(normcosarg, normsinarg);
|
||||
normcosarg.shallowReduce(context, angleUnit, target);
|
||||
normsinarg.shallowReduce(context, angleUnit, target);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -51,7 +51,7 @@ ComplexCartesian ComplexHelper::complexCartesianFromComplexPolar(const Expressio
|
||||
Expression r = polar.norm();
|
||||
Expression th = polar.arg();
|
||||
assert(!r.isUninitialized() && !th.isUninitialized());
|
||||
Expression argument = angleUnit == Preferences::AngleUnit::Radian ? th : th.radianToDegree(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation);
|
||||
Expression argument = th;
|
||||
return ComplexCartesian::Builder(
|
||||
complexCartesianFromComplexPolarHelper(r.clone(), Cosine::Builder(argument.clone()), context, angleUnit),
|
||||
complexCartesianFromComplexPolarHelper(r, Sine::Builder(argument), context, angleUnit)
|
||||
@@ -93,9 +93,6 @@ ComplexPolar ComplexHelper::complexPolarFromComplexCartesian(const ExpressionNod
|
||||
// if b != 0, argument = sign(b) * Pi/2 - arctan(a/b)
|
||||
// First, compute arctan(a/b) or (Pi/180)*arctan(a/b)
|
||||
Expression arcTangent = ArcTangent::Builder(Division(a, b.clone()).shallowReduce(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation)).shallowReduce(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation);
|
||||
if (angleUnit == Preferences::AngleUnit::Degree) {
|
||||
arcTangent = arcTangent.degreeToRadian(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation);
|
||||
}
|
||||
// Then, compute sign(b) * Pi/2 - arctan(a/b)
|
||||
argument = Subtraction(
|
||||
Multiplication(
|
||||
|
||||
@@ -16,6 +16,10 @@ ExpressionNode::Sign ConstantNode::sign(Context * context, Preferences::AngleUni
|
||||
return Sign::Unknown;
|
||||
}
|
||||
|
||||
bool ConstantNode::isReal(Context & context, Preferences::AngleUnit angleUnit) const {
|
||||
return !isIComplex();
|
||||
}
|
||||
|
||||
ComplexCartesian ConstantNode::complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const {
|
||||
if (isIComplex()) {
|
||||
return ComplexCartesian::Builder(Rational(0), Rational(1));
|
||||
@@ -47,8 +51,21 @@ Evaluation<T> ConstantNode::templatedApproximate(Context& context, Preferences::
|
||||
return Complex<T>(M_E);
|
||||
}
|
||||
|
||||
Expression ConstantNode::shallowReduce(Context & context, Preferences::AngleUnit angleUnit, ReductionTarget target) {
|
||||
return Constant(this).shallowReduce(context, angleUnit);
|
||||
}
|
||||
|
||||
Constant::Constant(char name) : SymbolAbstract(TreePool::sharedPool()->createTreeNode<ConstantNode>(SymbolAbstract::AlignedNodeSize(1, sizeof(ConstantNode)))) {
|
||||
node()->setName(&name, 1);
|
||||
}
|
||||
|
||||
Expression Constant::shallowReduce(Context & context, Preferences::AngleUnit angleUnit) {
|
||||
if (isIComplex()) {
|
||||
ComplexCartesian c = ComplexCartesian::Builder(Rational(0), Rational(1));
|
||||
replaceWithInPlace(c);
|
||||
return c;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -420,12 +420,14 @@ Expression Expression::ExpressionWithoutSymbols(Expression e, Context & context)
|
||||
return e;
|
||||
}
|
||||
|
||||
Expression Expression::radianToDegree(Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target) {
|
||||
return Multiplication(*this, Division(Rational(180), Constant(Ion::Charset::SmallPi)).shallowReduce(context, angleUnit, target)).shallowReduce(context, angleUnit, target);
|
||||
Expression Expression::radianToDegree() {
|
||||
// e*180/Pi
|
||||
return Multiplication(*this, Rational(180), Power(Constant(Ion::Charset::SmallPi), Rational(-1)));
|
||||
}
|
||||
|
||||
Expression Expression::degreeToRadian(Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target) {
|
||||
return Multiplication(*this, Division(Constant(Ion::Charset::SmallPi), Rational(180)).shallowReduce(context, angleUnit, target)).shallowReduce(context, angleUnit, target);
|
||||
Expression Expression::degreeToRadian() {
|
||||
// e*Pi/180
|
||||
return Multiplication(*this, Power(Rational(180), Rational(-1)), Constant(Ion::Charset::SmallPi));
|
||||
}
|
||||
|
||||
Expression Expression::reduce(Context & context, Preferences::AngleUnit angleUnit) {
|
||||
|
||||
@@ -522,8 +522,49 @@ Expression Multiplication::privateShallowReduce(Context & context, Preferences::
|
||||
}
|
||||
}
|
||||
|
||||
// Step 8: Let's remove the multiplication altogether if it has one child
|
||||
// Step 7: Let's remove the multiplication altogether if it has one child
|
||||
Expression result = squashUnaryHierarchyInPlace();
|
||||
if (result != *this) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Step 8: 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. */
|
||||
if (allChildrenAreReal(context, angleUnit) == 0) {
|
||||
int nbChildren = numberOfChildren();
|
||||
int i = nbChildren-1;
|
||||
assert(childAtIndex(i).type() == ExpressionNode::Type::ComplexCartesian);
|
||||
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), context, angleUnit, target);
|
||||
removeChildAtIndexInPlace(i);
|
||||
i--;
|
||||
}
|
||||
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(context, angleUnit, target);
|
||||
imag.shallowReduce(context, angleUnit, target);
|
||||
return newComplexCartesian.shallowReduce(context, angleUnit);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,10 @@ void NAryExpressionNode::sortChildrenInPlace(ExpressionOrder order, bool canBeIn
|
||||
}
|
||||
}
|
||||
|
||||
bool NAryExpressionNode::isReal(Context & context, Preferences::AngleUnit angleUnit) const {
|
||||
return NAryExpression(this).allChildrenAreReal(context, angleUnit) == 1;
|
||||
}
|
||||
|
||||
Expression NAryExpressionNode::squashUnaryHierarchyInPlace() {
|
||||
NAryExpression reference = NAryExpression(this);
|
||||
if (reference.numberOfChildren() == 1) {
|
||||
@@ -76,4 +80,22 @@ int NAryExpressionNode::simplificationOrderGreaterType(const ExpressionNode * e,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NAryExpression::allChildrenAreReal(Context & context, Preferences::AngleUnit angleUnit) const {
|
||||
int i = 0;
|
||||
/* The addition children are assumed to be sorted. ComplexCartesian children
|
||||
* are supposed to be the last ones before matrices. We just test children
|
||||
* to be real until we reach the first ComplexCartesian. */
|
||||
while (i < numberOfChildren()) {
|
||||
Expression c = childAtIndex(i);
|
||||
if (c.type() == ExpressionNode::Type::ComplexCartesian) {
|
||||
return 0;
|
||||
}
|
||||
if (!c.isReal(context, angleUnit)) {
|
||||
return -1;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -79,7 +79,13 @@ int PowerNode::getPolynomialCoefficients(Context & context, const char * symbolN
|
||||
return Power(this).getPolynomialCoefficients(context, symbolName, coefficients);
|
||||
}
|
||||
|
||||
// Private
|
||||
bool PowerNode::isReal(Context & context, Preferences::AngleUnit angleUnit) const {
|
||||
ExpressionNode * base = childAtIndex(0);
|
||||
if (base->isReal(context, angleUnit) && base->sign(&context, angleUnit) == Sign::Positive && childAtIndex(1)->isReal(context, angleUnit)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ComplexCartesian PowerNode::complexCartesian(Context & context, Preferences::AngleUnit angleUnit) const {
|
||||
Power p(this);
|
||||
@@ -125,6 +131,8 @@ ComplexPolar PowerNode::complexPolar(Context & context, Preferences::AngleUnit a
|
||||
return ComplexPolar::Builder(norm, argument);
|
||||
}
|
||||
|
||||
// Private
|
||||
|
||||
template<typename T>
|
||||
Complex<T> PowerNode::compute(const std::complex<T> c, const std::complex<T> d) {
|
||||
std::complex<T> result;
|
||||
@@ -359,22 +367,76 @@ Expression Power::shallowReduce(Context & context, Preferences::AngleUnit angleU
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Step 0: if both children are true complexes, the result is undefined. We
|
||||
* can assert that evaluations are Complex, as matrix are not simplified */
|
||||
|
||||
Evaluation<float> c0Approximated = childAtIndex(0).node()->approximate(1.0f, context, angleUnit);
|
||||
// TODO: do we need this?
|
||||
/*Evaluation<float> c0Approximated = childAtIndex(0).node()->approximate(1.0f, context, angleUnit);
|
||||
Evaluation<float> c1Approximated = childAtIndex(1).node()->approximate(1.0f, context, angleUnit);
|
||||
Complex<float> c0 = static_cast<Complex<float>&>(c0Approximated);
|
||||
Complex<float> c1 = static_cast<Complex<float>&>(c1Approximated);
|
||||
bool bothChildrenComplexes = c0.imag() != 0 && c1.imag() != 0 && !std::isnan(c0.imag()) && !std::isnan(c1.imag());
|
||||
bool nonComplexNegativeChild0 = c0.imag() == 0 && c0.real() < 0;
|
||||
bool nonNullChild0 = !std::isnan(c0.real()) && !std::isnan(c0.imag()) && (c0.real() > Expression::epsilon<float>() || c0.imag() > Expression::epsilon<float>());
|
||||
if (bothChildrenComplexes) {
|
||||
return *this;
|
||||
}*/
|
||||
|
||||
/* Step 0: if both children are true unresolved complexes, the result is not simplified. TODO? */
|
||||
|
||||
Expression power = *this;
|
||||
Expression base = childAtIndex(0);
|
||||
Expression index = childAtIndex(1);
|
||||
/* Step 0: if both children are true unresolved complexes, the result is not simplified. TODO? */
|
||||
if (!base.isReal(context, angleUnit) && !index.isReal(context, angleUnit)) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* Step 1: we now bubble up ComplexCartesian, we handle different case */
|
||||
|
||||
ComplexCartesian complexBase;
|
||||
ComplexCartesian complexIndex;
|
||||
ComplexCartesian result;
|
||||
// First, (x+iy)^q with q special values
|
||||
// TODO: explain here why?
|
||||
if (base.type() == ExpressionNode::Type::ComplexCartesian) {
|
||||
complexBase = static_cast<ComplexCartesian &>(base);
|
||||
Integer ten(10);
|
||||
if (index.type() == ExpressionNode::Type::Rational) {
|
||||
Rational r = static_cast<Rational &>(index);
|
||||
if (r.isMinusOne()) {
|
||||
// (x+iy)^(-1)
|
||||
result = complexBase.inverse(context, angleUnit, target);
|
||||
} else if (r.isHalf()) {
|
||||
// (x+iy)^(1/2)
|
||||
result = complexBase.squareRoot(context, angleUnit, target);
|
||||
} else if (r.isMinusHalf()) {
|
||||
// (x+iy)^(-1/2)
|
||||
result = complexBase.squareRoot(context, angleUnit, target).inverse(context, angleUnit, target);
|
||||
} else if (r.integerDenominator().isOne() && r.unsignedIntegerNumerator().isLowerThan(ten)) {
|
||||
if (r.sign() == ExpressionNode::Sign::Positive) {
|
||||
// (x+iy)^n, n integer positive n < 10
|
||||
result = complexBase.powerInteger(r.unsignedIntegerNumerator().extractedInt(), context, angleUnit, target);
|
||||
} else {
|
||||
// (x+iy)^(-n), n integer positive n < 10
|
||||
result = complexBase.powerInteger(r.unsignedIntegerNumerator().extractedInt(), context, angleUnit, target).inverse(context, angleUnit, target);
|
||||
}
|
||||
}
|
||||
if (!result.isUninitialized()) {
|
||||
replaceWithInPlace(result);
|
||||
return result.shallowReduce(context, angleUnit);
|
||||
}
|
||||
}
|
||||
}
|
||||
// All other cases where one child at least is a ComplexCartesian
|
||||
if ((base.isReal(context, angleUnit) && index.type() == ExpressionNode::Type::ComplexCartesian) ||
|
||||
(base.type() == ExpressionNode::Type::ComplexCartesian && index.isReal(context, angleUnit)) ||
|
||||
(base.type() == ExpressionNode::Type::ComplexCartesian && index.type() == ExpressionNode::Type::ComplexCartesian)) {
|
||||
complexBase = base.type() == ExpressionNode::Type::ComplexCartesian ? static_cast<ComplexCartesian &>(base) : ComplexCartesian::Builder(base, Rational(0));
|
||||
complexIndex = index.type() == ExpressionNode::Type::ComplexCartesian ? static_cast<ComplexCartesian &>(index) : ComplexCartesian::Builder(index, Rational(0));
|
||||
result = complexBase.power(complexIndex, context, angleUnit, target);
|
||||
replaceWithInPlace(result);
|
||||
return result.shallowReduce(context, angleUnit);
|
||||
}
|
||||
|
||||
/* Step 1: We handle simple cases as x^0, x^1, 0^x and 1^x first for 2 reasons:
|
||||
* - we can assert this step that there is no division by 0:
|
||||
* - we can assert after this step that there is no division by 0:
|
||||
* for instance, 0^(-2)->undefined
|
||||
* - we save computational time by early escaping for these cases. */
|
||||
if (childAtIndex(1).type() == ExpressionNode::Type::Rational) {
|
||||
@@ -388,7 +450,7 @@ Expression Power::shallowReduce(Context & context, Preferences::AngleUnit angleU
|
||||
return result;
|
||||
}
|
||||
// x^0
|
||||
if (target == ExpressionNode::ReductionTarget::User || nonNullChild0) {
|
||||
if (target == ExpressionNode::ReductionTarget::User || childAtIndex(0).isNumber()) {
|
||||
/* Warning: if the ReductionTarget is User, in all other cases but 0^0,
|
||||
* we replace x^0 by one. This is almost always true except when x = 0.
|
||||
* However, not substituting x^0 by one would prevent from simplifying
|
||||
@@ -437,7 +499,7 @@ Expression Power::shallowReduce(Context & context, Preferences::AngleUnit angleU
|
||||
}
|
||||
}
|
||||
|
||||
if (target == ExpressionNode::ReductionTarget::User && childAtIndex(1).type() == ExpressionNode::Type::Rational) {
|
||||
/*if (target == ExpressionNode::ReductionTarget::User && childAtIndex(1).type() == ExpressionNode::Type::Rational) {
|
||||
const Rational b = childAtIndex(1).convert<Rational>();
|
||||
// i^(p/q)
|
||||
if (childAtIndex(0).type() == ExpressionNode::Type::Constant && childAtIndex(0).convert<Constant>().isIComplex()) {
|
||||
@@ -446,7 +508,7 @@ Expression Power::shallowReduce(Context & context, Preferences::AngleUnit angleU
|
||||
replaceWithInPlace(result);
|
||||
return result.shallowReduce(context, angleUnit, target);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// (±inf)^x
|
||||
if (childAtIndex(0).type() == ExpressionNode::Type::Infinity) {
|
||||
@@ -508,7 +570,7 @@ Expression Power::shallowReduce(Context & context, Preferences::AngleUnit angleU
|
||||
}
|
||||
}
|
||||
// e^(i*Pi*r) with r rational
|
||||
if (!letPowerAtRoot && isNthRootOfUnity()) {
|
||||
/*if (!letPowerAtRoot && isNthRootOfUnity()) {
|
||||
Expression m = childAtIndex(1);
|
||||
Expression i = m.childAtIndex(m.numberOfChildren()-1);
|
||||
static_cast<Multiplication &>(m).removeChildAtIndexInPlace(m.numberOfChildren()-1);
|
||||
@@ -525,7 +587,7 @@ Expression Power::shallowReduce(Context & context, Preferences::AngleUnit angleU
|
||||
complexPart.shallowReduce(context, angleUnit, target);
|
||||
replaceWithInPlace(a);
|
||||
return a.shallowReduce(context, angleUnit, target);
|
||||
}
|
||||
}*/
|
||||
// x^log(y,x)->y if y > 0
|
||||
if (childAtIndex(1).type() == ExpressionNode::Type::Logarithm) {
|
||||
if (childAtIndex(1).numberOfChildren() == 2 && childAtIndex(0).isIdenticalTo(childAtIndex(1).childAtIndex(1))) {
|
||||
|
||||
Reference in New Issue
Block a user