star-sp

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

commit 25ac4b841f2607526f2623bc325d0d6b0831067e
parent 1506e802be885d6662140854166579fee88d89e2
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 15 Apr 2015 11:04:36 +0200

Comment the RNG proxy API and implementation

Diffstat:
Msrc/ssp.h | 12+++++++-----
Msrc/ssp_rng_proxy.c | 61++++++++++++++++++++++++++++++++++++++++++++-----------------
2 files changed, 51 insertions(+), 22 deletions(-)

diff --git a/src/ssp.h b/src/ssp.h @@ -155,8 +155,8 @@ ssp_rng_read FILE* stream); /******************************************************************************* - * Proxy of Random Number Generators. A proxy ensures that the RNG that it - * manages, provide unconnected random numbers + * Proxy of Random Number Generators - It manages a list of `nbuckets' RNGs + * whose each have independant `infinite' random sequences ******************************************************************************/ SSP_API res_T ssp_rng_proxy_create @@ -173,6 +173,8 @@ SSP_API res_T ssp_rng_proxy_ref_put (struct ssp_rng_proxy* proxy); +/* Create the RNG of `ibucket'. Return a RES_BAD_ARG error if RNG was already + * created for `ibucket'. Call ssp_rng_ref_put to release the returned RNG */ SSP_API res_T ssp_rng_proxy_create_rng (struct ssp_rng_proxy* proxy, @@ -229,7 +231,7 @@ ssp_ran_hemisphere_uniform_pdf(const float up[3], const float sample[3]) return f3_dot(sample, up) < 0.f ? 0.f : (float)(1.0/(2.0*PI)); } -/* Cosine weighted sampling of an unit hemisphere whise up direction is +/* Cosine weighted sampling of an unit hemisphere whose up direction is * implicitly the Z axis. The PDF of the generated sample is stored in * sample[3] */ static INLINE float* @@ -248,7 +250,7 @@ ssp_ran_hemisphere_cos_local(struct ssp_rng* rng, float sample[4]) return sample; } -/* Return the probability distribution for an hemispheric consine weighted +/* Return the probability distribution for an hemispheric cosine weighted * random variate with an implicit up direction in Z */ static INLINE float ssp_ran_hemisphere_cos_local_pdf(const float sample[3]) @@ -268,7 +270,7 @@ ssp_ran_hemisphere_cos(struct ssp_rng* rng, const float up[3], float sample[4]) return f33_mulf3(sample, f33_basis(basis, up), sample); } -/* Return the probability distribution for an hemispheric consine weighted +/* Return the probability distribution for an hemispheric cosine weighted * random variate with an explicit `up' direction */ static INLINE float ssp_ran_hemisphere_cos_pdf(const float up[3], const float sample[3]) diff --git a/src/ssp_rng_proxy.c b/src/ssp_rng_proxy.c @@ -39,32 +39,60 @@ #define BUCKET_SIZE 1000000 +/* FIFO list of RNG states */ struct rng_state_cache { - FILE* stream; + FILE* stream; /* Stream in which the RNG states are stored */ long head, tail; /* Position onto the head/tail `states' stream */ }; +/* A proxy manages a list of N independent RNGs of the same type named buckets. + * One ensure that each bucket have independent `infinite' random numbers by + * partitioning a unique random sequence in N random pools, each containing + * BUCKET_SIZE random numbers. When a bucket has no more random number in its + * affected pool, it silently retrieves a new pool of BUCKET_SIZE random + * numbers from the proxy. + * + * Mapping of the partitions of the unique random sequence to N buckets + * BUCKET_SIZE + * / \ + * +---------+---------+- -+---------+---------+---------+- + * | Bucket0 | Bucket1 | ... |BucketN-1| Bucket0 | Bucket1 | ... + * +---------+---------+- -+---------+---------+---------+- + * Unique random sequence */ struct ssp_rng_proxy { - struct ssp_rng_type type; /* Wrapped RNG type */ + struct ssp_rng_type type; /* Type of the RNGs managed by the proxy */ - struct ssp_rng* rng; /* Main RNG */ + struct ssp_rng* rng; /* Main `type' RNG */ - int* buckets; /* Flag that defines which buckets are created */ - struct ssp_rng** pools; /* Cache of bucketized RNGs */ - struct rng_state_cache* states; + /* The following arrays have the same size */ + int* buckets; /* Flag that defines which bucket RNGs are created */ + struct ssp_rng** pools; /* `type' RNGs wrapped by bucket RNGs */ + struct rng_state_cache* states; /* Cache of `type' RNG states */ struct mutex* mutex; struct mem_allocator* allocator; ref_T ref; }; +/* Return a RNG with a pool of BUCKET_SIZE indenpendant random numbers. Each + * pool are ensure to be independant per `bucket_id' in [0, N) and per function + * call, i.e. calling this function X times with the same bucket_id will + * provide X different random pools. + * + * BUCKET_SIZE + * / \ + * +------------+- -+------------+------------+- + * | Bucket 0 | ... | Bucket N-1 | Bucket 0 | ... + * | 1st pool | | 1st pool | 2nd pool | + * +------------+- -+------------+------------+- + * Unique random sequences */ static struct ssp_rng* rng_proxy_next_ran_pool (struct ssp_rng_proxy* proxy, const size_t bucket_id); /******************************************************************************* - * State cache + * Cache of RNG states ******************************************************************************/ static res_T rng_state_cache_init(struct rng_state_cache* cache) @@ -102,7 +130,7 @@ rng_state_cache_read(struct rng_state_cache* cache, struct ssp_rng* rng) if(res != RES_OK) return res; cache->head = ftell(cache->stream); - /* Flush the state cache stream if ther is no more RNG state */ + /* Flush the state cache stream if there is no more RNG state */ if(rng_state_cache_is_empty(cache)) { fclose(cache->stream); cache->stream = tmpfile(); @@ -126,12 +154,12 @@ rng_state_cache_write(struct rng_state_cache* cache, struct ssp_rng* rng) } /******************************************************************************* - * Bucketized RNG + * RNG that control the scheduling of random number pools for a given bucket ******************************************************************************/ struct rng_bucket { struct ssp_rng* pool; /* Wrapped RNG providing a pool of BUCKET_SIZE RNs */ struct ssp_rng_proxy* proxy; /* The RNG proxy */ - size_t name; /* Unique bucket identifier */ + size_t name; /* Unique bucket identifier in [0, #buckets) */ size_t count; /* Remaining unique random numbers in `pool' */ }; @@ -147,7 +175,7 @@ static void rng_bucket_set(void* data, const unsigned long seed) { (void)data, (void)seed; - FATAL("The seed can't be set explicitly on proxy managed RNGs\n"); + FATAL("The seed can't be set explicitly on bucket RNGs\n"); } static unsigned long @@ -195,7 +223,7 @@ static res_T rng_bucket_read(void* data, FILE* file) { (void)data, (void)file; - FATAL("A proxy managed RNG can't be de-serialized\n"); + FATAL("A bucket RNG can't be de-serialized\n"); return RES_BAD_OP; } @@ -203,7 +231,7 @@ static res_T rng_bucket_write(const void* data, FILE* file) { (void)data, (void)file; - FATAL("A proxy managed RNG can't be serialized\n"); + FATAL("A bucket RNG can't be serialized\n"); return RES_BAD_OP; } @@ -223,7 +251,7 @@ static void rng_bucket_release(void* data) { struct rng_bucket* rng = (struct rng_bucket*)data; - ASSERT(data); + ASSERT(data && rng->proxy); ATOMIC_SET(&rng->proxy->buckets[rng->name], 0); SSP(rng_proxy_ref_put(rng->proxy)); } @@ -246,6 +274,7 @@ static const struct ssp_rng_type rng_bucket = { /******************************************************************************* * Helper functions ******************************************************************************/ +/* Scheduler of random number pools */ struct ssp_rng* rng_proxy_next_ran_pool (struct ssp_rng_proxy* proxy, @@ -267,7 +296,7 @@ rng_proxy_next_ran_pool } mutex_unlock(proxy->mutex); - /* Set the new RNG pool state */ + /* Read the RNG pool state of `bucket_name' */ res = rng_state_cache_read (proxy->states + bucket_name, proxy->pools[bucket_name]); if(res != RES_OK) FATAL("RNG proxy: Unrecoverable IO error\n"); @@ -309,10 +338,8 @@ rng_proxy_setup(struct ssp_rng_proxy* proxy, const size_t nbuckets) FOR_EACH(ibucket, 0, nbuckets) { res = rng_state_cache_init(proxy->states+ibucket); if(res != RES_OK) goto error; - res = ssp_rng_create(proxy->allocator, &proxy->type, proxy->pools+ibucket); if(res != RES_OK) goto error; - proxy->buckets[ibucket] = 0; }