From 04ccc285c8bf6008cfdac8f1cb0b2255411980c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 23 Aug 2019 15:08:33 +0200 Subject: [PATCH] [poincare] InvNorm --- poincare/Makefile | 1 + poincare/include/poincare/expression.h | 1 + poincare/include/poincare/expression_node.h | 1 + poincare/include/poincare/inv_norm.h | 50 ++++++++++++++++++++ poincare/include/poincare_nodes.h | 1 + poincare/src/inv_norm.cpp | 52 +++++++++++++++++++++ poincare/src/normal_distribution.cpp | 10 ++-- poincare/src/parsing/parser.h | 1 + poincare/src/tree_handle.cpp | 1 + poincare/test/approximation.cpp | 3 ++ 10 files changed, 116 insertions(+), 5 deletions(-) create mode 100644 poincare/include/poincare/inv_norm.h create mode 100644 poincare/src/inv_norm.cpp diff --git a/poincare/Makefile b/poincare/Makefile index ea7a78291..60b627637 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -82,6 +82,7 @@ poincare_src += $(addprefix poincare/src/,\ infinity.cpp \ integer.cpp \ integral.cpp \ + inv_norm.cpp \ layout_helper.cpp \ least_common_multiple.cpp \ logarithm.cpp \ diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 5d4ef4662..96bb84efe 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -54,6 +54,7 @@ class Expression : public TreeHandle { friend class HyperbolicTrigonometricFunction; friend class ImaginaryPart; friend class Integral; + friend class InvNorm; friend class LeastCommonMultiple; friend class Logarithm; friend class Matrix; diff --git a/poincare/include/poincare/expression_node.h b/poincare/include/poincare/expression_node.h index c8b787151..79fc3226e 100644 --- a/poincare/include/poincare/expression_node.h +++ b/poincare/include/poincare/expression_node.h @@ -68,6 +68,7 @@ public: HyperbolicTangent, ImaginaryPart, Integral, + InvNorm, LeastCommonMultiple, Logarithm, MatrixTrace, diff --git a/poincare/include/poincare/inv_norm.h b/poincare/include/poincare/inv_norm.h new file mode 100644 index 000000000..8a25ef037 --- /dev/null +++ b/poincare/include/poincare/inv_norm.h @@ -0,0 +1,50 @@ +#ifndef POINCARE_INV_NORM_H +#define POINCARE_INV_NORM_H + +#include +#include + +namespace Poincare { + +class InvNormNode final : public ExpressionNode { +public: + + // TreeNode + size_t size() const override { return sizeof(InvNormNode); } + int numberOfChildren() const override; +#if POINCARE_TREE_LOG + virtual void logNodeName(std::ostream & stream) const override { + stream << "InvNorm"; + } +#endif + + // Properties + Type type() const override { return Type::InvNorm; } + +private: + // Layout + Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + + // Simplication + Expression shallowReduce(ReductionContext reductionContext) override; + LayoutShape leftLayoutShape() const override { return LayoutShape::MoreLetters; }; + LayoutShape rightLayoutShape() const override { return LayoutShape::BoundaryPunctuation; } + + // Evaluation + Evaluation approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, complexFormat, angleUnit); } + Evaluation approximate(DoublePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, complexFormat, angleUnit); } + template Evaluation templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; +}; + +class InvNorm final : public Expression { +public: + InvNorm(const InvNormNode * n) : Expression(n) {} + static InvNorm Builder(Expression child0, Expression child1, Expression child2) { return TreeHandle::FixedArityBuilder(ArrayBuilder(child0, child1, child2).array(), 3); } + static constexpr Expression::FunctionHelper s_functionHelper = Expression::FunctionHelper("invnorm", 3, &UntypedBuilderThreeChildren); + Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); +}; + +} + +#endif diff --git a/poincare/include/poincare_nodes.h b/poincare/include/poincare_nodes.h index d36d674d5..6709e2028 100644 --- a/poincare/include/poincare_nodes.h +++ b/poincare/include/poincare_nodes.h @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include diff --git a/poincare/src/inv_norm.cpp b/poincare/src/inv_norm.cpp new file mode 100644 index 000000000..107cc7544 --- /dev/null +++ b/poincare/src/inv_norm.cpp @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include + +namespace Poincare { + +constexpr Expression::FunctionHelper InvNorm::s_functionHelper; + +int InvNormNode::numberOfChildren() const { return InvNorm::s_functionHelper.numberOfChildren(); } + +Layout InvNormNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + return LayoutHelper::Prefix(InvNorm(this), floatDisplayMode, numberOfSignificantDigits, InvNorm::s_functionHelper.name()); +} + +int InvNormNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, InvNorm::s_functionHelper.name()); +} + +Expression InvNormNode::shallowReduce(ReductionContext reductionContext) { + return InvNorm(this).shallowReduce(reductionContext); +} + +template +Evaluation InvNormNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { + Evaluation aEvaluation = childAtIndex(0)->approximate(T(), context, complexFormat, angleUnit); + Evaluation muEvaluation = childAtIndex(1)->approximate(T(), context, complexFormat, angleUnit); + Evaluation sigmaEvaluation = childAtIndex(2)->approximate(T(), context, complexFormat, angleUnit); + + T a = aEvaluation.toScalar(); + T mu = muEvaluation.toScalar(); + T sigma = sigmaEvaluation.toScalar(); + + if (std::isnan(a) || std::isnan(mu) || std::isnan(sigma)) { + return Complex::Undefined(); + } + return Complex::Builder(NormalDistribution::CumulativeDistributiveInverseForProbability(a, mu, sigma)); +} + +Expression InvNorm::shallowReduce(ExpressionNode::ReductionContext reductionContext) { + { + Expression e = Expression::defaultShallowReduce(); + if (e.isUndefined()) { + return e; + } + } + //TODO LEA + return *this; +} + +} diff --git a/poincare/src/normal_distribution.cpp b/poincare/src/normal_distribution.cpp index 3be5ba30e..5b6d0c35e 100644 --- a/poincare/src/normal_distribution.cpp +++ b/poincare/src/normal_distribution.cpp @@ -47,16 +47,16 @@ T NormalDistribution::StandardNormalCumulativeDistributiveFunctionAtAbscissa(T a template T NormalDistribution::StandardNormalCumulativeDistributiveInverseForProbability(T probability) { - if (probability >= 1.0) { + if (probability >= (T)1.0) { return INFINITY; } - if (probability <= 0.0) { + if (probability <= (T)0.0) { return -INFINITY; } - if (probability < 0.5) { - return -StandardNormalCumulativeDistributiveInverseForProbability(1.0-probability); + if (probability < (T)0.5) { + return -StandardNormalCumulativeDistributiveInverseForProbability(((T)1.0)-probability); } - return std::sqrt(2.0) * erfInv(2.0 * probability - 1.0); + return std::sqrt((T)2.0) * erfInv(((T)2.0) * probability - (T)1.0); } template float NormalDistribution::EvaluateAtAbscissa(float, float, float); diff --git a/poincare/src/parsing/parser.h b/poincare/src/parsing/parser.h index e86f738a8..75be59de0 100644 --- a/poincare/src/parsing/parser.h +++ b/poincare/src/parsing/parser.h @@ -116,6 +116,7 @@ private: &ImaginaryPart::s_functionHelper, &Integral::s_functionHelper, &MatrixInverse::s_functionHelper, + &InvNorm::s_functionHelper, &LeastCommonMultiple::s_functionHelper, &NaperianLogarithm::s_functionHelper, &CommonLogarithm::s_functionHelper, diff --git a/poincare/src/tree_handle.cpp b/poincare/src/tree_handle.cpp index 68e24ee6d..a0fe8d645 100644 --- a/poincare/src/tree_handle.cpp +++ b/poincare/src/tree_handle.cpp @@ -302,6 +302,7 @@ template HyperbolicTangent TreeHandle::FixedArityBuilder(TreeHandle*, size_t); template Integral TreeHandle::FixedArityBuilder(TreeHandle*, size_t); template IntegralLayout TreeHandle::FixedArityBuilder(TreeHandle*, size_t); +template InvNorm TreeHandle::FixedArityBuilder(TreeHandle*, size_t); template LeastCommonMultiple TreeHandle::FixedArityBuilder(TreeHandle*, size_t); template LeftParenthesisLayout TreeHandle::FixedArityBuilder(TreeHandle*, size_t); template LeftSquareBracketLayout TreeHandle::FixedArityBuilder(TreeHandle*, size_t); diff --git a/poincare/test/approximation.cpp b/poincare/test/approximation.cpp index e9a64da99..dae16a713 100644 --- a/poincare/test/approximation.cpp +++ b/poincare/test/approximation.cpp @@ -270,6 +270,9 @@ QUIZ_CASE(poincare_approximation_function) { assert_expression_approximates_to("int(x,x, 1, 2)", "1.5"); assert_expression_approximates_to("int(x,x, 1, 2)", "1.5"); + assert_expression_approximates_to("invnorm(0.56, 1.3, 2.4)", "1.662326"); + //assert_expression_approximates_to("invnorm(0.56, 1.3, 2.4)", "1.6623258450088"); FIXME precision error + assert_expression_approximates_to("ln(2)", "0.6931472"); assert_expression_approximates_to("ln(2)", "6.9314718055995ᴇ-1");