star-sp

Random number generators and distributions
git clone git://git.meso-star.fr/star-sp.git
Log | Files | Refs | README | LICENSE

commit 5b4bfe8c675f554652e9becc7a7c88a05262b772
parent 4932c7c325e283cb6c25eacc3c2fa1a7f5fc4e4a
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Wed, 25 Oct 2017 15:17:28 +0200

Add some missing pdf functions.

Diffstat:
Msrc/ssp.h | 22++++++++++++++++++++++
Msrc/ssp_ranst_piecewise_linear.c | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_ssp_ran_piecewise_linear.h | 37+++++++++++++++++++++++++++++++++++--
3 files changed, 113 insertions(+), 2 deletions(-)

diff --git a/src/ssp.h b/src/ssp.h @@ -815,6 +815,16 @@ ssp_ranst_piecewise_linear_float_get (const struct ssp_ranst_piecewise_linear_float *ran, struct ssp_rng* rng); +SSP_API double +ssp_ranst_piecewise_linear_pdf + (const struct ssp_ranst_piecewise_linear *ran, + double x); + +SSP_API float +ssp_ranst_piecewise_linear_float_pdf + (const struct ssp_ranst_piecewise_linear_float *ran, + float x); + /******************************************************************************* * Uniform disk distribution. * @@ -833,6 +843,18 @@ ssp_ran_uniform_disk_float const float radius, float pt[2]); +static INLINE double +ssp_ran_uniform_disk_pdf(const double radius) +{ + return 1 / (radius * radius); +} + +static INLINE float +ssp_ran_uniform_disk_float_pdf(const float radius) +{ + return 1 / (radius * radius); +} + END_DECLS #endif /* SSP_H */ diff --git a/src/ssp_ranst_piecewise_linear.c b/src/ssp_ranst_piecewise_linear.c @@ -34,6 +34,8 @@ #include <rsys/mem_allocator.h> #include <rsys/ref_count.h> +#include <algorithm> + using piecewise_dist = RAN_NAMESPACE::piecewise_linear_distribution<double>; using piecewise_dist_float = RAN_NAMESPACE::piecewise_linear_distribution<float>; @@ -176,9 +178,16 @@ ssp_ranst_piecewise_linear_setup const double* weights, const size_t size) { + size_t i; if(!ran || !intervals || !weights || size < 2) return RES_BAD_ARG; + /* Checking param validity to avoid an assert when using ran */ + for(i=0; i < size-1; i++) { + if(weights[i] < 0) return RES_BAD_ARG; + if(intervals[i+1] <= intervals[i]) return RES_BAD_ARG; + } + if (intervals[size-1] - intervals[size-2] <= 0) return RES_BAD_ARG; piecewise_dist::param_type p{intervals, intervals + size, weights}; ran->distrib->param(p); return RES_OK; @@ -191,9 +200,16 @@ ssp_ranst_piecewise_linear_float_setup const float* weights, const size_t size) { + size_t i; if(!ran || !intervals || !weights || size < 2) return RES_BAD_ARG; + /* Checking param validity to avoid an assert when using ran */ + for(i=0; i < size-1; i++) { + if(weights[i] < 0) return RES_BAD_ARG; + if(intervals[i+1] <= intervals[i]) return RES_BAD_ARG; + } + if (weights[size-1] < 0) return RES_BAD_ARG; piecewise_dist_float::param_type p{ intervals, intervals + size, weights }; ran->distrib->param(p); return RES_OK; @@ -253,3 +269,42 @@ ssp_ranst_piecewise_linear_float_get return ran->distrib->operator()(r); } +double +ssp_ranst_piecewise_linear_pdf + (const struct ssp_ranst_piecewise_linear *ran, + double x) +{ + ASSERT(ran); + if (x<ran->distrib->min() || x>ran->distrib->max()) + return 0; + + const auto& inter = ran->distrib->intervals(); + const auto& dens = ran->distrib->densities(); + auto b = std::lower_bound(inter.begin(), inter.end(), x); + size_t idx = b - inter.begin(); + if (x == *b) return dens[idx]; + idx--; + ASSERT(idx < inter.size() - 1); + return (dens[idx+1] * (x - inter[idx]) + dens[idx] * (inter[idx+1] - x)) + / (inter[idx+1]- inter[idx]); +} + +float +ssp_ranst_piecewise_linear_float_pdf + (const struct ssp_ranst_piecewise_linear_float *ran, + float x) +{ + ASSERT(ran); + if (x<ran->distrib->min() || x>ran->distrib->max()) + return 0; + + const auto& inter = ran->distrib->intervals(); + const auto& dens = ran->distrib->densities(); + auto b = std::lower_bound(inter.begin(), inter.end(), x); + size_t idx = b - inter.begin(); + if (x == *b) return dens[idx]; + idx--; + ASSERT(idx < inter.size() - 1); + return (dens[idx+1] * (x - inter[idx]) + dens[idx] * (inter[idx+1] - x)) + / (inter[idx+1] - inter[idx]); +} +\ No newline at end of file diff --git a/src/test_ssp_ran_piecewise_linear.h b/src/test_ssp_ran_piecewise_linear.h @@ -45,9 +45,11 @@ #define RANST_PIECEWISE_LINEAR_CREATE ssp_ranst_piecewise_linear_create #define RANST_PIECEWISE_LINEAR_SETUP ssp_ranst_piecewise_linear_setup #define RANST_PIECEWISE_LINEAR_GET ssp_ranst_piecewise_linear_get +#define RANST_PIECEWISE_LINEAR_PDF ssp_ranst_piecewise_linear_pdf #define RANST_PIECEWISE_LINEAR_REF_GET ssp_ranst_piecewise_linear_ref_get #define RANST_PIECEWISE_LINEAR_REF_PUT ssp_ranst_piecewise_linear_ref_put #define EQ_EPS_R eq_eps +#define EPS_R DBL_EPSILON #define SQRT sqrt #elif TYPE_FLOAT==1 @@ -57,9 +59,11 @@ #define RANST_PIECEWISE_LINEAR_CREATE ssp_ranst_piecewise_linear_float_create #define RANST_PIECEWISE_LINEAR_SETUP ssp_ranst_piecewise_linear_float_setup #define RANST_PIECEWISE_LINEAR_GET ssp_ranst_piecewise_linear_float_get +#define RANST_PIECEWISE_LINEAR_PDF ssp_ranst_piecewise_linear_float_pdf #define RANST_PIECEWISE_LINEAR_REF_GET ssp_ranst_piecewise_linear_float_ref_get #define RANST_PIECEWISE_LINEAR_REF_PUT ssp_ranst_piecewise_linear_float_ref_put #define EQ_EPS_R eq_epsf +#define EPS_R FLT_EPSILON #define SQRT sqrtf #else #error "TYPE_SUFFIX must be defined either 0 or 1" @@ -75,8 +79,8 @@ TEST() REAL exp_mean = 5, mean; REAL exp_std = 10 / SQRT(12) /*sqrt((b - a)² / 12) */, std; REAL x = 0, x2 = 0; - const REAL intervals[] = { 0, 1, 3, 5, 7, 8, 10 }; - const REAL weights[] = { 1, 1, 1, 1, 1, 1, 1 }; + REAL intervals[] = { 0, 1, 3, 5, 7, 8, 10 }; + REAL weights[] = { 1, 1, 1, 1, 1, 1, 1 }; mem_init_proxy_allocator(&allocator, &mem_default_allocator); @@ -100,6 +104,27 @@ TEST() CHECK(RANST_PIECEWISE_LINEAR_SETUP (pwl, intervals, weights, sizeof(intervals)/sizeof(REAL)), RES_OK); + CHECK(RANST_PIECEWISE_LINEAR_REF_PUT(pwl), RES_OK); + CHECK(RANST_PIECEWISE_LINEAR_CREATE(&allocator, &pwl), RES_OK); + + weights[1] = -1; + CHECK(RANST_PIECEWISE_LINEAR_SETUP + (pwl, intervals, weights, sizeof(intervals) / sizeof(REAL)), RES_BAD_ARG); + weights[1] = 1; + + intervals[1] = 4; + CHECK(RANST_PIECEWISE_LINEAR_SETUP + (pwl, intervals, weights, sizeof(intervals) / sizeof(REAL)), RES_BAD_ARG); + intervals[1] = 1; + + intervals[1] = 3; + CHECK(RANST_PIECEWISE_LINEAR_SETUP + (pwl, intervals, weights, sizeof(intervals) / sizeof(REAL)), RES_BAD_ARG); + intervals[1] = 1; + + CHECK(RANST_PIECEWISE_LINEAR_SETUP + (pwl, intervals, weights, sizeof(intervals) / sizeof(REAL)), RES_OK); + CHECK(RANST_PIECEWISE_LINEAR_REF_GET(NULL), RES_BAD_ARG); CHECK(RANST_PIECEWISE_LINEAR_REF_GET(pwl), RES_OK); @@ -109,9 +134,15 @@ TEST() FOR_EACH(i, 0, NBS) { REAL r = RANST_PIECEWISE_LINEAR_GET(pwl, rng); CHECK(0 <= r && r <= 10, 1); + REAL pdf = RANST_PIECEWISE_LINEAR_PDF(pwl, r); + CHECK(EQ_EPS_R(pdf, (REAL)0.1, EPS_R), 1); x += r; x2 += r * r; } + CHECK(EQ_EPS_R(RANST_PIECEWISE_LINEAR_PDF(pwl, 0), (REAL)0.1, EPS_R), 1); + CHECK(EQ_EPS_R(RANST_PIECEWISE_LINEAR_PDF(pwl, 10), (REAL)0.1, EPS_R), 1); + CHECK(RANST_PIECEWISE_LINEAR_PDF(pwl, -1), 0); + CHECK(RANST_PIECEWISE_LINEAR_PDF(pwl, 11), 0); mean = x/NBS; std = SQRT(x2/NBS - mean*mean); @@ -134,8 +165,10 @@ TEST() #undef RANST_PIECEWISE_LINEAR_CREATE #undef RANST_PIECEWISE_LINEAR_SETUP #undef RANST_PIECEWISE_LINEAR_GET +#undef RANST_PIECEWISE_LINEAR_PDF #undef RANST_PIECEWISE_LINEAR_REF_GET #undef RANST_PIECEWISE_LINEAR_REF_PUT #undef EQ_EPS_R +#undef EPS_R #undef SQRT #undef TYPE_FLOAT