star-sp

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

commit 8675beba45401991b00c05ac7fd9ba498575f7fb
parent 99643458cecabf51beaf15721ba7d104b121b9ac
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Mon,  4 Jul 2016 18:44:18 +0200

Add piecewise linear distribution

Diffstat:
Mcmake/CMakeLists.txt | 1+
Msrc/ssp.h | 29+++++++++++++++++++++++++++++
Msrc/ssp_distributions.cpp | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/ssp_distributions.h | 9+++++++++
Asrc/test_ssp_ran_piecewise_linear.c | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 258 insertions(+), 0 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -156,6 +156,7 @@ if(NOT NO_TEST) new_test(test_ssp_ran_triangle ${MATH_LIB}) new_test(test_ssp_rng_proxy) new_test(test_ssp_ran_gaussian) + new_test(test_ssp_ran_piecewise_linear) endif() ################################################################################ diff --git a/src/ssp.h b/src/ssp.h @@ -59,6 +59,7 @@ struct ssp_rng; struct ssp_rng_proxy; struct ssp_ran_discrete; struct ssp_ran_gaussian; +struct ssp_ran_piecewise_linear; /* Forward declaration of external types */ struct mem_allocator; @@ -609,6 +610,34 @@ SSP_API double ssp_distribution_gaussian_pdf (const struct ssp_ran_gaussian* ran, double x); +/******************************************************************************* + * Piecewise linear distribution + ******************************************************************************/ + +SSP_API res_T +ssp_ran_piecewise_linear_create + (struct mem_allocator* allocator, /* May be NULL <=> Use default allocator */ + struct ssp_ran_piecewise_linear **ran); + +SSP_API res_T +ssp_ran_piecewise_linear_init + (struct ssp_ran_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_piecewise_linear* ran); + +SSP_API res_T +ssp_ran_piecewise_linear_ref_put + (struct ssp_ran_piecewise_linear* ran); + +SSP_API double +ssp_ran_piecewise_linear_get + (const struct ssp_ran_piecewise_linear *ran, struct ssp_rng* rng); + END_DECLS #endif /* SSP_H */ diff --git a/src/ssp_distributions.cpp b/src/ssp_distributions.cpp @@ -33,6 +33,31 @@ gaussian_release(ref_T* ref) } /******************************************************************************* + * Piecewise linear distribution utilities + ******************************************************************************/ + +using piecewise_dist=RAN_NAMESPACE::piecewise_linear_distribution<double>; + +struct ran_piecewise_linear_state +{ + piecewise_dist *distrib; +}; + +static void +piecewise_release(ref_T* ref) +{ + ssp_ran_piecewise_linear* ran; + ASSERT(ref); + ran = CONTAINER_OF(ref, struct ssp_ran_piecewise_linear, ref); + if(ran->state) { + ran->state->distrib->~piecewise_dist(); + MEM_RM(ran->allocator, ran->state->distrib); + MEM_RM(ran->allocator, ran->state); + } + MEM_RM(ran->allocator, ran); +} + +/******************************************************************************* * Gaussian distribution exported functions ******************************************************************************/ res_T @@ -44,6 +69,9 @@ ssp_ran_gaussian_create void *tmp = nullptr; res_T res = RES_OK; + if (!allocator || !out_ran) + return RES_BAD_ARG; + allocator = allocator ? allocator : &mem_default_allocator; ran = static_cast<struct ssp_ran_gaussian*>( @@ -120,6 +148,7 @@ double ssp_ran_gaussian_get (const struct ssp_ran_gaussian *ran, struct ssp_rng* rng) { + if(!ran || !rng) return RES_BAD_ARG; class rng_cxx r(*rng); return ran->state->distrib->operator()(r); } @@ -128,6 +157,99 @@ double ssp_ran_gaussian_pdf (const struct ssp_ran_gaussian *ran, double x) { + if(!ran) return RES_BAD_ARG; const double tmp = (x - ran->state->mu) * ran->state->K1; return ran->state->K2 * exp(-0.5 * tmp * tmp); } + +/******************************************************************************* + * Piecewise linear distribution exported functions + ******************************************************************************/ + +res_T +ssp_ran_piecewise_linear_create + (struct mem_allocator* allocator, + struct ssp_ran_piecewise_linear **out_ran) +{ + ssp_ran_piecewise_linear *ran = nullptr; + void *tmp = nullptr; + res_T res = RES_OK; + + if (!allocator || !out_ran) + return RES_BAD_ARG; + + allocator = allocator ? allocator : &mem_default_allocator; + + ran = static_cast<ssp_ran_piecewise_linear*>( + MEM_CALLOC(allocator, 1, sizeof(ssp_ran_piecewise_linear))); + if (!ran) { + res = RES_MEM_ERR; + goto err; + } + ref_init(&ran->ref); + ran->state = static_cast<ran_piecewise_linear_state*>( + MEM_CALLOC(allocator, 1, sizeof(ran_piecewise_linear_state))); + if (!ran->state) { + res = RES_MEM_ERR; + goto err; + } + tmp = MEM_ALLOC(allocator, sizeof(piecewise_dist)); + if (!tmp) { + res = RES_MEM_ERR; + goto err; + } + ran->allocator = allocator; + ran->state->distrib = static_cast<piecewise_dist*>(new(tmp) piecewise_dist); + if (out_ran) *out_ran = ran; + end: + return res; + err: + if (ran) { + ref_put(&ran->ref, piecewise_release); + ran = nullptr; + } + goto end; +} + +res_T +ssp_ran_piecewise_linear_init + (struct ssp_ran_piecewise_linear *ran, + const double* intervals, + const double* weights, + size_t size) +{ + if (!ran || !intervals || !weights || size < 2) + return RES_BAD_ARG; + + piecewise_dist::param_type p{intervals, intervals + size, weights}; + ran->state->distrib->param(p); + + return RES_OK; +} + +res_T +ssp_ran_piecewise_linear_ref_get + (struct ssp_ran_piecewise_linear* ran) +{ + if(!ran) return RES_BAD_ARG; + ref_get(&ran->ref); + return RES_OK; +} + +res_T +ssp_ran_piecewise_linear_ref_put + (struct ssp_ran_piecewise_linear* ran) +{ + if(!ran) return RES_BAD_ARG; + ref_put(&ran->ref, piecewise_release); + return RES_OK; +} + +double +ssp_ran_piecewise_linear_get + (const struct ssp_ran_piecewise_linear *ran, struct ssp_rng* rng) +{ + if(!ran || !rng) return RES_BAD_ARG; + class rng_cxx r(*rng); + return ran->state->distrib->operator()(r); +} diff --git a/src/ssp_distributions.h b/src/ssp_distributions.h @@ -6,6 +6,7 @@ /* Forward declaration of opaque types */ struct ran_gaussian_state; +struct ran_piecewise_linear_state; /* Forward declaration of external types */ struct ssp_rng; @@ -19,4 +20,12 @@ struct ssp_ran_gaussian { struct ran_gaussian_state *state; }; +struct ssp_ran_piecewise_linear { + size_t sizeof_params; + size_t sizeof_state; + ref_T ref; + struct mem_allocator* allocator; + struct ran_piecewise_linear_state *state; +}; + #endif diff --git a/src/test_ssp_ran_piecewise_linear.c b/src/test_ssp_ran_piecewise_linear.c @@ -0,0 +1,97 @@ +/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com) + * + * This software is a program whose purpose is to test the spp library. + * + * 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 "test_ssp_utils.h" + +#define NBS 1000000 + +int +main(int argc, char** argv) +{ + struct ssp_rng_proxy* proxy; + struct ssp_rng* rng; + struct mem_allocator allocator; + struct ssp_ran_piecewise_linear *pwl; + int i; + double exp_mean = 5, mean; + double exp_std = 10 / sqrt(12) /*sqrt((b - a)² / 12) */, std; + double x = 0, x2 = 0; + const double intervals[] = { 0, 1, 3, 5, 7, 8, 10 }; + const double weights[] = { 1, 1, 1, 1, 1, 1, 1 }; + (void)argc, (void)argv; + + mem_init_proxy_allocator(&allocator, &mem_default_allocator); + + 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, &pwl), RES_BAD_ARG); + CHECK(ssp_ran_piecewise_linear_create(&allocator, NULL), RES_BAD_ARG); + CHECK(ssp_ran_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_ran_piecewise_linear_ref_get(NULL), RES_BAD_ARG); + CHECK(ssp_ran_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_ran_piecewise_linear_get(NULL, rng), RES_BAD_ARG); + CHECK(ssp_ran_piecewise_linear_get(pwl, NULL), RES_BAD_ARG); + + for (i = 0; i < NBS; i++) { + double _x = ssp_ran_piecewise_linear_get(pwl, rng); + CHECK(0 <= _x && _x <= 10, 1); + x += _x; + x2 += _x * _x; + } + + mean = x/NBS; + std = sqrt(x2/NBS - x/NBS*x/NBS); + printf("%g %g\n", mean, std); + 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_rng_ref_put(rng), RES_OK); + CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHECK(mem_allocated_size(), 0); + return 0; +}