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:
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;
}