star-sp

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

commit b739d0c52f6e096ca51950cc69cf7193e13aca5b
parent d9296c00b885fe90a96d147b0220fa54e8c369b5
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed,  8 Dec 2021 12:28:09 +0100

Add and test the function ssp_rng_proxy_flush_sequences

This function is used to discard the random numbers of the current
sequence as well as the random numbers of the next sequences. It will be
usefull to synchronise the proxies distributed between several processes.

Diffstat:
Msrc/ssp.h | 9+++++++++
Msrc/ssp_rng_proxy.c | 41+++++++++++++++++++++++++++++++++++++++++
Msrc/test_ssp_rng_proxy.c | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 141 insertions(+), 0 deletions(-)

diff --git a/src/ssp.h b/src/ssp.h @@ -280,6 +280,15 @@ ssp_rng_proxy_get_sequence_id (const struct ssp_rng_proxy* proxy, size_t* sequence_id); +/* Discard the random numbers of `n' sequences. If `n' is 0, nothing happens. + * If `n' is greater than or equal to one, the random numbers of the current + * sequence are ignored as well as the random numbers of the following + * sequences until the sequence identifier has been incremented by `n-1'. */ +SSP_API res_T +ssp_rng_proxy_flush_sequences + (struct ssp_rng_proxy* proxy, + const size_t n); + /******************************************************************************* * Miscellaneous distributions ******************************************************************************/ diff --git a/src/ssp_rng_proxy.c b/src/ssp_rng_proxy.c @@ -834,3 +834,44 @@ ssp_rng_proxy_get_sequence_id(const struct ssp_rng_proxy* proxy, size_t* id) *id = proxy->sequence_id; return RES_OK; } + +res_T +ssp_rng_proxy_flush_sequences + (struct ssp_rng_proxy* proxy, + const size_t nseqs) +{ + res_T res = RES_OK; + + if(!proxy) { + res = RES_BAD_ARG; + goto error; + } + + /* Nothing to discard */ + if(nseqs == 0) goto exit; + + /* Flush the random numbers of the 'nseqs' sequences. Note that the status of + * the proxy RNG is set to the state of the 1st random number of the next + * sequence. To clear the random numbers of the last sequence queried by the + * proxy-managed RNGs, simply clear their cache and reset them. So we only + * reject '(nseqs - 1)*sequence_size' random numbers and not + * 'nseqs*sequence_size' */ + mutex_lock(proxy->mutex); + res = ssp_rng_discard(proxy->rng, proxy->sequence_size * (nseqs-1)); + mutex_unlock(proxy->mutex); + if(res != RES_OK) goto error; + + proxy->sequence_id += (nseqs-1); + + /* Discard the cached RNG states */ + rng_proxy_clear_caches(proxy); + + /* Notify to bucket RNGs that the proxy RNG state was updated */ + SIG_BROADCAST + (proxy->signals+RNG_PROXY_SIG_SET_STATE, rng_proxy_cb_T, ARG1(proxy)); + +exit: + return res; +error: + goto exit; +} diff --git a/src/test_ssp_rng_proxy.c b/src/test_ssp_rng_proxy.c @@ -756,6 +756,96 @@ test_sequence(void) CHK(ssp_rng_ref_put(rng) == RES_OK); } +static void +test_flush_sequence() +{ + 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 i; + + args.type = SSP_RNG_MT19937_64; + args.sequence_offset = 0; + args.sequence_size = 10; + args.sequence_pitch = 10; + 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(proxy, &id) == RES_OK); + CHK(id == SSP_SEQUENCE_ID_NONE); + CHK(ssp_rng_get(rng) == ssp_rng_get(rng0)); + + /* Flush 0 sequence, i.e. do nothing */ + CHK(ssp_rng_proxy_flush_sequences(NULL, 0) == RES_BAD_ARG); + CHK(ssp_rng_proxy_flush_sequences(proxy, 0) == RES_OK); + CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); + CHK(id == 0); + CHK(ssp_rng_get(rng) == ssp_rng_get(rng0)); + + /* Discard several numbers of the rng1 to fill the cache of rng0. We will + * thus be able to check the cache clearing when we will flush sequences */ + CHK(ssp_rng_discard(rng1, 314) == RES_OK); + CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); + CHK(id == 62); + + /* Flush the remaining random number of the current sequence */ + CHK(ssp_rng_proxy_flush_sequences(proxy, 1) == RES_OK); + + /* We are still in the sequence 62 but without any available random numbers */ + CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); + CHK(id == 62); + + /* Synchronize RNG with the current state of the proxy */ + CHK(ssp_rng_discard + (rng, args.sequence_size*63 /*#random number to discard */ + - 2/*... minus the 2 already consumed random numbers*/) == RES_OK); + + /* Check RNG states */ + 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 == 63); + } + + /* Fill the cache of the rng1 */ + CHK(ssp_rng_discard(rng0, 1013) == RES_OK); + CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); + CHK(id == 63 + 203/*ceil(1023/(args.sequence_size*0.5))*/); + + /* Discard several sequences */ + CHK(ssp_rng_proxy_flush_sequences(proxy, 314) == RES_OK); + + /* Synchronize RNG with the current state of the proxy */ + CHK(ssp_rng_discard(rng, args.sequence_size*(203 + 314 - 1)) == RES_OK); + + /* Check RNG states */ + 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 == 63 + 203 + 314); + } + + 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 main(int argc, char** argv) { @@ -771,6 +861,7 @@ main(int argc, char** argv) test_write(); test_cache(); test_sequence(); + test_flush_sequence(); CHK(mem_allocated_size() == 0); return 0; }