star-sp

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

commit 70f003a188d55e51a16e4b6ce97a16b8f45e8c19
parent 33a383a157ae3108e766d6bd79d39964dbd7b147
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Mon,  8 Oct 2018 17:24:10 +0200

Merge branch 'release_0.8'

Diffstat:
MREADME.md | 12++++++++++--
Mcmake/CMakeLists.txt | 23+++++++++++++++--------
Msrc/ssp.h | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/ssp_ran.c | 58+++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/ssp_rng.c | 6+++++-
Asrc/test_ssp_ran_sphere_cap.c | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/test_ssp_ran_sphere_cap.h | 147+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 347 insertions(+), 14 deletions(-)

diff --git a/README.md b/README.md @@ -34,10 +34,18 @@ variable to the directory that contains the `boost` include directory. ## Release notes +### Version 0.8 + +- Add the `ssp_ran_sphere_cap_uniform[_local][_float]` random variates that + uniformly distributes a point onto a unit sphere cap centered in zero. +- Fix the allocation of the `ssp_rng` data structure: the `ssp_rng` structure + contains a long double attribute that might be not correctly aligned on 16 + bytes. + ### Version 0.7 -- Add the `ssp_ran_circle_uniform` random variate that uniformly distribute a 2 - dimensional position onto a unit circle. +- Add the `ssp_ran_circle_uniform` random variate that uniformly distributes a + 2 dimensional position onto a unit circle. ### Version 0.6 diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -29,7 +29,7 @@ # The fact that you are presently reading this means that you have had # knowledge of the CeCILL license and that you accept its terms. -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.0) project(star-sp C CXX) enable_testing() @@ -54,7 +54,7 @@ include(rcmake_runtime) if(MSVC) # Currently, the C++11 random library on MSVC is bugged and consequently we # use the Boost library instead - find_package(Boost 1.58 REQUIRED COMPONENTS random) + find_package(Boost 1.67 REQUIRED COMPONENTS random) add_definitions(-DUSE_BOOST_RANDOM) include_directories(${RSys_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ${Random123_INCLUDE_DIR}) else() @@ -71,7 +71,7 @@ rcmake_append_runtime_dirs(_runtime_dirs RSys ${Boost_LIBRARY_DIRS}) # Configure and define targets ################################################################################ set(VERSION_MAJOR 0) -set(VERSION_MINOR 7) +set(VERSION_MINOR 8) set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) @@ -98,6 +98,12 @@ rcmake_prepend_path(SSP_FILES_INC_API ${SSP_SOURCE_DIR}) rcmake_prepend_path(SSP_FILES_DOC ${PROJECT_SOURCE_DIR}/../) set_source_files_properties(${SSP_FILES_SRC} PROPERTIES LANGUAGE CXX) +if(CMAKE_COMPILER_IS_GNUCXX) + # Random123 warning that cannot be disabled by a GCC pragma + set_source_files_properties(${SSP_SOURCE_DIR}/ssp_rng.c PROPERTIES + COMPILE_FLAGS "-Wno-expansion-to-defined") +endif() + add_library(ssp SHARED ${SSP_FILES_SRC} ${SSP_FILES_INC} ${SSP_FILES_INC_API}) set_target_properties(ssp PROPERTIES DEFINE_SYMBOL SSP_SHARED_BUILD @@ -161,15 +167,16 @@ if(NOT NO_TEST) if(BUILD_R123_AES) register_test(test_ssp_rng_aes test_ssp_rng aes) endif() + new_test(test_ssp_ran_circle ${MATH_LIB}) new_test(test_ssp_ran_discrete) + new_test(test_ssp_ran_gaussian) new_test(test_ssp_ran_hemisphere ${MATH_LIB}) - new_test(test_ssp_ran_sphere ${MATH_LIB}) - new_test(test_ssp_ran_circle ${MATH_LIB}) new_test(test_ssp_ran_hg ${MATH_LIB}) - 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) + new_test(test_ssp_rng_proxy) + new_test(test_ssp_ran_sphere ${MATH_LIB}) + new_test(test_ssp_ran_sphere_cap ${MATH_LIB}) + new_test(test_ssp_ran_triangle ${MATH_LIB}) new_test(test_ssp_ran_uniform_disk) rcmake_copy_runtime_libraries(test_ssp_rng) endif() diff --git a/src/ssp.h b/src/ssp.h @@ -74,7 +74,7 @@ struct ssp_rng_type { res_T (*set)(void* state, const uint64_t seed); uint64_t (*get)(void* state); - res_T(*discard)(void* state, uint64_t n); + res_T (*discard)(void* state, uint64_t n); res_T (*read)(void* state, FILE* file); res_T (*write)(const void* state, FILE* file); double (*entropy)(const void* state); @@ -303,7 +303,7 @@ ssp_ran_exp_float_pdf /* 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 */ + * P(x) dx = 1 / (sigma*sqrt(2*PI)) * exp(-1/2*((x-mu)/sigma)^2) dx */ SSP_API double ssp_ran_gaussian (struct ssp_rng* rng, @@ -927,6 +927,74 @@ ssp_ran_uniform_disk_float return f33_mulf3(pt, f33_basis(basis, up), sample_local); } +/******************************************************************************* + * Uniform distribution of a point ont a sphere cap + * pdf = 1/(2*PI*(1-cos(theta_max)) + ******************************************************************************/ +/* Uniform sampling of unit sphere cap centered in zero whose up direction + * is implicity the Z axis. */ +SSP_API double* +ssp_ran_sphere_cap_uniform_local + (struct ssp_rng* rng, + /* In [-1, 1]. Height where the sphere cap begins. It equal cos(theta_max) + * where theta_max is the aperture angle from the up axis */ + const double height, + double sample[3], + double* pdf); /* Can be NULL => pdf not computed */ + +SSP_API float* +ssp_ran_sphere_cap_uniform_float_local + (struct ssp_rng* rng, + const float height, /* In [-1, 1]. Height of the sphere cap. */ + float sample[3], + float* pdf); /* Can be NULL => pdf not computed */ + +static INLINE double +ssp_ran_sphere_cap_uniform_pdf(const double height) +{ + ASSERT(height <= 1.0 && height >= -1.0); + return height == 1.0 ? INF : 1.0/(2.0*PI*(1-height)); +} + +static INLINE float +ssp_ran_sphere_cap_uniform_float_pdf(const float height) +{ + ASSERT(height <= 1.f && height >= -1.f); + return height == 1.f ? (float)INF : 1.f/(2.f*(float)PI*(1.f-height)); +} + +/* Uniform sampling of unit sphere cap centered in zero whose up direction + * is explicitly defined */ +static INLINE double* +ssp_ran_sphere_cap_uniform + (struct ssp_rng* rng, + const double up[3], + const double height, + double sample[3], + double* pdf) /* Can be NULL */ +{ + double sample_local[3]; + double basis[9]; + ASSERT(up); + ssp_ran_sphere_cap_uniform_local(rng, height, sample_local, pdf); + return d33_muld3(sample, d33_basis(basis, up), sample_local); +} + +static INLINE float* +ssp_ran_sphere_cap_uniform_float + (struct ssp_rng* rng, + const float up[3], + const float height, + float sample[3], + float* pdf) +{ + float sample_local[3]; + float basis[9]; + ASSERT(up); + ssp_ran_sphere_cap_uniform_float_local(rng, height, sample_local, pdf); + return f33_mulf3(sample, f33_basis(basis, up), sample_local); +} + END_DECLS #endif /* SSP_H */ diff --git a/src/ssp_ran.c b/src/ssp_ran.c @@ -219,7 +219,7 @@ ssp_ran_circle_uniform return sample; } -float* +float* ssp_ran_circle_uniform_float (struct ssp_rng* rng, float sample[2], @@ -521,3 +521,59 @@ ssp_ran_uniform_disk_float_local if (pdf) *pdf = 1 / (radius * radius); return pt; } + +double* +ssp_ran_sphere_cap_uniform_local + (struct ssp_rng* rng, + const double height, + double pt[3], + double* pdf) +{ + ASSERT(rng && pt && (height >= -1 || height <= 1)); + + if(height == 1) { + d3(pt, 0, 0, 1); + if(pdf) *pdf = INF; + } else if(height == -1) { + ssp_ran_sphere_uniform(rng, pt, pdf); + } else { + const double cos_aperture = height; + double phi, cos_theta, sin_theta; + phi = ssp_rng_uniform_double(rng, 0, 2.0*PI); + cos_theta = ssp_rng_uniform_double(rng, cos_aperture, 1); + sin_theta = cos2sin(cos_theta); + pt[0] = cos(phi) * sin_theta; + pt[1] = sin(phi) * sin_theta; + pt[2] = cos_theta; + if(pdf) *pdf = 1.0/(2.0*PI*(1.0-cos_aperture)); + } + return pt; +} + +float* +ssp_ran_sphere_cap_uniform_float_local + (struct ssp_rng* rng, + const float height, + float pt[3], + float* pdf) +{ + ASSERT(rng && pt && (height >= -1 || height <= 1)); + if(height == 1) { + f3(pt, 0, 0, 1); + if(pdf) *pdf = (float)INF; + } else if(height == -1) { + ssp_ran_sphere_uniform_float(rng, pt, pdf); + } else { + const float cos_aperture = height; + float phi, cos_theta, sin_theta; + phi = ssp_rng_uniform_float(rng, 0, 2.f*(float)PI); + cos_theta = ssp_rng_uniform_float(rng, cos_aperture, 1); + sin_theta = (float)cos2sin(cos_theta); + pt[0] = cosf(phi) * sin_theta; + pt[1] = sinf(phi) * sin_theta; + pt[2] = cos_theta; + if(pdf) *pdf = 1.f/(2.f*(float)PI*(1.f-cos_aperture)); + } + return pt; +} + diff --git a/src/ssp_rng.c b/src/ssp_rng.c @@ -479,11 +479,15 @@ ssp_rng_create } allocator = mem_allocator ? mem_allocator : &mem_default_allocator; - rng = (struct ssp_rng*)MEM_CALLOC(allocator, 1, sizeof(struct ssp_rng)); + + /* Align the rng on 16 bytes since its 'r' attrib is a long double that on + * Linux 64-bits systems must be aligned on 16 bytes. */ + rng = (struct ssp_rng*)MEM_ALLOC_ALIGNED(allocator, sizeof(*rng), 16); if(!rng) { res = RES_MEM_ERR; goto error; } + memset(rng, 0, sizeof(struct ssp_rng)); rng->allocator = allocator; ref_init(&rng->ref); diff --git a/src/test_ssp_ran_sphere_cap.c b/src/test_ssp_ran_sphere_cap.c @@ -0,0 +1,43 @@ +/* Copyright (C) |Meso|Star> 2015-2018 (contact@meso-star.com) + * + * 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. */ + +#define TYPE_FLOAT 0 +#include "test_ssp_ran_sphere_cap.h" + +#define TYPE_FLOAT 1 +#include "test_ssp_ran_sphere_cap.h" + +int +main(int argc, char** argv) +{ + (void)argc, (void)argv; + test_float(); + test_double(); + return 0; +} + diff --git a/src/test_ssp_ran_sphere_cap.h b/src/test_ssp_ran_sphere_cap.h @@ -0,0 +1,147 @@ +/* Copyright (C) |Meso|Star> 2015-2018 (contact@meso-star.com) + * + * 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. */ + +#ifndef TEST_SSP_RAN_SPHERE_CAP_H +#define TEST_SSP_RAN_SPHERE_CAP_H + +#include "ssp.h" +#include "test_ssp_utils.h" + +#define NSAMPS 1024 + +#endif /* TEST_SSP_RAN_SPHERE_H */ + +#if TYPE_FLOAT==0 + #define REAL double + #define TEST test_double + #define RAN_SPHERE_CAP_UNIFORM_LOCAL ssp_ran_sphere_cap_uniform_local + #define RAN_SPHERE_CAP_UNIFORM_PDF ssp_ran_sphere_cap_uniform_pdf + #define RAN_SPHERE_CAP_UNIFORM ssp_ran_sphere_cap_uniform + #define RAN_SPHERE_UNIFORM ssp_ran_sphere_uniform + #define EQ_EPS eq_eps + #define R3_EQ_EPS d3_eq_eps + #define R3_IS_NORMALIZED d3_is_normalized + #define R3_NORMALIZE d3_normalize + #define R3_DOT d3_dot +#elif TYPE_FLOAT==1 + #define REAL float + #define TEST test_float + #define RAN_SPHERE_CAP_UNIFORM_LOCAL ssp_ran_sphere_cap_uniform_float_local + #define RAN_SPHERE_CAP_UNIFORM_PDF ssp_ran_sphere_cap_uniform_float_pdf + #define RAN_SPHERE_CAP_UNIFORM ssp_ran_sphere_cap_uniform_float + #define RAN_SPHERE_UNIFORM ssp_ran_sphere_uniform_float + #define EQ_EPS eq_epsf + #define R3_EQ_EPS f3_eq_eps + #define R3_IS_NORMALIZED f3_is_normalized + #define R3_NORMALIZE f3_normalize + #define R3_DOT f3_dot +#else + #error "TYPE_FLOAT must be defined either 0 or 1" +#endif + +static void +TEST(void) +{ + struct ssp_rng* rng; + struct mem_allocator allocator; + REAL pdf; + REAL samps[NSAMPS][3]; + REAL up[3]; + int i, j; + + mem_init_proxy_allocator(&allocator, &mem_default_allocator); + CHK(ssp_rng_create(&allocator, &ssp_rng_mt19937_64, &rng) == RES_OK); + + CHK(RAN_SPHERE_CAP_UNIFORM_LOCAL(rng, 1, samps[0], &pdf) == samps[0]); + CHK(samps[0][0] == 0); + CHK(samps[0][1] == 0); + CHK(samps[0][2] == 1); + CHK(IS_INF(pdf)); + + CHK(RAN_SPHERE_CAP_UNIFORM_LOCAL(rng,-1, samps[0], &pdf) == samps[0]); + CHK(EQ_EPS(pdf, 1/(4*(REAL)PI), (REAL)1.e-6)); + + /* Check NULL pdf */ + CHK(RAN_SPHERE_CAP_UNIFORM_LOCAL(rng, (REAL)0.2, samps[0], NULL) == samps[0]); + + FOR_EACH(i, 0, NSAMPS) { + const REAL height = (REAL)-0.7; + CHK(RAN_SPHERE_CAP_UNIFORM_LOCAL(rng, height, samps[i], &pdf) == samps[i]); + CHK(R3_IS_NORMALIZED(samps[i])); + CHK(EQ_EPS(pdf, 1/(2*(REAL)PI*(1-height)), (REAL)1.e-6)); + CHK(EQ_EPS(pdf, RAN_SPHERE_CAP_UNIFORM_PDF(height), (REAL)1.e-6)); + CHK(samps[i][2] >= height); + FOR_EACH(j, 0, i) { + CHK(!R3_EQ_EPS(samps[j], samps[i], (REAL)1.e-6)); + } + } + + /* Sample an up vector */ + RAN_SPHERE_UNIFORM(rng, up, NULL); + + CHK(RAN_SPHERE_CAP_UNIFORM(rng, up, 1, samps[0], &pdf) == samps[0]); + CHK(R3_EQ_EPS(samps[0], up, (REAL)1.e-6)); + CHK(IS_INF(pdf)); + + CHK(RAN_SPHERE_CAP_UNIFORM(rng, up, -1, samps[0], &pdf) == samps[0]); + CHK(EQ_EPS(pdf, 1/(4*(REAL)PI), (REAL)1.e-6)); + + /* Check NULL pdf */ + CHK(RAN_SPHERE_CAP_UNIFORM(rng, up, (REAL)0.2, samps[0], NULL) == samps[0]); + + FOR_EACH(i, 0, NSAMPS) { + const REAL height = (REAL)0.3; + CHK(RAN_SPHERE_CAP_UNIFORM(rng, up, height, samps[i], &pdf) == samps[i]); + CHK(R3_IS_NORMALIZED(samps[i])); + CHK(EQ_EPS(pdf, 1/(2*(REAL)PI*(1-height)), (REAL)1.e-6)); + CHK(EQ_EPS(pdf, RAN_SPHERE_CAP_UNIFORM_PDF(height), (REAL)1.e-6)); + CHK(R3_DOT(up, samps[i]) >= height); + FOR_EACH(j, 0, i) { + CHK(!R3_EQ_EPS(samps[j], samps[i], (REAL)1.e-6)); + } + } + + ssp_rng_ref_put(rng); + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + + CHK(mem_allocated_size() == 0); +} + +#undef REAL +#undef TEST +#undef RAN_SPHERE_CAP_UNIFORM_LOCAL +#undef RAN_SPHERE_CAP_UNIFORM_PDF +#undef RAN_SPHERE_CAP_UNIFORM +#undef RAN_SPHERE_UNIFORM +#undef EQ_EPS +#undef R3_EQ_EPS +#undef R3_IS_NORMALIZED +#undef R3_NORMALIZE +#undef R3_DOT +#undef TYPE_FLOAT