star-sp

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

commit 47102f3c8e342e35326a71b6bec2030008fdf995
parent 7988e07b4898f422c200216a9870942fcf4e9572
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Thu,  7 Jul 2016 16:55:08 +0200

API break: change naming pattern for state-based distributions.

discrete distribution now uses C++11 std::discrete_distribution, though.

Diffstat:
Mcmake/CMakeLists.txt | 1-
Msrc/ssp.h | 82++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/ssp_distributions.cpp | 325+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Dsrc/ssp_ran_discrete.c | 203-------------------------------------------------------------------------------
Msrc/test_ssp_ran_discrete.c | 48++++++++++++++++++++++++------------------------
Msrc/test_ssp_ran_gaussian.c | 30+++++++++++++++---------------
Msrc/test_ssp_ran_piecewise_linear.c | 34+++++++++++++++++-----------------
7 files changed, 326 insertions(+), 397 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -71,7 +71,6 @@ set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(SSP_FILES_SRC - ssp_ran_discrete.c ssp_rng.c ssp_rng_proxy.c ssp_distributions.cpp) diff --git a/src/ssp.h b/src/ssp.h @@ -57,8 +57,9 @@ /* Forward declaration of opaque types */ struct ssp_rng; struct ssp_rng_proxy; -struct ssp_ran_discrete; -struct ssp_ran_type; +struct ssp_ranst_discrete; +struct ssp_ranst_gaussian; +struct ssp_ranst_piecewise_linear; /* Forward declaration of external types */ struct mem_allocator; @@ -252,41 +253,41 @@ ssp_rng_proxy_get_type struct ssp_rng_type* type); /******************************************************************************* - * General discrete distribution + * General discrete distribution with state ******************************************************************************/ /* Create a discrete random variate data structure from a list of weights. * `weights' contain the weights of `nweights' discrete events. Its elements * must be positive but they needn't add up to one. */ SSP_API res_T -ssp_ran_discrete_create +ssp_ranst_discrete_create (struct mem_allocator* allocator, /* May be NULL <=> Use default allocator */ - struct ssp_ran_discrete** ran); + struct ssp_ranst_discrete** ran); SSP_API res_T -ssp_ran_discrete_setup - (struct ssp_ran_discrete* discrete, +ssp_ranst_discrete_setup + (struct ssp_ranst_discrete* discrete, const double* weights, const size_t nweights); SSP_API res_T -ssp_ran_discrete_ref_get - (struct ssp_ran_discrete* ran); +ssp_ranst_discrete_ref_get + (struct ssp_ranst_discrete* ran); SSP_API res_T -ssp_ran_discrete_ref_put - (struct ssp_ran_discrete* ran); +ssp_ranst_discrete_ref_put + (struct ssp_ranst_discrete* ran); /* Return the index of the sampled discret event. */ SSP_API size_t -ssp_ran_discrete +ssp_ranst_discrete_get (struct ssp_rng* rng, - struct ssp_ran_discrete* ran); + const struct ssp_ranst_discrete* ran); /* Return the PDF of the discret event `i'. */ SSP_API double -ssp_ran_discrete_pdf +ssp_ranst_discrete_pdf (const size_t i, - struct ssp_ran_discrete* ran); + const struct ssp_ranst_discrete* ran); /******************************************************************************* * Miscellaneous distributions @@ -303,7 +304,8 @@ ssp_ran_exp_pdf (const double x, const double mu); -/* Random variate from the gaussian (or normal) distribution with mean `mu': +/* Stateless random variate from the gaussian (or normal) distribution + * with mean `mu': * P(x) dx = 1 / (sigma*sqrt(2*PI)) * exp(1/2*((x-mu)/sigma)^2) dx */ SSP_API double ssp_ran_gaussian @@ -579,65 +581,65 @@ ssp_ran_sphere_hg } /******************************************************************************* - * Gaussian distribution + * Gaussian distribution with state ******************************************************************************/ SSP_API res_T -ssp_ran_gaussian_create +ssp_ranst_gaussian_create (struct mem_allocator* allocator, /* May be NULL <=> Use default allocator */ - struct ssp_ran_type** ran); + struct ssp_ranst_gaussian** ran); SSP_API res_T -ssp_ran_gaussian_init - (struct ssp_ran_type* ran, +ssp_ranst_gaussian_setup + (struct ssp_ranst_gaussian* ran, double mu, double sigma); SSP_API res_T -ssp_ran_gaussian_ref_get - (struct ssp_ran_type* ran); +ssp_ranst_gaussian_ref_get + (struct ssp_ranst_gaussian* ran); SSP_API res_T -ssp_ran_gaussian_ref_put - (struct ssp_ran_type* ran); +ssp_ranst_gaussian_ref_put + (struct ssp_ranst_gaussian* ran); SSP_API double -ssp_ran_gaussian_get - (const struct ssp_ran_type* ran, +ssp_ranst_gaussian_get + (const struct ssp_ranst_gaussian* ran, struct ssp_rng* rng); SSP_API double -ssp_distribution_gaussian_pdf - (const struct ssp_ran_type* ran, +ssp_ranst_gaussian_pdf + (const struct ssp_ranst_gaussian* ran, double x); /******************************************************************************* - * Piecewise linear distribution + * Piecewise linear distribution with state ******************************************************************************/ SSP_API res_T -ssp_ran_piecewise_linear_create +ssp_ranst_piecewise_linear_create (struct mem_allocator* allocator, /* May be NULL <=> Use default allocator */ - struct ssp_ran_type **ran); + struct ssp_ranst_piecewise_linear **ran); SSP_API res_T -ssp_ran_piecewise_linear_init - (struct ssp_ran_type *ran, +ssp_ranst_piecewise_linear_setup + (struct ssp_ranst_piecewise_linear *ran, const double* intervals, const double* weights, size_t size); SSP_API res_T -ssp_ran_piecewise_linear_ref_get - (struct ssp_ran_type* ran); +ssp_ranst_piecewise_linear_ref_get + (struct ssp_ranst_piecewise_linear* ran); SSP_API res_T -ssp_ran_piecewise_linear_ref_put - (struct ssp_ran_type* ran); +ssp_ranst_piecewise_linear_ref_put + (struct ssp_ranst_piecewise_linear* ran); SSP_API double -ssp_ran_piecewise_linear_get - (const struct ssp_ran_type *ran, +ssp_ranst_piecewise_linear_get + (const struct ssp_ranst_piecewise_linear *ran, struct ssp_rng* rng); /******************************************************************************* diff --git a/src/ssp_distributions.cpp b/src/ssp_distributions.cpp @@ -1,15 +1,10 @@ #include <rsys/mem_allocator.h> #include <rsys/ref_count.h> +#include <rsys/dynamic_array_double.h> #include <rsys/math.h> + #include "ssp_rng_c.h" -/* one single type for all distributions - * only the state type depends on the distribution type */ -struct ssp_ran_type { - ref_T ref; - struct mem_allocator* allocator; - void* state; -}; /******************************************************************************* * Gaussian distribution utilities @@ -17,8 +12,10 @@ struct ssp_ran_type { using normal_dist=RAN_NAMESPACE::normal_distribution<double>; -struct ran_gaussian_state +struct ssp_ranst_gaussian { + ref_T ref; + struct mem_allocator* allocator; normal_dist* distrib; double mu; double K1; // 1.0 / sigma; @@ -28,15 +25,12 @@ struct ran_gaussian_state static void gaussian_release(ref_T* ref) { - ssp_ran_type* ran; - ran_gaussian_state* state; + ssp_ranst_gaussian* ran; ASSERT(ref); - ran = CONTAINER_OF(ref, ssp_ran_type, ref); - state = static_cast<ran_gaussian_state*>(ran->state); - if(state) { - state->distrib->~normal_dist(); - MEM_RM(ran->allocator, state->distrib); - MEM_RM(ran->allocator, state); + ran = CONTAINER_OF(ref, ssp_ranst_gaussian, ref); + if(ran->distrib) { + ran->distrib->~normal_dist(); + MEM_RM(ran->allocator, ran->distrib); } MEM_RM(ran->allocator, ran); } @@ -47,38 +41,194 @@ gaussian_release(ref_T* ref) using piecewise_dist=RAN_NAMESPACE::piecewise_linear_distribution<double>; -struct ran_piecewise_linear_state +struct ssp_ranst_piecewise_linear { + ref_T ref; + struct mem_allocator* allocator; piecewise_dist* distrib; }; static void piecewise_release(ref_T* ref) { - ssp_ran_type* ran; - ran_piecewise_linear_state* state; + ssp_ranst_piecewise_linear* ran; + ASSERT(ref); + ran = CONTAINER_OF(ref, ssp_ranst_piecewise_linear, ref); + if(ran->distrib) { + ran->distrib->~piecewise_dist(); + MEM_RM(ran->allocator, ran->distrib); + } + MEM_RM(ran->allocator, ran); +} + +/******************************************************************************* + * Discrete distribution utilities + ******************************************************************************/ + +using discrete_dist=RAN_NAMESPACE::discrete_distribution<size_t>; + +struct ssp_ranst_discrete { + struct darray_double pdf; + ref_T ref; + struct mem_allocator* allocator; + discrete_dist* distrib; +}; + +static void +ran_discrete_release(ref_T* ref) +{ + struct ssp_ranst_discrete* ran; ASSERT(ref); - ran = CONTAINER_OF(ref, ssp_ran_type, ref); - state = static_cast<ran_piecewise_linear_state*>(ran->state); - if(state) { - state->distrib->~piecewise_dist(); - MEM_RM(ran->allocator, state->distrib); - MEM_RM(ran->allocator, state); + ran = CONTAINER_OF(ref, struct ssp_ranst_discrete, ref); + if(ran->distrib) { + ran->distrib->~discrete_dist(); + MEM_RM(ran->allocator, ran->distrib); } + darray_double_release(&ran->pdf); MEM_RM(ran->allocator, ran); } /******************************************************************************* + * Discrete distribution exported functions + ******************************************************************************/ + +res_T +ssp_ranst_discrete_create + (struct mem_allocator* allocator, + struct ssp_ranst_discrete** out_ran) +{ + ssp_ranst_discrete* ran = nullptr; + void* mem = nullptr; + res_T res = RES_OK; + + if(!out_ran) { + res = RES_BAD_ARG; + goto error; + } + allocator = allocator ? allocator : &mem_default_allocator; + + ran = static_cast<ssp_ranst_discrete*>( + MEM_CALLOC(allocator, 1, sizeof(ssp_ranst_discrete))); + if(!ran) { + res = RES_MEM_ERR; + goto error; + } + ref_init(&ran->ref); + + mem = MEM_ALLOC(allocator, sizeof(discrete_dist)); + if (!mem) { + res = RES_MEM_ERR; + goto error; + } + ran->allocator = allocator; + ran->distrib = static_cast<discrete_dist*>(new(mem) discrete_dist); + darray_double_init(allocator, &ran->pdf); + +exit: + if(out_ran) *out_ran = ran; + return res; +error: + if(ran) { + SSP(ranst_discrete_ref_put(ran)); + ran = NULL; + } + goto exit; +} + +res_T +ssp_ranst_discrete_setup + (struct ssp_ranst_discrete* ran, + const double* weights, + const size_t nweights) +{ + double* pdf; + double sum = 0; + size_t i; + res_T res = RES_OK; + + if(!ran || !weights || !nweights) { + res = RES_BAD_ARG; + goto error; + } + + res = darray_double_resize(&ran->pdf, nweights); + if(res != RES_OK) goto error; + + pdf = darray_double_data_get(&ran->pdf); + + for(i = 0; i < nweights; i++) { + if(weights[i] < 0.f) { + res = RES_BAD_ARG; + goto error; + } + sum += weights[i]; + pdf[i] = weights[i]; + } + if (sum == 0) { + res = RES_BAD_ARG; + goto error; + } + + sum = 1 / sum; + for(i = 0; i < nweights; i++) { + pdf[i] *= sum; + } + + { + discrete_dist::param_type p{weights, weights + nweights}; + ran->distrib->param(p); + } + +exit: + return res; +error: + if(ran) { + darray_double_clear(&ran->pdf); + } + goto exit; +} + +res_T +ssp_ranst_discrete_ref_get(struct ssp_ranst_discrete* ran) +{ + if(!ran) return RES_BAD_ARG; + ref_get(&ran->ref); + return RES_OK; +} + +res_T +ssp_ranst_discrete_ref_put(struct ssp_ranst_discrete* ran) +{ + if(!ran) return RES_BAD_ARG; + ref_put(&ran->ref, ran_discrete_release); + return RES_OK; +} + +size_t +ssp_ranst_discrete_get(struct ssp_rng* rng, const struct ssp_ranst_discrete* ran) +{ + class rng_cxx r(*rng); + return ran->distrib->operator()(r); +} + +double +ssp_ranst_discrete_pdf(const size_t i, const struct ssp_ranst_discrete* ran) +{ + ASSERT(ran && i < darray_double_size_get(&ran->pdf)); + return darray_double_cdata_get(&ran->pdf)[i]; +} + +/******************************************************************************* * Gaussian distribution exported functions ******************************************************************************/ + res_T -ssp_ran_gaussian_create +ssp_ranst_gaussian_create (struct mem_allocator* allocator, - struct ssp_ran_type** out_ran) + struct ssp_ranst_gaussian** out_ran) { - ssp_ran_type* ran = nullptr; - ran_gaussian_state* state; - void* tmp = nullptr; + ssp_ranst_gaussian* ran = nullptr; + void* mem = nullptr; res_T res = RES_OK; if (!out_ran) @@ -86,61 +236,54 @@ ssp_ran_gaussian_create allocator = allocator ? allocator : &mem_default_allocator; - ran = static_cast<ssp_ran_type*>(MEM_CALLOC(allocator, 1, sizeof(ssp_ran_type))); + ran = static_cast<ssp_ranst_gaussian*>( + MEM_CALLOC(allocator, 1, sizeof(ssp_ranst_gaussian))); if (!ran) { res = RES_MEM_ERR; goto err; } ref_init(&ran->ref); - state = static_cast<ran_gaussian_state*>( - MEM_CALLOC(allocator, 1, sizeof(ran_gaussian_state))); - ran->state = state; - if (!state) { - res = RES_MEM_ERR; - goto err; - } - tmp = MEM_ALLOC(allocator, sizeof(normal_dist)); - if (!tmp) { + + mem = MEM_ALLOC(allocator, sizeof(normal_dist)); + if (!mem) { res = RES_MEM_ERR; goto err; } ran->allocator = allocator; - state->distrib = static_cast<normal_dist*>(new(tmp) normal_dist); - state->K1 = -1; /* invalid */ + ran->distrib = static_cast<normal_dist*>(new(mem) normal_dist); + ran->K1 = -1; /* invalid */ if (out_ran) *out_ran = ran; end: return res; err: if (ran) { - ref_put(&ran->ref, gaussian_release); + SSP(ranst_gaussian_ref_put(ran)); ran = nullptr; } goto end; } res_T -ssp_ran_gaussian_init - (struct ssp_ran_type* ran, +ssp_ranst_gaussian_setup + (struct ssp_ranst_gaussian* ran, double mu, double sigma) { - ran_gaussian_state* state; if (!ran || sigma < 0) return RES_BAD_ARG; normal_dist::param_type p{mu, sigma}; - state = static_cast<ran_gaussian_state*>(ran->state); - state->distrib->param(p); - state->mu = mu; - state->K1 = 1.0 / sigma; - state->K2 = 1.0 / (sigma * SQRT_2_PI); + ran->distrib->param(p); + ran->mu = mu; + ran->K1 = 1.0 / sigma; + ran->K2 = 1.0 / (sigma * SQRT_2_PI); return RES_OK; } res_T -ssp_ran_gaussian_ref_get - (struct ssp_ran_type* ran) +ssp_ranst_gaussian_ref_get + (struct ssp_ranst_gaussian* ran) { if(!ran) return RES_BAD_ARG; ref_get(&ran->ref); @@ -148,8 +291,8 @@ ssp_ran_gaussian_ref_get } res_T -ssp_ran_gaussian_ref_put - (struct ssp_ran_type* ran) +ssp_ranst_gaussian_ref_put + (struct ssp_ranst_gaussian* ran) { if(!ran) return RES_BAD_ARG; ref_put(&ran->ref, gaussian_release); @@ -157,23 +300,21 @@ ssp_ran_gaussian_ref_put } double -ssp_ran_gaussian_get - (const struct ssp_ran_type* ran, struct ssp_rng* rng) +ssp_ranst_gaussian_get + (const struct ssp_ranst_gaussian* ran, struct ssp_rng* rng) { class rng_cxx r(*rng); - ran_gaussian_state* state = static_cast<ran_gaussian_state*>(ran->state); - ASSERT(state->K1 > 0); - return state->distrib->operator()(r); + ASSERT(ran->K1 > 0); + return ran->distrib->operator()(r); } double -ssp_ran_gaussian_pdf - (const struct ssp_ran_type* ran, double x) +ssp_ranst_gaussian_pdf + (const struct ssp_ranst_gaussian* ran, double x) { - ran_gaussian_state* state = static_cast<ran_gaussian_state*>(ran->state); - const double tmp = (x - state->mu) * state->K1; - ASSERT(state->K1 > 0); - return state->K2 * exp(-0.5 * tmp * tmp); + const double tmp = (x - ran->mu) * ran->K1; + ASSERT(ran->K1 > 0); + return ran->K2 * exp(-0.5 * tmp * tmp); } /******************************************************************************* @@ -181,13 +322,12 @@ ssp_ran_gaussian_pdf ******************************************************************************/ res_T -ssp_ran_piecewise_linear_create +ssp_ranst_piecewise_linear_create (struct mem_allocator* allocator, - struct ssp_ran_type** out_ran) + struct ssp_ranst_piecewise_linear** out_ran) { - ssp_ran_type* ran = nullptr; - ran_piecewise_linear_state* state; - void* tmp = nullptr; + ssp_ranst_piecewise_linear* ran = nullptr; + void* mem = nullptr; res_T res = RES_OK; if (!out_ran) @@ -195,40 +335,35 @@ ssp_ran_piecewise_linear_create allocator = allocator ? allocator : &mem_default_allocator; - ran = static_cast<ssp_ran_type*>(MEM_CALLOC(allocator, 1, sizeof(ssp_ran_type))); + ran = static_cast<ssp_ranst_piecewise_linear*>( + MEM_CALLOC(allocator, 1, sizeof(ssp_ranst_piecewise_linear))); if (!ran) { res = RES_MEM_ERR; goto err; } ref_init(&ran->ref); - state = static_cast<ran_piecewise_linear_state*>( - MEM_CALLOC(allocator, 1, sizeof(ran_piecewise_linear_state))); - ran->state = state; - if (!state) { - res = RES_MEM_ERR; - goto err; - } - tmp = MEM_ALLOC(allocator, sizeof(piecewise_dist)); - if (!tmp) { + + mem = MEM_ALLOC(allocator, sizeof(piecewise_dist)); + if (!mem) { res = RES_MEM_ERR; goto err; } ran->allocator = allocator; - state->distrib = static_cast<piecewise_dist*>(new(tmp) piecewise_dist); + ran->distrib = static_cast<piecewise_dist*>(new(mem) piecewise_dist); if (out_ran) *out_ran = ran; end: return res; err: if (ran) { - ref_put(&ran->ref, piecewise_release); + SSP(ranst_piecewise_linear_ref_put(ran)); ran = nullptr; } goto end; } res_T -ssp_ran_piecewise_linear_init - (struct ssp_ran_type* ran, +ssp_ranst_piecewise_linear_setup + (struct ssp_ranst_piecewise_linear* ran, const double* intervals, const double* weights, size_t size) @@ -237,16 +372,14 @@ ssp_ran_piecewise_linear_init return RES_BAD_ARG; piecewise_dist::param_type p{intervals, intervals + size, weights}; - ran_piecewise_linear_state* state - = static_cast<ran_piecewise_linear_state*>(ran->state); - state->distrib->param(p); + ran->distrib->param(p); return RES_OK; } res_T -ssp_ran_piecewise_linear_ref_get - (struct ssp_ran_type* ran) +ssp_ranst_piecewise_linear_ref_get + (struct ssp_ranst_piecewise_linear* ran) { if(!ran) return RES_BAD_ARG; ref_get(&ran->ref); @@ -254,8 +387,8 @@ ssp_ran_piecewise_linear_ref_get } res_T -ssp_ran_piecewise_linear_ref_put - (struct ssp_ran_type* ran) +ssp_ranst_piecewise_linear_ref_put + (struct ssp_ranst_piecewise_linear* ran) { if(!ran) return RES_BAD_ARG; ref_put(&ran->ref, piecewise_release); @@ -263,12 +396,10 @@ ssp_ran_piecewise_linear_ref_put } double -ssp_ran_piecewise_linear_get - (const struct ssp_ran_type* ran, +ssp_ranst_piecewise_linear_get + (const struct ssp_ranst_piecewise_linear* ran, struct ssp_rng* rng) { class rng_cxx r(*rng); - ran_piecewise_linear_state* state - = static_cast<ran_piecewise_linear_state*>(ran->state); - return state->distrib->operator()(r); + return ran->distrib->operator()(r); } diff --git a/src/ssp_ran_discrete.c b/src/ssp_ran_discrete.c @@ -1,203 +0,0 @@ -/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com) - * - * This software is a library whose purpose is to generate [pseudo] random - * numbers and random variates. - * - * This software is governed by the CeCILL license under French law and - * abiding by the rules of distribution of free software. You can use, - * modify and/or redistribute the software under the terms of the CeCILL - * license as circulated by CEA, CNRS and INRIA at the following URL - * "http://www.cecill.info". - * - * As a counterpart to the access to the source code and rights to copy, - * modify and redistribute granted by the license, users are provided only - * with a limited warranty and the software's author, the holder of the - * economic rights, and the successive licensors have only limited - * liability. - * - * In this respect, the user's attention is drawn to the risks associated - * with loading, using, modifying and/or developing or reproducing the - * software by the user in light of its specific status of free software, - * that may mean that it is complicated to manipulate, and that also - * therefore means that it is reserved for developers and experienced - * professionals having in-depth computer knowledge. Users are therefore - * encouraged to load and test the software's suitability as regards their - * requirements in conditions enabling the security of their systems and/or - * data to be ensured and, more generally, to use and operate it in the - * same conditions as regards security. - * - * The fact that you are presently reading this means that you have had - * knowledge of the CeCILL license and that you accept its terms. */ - -#include "ssp.h" - -#include <rsys/algorithm.h> -#include <rsys/dynamic_array_double.h> -#include <rsys/mem_allocator.h> -#include <rsys/ref_count.h> - -struct ssp_ran_discrete { - struct darray_double cdf; - struct darray_double pdf; - ref_T ref; - struct mem_allocator* allocator; -}; - -/******************************************************************************* - * Helper function - ******************************************************************************/ -static FINLINE int -cmp_double(const void* key, const void* val) -{ - const double* a = (const double*)key; - const double* b = (const double*)val; - ASSERT(a && b); - return *a < *b ? -1 : *a > *b ? 1 : 0; -} - -static void -ran_discrete_release(ref_T* ref) -{ - struct ssp_ran_discrete* ran; - ASSERT(ref); - ran = CONTAINER_OF(ref, struct ssp_ran_discrete, ref); - darray_double_release(&ran->cdf); - darray_double_release(&ran->pdf); - MEM_RM(ran->allocator, ran); -} - -/******************************************************************************* - * Exported functions - ******************************************************************************/ -res_T -ssp_ran_discrete_create - (struct mem_allocator* mem_allocator, - struct ssp_ran_discrete** out_ran) -{ - struct mem_allocator* allocator = NULL; - struct ssp_ran_discrete* ran = NULL; - res_T res = RES_OK; - - if(!out_ran) { - res = RES_BAD_ARG; - goto error; - } - allocator = mem_allocator ? mem_allocator : &mem_default_allocator; - ran = (struct ssp_ran_discrete*) - MEM_CALLOC(allocator, 1, sizeof(struct ssp_ran_discrete)); - if(!ran) { - res = RES_MEM_ERR; - goto error; - } - ref_init(&ran->ref); - ran->allocator = allocator; - darray_double_init(allocator, &ran->cdf); - darray_double_init(allocator, &ran->pdf); - -exit: - if(out_ran) *out_ran = ran; - return res; -error: - if(ran) { - SSP(ran_discrete_ref_put(ran)); - ran = NULL; - } - goto exit; -} - -res_T -ssp_ran_discrete_setup - (struct ssp_ran_discrete* ran, - const double* weights, - const size_t nweights) -{ - double* cdf; - double* pdf; - size_t i; - res_T res = RES_OK; - - if(!ran || !weights || !nweights) { - res = RES_BAD_ARG; - goto error; - } - - res = darray_double_resize(&ran->cdf, nweights); - if(res != RES_OK) goto error; - res = darray_double_resize(&ran->pdf, nweights); - if(res != RES_OK) goto error; - - cdf = darray_double_data_get(&ran->cdf); - pdf = darray_double_data_get(&ran->pdf); - - if(weights[0] < 0.f) { - res = RES_BAD_ARG; - goto error; - } - pdf[0] = weights[0]; - cdf[0] = weights[0]; - FOR_EACH(i, 1, nweights) { - if(weights[i] < 0.f) { - res = RES_BAD_ARG; - goto error; - } - pdf[i] = weights[i]; - cdf[i] = weights[i] + cdf[i-1]; - } - if(!eq_eps(weights[nweights-1], 1.0, 1.e-8)) { - /* Normalize the weights */ - const double len = cdf[nweights-1]; - FOR_EACH(i, 0, nweights) { - pdf[i] /= len; - cdf[i] /= len; - } - } - -exit: - return res; -error: - if(ran) { - darray_double_clear(&ran->cdf); - darray_double_clear(&ran->pdf); - } - goto exit; -} - -res_T -ssp_ran_discrete_ref_get(struct ssp_ran_discrete* ran) -{ - if(!ran) return RES_BAD_ARG; - ref_get(&ran->ref); - return RES_OK; -} - -res_T -ssp_ran_discrete_ref_put(struct ssp_ran_discrete* ran) -{ - if(!ran) return RES_BAD_ARG; - ref_put(&ran->ref, ran_discrete_release); - return RES_OK; -} - -size_t -ssp_ran_discrete(struct ssp_rng* rng, struct ssp_ran_discrete* ran) -{ - const double* found; - double r; - ASSERT(rng && ran && darray_double_size_get(&ran->cdf) != 0); - - r = ssp_rng_canonical(rng); - found = (const double*)search_lower_bound(&r, - darray_double_cdata_get(&ran->cdf), - darray_double_size_get(&ran->cdf), - sizeof(double), cmp_double); - ASSERT(found && *found >= r); - return found - darray_double_cdata_get(&ran->cdf); -} - -double -ssp_ran_discrete_pdf(const size_t i, struct ssp_ran_discrete* ran) -{ - ASSERT(ran && i < darray_double_size_get(&ran->pdf)); - return darray_double_cdata_get(&ran->pdf)[i]; -} - diff --git a/src/test_ssp_ran_discrete.c b/src/test_ssp_ran_discrete.c @@ -40,7 +40,7 @@ int main(int argc, char** argv) { struct mem_allocator allocator; - struct ssp_ran_discrete* ran; + struct ssp_ranst_discrete* ran; struct ssp_rng* rng; const double weights[] = { 0.5, 0.1, 0.2, 0.05, 0.15 }; const size_t nweights = sizeof(weights)/sizeof(double); @@ -52,32 +52,32 @@ main(int argc, char** argv) mem_init_proxy_allocator(&allocator, &mem_default_allocator); CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK); - CHECK(ssp_ran_discrete_create(NULL, NULL), RES_BAD_ARG); - CHECK(ssp_ran_discrete_create(NULL, &ran), RES_OK); + CHECK(ssp_ranst_discrete_create(NULL, NULL), RES_BAD_ARG); + CHECK(ssp_ranst_discrete_create(NULL, &ran), RES_OK); - CHECK(ssp_ran_discrete_ref_get(NULL), RES_BAD_ARG); - CHECK(ssp_ran_discrete_ref_get(ran), RES_OK); - CHECK(ssp_ran_discrete_ref_put(NULL), RES_BAD_ARG); - CHECK(ssp_ran_discrete_ref_put(ran), RES_OK); - CHECK(ssp_ran_discrete_ref_put(ran), RES_OK); + CHECK(ssp_ranst_discrete_ref_get(NULL), RES_BAD_ARG); + CHECK(ssp_ranst_discrete_ref_get(ran), RES_OK); + CHECK(ssp_ranst_discrete_ref_put(NULL), RES_BAD_ARG); + CHECK(ssp_ranst_discrete_ref_put(ran), RES_OK); + CHECK(ssp_ranst_discrete_ref_put(ran), RES_OK); - CHECK(ssp_ran_discrete_create(&allocator, &ran), RES_OK); + CHECK(ssp_ranst_discrete_create(&allocator, &ran), RES_OK); - CHECK(ssp_ran_discrete_setup(NULL, NULL, 0), RES_BAD_ARG); - CHECK(ssp_ran_discrete_setup(ran, NULL, 0), RES_BAD_ARG); - CHECK(ssp_ran_discrete_setup(NULL, weights, 0), RES_BAD_ARG); - CHECK(ssp_ran_discrete_setup(ran, weights, 0), RES_BAD_ARG); - CHECK(ssp_ran_discrete_setup(NULL, NULL, nweights), RES_BAD_ARG); - CHECK(ssp_ran_discrete_setup(ran, NULL, nweights), RES_BAD_ARG); - CHECK(ssp_ran_discrete_setup(NULL, weights, nweights), RES_BAD_ARG); - CHECK(ssp_ran_discrete_setup(ran, weights, nweights), RES_OK); + CHECK(ssp_ranst_discrete_setup(NULL, NULL, 0), RES_BAD_ARG); + CHECK(ssp_ranst_discrete_setup(ran, NULL, 0), RES_BAD_ARG); + CHECK(ssp_ranst_discrete_setup(NULL, weights, 0), RES_BAD_ARG); + CHECK(ssp_ranst_discrete_setup(ran, weights, 0), RES_BAD_ARG); + CHECK(ssp_ranst_discrete_setup(NULL, NULL, nweights), RES_BAD_ARG); + CHECK(ssp_ranst_discrete_setup(ran, NULL, nweights), RES_BAD_ARG); + CHECK(ssp_ranst_discrete_setup(NULL, weights, nweights), RES_BAD_ARG); + CHECK(ssp_ranst_discrete_setup(ran, weights, nweights), RES_OK); memset(tmp, 0, sizeof(tmp)); FOR_EACH(i, 0, NSAMPS) { - const size_t k = ssp_ran_discrete(rng, ran); + const size_t k = ssp_ranst_discrete_get(rng, ran); double pdf; CHECK(k < nweights, 1); - pdf = ssp_ran_discrete_pdf(k, ran); + pdf = ssp_ranst_discrete_pdf(k, ran); ++tmp[k]; CHECK(pdf, weights[k]); CHECK(pdf >= 0.f, 1); @@ -87,19 +87,19 @@ main(int argc, char** argv) NCHECK(tmp[i], 0); } - CHECK(ssp_ran_discrete_setup(ran, weights, nweights-1), RES_OK); + CHECK(ssp_ranst_discrete_setup(ran, weights, nweights-1), RES_OK); FOR_EACH(i, 0, NSAMPS) { - const size_t k = ssp_ran_discrete(rng, ran); + const size_t k = ssp_ranst_discrete_get(rng, ran); double pdf; CHECK(k < nweights-1, 1); - pdf = ssp_ran_discrete_pdf(k, ran); + pdf = ssp_ranst_discrete_pdf(k, ran); CHECK(pdf >= 0.f, 1); CHECK(pdf <= 1.f, 1); } accum = 0; - FOR_EACH(i, 0, nweights-1) accum += ssp_ran_discrete_pdf(i, ran); + FOR_EACH(i, 0, nweights-1) accum += ssp_ranst_discrete_pdf(i, ran); CHECK(eq_eps(accum, 1, 1.e-8), 1); - CHECK(ssp_ran_discrete_ref_put(ran), RES_OK); + CHECK(ssp_ranst_discrete_ref_put(ran), RES_OK); CHECK(ssp_rng_ref_put(rng), RES_OK); check_memory_allocator(&allocator); diff --git a/src/test_ssp_ran_gaussian.c b/src/test_ssp_ran_gaussian.c @@ -40,7 +40,7 @@ main(int argc, char** argv) struct ssp_rng_proxy* proxy; struct ssp_rng* rng; struct mem_allocator allocator; - struct ssp_ran_type *gaussian; + struct ssp_ranst_gaussian *gaussian; int i; double x = 0, x2 = 0; double exp_mean = 10, mean; @@ -54,26 +54,26 @@ main(int argc, char** argv) CHECK(ssp_rng_proxy_create(&allocator, &ssp_rng_threefry, 1, &proxy), RES_OK); CHECK(ssp_rng_proxy_create_rng(proxy, 0, &rng), RES_OK); - CHECK(ssp_ran_gaussian_create(NULL, NULL), RES_BAD_ARG); - CHECK(ssp_ran_gaussian_create(NULL, &gaussian), RES_OK); - CHECK(ssp_ran_gaussian_ref_put(gaussian), RES_OK); + CHECK(ssp_ranst_gaussian_create(NULL, NULL), RES_BAD_ARG); + CHECK(ssp_ranst_gaussian_create(NULL, &gaussian), RES_OK); + CHECK(ssp_ranst_gaussian_ref_put(gaussian), RES_OK); - CHECK(ssp_ran_gaussian_create(&allocator, NULL), RES_BAD_ARG); - CHECK(ssp_ran_gaussian_create(&allocator, &gaussian), RES_OK); + CHECK(ssp_ranst_gaussian_create(&allocator, NULL), RES_BAD_ARG); + CHECK(ssp_ranst_gaussian_create(&allocator, &gaussian), RES_OK); - CHECK(ssp_ran_gaussian_init(NULL, exp_mean, exp_std), RES_BAD_ARG); - CHECK(ssp_ran_gaussian_init(gaussian, exp_mean, -1), RES_BAD_ARG); - CHECK(ssp_ran_gaussian_init(gaussian, exp_mean, exp_std), RES_OK); + CHECK(ssp_ranst_gaussian_setup(NULL, exp_mean, exp_std), RES_BAD_ARG); + CHECK(ssp_ranst_gaussian_setup(gaussian, exp_mean, -1), RES_BAD_ARG); + CHECK(ssp_ranst_gaussian_setup(gaussian, exp_mean, exp_std), RES_OK); - CHECK(ssp_ran_gaussian_ref_get(NULL), RES_BAD_ARG); - CHECK(ssp_ran_gaussian_ref_get(gaussian), RES_OK); + CHECK(ssp_ranst_gaussian_ref_get(NULL), RES_BAD_ARG); + CHECK(ssp_ranst_gaussian_ref_get(gaussian), RES_OK); - CHECK(ssp_ran_gaussian_ref_put(NULL), RES_BAD_ARG); - CHECK(ssp_ran_gaussian_ref_put(gaussian), RES_OK); + CHECK(ssp_ranst_gaussian_ref_put(NULL), RES_BAD_ARG); + CHECK(ssp_ranst_gaussian_ref_put(gaussian), RES_OK); time_current(&start); for (i = 0; i < NBS; i++) { - double _x = ssp_ran_gaussian_get(gaussian, rng); + double _x = ssp_ranst_gaussian_get(gaussian, rng); x += _x; x2 += _x * _x; } @@ -109,7 +109,7 @@ main(int argc, char** argv) CHECK(fabs(mean - exp_mean) < 0.003, 1); CHECK(fabs(std - exp_std) < 0.001, 1); - CHECK(ssp_ran_gaussian_ref_put(gaussian), RES_OK); + CHECK(ssp_ranst_gaussian_ref_put(gaussian), RES_OK); CHECK(ssp_rng_ref_put(rng), RES_OK); CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK); diff --git a/src/test_ssp_ran_piecewise_linear.c b/src/test_ssp_ran_piecewise_linear.c @@ -39,7 +39,7 @@ main(int argc, char** argv) struct ssp_rng_proxy* proxy; struct ssp_rng* rng; struct mem_allocator allocator; - struct ssp_ran_type *pwl; + struct ssp_ranst_piecewise_linear *pwl; int i; double exp_mean = 5, mean; double exp_std = 10 / sqrt(12) /*sqrt((b - a)² / 12) */, std; @@ -53,27 +53,27 @@ main(int argc, char** argv) CHECK(ssp_rng_proxy_create(&allocator, &ssp_rng_threefry, 1, &proxy), RES_OK); CHECK(ssp_rng_proxy_create_rng(proxy, 0, &rng), RES_OK); - CHECK(ssp_ran_piecewise_linear_create(NULL, NULL), RES_BAD_ARG); - CHECK(ssp_ran_piecewise_linear_create(NULL, &pwl), RES_OK); - CHECK(ssp_ran_piecewise_linear_ref_put(pwl), RES_OK); + CHECK(ssp_ranst_piecewise_linear_create(NULL, NULL), RES_BAD_ARG); + CHECK(ssp_ranst_piecewise_linear_create(NULL, &pwl), RES_OK); + CHECK(ssp_ranst_piecewise_linear_ref_put(pwl), RES_OK); - CHECK(ssp_ran_piecewise_linear_create(&allocator, NULL), RES_BAD_ARG); - CHECK(ssp_ran_piecewise_linear_create(&allocator, &pwl), RES_OK); + CHECK(ssp_ranst_piecewise_linear_create(&allocator, NULL), RES_BAD_ARG); + CHECK(ssp_ranst_piecewise_linear_create(&allocator, &pwl), RES_OK); - CHECK(ssp_ran_piecewise_linear_init(NULL, intervals, weights, sizeof(intervals)/sizeof(double)), RES_BAD_ARG); - CHECK(ssp_ran_piecewise_linear_init(pwl, NULL, weights, sizeof(intervals)/sizeof(double)), RES_BAD_ARG); - CHECK(ssp_ran_piecewise_linear_init(pwl, intervals, NULL, sizeof(intervals)/sizeof(double)), RES_BAD_ARG); - CHECK(ssp_ran_piecewise_linear_init(pwl, intervals, weights, 1), RES_BAD_ARG); - CHECK(ssp_ran_piecewise_linear_init(pwl, intervals, weights, sizeof(intervals)/sizeof(double)), RES_OK); + CHECK(ssp_ranst_piecewise_linear_setup(NULL, intervals, weights, sizeof(intervals)/sizeof(double)), RES_BAD_ARG); + CHECK(ssp_ranst_piecewise_linear_setup(pwl, NULL, weights, sizeof(intervals)/sizeof(double)), RES_BAD_ARG); + CHECK(ssp_ranst_piecewise_linear_setup(pwl, intervals, NULL, sizeof(intervals)/sizeof(double)), RES_BAD_ARG); + CHECK(ssp_ranst_piecewise_linear_setup(pwl, intervals, weights, 1), RES_BAD_ARG); + CHECK(ssp_ranst_piecewise_linear_setup(pwl, intervals, weights, sizeof(intervals)/sizeof(double)), RES_OK); - CHECK(ssp_ran_piecewise_linear_ref_get(NULL), RES_BAD_ARG); - CHECK(ssp_ran_piecewise_linear_ref_get(pwl), RES_OK); + CHECK(ssp_ranst_piecewise_linear_ref_get(NULL), RES_BAD_ARG); + CHECK(ssp_ranst_piecewise_linear_ref_get(pwl), RES_OK); - CHECK(ssp_ran_piecewise_linear_ref_put(NULL), RES_BAD_ARG); - CHECK(ssp_ran_piecewise_linear_ref_put(pwl), RES_OK); + CHECK(ssp_ranst_piecewise_linear_ref_put(NULL), RES_BAD_ARG); + CHECK(ssp_ranst_piecewise_linear_ref_put(pwl), RES_OK); for (i = 0; i < NBS; i++) { - double _x = ssp_ran_piecewise_linear_get(pwl, rng); + double _x = ssp_ranst_piecewise_linear_get(pwl, rng); CHECK(0 <= _x && _x <= 10, 1); x += _x; x2 += _x * _x; @@ -85,7 +85,7 @@ main(int argc, char** argv) CHECK(fabs(mean - exp_mean) < 0.001, 1); CHECK(fabs(std - exp_std) < 0.001, 1); - CHECK(ssp_ran_piecewise_linear_ref_put(pwl), RES_OK); + CHECK(ssp_ranst_piecewise_linear_ref_put(pwl), RES_OK); CHECK(ssp_rng_ref_put(rng), RES_OK); CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK);