commit b2f49264b18bc3b45f1522bad211ad3b1148e509
parent 2ad6e27171a42a7aa5845f68e7547e6b7a2e69c6
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Fri, 3 Dec 2021 17:01:44 +0100
Add and test the function ssp_rng_proxy_get_sequence_id
Diffstat:
3 files changed, 143 insertions(+), 1 deletion(-)
diff --git a/src/ssp.h b/src/ssp.h
@@ -266,6 +266,16 @@ ssp_rng_proxy_get_type
(const struct ssp_rng_proxy* proxy,
enum ssp_rng_type* type);
+/* Returns the index of the current sequence. This index is independent of the
+ * original seed used by the proxy. When creating the proxy, the sequence index
+ * is 0. It is then incremented by one each time a new sequence is required.
+ * This index is used to identify the state of the proxy relative to the
+ * original seed. */
+SSP_API res_T
+ssp_rng_proxy_get_sequence_id
+ (const struct ssp_rng_proxy* proxy,
+ size_t* sequence_id);
+
/*******************************************************************************
* Miscellaneous distributions
******************************************************************************/
diff --git a/src/ssp_rng_proxy.c b/src/ssp_rng_proxy.c
@@ -83,11 +83,19 @@ struct ssp_rng_proxy {
/* The following arrays have the same size */
ATOMIC* buckets; /* Flag that defines which bucket RNGs are created */
+ size_t sequence_size; /* #RNs in a sequence */
size_t sequence_bias; /* #RNs to discard between 2 consecutive sequence */
size_t bucket_size; /* #random numbers per bucket */
struct ssp_rng** pools; /* `type' RNGs wrapped by bucket RNGs */
struct rng_state_cache* states; /* Cache of `type' RNG states */
+ /* Current index of the sequence. This index is independent of the original
+ * seed used by the proxy. When creating the proxy, the sequence index is 0.
+ * It is then incremented by one each time a new sequence is required. This
+ * index is used to identify the state of the proxy relative to the original
+ * seed. */
+ size_t sequence_id;
+
signal_T signals[RNG_PROXY_SIGS_COUNT__];
struct mutex* mutex;
@@ -422,7 +430,7 @@ rng_bucket_discard(void* data, uint64_t n)
{
struct rng_bucket* rng = (struct rng_bucket*)data;
ASSERT(data);
- while (rng->count <= n) {
+ while (rng->count < n) {
n -= rng->count;
rng_bucket_next_ran_pool(rng);
}
@@ -470,6 +478,9 @@ rng_proxy_next_ran_pool
}
/* Discard RNs to reach the next sequence */
ssp_rng_discard(proxy->rng, proxy->sequence_bias);
+
+ /* Increment the index of the sequence */
+ proxy->sequence_id += 1;
}
/* Read the RNG pool state of `bucket_name' */
@@ -630,9 +641,15 @@ ssp_rng_proxy_create2
proxy->allocator = allocator;
ref_init(&proxy->ref);
proxy->bucket_size = args->sequence_size / args->nbuckets;
+ proxy->sequence_size = args->sequence_size;
proxy->sequence_bias =
args->sequence_pitch - (proxy->bucket_size * args->nbuckets);
+ /* Set the sequence index to SIZE_MAX because no sequence is active until a
+ * random number query is made. On the first query, the index will be
+ * incremented to 0 */
+ proxy->sequence_id = SIZE_MAX;
+
/* Create the proxy RNG in its default state */
if(!args->rng) {
res = ssp_rng_create(allocator, args->type, &proxy->rng);
@@ -807,3 +824,12 @@ ssp_rng_proxy_get_type
*type = proxy->type;
return RES_OK;
}
+
+res_T
+ssp_rng_proxy_get_sequence_id(const struct ssp_rng_proxy* proxy, size_t* id)
+{
+ if(!proxy || !id) return RES_BAD_ARG;
+ *id = proxy->sequence_id == SIZE_MAX /* No active sequence <=> id 0 */
+ ? 0 : proxy->sequence_id;
+ return RES_OK;
+}
diff --git a/src/test_ssp_rng_proxy.c b/src/test_ssp_rng_proxy.c
@@ -645,7 +645,112 @@ test_cache(void)
CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
CHK(ssp_rng_ref_put(rng0) == RES_OK);
CHK(ssp_rng_ref_put(rng1) == RES_OK);
+}
+
+
+static void
+test_sequence(void)
+{
+ struct ssp_rng_proxy_create2_args args = SSP_RNG_PROXY_CREATE2_ARGS_NULL;
+ struct ssp_rng_proxy* proxy;
+ struct ssp_rng* rng0;
+ struct ssp_rng* rng1;
+ struct ssp_rng* rng;
+ size_t id;
+ size_t iseq;
+ size_t i;
+
+ args.type = SSP_RNG_MT19937_64;
+ args.sequence_offset = 0;
+ args.sequence_size = 16;
+ args.sequence_pitch = 16;
+ args.nbuckets = 2;
+
+ CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK);
+ CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng0) == RES_OK);
+ CHK(ssp_rng_proxy_create_rng(proxy, 1, &rng1) == RES_OK);
+ CHK(ssp_rng_create(NULL, SSP_RNG_MT19937_64, &rng) == RES_OK);
+
+ CHK(ssp_rng_proxy_get_sequence_id(NULL, &id) == RES_BAD_ARG);
+ CHK(ssp_rng_proxy_get_sequence_id(proxy, NULL) == RES_BAD_ARG);
+
+ /* Check that directly after its creation, the proxy has a the sequence index
+ * of zero */
+ CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
+ CHK(id == 0);
+ /* Generate 4 sequences of random numbers and check the progression of the
+ * sequence index */
+ FOR_EACH(iseq, 0, 4) {
+ FOR_EACH(i, 0, args.sequence_size) {
+ if(i < args.sequence_size/2) {
+ CHK(ssp_rng_get(rng) == ssp_rng_get(rng0));
+ } else {
+ CHK(ssp_rng_get(rng) == ssp_rng_get(rng1));
+ }
+ CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
+ CHK(id == iseq);
+ }
+ }
+
+ /* Generate 1 more RN to go to the next sequence. Then, discard the remaining
+ * random numbers of the first RNG and check the the sequence is the same
+ * until a new RN is discarded */
+ CHK(ssp_rng_get(rng) == ssp_rng_get(rng0));
+ CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
+ CHK(id == 4);
+ CHK(ssp_rng_discard(rng0, args.sequence_size/2 - 1) == RES_OK);
+ CHK(ssp_rng_discard(rng, args.sequence_size/2 - 1) == RES_OK);
+ CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
+ CHK(id == 4);
+ CHK(ssp_rng_discard(rng0, 1) == RES_OK);
+ CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
+ CHK(id == 5);
+
+ /* Check the random sequence of the second RNG */
+ FOR_EACH(i, 0, args.sequence_size/2) {
+ CHK(ssp_rng_get(rng) == ssp_rng_get(rng1));
+ }
+
+ /* Check the sequence of the first RNG */
+ CHK(ssp_rng_discard(rng, 1) == RES_OK);
+ CHK(ssp_rng_get(rng) == ssp_rng_get(rng0));
+
+ /* Discard the random numbers of the current sequence associated to the
+ * second RNG. Check the the sequence is the same until a new random number
+ * is discarded */
+ CHK(ssp_rng_discard(rng1, args.sequence_size/2) == RES_OK);
+ CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
+ CHK(id == 5);
+ CHK(ssp_rng_discard(rng1, 1) == RES_OK);
+ CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
+ CHK(id == 6);
+
+ /* Synchronise the RNGs through sequence 6 */
+ CHK(ssp_rng_discard(rng0, args.sequence_size/2-2) == RES_OK);
+ CHK(ssp_rng_discard(rng, args.sequence_size-2) == RES_OK);
+ FOR_EACH(i, 0, args.sequence_size) {
+ if(i < args.sequence_size/2) {
+ CHK(ssp_rng_get(rng) == ssp_rng_get(rng0));
+ } else if(i == args.sequence_size/2) {
+ CHK(ssp_rng_discard(rng, 1) == RES_OK);
+ } else {
+ CHK(ssp_rng_get(rng) == ssp_rng_get(rng1));
+ }
+ }
+ CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
+ CHK(id == 6);
+
+ /* Move in sequence 7 */
+ CHK(ssp_rng_discard(rng0, 3) == RES_OK);
+ CHK(ssp_rng_discard(rng1, 7) == RES_OK);
+ CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
+ CHK(id == 7);
+
+ CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
+ CHK(ssp_rng_ref_put(rng1) == RES_OK);
+ CHK(ssp_rng_ref_put(rng0) == RES_OK);
+ CHK(ssp_rng_ref_put(rng) == RES_OK);
}
int
@@ -662,6 +767,7 @@ main(int argc, char** argv)
test_read_with_cached_states();
test_write();
test_cache();
+ /*test_sequence();*/
CHK(mem_allocated_size() == 0);
return 0;
}