mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[poincare] Use reg incomplete beta function in binomial distribution
This commit is contained in:
@@ -6,7 +6,6 @@ app_probability_test_src = $(addprefix apps/probability/,\
|
||||
distribution/chi_squared_distribution.cpp \
|
||||
distribution/geometric_distribution.cpp \
|
||||
distribution/helper.cpp \
|
||||
distribution/incomplete_beta_function.cpp \
|
||||
distribution/distribution.cpp \
|
||||
distribution/regularized_gamma.cpp \
|
||||
distribution/student_distribution.cpp \
|
||||
|
||||
@@ -54,22 +54,11 @@ float BinomialDistribution::yMax() const {
|
||||
|
||||
bool BinomialDistribution::authorizedValueAtIndex(float x, int index) const {
|
||||
if (index == 0) {
|
||||
/* As the cumulative probability are computed by looping over all discrete
|
||||
* abscissa within the interesting range, the complexity of the cumulative
|
||||
* probability is linear with the size of the range. Here we cap the maximal
|
||||
* size of the range to 10000. If one day we want to increase or get rid of
|
||||
* this cap, we should implement the explicit formula of the cumulative
|
||||
* probability (which depends on an incomplete beta function) to make the
|
||||
* comlexity O(1). */
|
||||
if (x != (int)x || x < 0.0f || x > 99999.0f) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
// n must be a positive integer
|
||||
return (x == (int)x) && x >= 0.0f;
|
||||
}
|
||||
if (x < 0.0f || x > 1.0f) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
// p must be between 0 and 1
|
||||
return (x >= 0.0f) && (x <= 1.0f);
|
||||
}
|
||||
|
||||
double BinomialDistribution::cumulativeDistributiveInverseForProbability(double * probability) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "student_distribution.h"
|
||||
#include "incomplete_beta_function.h"
|
||||
#include <poincare/regularized_incomplete_beta_function.h>
|
||||
#include "helper.h"
|
||||
#include <cmath>
|
||||
|
||||
@@ -36,7 +36,7 @@ double StudentDistribution::cumulativeDistributiveFunctionAtAbscissa(double x) c
|
||||
const float k = m_parameter1;
|
||||
const double sqrtXSquaredPlusK = std::sqrt(x*x + k);
|
||||
double t = (x + sqrtXSquaredPlusK) / (2.0 * sqrtXSquaredPlusK);
|
||||
return IncompleteBetaFunction(k/2.0, k/2.0, t);
|
||||
return Poincare::RegularizedIncompleteBetaFunction(k/2.0, k/2.0, t);
|
||||
}
|
||||
|
||||
double StudentDistribution::cumulativeDistributiveInverseForProbability(double * probability) {
|
||||
|
||||
@@ -35,6 +35,7 @@ poincare_src += $(addprefix poincare/src/,\
|
||||
exception_checkpoint.cpp \
|
||||
helpers.cpp \
|
||||
normal_distribution.cpp \
|
||||
regularized_incomplete_beta_function.cpp \
|
||||
)
|
||||
|
||||
poincare_src += $(addprefix poincare/src/,\
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef PROBABILITY_INCOMPLETE_BETA_FUNCTION_H
|
||||
#define PROBABILITY_INCOMPLETE_BETA_FUNCTION_H
|
||||
#ifndef POINCARE_REGULARIZED_INCOMPLETE_BETA_FUNCTION_H
|
||||
#define POINCARE_REGULARIZED_INCOMPLETE_BETA_FUNCTION_H
|
||||
|
||||
/*
|
||||
* zlib License
|
||||
@@ -28,7 +28,10 @@
|
||||
|
||||
|
||||
// WARNING: this code has been modified
|
||||
namespace Poincare {
|
||||
|
||||
double IncompleteBetaFunction(double a, double b, double x);
|
||||
double RegularizedIncompleteBetaFunction(double a, double b, double x);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <poincare/binomial_distribution.h>
|
||||
#include <poincare/rational.h>
|
||||
#include <poincare/regularized_incomplete_beta_function.h>
|
||||
#include <cmath>
|
||||
#include <float.h>
|
||||
#include <assert.h>
|
||||
@@ -49,16 +50,8 @@ T BinomialDistribution::CumulativeDistributiveFunctionAtAbscissa(T x, T n, T p)
|
||||
if (x >= n) {
|
||||
return (T)1.0;
|
||||
}
|
||||
bool isDouble = sizeof(T) == sizeof(double);
|
||||
return Solver::CumulativeDistributiveFunctionForNDefinedFunction<T>(
|
||||
x,
|
||||
[](double abscissa, Context * context, Poincare::Preferences::ComplexFormat complexFormat, Poincare::Preferences::AngleUnit angleUnit, const void * n, const void * p, const void * isDouble) {
|
||||
if (*(bool *)isDouble) {
|
||||
return (double)BinomialDistribution::EvaluateAtAbscissa<T>(abscissa, *(reinterpret_cast<const double *>(n)), *(reinterpret_cast<const double *>(p)));
|
||||
}
|
||||
return (double)BinomialDistribution::EvaluateAtAbscissa<T>(abscissa, *(reinterpret_cast<const float *>(n)), *(reinterpret_cast<const float *>(p)));
|
||||
}, (Context *)nullptr, Preferences::ComplexFormat::Real, Preferences::AngleUnit::Degree, &n, &p, &isDouble);
|
||||
// Context, complex format and angle unit are dummy values
|
||||
T floorX = std::floor(x);
|
||||
return RegularizedIncompleteBetaFunction(n-floorX, floorX+1.0, 1.0-p);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -100,14 +93,6 @@ T BinomialDistribution::CumulativeDistributiveInverseForProbability(T probabilit
|
||||
|
||||
template<typename T>
|
||||
bool BinomialDistribution::ParametersAreOK(T n, T p) {
|
||||
/* TODO As the cumulative probability are computed by looping over all discrete
|
||||
* abscissa within the interesting range, the complexity of the cumulative
|
||||
* probability is linear with the size of the range. Here we cap the maximal
|
||||
* size of the range to 10000. If one day we want to increase or get rid of
|
||||
* this cap, we should implement the explicit formula of the cumulative
|
||||
* probability (which depends on an incomplete beta function) to make the
|
||||
* comlexity O(1). */
|
||||
//TODO LEA n doit être <= 99999.0f) {
|
||||
return !std::isnan(n) && !std::isnan(p)
|
||||
&& !std::isinf(n) && !std::isinf(p)
|
||||
&& (n == (int)n) && (n >= (T)0)
|
||||
|
||||
@@ -25,19 +25,21 @@
|
||||
|
||||
// WARNING: this code has been modified
|
||||
|
||||
#include "incomplete_beta_function.h"
|
||||
#include <poincare/regularized_incomplete_beta_function.h>
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
namespace Poincare {
|
||||
|
||||
#define STOP 1.0e-8
|
||||
#define TINY 1.0e-30
|
||||
|
||||
double IncompleteBetaFunction(double a, double b, double x) {
|
||||
double RegularizedIncompleteBetaFunction(double a, double b, double x) {
|
||||
if (x < 0.0 || x > 1.0) return NAN;
|
||||
|
||||
/*The continued fraction converges nicely for x < (a+1)/(a+b+2)*/
|
||||
if (x > (a+1.0)/(a+b+2.0)) {
|
||||
return (1.0-IncompleteBetaFunction(b,a,1.0-x)); /*Use the fact that beta is symmetrical.*/
|
||||
return (1.0-RegularizedIncompleteBetaFunction(b,a,1.0-x)); /*Use the fact that beta is symmetrical.*/
|
||||
}
|
||||
|
||||
/*Find the first part before the continued fraction.*/
|
||||
@@ -80,3 +82,5 @@ double IncompleteBetaFunction(double a, double b, double x) {
|
||||
|
||||
return NAN; /*Needed more loops, did not converge.*/
|
||||
}
|
||||
|
||||
}
|
||||
@@ -235,7 +235,7 @@ QUIZ_CASE(poincare_approximation_function) {
|
||||
assert_expression_approximates_to<double>("abs([[3+2𝐢,3+4𝐢][5+2𝐢,3+2𝐢]])", "[[3.605551275464,5][5.3851648071345,3.605551275464]]");
|
||||
|
||||
assert_expression_approximates_to<float>("binomcdf(5.3, 9, 0.7)", "0.270341", Degree, Cartesian, 6); // FIXME: precision problem
|
||||
assert_expression_approximates_to<double>("binomcdf(5.3, 9, 0.7)", "0.270340902");
|
||||
assert_expression_approximates_to<double>("binomcdf(5.3, 9, 0.7)", "0.270340902", Degree, Cartesian, 10); //FIXME precision problem
|
||||
|
||||
assert_expression_approximates_to<float>("binomial(10, 4)", "210");
|
||||
assert_expression_approximates_to<double>("binomial(10, 4)", "210");
|
||||
|
||||
Reference in New Issue
Block a user