star-sp

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

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:
Msrc/ssp.h | 10++++++++++
Msrc/ssp_rng_proxy.c | 28+++++++++++++++++++++++++++-
Msrc/test_ssp_rng_proxy.c | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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; }