[poincare] SignFunction: improve shallowReduce: sign(-x) = -sign(x)

This commit is contained in:
Émilie Feral
2018-12-17 11:24:44 +01:00
committed by Léa Saviot
parent 68b6d4211b
commit cbd4f44539
5 changed files with 25 additions and 11 deletions

View File

@@ -51,7 +51,7 @@ public:
static Expression UntypedBuilder(Expression children) { return Builder(children.childAtIndex(0)); }
static constexpr Expression::FunctionHelper s_functionHelper = Expression::FunctionHelper("sign", 1, &UntypedBuilder);
Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit);
Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target);
private:
explicit SignFunction(Expression child) : Expression(TreePool::sharedPool()->createTreeNode<SignFunctionNode>()) {
replaceChildAtIndexInPlace(0, child);

View File

@@ -94,7 +94,7 @@ Expression ComplexCartesian::argument(Context & context, Preferences::AngleUnit
return sub;
} else {
// if b == 0, argument = (1-sign(a))*Pi/2
Expression signa = SignFunction::Builder(a).shallowReduce(context, angleUnit);
Expression signa = SignFunction::Builder(a).shallowReduce(context, angleUnit, target);
Subtraction sub(Rational(1), signa);
signa.shallowReduce(context, angleUnit, target);
Multiplication mul(Rational(1,2), Constant(Ion::Charset::SmallPi), sub);

View File

@@ -96,7 +96,7 @@ ComplexPolar ComplexHelper::complexPolarFromComplexCartesian(const ExpressionNod
// Then, compute sign(b) * Pi/2 - arctan(a/b)
argument = Subtraction(
Multiplication(
SignFunction::Builder(b).shallowReduce(context, angleUnit),
SignFunction::Builder(b).shallowReduce(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation),
Division(Constant(Ion::Charset::SmallPi), Rational(2)).shallowReduce(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation)
).shallowReduce(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation),
arcTangent
@@ -106,7 +106,7 @@ ComplexPolar ComplexHelper::complexPolarFromComplexCartesian(const ExpressionNod
argument = Multiplication(
Subtraction(
Rational(1),
SignFunction::Builder(a).shallowReduce(context, angleUnit)
SignFunction::Builder(a).shallowReduce(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation)
).shallowReduce(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation),
Division(Constant(Ion::Charset::SmallPi), Rational(2)).shallowReduce(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation)
).shallowReduce(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation);

View File

@@ -32,7 +32,7 @@ int SignFunctionNode::serialize(char * buffer, int bufferSize, Preferences::Prin
}
Expression SignFunctionNode::shallowReduce(Context & context, Preferences::AngleUnit angleUnit, ReductionTarget target) {
return SignFunction(this).shallowReduce(context, angleUnit);
return SignFunction(this).shallowReduce(context, angleUnit, target);
}
template<typename T>
@@ -46,7 +46,7 @@ Complex<T> SignFunctionNode::computeOnComplex(const std::complex<T> c, Preferenc
return Complex<T>(1.0);
}
Expression SignFunction::shallowReduce(Context & context, Preferences::AngleUnit angleUnit) {
Expression SignFunction::shallowReduce(Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target) {
{
Expression e = Expression::defaultShallowReduce(context, angleUnit);
if (e.isUndefined()) {
@@ -59,16 +59,30 @@ Expression SignFunction::shallowReduce(Context & context, Preferences::AngleUnit
}
#endif
Rational one(1);
if (childAtIndex(0).sign(&context, angleUnit) != ExpressionNode::Sign::Unknown) {
if (childAtIndex(0).sign(&context, angleUnit) == ExpressionNode::Sign::Negative) {
Expression child = childAtIndex(0);
ExpressionNode::Sign s = child.sign(&context, angleUnit);
if (s != ExpressionNode::Sign::Unknown) {
if (s == ExpressionNode::Sign::Negative) {
one = Rational(-1);
}
} else {
Evaluation<float> childApproximated = childAtIndex(0).node()->approximate(1.0f, context, angleUnit);
Evaluation<float> childApproximated = child.node()->approximate(1.0f, context, angleUnit);
assert(childApproximated.type() == EvaluationNode<float>::Type::Complex);
Complex<float> c = static_cast<Complex<float>&>(childApproximated);
// c has no sign (c is complex or NAN)
if (std::isnan(c.imag()) || std::isnan(c.real()) || c.imag() != 0) {
return *this;
// sign(-x) = sign(x)
Expression oppChild = child.makePositiveAnyNegativeNumeralFactor(context, angleUnit);
if (oppChild.isUninitialized()) {
return *this;
} else {
Expression sign = *this;
Multiplication m(Rational(-1));
replaceWithInPlace(m);
m.addChildAtIndexInPlace(sign, 1, 1);
sign.shallowReduce(context, angleUnit, target);
return m.shallowReduce(context, angleUnit, target);
}
}
if (c.real() < 0) {
one = Rational(-1);

View File

@@ -62,7 +62,7 @@ ComplexCartesian SquareRootNode::complexCartesian(Context & context, Preferences
// a = sqrt(x^2+y^2)+x
Multiplication real = complexCartesianHelper(Addition(norm.clone(), x.clone()), context, angleUnit);
Multiplication imag = complexCartesianHelper(Subtraction(norm, x), context, angleUnit);
imag.addChildAtIndexInPlace(SignFunction::Builder(y).shallowReduce(context, angleUnit), imag.numberOfChildren(), imag.numberOfChildren());
imag.addChildAtIndexInPlace(SignFunction::Builder(y).shallowReduce(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation), imag.numberOfChildren(), imag.numberOfChildren());
return ComplexCartesian::Builder(
real.shallowReduce(context, angleUnit, ReductionTarget::BottomUpComputation),
imag.shallowReduce(context, angleUnit, ReductionTarget::BottomUpComputation)