star-sp

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

commit 543cf67f1416ff96ed4be215b044d9efda8c3913
parent 746f4b8ea0ebb9117c74b33cd577aa54518453dd
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Wed, 25 Oct 2017 17:50:32 +0200

Add world version of uniform_disk distribution.

Diffstat:
Msrc/ssp.h | 44++++++++++++++++++++++++++++++++++++--------
Msrc/ssp_ran.c | 10++++++----
Msrc/test_ssp_ran_uniform_disk.h | 72+++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
3 files changed, 95 insertions(+), 31 deletions(-)

diff --git a/src/ssp.h b/src/ssp.h @@ -833,35 +833,63 @@ ssp_ranst_piecewise_linear_float_pdf /******************************************************************************* * Uniform disk distribution. - * - * TODO: provide a world space version. ******************************************************************************/ SSP_API double* -ssp_ran_uniform_disk +ssp_ran_uniform_disk_local (struct ssp_rng* rng, const double radius, - double pt[2], + double pt[3], /* pt[2] <= 0 */ double* pdf); /* Can be NULL => pdf not computed */ SSP_API float* -ssp_ran_uniform_disk_float +ssp_ran_uniform_disk_float_local (struct ssp_rng* rng, const float radius, - float pt[2], + float pt[3], /* pt[2] <= 0 */ float* pdf); /* Can be NULL => pdf not computed */ static INLINE double -ssp_ran_uniform_disk_pdf(const double radius) +ssp_ran_uniform_disk_local_pdf(const double radius) { return 1 / (radius * radius); } static INLINE float -ssp_ran_uniform_disk_float_pdf(const float radius) +ssp_ran_uniform_disk_float_local_pdf(const float radius) { return 1 / (radius * radius); } +static INLINE double* +ssp_ran_uniform_disk + (struct ssp_rng* rng, + const double radius, + const double up[3], + double pt[3], + double* pdf) /* Can be NULL => pdf not computed */ +{ + double sample_local[3]; + double basis[9]; + ASSERT(rng && up && pt && radius > 0); + ssp_ran_uniform_disk_local(rng, radius, sample_local, pdf); + return d33_muld3(pt, d33_basis(basis, up), sample_local); +} + +static INLINE float* +ssp_ran_uniform_disk_float + (struct ssp_rng* rng, + const float radius, + const float up[3], + float pt[3], + float* pdf) /* Can be NULL => pdf not computed */ +{ + float sample_local[3]; + float basis[9]; + ASSERT(rng && up && pt && radius > 0); + ssp_ran_uniform_disk_float_local(rng, radius, sample_local, pdf); + return f33_mulf3(pt, f33_basis(basis, up), sample_local); +} + END_DECLS #endif /* SSP_H */ diff --git a/src/ssp_ran.c b/src/ssp_ran.c @@ -457,10 +457,10 @@ ssp_ran_sphere_hg_float_pdf } double* -ssp_ran_uniform_disk +ssp_ran_uniform_disk_local (struct ssp_rng* rng, const double radius, - double pt[2], + double pt[3], double* pdf) { double theta, r; @@ -469,15 +469,16 @@ ssp_ran_uniform_disk r = radius * sqrt(ssp_rng_canonical(rng)); pt[0] = r * cos(theta); pt[1] = r * sin(theta); + pt[2] = 0; if (pdf) *pdf = 1 / (radius * radius); return pt; } float* -ssp_ran_uniform_disk_float +ssp_ran_uniform_disk_float_local (struct ssp_rng* rng, const float radius, - float pt[2], + float pt[3], float* pdf) { float theta, r; @@ -486,6 +487,7 @@ ssp_ran_uniform_disk_float r = radius * sqrtf(ssp_rng_canonical_float(rng)); pt[0] = r * cosf(theta); pt[1] = r * sinf(theta); + pt[2] = 0; if (pdf) *pdf = 1 / (radius * radius); return pt; } \ No newline at end of file diff --git a/src/test_ssp_ran_uniform_disk.h b/src/test_ssp_ran_uniform_disk.h @@ -44,13 +44,25 @@ #if TYPE_FLOAT==0 #define REAL double #define TEST test_double +#define RNG_UNIFORM_R ssp_rng_uniform_double +#define RNG_UNIFORM_DISK_LOCAL ssp_ran_uniform_disk_local #define RNG_UNIFORM_DISK ssp_ran_uniform_disk +#define R33_BASIS d33_basis +#define R33_MULR3 d33_muld3 +#define R3_EQ_EPS d3_eq_eps +#define R3_NORMALIZE d3_normalize #define SQRT sqrt #elif TYPE_FLOAT==1 #define REAL float #define TEST test_float +#define RNG_UNIFORM_R ssp_rng_uniform_float +#define RNG_UNIFORM_DISK_LOCAL ssp_ran_uniform_disk_float_local #define RNG_UNIFORM_DISK ssp_ran_uniform_disk_float +#define R33_BASIS f33_basis +#define R33_MULR3 f33_mulf3 +#define R3_EQ_EPS f3_eq_eps +#define R3_NORMALIZE f3_normalize #define SQRT sqrtf #else #error "TYPE_SUFFIX must be defined either 0 or 1" @@ -59,25 +71,40 @@ static void TEST() { - struct ssp_rng_proxy* proxy; - struct ssp_rng* rng; + struct ssp_rng* rng0, *rng1; struct mem_allocator allocator; int i; - unsigned r, c, nb = 0; - REAL pt[2]; - REAL x = 0, x2 = 0; + int r, c, nb = 0; + REAL pt[3], pt2[3], up[3]; + REAL frame[9]; + REAL x_sum = 0, x2_sum = 0; REAL mean, std; - REAL exp_mean = 20 * 20 * NBS / ((REAL)PI * 100 * 100), exp_std = 0; + REAL exp_mean = NBS * (20 * 20 / ((REAL)PI * 100 * 100)), exp_std = 0; unsigned counts[10][10]; + uint64_t seed = 1234; 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_rng_create(&allocator, &ssp_rng_threefry, &rng0), RES_OK); + CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng1), RES_OK); + + up[0] = RNG_UNIFORM_R(rng1, -1, 1); + up[1] = RNG_UNIFORM_R(rng1, -1, 1); + up[2] = RNG_UNIFORM_R(rng1, -1, 1); + R3_NORMALIZE(up, up); + R33_BASIS(frame, up); + + ssp_rng_set(rng0, seed); + ssp_rng_set(rng1, seed); memset(counts, 0, sizeof(counts)); for(i = 0; i < NBS; i++) { - RNG_UNIFORM_DISK(rng, 100, pt, NULL); + REAL tmp[3]; + RNG_UNIFORM_DISK_LOCAL(rng0, 100, pt, NULL); + RNG_UNIFORM_DISK(rng1, 100, up, pt2, NULL); + R33_MULR3(tmp, frame, pt); + CHECK(R3_EQ_EPS(tmp, pt2, (REAL)1.e-6), 1); + ASSERT(pt[2] == 0); /* locate pt in a 10x10 grid */ r = (unsigned)((100 + pt[0]) / 20); c = (unsigned)((100 + pt[1]) / 20); @@ -85,26 +112,27 @@ TEST() } for(r = 0; r < 10; r++) { - unsigned _x = (r >= 5 ? r - 4 : r - 5) * 20; + int x = (r >= 5 ? r - 4 : r - 5) * 20; for(c = 0; c < 10; c++) { - unsigned _y = (c >= 5 ? c - 4 : c - 5) * 20; - unsigned r2 = _x * _x + _y * _y; + int y = (c >= 5 ? c - 4 : c - 5) * 20; + unsigned r2 = x * x + y * y; if(r2 > 100 * 100) /* this square is not (fully) in the disk */ continue; ++nb; - x += counts[r][c]; - x2 += counts[r][c] * counts[r][c]; + x_sum += counts[r][c]; + x2_sum += counts[r][c] * counts[r][c]; } } - mean = x / nb; - std = SQRT(x2 / nb - x / nb*x / nb); + mean = x_sum / nb; + std = x2_sum / nb - mean*mean; + std = std > 0 ? SQRT(std) : 0; printf("%g %g\n", mean, std); CHECK(fabs(mean - exp_mean) < 10, 1); - CHECK(fabs(std - exp_std) < 100, 1); + CHECK(fabs(std - exp_std) < 200, 1); - CHECK(ssp_rng_ref_put(rng), RES_OK); - CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK); + CHECK(ssp_rng_ref_put(rng0), RES_OK); + CHECK(ssp_rng_ref_put(rng1), RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); @@ -113,6 +141,12 @@ TEST() #undef REAL #undef TEST +#undef RNG_UNIFORM_R +#undef RNG_UNIFORM_DISK_LOCAL #undef RNG_UNIFORM_DISK +#undef R33_BASIS +#undef R33_MULR3 +#undef R3_EQ_EPS +#undef R3_NORMALIZE #undef SQRT #undef TYPE_FLOAT