star-sp

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

test_ssp_rng_proxy.c (29251B)


      1 /* Copyright (C) 2015-2025 |Méso|Star> (contact@meso-star.com)
      2  *
      3  * This program is free software: you can redistribute it and/or modify
      4  * it under the terms of the GNU General Public License as published by
      5  * the Free Software Foundation, either version 3 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * This program is distributed in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     11  * GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     15 
     16 #include "ssp.h"
     17 #include "test_ssp_utils.h"
     18 
     19 #define NRANDS 2000000
     20 #define COUNT 4605307
     21 
     22 static void
     23 test_creation(void)
     24 {
     25   struct ssp_rng_proxy* proxy;
     26   enum ssp_rng_type type;
     27 
     28   CHK(ssp_rng_proxy_create(NULL, -1, 0, NULL) == RES_BAD_ARG);
     29   CHK(ssp_rng_proxy_create(NULL, SSP_RNG_MT19937_64, 0, NULL) == RES_BAD_ARG);
     30   CHK(ssp_rng_proxy_create(NULL, -1, 4, NULL) == RES_BAD_ARG);
     31   CHK(ssp_rng_proxy_create(NULL, SSP_RNG_MT19937_64, 4, NULL) == RES_BAD_ARG);
     32   CHK(ssp_rng_proxy_create(NULL, -1, 0, &proxy) == RES_BAD_ARG);
     33   CHK(ssp_rng_proxy_create(NULL, SSP_RNG_MT19937_64, 0, &proxy) == RES_BAD_ARG);
     34   CHK(ssp_rng_proxy_create(NULL, -1, 4, &proxy) == RES_BAD_ARG);
     35   CHK(ssp_rng_proxy_create(NULL, SSP_RNG_MT19937_64, 4, &proxy) == RES_OK);
     36 
     37   CHK(ssp_rng_proxy_get_type(NULL, NULL) == RES_BAD_ARG);
     38   CHK(ssp_rng_proxy_get_type(proxy, NULL) == RES_BAD_ARG);
     39   CHK(ssp_rng_proxy_get_type(NULL, &type) == RES_BAD_ARG);
     40   CHK(ssp_rng_proxy_get_type(proxy, &type) == RES_OK);
     41 
     42   CHK(type != SSP_RNG_KISS);
     43   CHK(type == SSP_RNG_MT19937_64);
     44 
     45   CHK(ssp_rng_proxy_ref_get(NULL) == RES_BAD_ARG);
     46   CHK(ssp_rng_proxy_ref_get(proxy) == RES_OK);
     47   CHK(ssp_rng_proxy_ref_put(NULL) == RES_BAD_ARG);
     48   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
     49   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
     50 
     51   CHK(ssp_rng_proxy_create
     52     (&mem_default_allocator, SSP_RNG_THREEFRY, 1, &proxy) == RES_OK);
     53   CHK(ssp_rng_proxy_get_type(proxy, &type) == RES_OK);
     54   CHK(type == SSP_RNG_THREEFRY);
     55   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
     56 
     57   CHK(ssp_rng_proxy_create(NULL, SSP_RNG_KISS, 4, &proxy) == RES_OK);
     58   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
     59 }
     60 
     61 static void
     62 test_creation2(void)
     63 {
     64   struct ssp_rng_proxy_create2_args args = SSP_RNG_PROXY_CREATE2_ARGS_NULL;
     65   struct ssp_rng_proxy* proxy;
     66 
     67   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG);
     68 
     69   args.type = SSP_RNG_MT19937_64;
     70   args.sequence_offset = 0;
     71   args.sequence_size = 32;
     72   args.sequence_pitch = 32;
     73   args.nbuckets = 1;
     74   CHK(ssp_rng_proxy_create2(NULL, &args, NULL) == RES_BAD_ARG);
     75 
     76   args.type = SSP_RNG_TYPE_NULL;
     77   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG);
     78   args.type = SSP_RNG_MT19937_64;
     79   args.sequence_size= 0;
     80   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG);
     81   args.sequence_size = 32;
     82   args.sequence_pitch = 0;
     83   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG);
     84   args.sequence_pitch = 31;
     85   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG);
     86   args.sequence_pitch = 32;
     87   args.nbuckets = 0;
     88   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG);
     89   args.nbuckets = 33;
     90   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG);
     91   args.nbuckets = 1;
     92   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK);
     93   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
     94 
     95   args.nbuckets = 4;
     96   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK);
     97   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
     98 
     99   args.nbuckets = 5;
    100   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK);
    101   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
    102 
    103   args.nbuckets = 32;
    104   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK);
    105   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
    106 
    107   args.sequence_offset = 1024;
    108   args.nbuckets = 4;
    109   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK);
    110   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
    111 
    112   args.type = SSP_RNG_KISS;
    113   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK);
    114   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
    115 }
    116 
    117 static void
    118 test_rng_from_proxy(void)
    119 {
    120   enum ssp_rng_type type;
    121   struct ssp_rng_proxy* proxy;
    122   struct ssp_rng* rng[4];
    123   uint64_t r[4];
    124   size_t i, j, k;
    125 
    126   CHK(ssp_rng_proxy_create(NULL, SSP_RNG_MT19937_64, 4, &proxy) == RES_OK);
    127 
    128   CHK(ssp_rng_proxy_create_rng(NULL, 0, NULL) == RES_BAD_ARG);
    129   CHK(ssp_rng_proxy_create_rng(proxy, 0, NULL) == RES_BAD_ARG);
    130   CHK(ssp_rng_proxy_create_rng(NULL, 0, &rng[0]) == RES_BAD_ARG);
    131   CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng[0]) == RES_OK);
    132   CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng[1]) == RES_BAD_ARG);
    133   CHK(ssp_rng_ref_put(rng[0]) == RES_OK);
    134 
    135   CHK(ssp_rng_proxy_create_rng(proxy, 4, &rng[0]) == RES_BAD_ARG);
    136 
    137   FOR_EACH(i, 0, 4) CHK(ssp_rng_proxy_create_rng(proxy, i, &rng[i]) == RES_OK);
    138   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
    139 
    140   CHK(ssp_rng_get_type(rng[0], &type) == RES_OK);
    141   FOR_EACH(i, 1, 4) {
    142     enum ssp_rng_type type2;
    143     CHK(ssp_rng_get_type(rng[i], &type2) == RES_OK);
    144     CHK(type == type2);
    145   }
    146 
    147   FOR_EACH(i, 0, NRANDS) {
    148     FOR_EACH(j, 0, 4) {
    149       r[j] = ssp_rng_get(rng[j]);
    150       FOR_EACH(k, 0, j) CHK(r[k] != r[j]);
    151     }
    152   }
    153 
    154   FOR_EACH(i, 0, 4) CHK(ssp_rng_ref_put(rng[i]) == RES_OK);
    155 }
    156 
    157 static void
    158 test_rng_from_proxy2(void)
    159 {
    160   struct ssp_rng_proxy_create2_args args = SSP_RNG_PROXY_CREATE2_ARGS_NULL;
    161   struct ssp_rng_proxy* proxy[2];
    162   struct ssp_rng* rng[4];
    163   const size_t block_sz = 99;
    164   const size_t nrands = 1000;
    165   uint64_t* r[4];
    166   size_t i, j;
    167 
    168   CHK((r[0] = mem_alloc(sizeof(uint64_t)*nrands)) != NULL);
    169   CHK((r[1] = mem_alloc(sizeof(uint64_t)*nrands)) != NULL);
    170   CHK((r[2] = mem_alloc(sizeof(uint64_t)*nrands)) != NULL);
    171   CHK((r[3] = mem_alloc(sizeof(uint64_t)*nrands)) != NULL);
    172 
    173   args.type = SSP_RNG_MT19937_64;
    174   args.sequence_size = block_sz;
    175   args.sequence_pitch = block_sz;
    176   args.nbuckets = 4;
    177   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy[0]) == RES_OK);
    178 
    179   CHK(ssp_rng_proxy_create_rng(proxy[0], 0, &rng[0]) == RES_OK);
    180   CHK(ssp_rng_proxy_create_rng(proxy[0], 1, &rng[1]) == RES_OK);
    181   CHK(ssp_rng_proxy_create_rng(proxy[0], 2, &rng[2]) == RES_OK);
    182   CHK(ssp_rng_proxy_create_rng(proxy[0], 3, &rng[3]) == RES_OK);
    183 
    184   /* Generate random numbers */
    185   FOR_EACH(i, 0, nrands) {
    186     r[0][i] = ssp_rng_get(rng[0]);
    187     r[1][i] = ssp_rng_get(rng[1]);
    188     r[2][i] = ssp_rng_get(rng[2]);
    189     r[3][i] = ssp_rng_get(rng[3]);
    190   }
    191 
    192   /* Check that each RNG generate a unique sequence of random numbers */
    193   FOR_EACH(i, 0, nrands) {
    194     FOR_EACH(j, 0, nrands) {
    195       CHK(r[0][i] != r[1][j]);
    196       CHK(r[0][i] != r[2][j]);
    197       CHK(r[0][i] != r[3][j]);
    198       CHK(r[1][i] != r[2][j]);
    199       CHK(r[1][i] != r[3][j]);
    200       CHK(r[2][i] != r[3][j]);
    201     }
    202   }
    203 
    204   CHK(ssp_rng_proxy_ref_put(proxy[0]) == RES_OK);
    205   CHK(ssp_rng_ref_put(rng[0]) == RES_OK);
    206   CHK(ssp_rng_ref_put(rng[1]) == RES_OK);
    207   CHK(ssp_rng_ref_put(rng[2]) == RES_OK);
    208   CHK(ssp_rng_ref_put(rng[3]) == RES_OK);
    209 
    210   args.type = SSP_RNG_MT19937_64;
    211   args.sequence_size = block_sz;
    212   args.sequence_pitch = 2*block_sz;
    213   args.nbuckets = 2;
    214 
    215   args.sequence_offset = 0;
    216   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy[0]) == RES_OK);
    217   args.sequence_offset = block_sz;
    218   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy[1]) == RES_OK);
    219 
    220   CHK(ssp_rng_proxy_create_rng(proxy[0], 0, &rng[0]) == RES_OK);
    221   CHK(ssp_rng_proxy_create_rng(proxy[0], 1, &rng[1]) == RES_OK);
    222   CHK(ssp_rng_proxy_create_rng(proxy[1], 0, &rng[2]) == RES_OK);
    223   CHK(ssp_rng_proxy_create_rng(proxy[1], 1, &rng[3]) == RES_OK);
    224 
    225   /* Generate random numbers */
    226   FOR_EACH(i, 0, nrands) {
    227     r[0][i] = ssp_rng_get(rng[0]);
    228     r[1][i] = ssp_rng_get(rng[1]);
    229     r[2][i] = ssp_rng_get(rng[2]);
    230     r[3][i] = ssp_rng_get(rng[3]);
    231   }
    232 
    233   /* Check that each RNG generate a unique sequence of random numbers */
    234   FOR_EACH(i, 0, nrands) {
    235     FOR_EACH(j, 0, nrands) {
    236       CHK(r[0][i] != r[1][j]);
    237       CHK(r[0][i] != r[2][j]);
    238       CHK(r[0][i] != r[3][j]);
    239       CHK(r[1][i] != r[2][j]);
    240       CHK(r[1][i] != r[3][j]);
    241       CHK(r[2][i] != r[3][j]);
    242     }
    243   }
    244 
    245   CHK(ssp_rng_proxy_ref_put(proxy[0]) == RES_OK);
    246   CHK(ssp_rng_proxy_ref_put(proxy[1]) == RES_OK);
    247   CHK(ssp_rng_ref_put(rng[0]) == RES_OK);
    248   CHK(ssp_rng_ref_put(rng[1]) == RES_OK);
    249   CHK(ssp_rng_ref_put(rng[2]) == RES_OK);
    250   CHK(ssp_rng_ref_put(rng[3]) == RES_OK);
    251 
    252   mem_rm(r[0]);
    253   mem_rm(r[1]);
    254   mem_rm(r[2]);
    255   mem_rm(r[3]);
    256 }
    257 
    258 static void
    259 test_multi_proxies(void)
    260 {
    261   struct ssp_rng_proxy* proxy1;
    262   struct ssp_rng_proxy* proxy2;
    263   struct ssp_rng* rng1;
    264   struct ssp_rng* rng2;
    265   struct ssp_rng* rng3;
    266   size_t i;
    267 
    268   CHK(ssp_rng_proxy_create(NULL, SSP_RNG_THREEFRY, 1, &proxy1) == RES_OK);
    269   CHK(ssp_rng_proxy_create(NULL, SSP_RNG_THREEFRY, 1, &proxy2) == RES_OK);
    270 
    271   CHK(ssp_rng_proxy_create_rng(proxy1, 0, &rng1) == RES_OK);
    272   CHK(ssp_rng_proxy_create_rng(proxy2, 0, &rng2) == RES_OK);
    273   ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng3);
    274 
    275   CHK(ssp_rng_proxy_ref_put(proxy1) == RES_OK);
    276   CHK(ssp_rng_proxy_ref_put(proxy2) == RES_OK);
    277 
    278   ssp_rng_discard(rng1, COUNT);
    279   ssp_rng_discard(rng3, COUNT+1);
    280   FOR_EACH(i, 0, COUNT) ssp_rng_get(rng2);
    281 
    282   CHK(ssp_rng_get(rng1) == ssp_rng_get(rng2));
    283   CHK(ssp_rng_get(rng1) == ssp_rng_get(rng3));
    284 
    285   CHK(ssp_rng_ref_put(rng1) == RES_OK);
    286   CHK(ssp_rng_ref_put(rng2) == RES_OK);
    287   CHK(ssp_rng_ref_put(rng3) == RES_OK);
    288 }
    289 
    290 static void
    291 test_proxy_from_rng(void)
    292 {
    293   struct ssp_rng_proxy_create2_args args = SSP_RNG_PROXY_CREATE2_ARGS_NULL;
    294   struct ssp_rng_proxy* proxy;
    295   struct ssp_rng* rng[4];
    296   enum ssp_rng_type type;
    297   uint64_t r[4];
    298   size_t i, j, k;
    299 
    300   CHK(ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng[0]) == RES_OK);
    301   CHK(ssp_rng_discard(rng[0], COUNT) == RES_OK);
    302 
    303   CHK(ssp_rng_proxy_create_from_rng(NULL, NULL, 0, NULL) == RES_BAD_ARG);
    304   CHK(ssp_rng_proxy_create_from_rng(NULL, rng[0], 0, NULL) == RES_BAD_ARG);
    305   CHK(ssp_rng_proxy_create_from_rng(NULL, NULL, 1, NULL) == RES_BAD_ARG);
    306   CHK(ssp_rng_proxy_create_from_rng(NULL, rng[0], 1, NULL) == RES_BAD_ARG);
    307   CHK(ssp_rng_proxy_create_from_rng(NULL, NULL, 0, &proxy) == RES_BAD_ARG);
    308   CHK(ssp_rng_proxy_create_from_rng(NULL, rng[0], 0, &proxy) == RES_BAD_ARG);
    309   CHK(ssp_rng_proxy_create_from_rng(NULL, NULL, 1, &proxy) == RES_BAD_ARG);
    310   CHK(ssp_rng_proxy_create_from_rng(NULL, rng[0], 1, &proxy) == RES_OK);
    311   CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng[1]) == RES_OK);
    312   CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng[2]) == RES_BAD_ARG);
    313   CHK(ssp_rng_proxy_create_rng(proxy, 1, &rng[2]) == RES_BAD_ARG);
    314 
    315   CHK(ssp_rng_get(rng[0]) == ssp_rng_get(rng[1]));
    316 
    317   CHK(ssp_rng_ref_put(rng[1]) == RES_OK);
    318   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
    319 
    320   CHK(ssp_rng_proxy_create_from_rng(NULL, rng[0], 4, &proxy) == RES_OK);
    321   CHK(ssp_rng_ref_put(rng[0]) == RES_OK);
    322   FOR_EACH(i, 0, 4) CHK(ssp_rng_proxy_create_rng(proxy, i, &rng[i]) == RES_OK);
    323   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
    324 
    325   CHK(ssp_rng_get_type(rng[0], &type) == RES_OK);
    326   FOR_EACH(i, 1, 4) {
    327     enum ssp_rng_type type2;
    328     CHK(ssp_rng_get_type(rng[i], &type2) == RES_OK);
    329     CHK(type == type2);
    330   }
    331 
    332   FOR_EACH(i, 0, NRANDS) {
    333     FOR_EACH(j, 0, 4) {
    334       r[j] = ssp_rng_get(rng[j]);
    335       FOR_EACH(k, 0, j) CHK(r[k] != r[j]);
    336     }
    337   }
    338 
    339   FOR_EACH(i, 1, 4) CHK(ssp_rng_ref_put(rng[i]) == RES_OK);
    340 
    341   args.rng = rng[0];
    342   args.sequence_offset = 0;
    343   args.sequence_size = 4000;
    344   args.sequence_pitch = 4000;
    345   args.nbuckets = 4;
    346   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG);
    347   CHK(ssp_rng_ref_put(rng[0]) == RES_OK);
    348 
    349   CHK(ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng[0]) == RES_OK);
    350   CHK(ssp_rng_discard(rng[0], 100) == RES_OK);
    351 
    352   args.rng = rng[0];
    353   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK);
    354   CHK(ssp_rng_ref_put(rng[0]) == RES_OK);
    355   FOR_EACH(i, 0, 4) {
    356     CHK(ssp_rng_proxy_create_rng(proxy, i, &rng[i]) == RES_OK);
    357   }
    358 
    359   FOR_EACH(i, 0, NRANDS) {
    360     FOR_EACH(j, 0, 4) {
    361       r[j] = ssp_rng_get(rng[j]);
    362       FOR_EACH(k, 0, j) CHK(r[k] != r[j]);
    363     }
    364   }
    365 
    366   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
    367   FOR_EACH(i, 0, 4) CHK(ssp_rng_ref_put(rng[i]) == RES_OK);
    368 }
    369 
    370 static void
    371 test_read(void)
    372 {
    373   struct ssp_rng_proxy* proxy;
    374   struct ssp_rng* rng;
    375   struct ssp_rng* rng1[4];
    376   FILE* stream;
    377   uint64_t r[4];
    378   size_t i, j, k;
    379 
    380   CHK(ssp_rng_create(NULL, SSP_RNG_MT19937_64, &rng) == RES_OK);
    381   CHK(ssp_rng_discard(rng, COUNT) == RES_OK);
    382 
    383   /* Create a RNG state */
    384   stream = tmpfile();
    385   CHK(stream != NULL);
    386   CHK(ssp_rng_write(rng, stream) == RES_OK);
    387   rewind(stream);
    388 
    389   /* Create a proxy from the RNG state */
    390   CHK(ssp_rng_proxy_create(NULL, SSP_RNG_MT19937_64, 4, &proxy) == RES_OK);
    391   CHK(ssp_rng_proxy_read(NULL, NULL) == RES_BAD_ARG);
    392   CHK(ssp_rng_proxy_read(proxy, NULL) == RES_BAD_ARG);
    393   CHK(ssp_rng_proxy_read(NULL, stream) == RES_BAD_ARG);
    394   CHK(ssp_rng_proxy_read(proxy, stream) == RES_OK);
    395 
    396   /* Create the list of RNG managed by the proxy */
    397   FOR_EACH(i, 0, 4) CHK(ssp_rng_proxy_create_rng(proxy, i, &rng1[i]) == RES_OK);
    398 
    399   /* Check the random number sequences */
    400   r[0] = ssp_rng_get(rng);
    401   CHK(r[0] == ssp_rng_get(rng1[0]));
    402   CHK(r[0] != ssp_rng_get(rng1[1]));
    403   CHK(r[0] != ssp_rng_get(rng1[2]));
    404   CHK(r[0] != ssp_rng_get(rng1[3]));
    405   FOR_EACH(i, 0, NRANDS) {
    406     FOR_EACH(j, 0, 4) {
    407       r[j] = ssp_rng_get(rng1[j]);
    408       FOR_EACH(k, 0, j) CHK(r[k] != r[j]);
    409     }
    410   }
    411 
    412   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
    413   CHK(ssp_rng_ref_put(rng) == RES_OK);
    414   FOR_EACH(i, 0, 4) CHK(ssp_rng_ref_put(rng1[i]) == RES_OK);
    415 
    416   CHK(fclose(stream) == 0);
    417 }
    418 
    419 static void
    420 test_read_with_cached_states(void)
    421 {
    422   struct ssp_rng_proxy_create2_args args = SSP_RNG_PROXY_CREATE2_ARGS_NULL;
    423   struct ssp_rng_proxy* proxy;
    424   struct ssp_rng* rng;
    425   struct ssp_rng* rng0;
    426   struct ssp_rng* rng1;
    427   FILE* stream;
    428   size_t iseq;
    429   size_t i;
    430 
    431   CHK(ssp_rng_create(NULL, SSP_RNG_MT19937_64, &rng) == RES_OK);
    432 
    433   /* Create a proxy with a very small sequence size of 2 RNs per bucket in
    434    * order to maximize the number of cached states. Furthermore, use the
    435    * Mersenne Twister RNG type since its internal state is the greatest one of
    436    * the proposed builtin type and is thus the one that will fill quickly the
    437    * cache stream. */
    438   args.type = SSP_RNG_MT19937_64;
    439   args.sequence_size = 10;
    440   args.sequence_pitch = 10;
    441   args.nbuckets = 2;
    442   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK);
    443   CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng0) == RES_OK);
    444   CHK(ssp_rng_proxy_create_rng(proxy, 1, &rng1) == RES_OK);
    445 
    446   /* Check RNG states */
    447   FOR_EACH(i, 0, args.sequence_size) {
    448     if(i < args.sequence_size/2) {
    449       CHK(ssp_rng_get(rng) == ssp_rng_get(rng0));
    450     } else {
    451       CHK(ssp_rng_get(rng) == ssp_rng_get(rng1));
    452     }
    453   }
    454 
    455   /* Discard several RNs for the 1st RNG to cache several states for the rng1 */
    456   CHK(ssp_rng_discard(rng0, 103) == RES_OK);
    457 
    458   /* Generate a RNG state */
    459   stream = tmpfile();
    460   CHK(stream != NULL);
    461   CHK(ssp_rng_discard(rng, 100000) == RES_OK);
    462   CHK(ssp_rng_write(rng, stream) == RES_OK);
    463   rewind(stream);
    464 
    465   /* Setup the proxy state and check that the RNGs managed by the proxy now use
    466    * the new state properly, even though RNG states were previously cached */
    467   CHK(ssp_rng_proxy_read(proxy, stream) == RES_OK);
    468   FOR_EACH(iseq, 0, 100) {
    469     FOR_EACH(i, 0, args.sequence_size) {
    470       if(i < args.sequence_size/2) {
    471         CHK(ssp_rng_get(rng) == ssp_rng_get(rng0));
    472       } else {
    473         CHK(ssp_rng_get(rng) == ssp_rng_get(rng1));
    474       }
    475     }
    476   }
    477 
    478   /* Discard several RNs for the first RNG only to make under pressure the
    479    * cache stream of 'rng1'. The cache memory limit is 32 MB maximum and the
    480    * size of a Mersenne Twister RNG state is greater than 6 KB. Consquently,
    481    * ~5500 RNG states will exceed the cache stream, i.e. 5500*2 = 11000
    482    * random generations (since there is 2 RNs per bucket). Above this limit,
    483    * 'rng1' will not rely anymore on the proxy RNG to manage its state. */
    484   CHK(ssp_rng_discard(rng0, 20000) == RES_OK);
    485 
    486   /* Generate a new RNG state */
    487   rewind(stream);
    488   CHK(ssp_rng_discard(rng, 100000) == RES_OK);
    489   CHK(ssp_rng_write(rng, stream) == RES_OK);
    490   rewind(stream);
    491 
    492   /* Now setup a new proxy state and check that the RNGs managed by the proxy
    493    * correctly use the new state */
    494   CHK(ssp_rng_proxy_read(proxy, stream) == RES_OK);
    495   FOR_EACH(iseq, 0, 100) {
    496     FOR_EACH(i, 0, args.sequence_size) {
    497       if(i < args.sequence_size/2) {
    498         CHK(ssp_rng_get(rng) == ssp_rng_get(rng0));
    499       } else {
    500         CHK(ssp_rng_get(rng) == ssp_rng_get(rng1));
    501       }
    502     }
    503   }
    504 
    505   /* Discard several RNs for the 1st RNG to cache several states for the rng1 */
    506   CHK(ssp_rng_discard(rng0, 100) == RES_OK);
    507 
    508   /* Finally verify that the cache was reset on proxy read */
    509   FOR_EACH(iseq, 0, 100) {
    510     FOR_EACH(i, 0, args.sequence_size) {
    511       if(i < args.sequence_size/2) {
    512         CHK(ssp_rng_discard(rng, 1) == RES_OK);
    513       } else {
    514         CHK(ssp_rng_get(rng) == ssp_rng_get(rng1));
    515       }
    516     }
    517   }
    518 
    519   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
    520   CHK(ssp_rng_ref_put(rng0) == RES_OK);
    521   CHK(ssp_rng_ref_put(rng1) == RES_OK);
    522   CHK(ssp_rng_ref_put(rng) == RES_OK);
    523 
    524   CHK(fclose(stream) == 0);
    525 }
    526 
    527 static void
    528 test_write(void)
    529 {
    530   struct ssp_rng_proxy* proxy;
    531   struct ssp_rng* rng0;
    532   struct ssp_rng* rng1;
    533   FILE* stream;
    534   uint64_t r;
    535 
    536   stream = tmpfile();
    537   CHK(stream != NULL);
    538 
    539   CHK(ssp_rng_proxy_create(NULL, SSP_RNG_RANLUX48, 1, &proxy) == RES_OK);
    540   CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng0) == RES_OK);
    541 
    542   CHK(ssp_rng_proxy_write(NULL, NULL) == RES_BAD_ARG);
    543   CHK(ssp_rng_proxy_write(proxy, NULL) == RES_BAD_ARG);
    544   CHK(ssp_rng_proxy_write(NULL, stream) == RES_BAD_ARG);
    545   CHK(ssp_rng_proxy_write(proxy, stream) == RES_OK);
    546 
    547   CHK(ssp_rng_create(NULL, SSP_RNG_RANLUX48, &rng1) == RES_OK);
    548   r = ssp_rng_get(rng0);
    549   CHK(r == ssp_rng_get(rng1));
    550 
    551   rewind(stream);
    552   CHK(ssp_rng_read(rng1, stream) == RES_OK);
    553   CHK(r == ssp_rng_get(rng1));
    554   CHK(ssp_rng_get(rng0) == ssp_rng_get(rng1));
    555 
    556   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
    557   CHK(ssp_rng_ref_put(rng0) == RES_OK);
    558   CHK(ssp_rng_ref_put(rng1) == RES_OK);
    559 
    560   CHK(fclose(stream) == 0);
    561 }
    562 
    563 static void
    564 test_cache(void)
    565 {
    566   struct ssp_rng_proxy_create2_args args = SSP_RNG_PROXY_CREATE2_ARGS_NULL;
    567   struct ssp_rng_proxy* proxy;
    568   struct ssp_rng* rng0;
    569   struct ssp_rng* rng1;
    570   struct ssp_rng* rng;
    571   const size_t nrands = 20000;
    572   size_t i;
    573 
    574   /* Create a proxy with a very small sequence size of 2 RNs per bucket in
    575    * order to maximize the number of cached states. Furthermore, use the
    576    * Mersenne Twister RNG type since its internal state is the greatest one of
    577    * the proposed builtin type and is thus the one that will fill quickly the
    578    * cache stream. */
    579   args.type = SSP_RNG_MT19937_64;
    580   args.sequence_size = 4;
    581   args.sequence_pitch = 4;
    582   args.nbuckets = 2;
    583 
    584   /* Simply test that the RNs generated by the proxy are the same than the
    585    * ones generated by a regular RNG. Since each RNG invocation are
    586    * interleaved, the cache pressure is very low, at most 1 RNG state is
    587    * cached. */
    588   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK);
    589   CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng0) == RES_OK);
    590   CHK(ssp_rng_proxy_create_rng(proxy, 1, &rng1) == RES_OK);
    591   CHK(ssp_rng_create(NULL, SSP_RNG_MT19937_64, &rng) == RES_OK);
    592   FOR_EACH(i, 0, nrands*2) {
    593     if((i / 2) % 2) {
    594       CHK(ssp_rng_get(rng1) == ssp_rng_get(rng));
    595     } else {
    596       CHK(ssp_rng_get(rng0) == ssp_rng_get(rng));
    597     }
    598   }
    599   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
    600   CHK(ssp_rng_ref_put(rng0) == RES_OK);
    601   CHK(ssp_rng_ref_put(rng1) == RES_OK);
    602   CHK(ssp_rng_ref_put(rng) == RES_OK);
    603 
    604   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK);
    605   CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng0) == RES_OK);
    606   CHK(ssp_rng_proxy_create_rng(proxy, 1, &rng1) == RES_OK);
    607   CHK(ssp_rng_create(NULL, SSP_RNG_MT19937_64, &rng) == RES_OK);
    608 
    609   /* Generate several RNs for the first RNG only to make under pressure the
    610    * cache stream of 'rng1'. The cache memory limit is 32 MB maximum and the
    611    * size of a Mersenne Twister RNG state is greater than 6 KB. Consquently,
    612    * ~5500 RNG states will exceed the cache stream, i.e. 5500*2 = 11000
    613    * random generations (since there is 2 RNs per bucket). Above this limit,
    614    * 'rng1' will not rely anymore on the proxy RNG to manage its state.
    615    *
    616    * For both RNGs, ensure that the generated RNs are the expected ones by
    617    * comparing them to the ones generated by a regular RNG */
    618   FOR_EACH(i, 0, nrands) {
    619     CHK(ssp_rng_get(rng0) == ssp_rng_get(rng));
    620     if(i % 2) CHK(ssp_rng_discard(rng, 2) == RES_OK);
    621   }
    622   CHK(ssp_rng_ref_put(rng) == RES_OK);
    623 
    624   /* Check the cache mechanisme of rng1 */
    625   CHK(ssp_rng_create(NULL, SSP_RNG_MT19937_64, &rng) == RES_OK);
    626   CHK(ssp_rng_discard(rng, 2) == RES_OK);
    627   FOR_EACH(i, 0, nrands) {
    628     CHK(ssp_rng_get(rng1) == ssp_rng_get(rng));
    629     if(i % 2) CHK(ssp_rng_discard(rng, 2) == RES_OK);
    630   }
    631 
    632   CHK(ssp_rng_ref_put(rng) == RES_OK);
    633 
    634   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
    635   CHK(ssp_rng_ref_put(rng0) == RES_OK);
    636   CHK(ssp_rng_ref_put(rng1) == RES_OK);
    637 }
    638 
    639 
    640 static void
    641 test_sequence(void)
    642 {
    643   struct ssp_rng_proxy_create2_args args = SSP_RNG_PROXY_CREATE2_ARGS_NULL;
    644   struct ssp_rng_proxy* proxy;
    645   struct ssp_rng* rng0;
    646   struct ssp_rng* rng1;
    647   struct ssp_rng* rng;
    648   size_t id;
    649   size_t iseq;
    650   size_t i;
    651 
    652   args.type = SSP_RNG_MT19937_64;
    653   args.sequence_offset = 0;
    654   args.sequence_size = 16;
    655   args.sequence_pitch = 16;
    656   args.nbuckets = 2;
    657 
    658   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK);
    659   CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng0) == RES_OK);
    660   CHK(ssp_rng_proxy_create_rng(proxy, 1, &rng1) == RES_OK);
    661   CHK(ssp_rng_create(NULL, SSP_RNG_MT19937_64, &rng) == RES_OK);
    662 
    663   CHK(ssp_rng_proxy_get_sequence_id(NULL, &id) == RES_BAD_ARG);
    664   CHK(ssp_rng_proxy_get_sequence_id(proxy, NULL) == RES_BAD_ARG);
    665 
    666   /* Check that directly after its creation, the proxy has a the sequence index
    667    * of SSP_SEQUENCE_ID_NONE */
    668   CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
    669   CHK(id == SSP_SEQUENCE_ID_NONE);
    670 
    671   /* Generate 4 sequences of random numbers and check the progression of the
    672    * sequence index */
    673   FOR_EACH(iseq, 0, 4) {
    674     FOR_EACH(i, 0, args.sequence_size) {
    675       if(i < args.sequence_size/2) {
    676         CHK(ssp_rng_get(rng) == ssp_rng_get(rng0));
    677       } else {
    678         CHK(ssp_rng_get(rng) == ssp_rng_get(rng1));
    679       }
    680       CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
    681       CHK(id == iseq);
    682     }
    683   }
    684 
    685   /* Generate 1 more RN to go to the next sequence. Then, discard the remaining
    686    * random numbers of the first RNG and check the the sequence is the same
    687    * until a new RN is discarded */
    688   CHK(ssp_rng_get(rng) == ssp_rng_get(rng0));
    689   CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
    690   CHK(id == 4);
    691   CHK(ssp_rng_discard(rng0, args.sequence_size/2 - 1) == RES_OK);
    692   CHK(ssp_rng_discard(rng,  args.sequence_size/2 - 1) == RES_OK);
    693   CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
    694   CHK(id == 4);
    695   CHK(ssp_rng_discard(rng0, 1) == RES_OK);
    696   CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
    697   CHK(id == 5);
    698 
    699   /* Check the random sequence of the second RNG */
    700   FOR_EACH(i, 0, args.sequence_size/2) {
    701     CHK(ssp_rng_get(rng) == ssp_rng_get(rng1));
    702   }
    703 
    704   /* Check the sequence of the first RNG */
    705   CHK(ssp_rng_discard(rng, 1) == RES_OK);
    706   CHK(ssp_rng_get(rng) == ssp_rng_get(rng0));
    707 
    708   /* Discard the random numbers of the current sequence associated to the
    709    * second RNG. Check the the sequence is the same until a new random number
    710    * is discarded */
    711   CHK(ssp_rng_discard(rng1, args.sequence_size/2) == RES_OK);
    712   CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
    713   CHK(id == 5);
    714   CHK(ssp_rng_discard(rng1, 1) == RES_OK);
    715   CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
    716   CHK(id == 6);
    717 
    718   /* Synchronise the RNGs through sequence 6 */
    719   CHK(ssp_rng_discard(rng0, args.sequence_size/2-2) == RES_OK);
    720   CHK(ssp_rng_discard(rng, args.sequence_size-2) == RES_OK);
    721   FOR_EACH(i, 0, args.sequence_size) {
    722     if(i < args.sequence_size/2) {
    723       CHK(ssp_rng_get(rng) == ssp_rng_get(rng0));
    724     } else if(i == args.sequence_size/2) {
    725       CHK(ssp_rng_discard(rng, 1) == RES_OK);
    726     } else {
    727       CHK(ssp_rng_get(rng) == ssp_rng_get(rng1));
    728     }
    729   }
    730   CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
    731   CHK(id == 6);
    732 
    733   /* Move in sequence 7 */
    734   CHK(ssp_rng_discard(rng0, 3) == RES_OK);
    735   CHK(ssp_rng_discard(rng1, 7) == RES_OK);
    736   CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
    737   CHK(id == 7);
    738 
    739   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
    740   CHK(ssp_rng_ref_put(rng1) == RES_OK);
    741   CHK(ssp_rng_ref_put(rng0) == RES_OK);
    742   CHK(ssp_rng_ref_put(rng) == RES_OK);
    743 }
    744 
    745 static void
    746 test_flush_sequence()
    747 {
    748   struct ssp_rng_proxy_create2_args args = SSP_RNG_PROXY_CREATE2_ARGS_NULL;
    749   struct ssp_rng_proxy* proxy;
    750   struct ssp_rng* rng0;
    751   struct ssp_rng* rng1;
    752   struct ssp_rng* rng;
    753   size_t id;
    754   size_t i;
    755 
    756   args.type = SSP_RNG_MT19937_64;
    757   args.sequence_offset = 0;
    758   args.sequence_size = 10;
    759   args.sequence_pitch = 10;
    760   args.nbuckets = 2;
    761 
    762   CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK);
    763   CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng0) == RES_OK);
    764   CHK(ssp_rng_proxy_create_rng(proxy, 1, &rng1) == RES_OK);
    765   CHK(ssp_rng_create(NULL, SSP_RNG_MT19937_64, &rng) == RES_OK);
    766 
    767   CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
    768   CHK(id == SSP_SEQUENCE_ID_NONE);
    769   CHK(ssp_rng_get(rng) == ssp_rng_get(rng0));
    770 
    771   /* Flush 0 sequence, i.e. do nothing */
    772   CHK(ssp_rng_proxy_flush_sequences(NULL, 0) == RES_BAD_ARG);
    773   CHK(ssp_rng_proxy_flush_sequences(proxy, 0) == RES_OK);
    774   CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
    775   CHK(id == 0);
    776   CHK(ssp_rng_get(rng) == ssp_rng_get(rng0));
    777 
    778   /* Discard several numbers of the rng1 to fill the cache of rng0. We will
    779    * thus be able to check the cache clearing when we will flush sequences */
    780   CHK(ssp_rng_discard(rng1, 314) == RES_OK);
    781   CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
    782   CHK(id == 62);
    783 
    784   /* Flush the remaining random number of the current sequence */
    785   CHK(ssp_rng_proxy_flush_sequences(proxy, 1) == RES_OK);
    786 
    787   /* We are still in the sequence 62 but without any available random numbers */
    788   CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
    789   CHK(id == 62);
    790 
    791   /* Synchronize RNG with the current state of the proxy */
    792   CHK(ssp_rng_discard
    793     (rng, args.sequence_size*63 /*#random number to discard */
    794      - 2/*... minus the 2 already consumed random numbers*/) == RES_OK);
    795 
    796   /* Check RNG states */
    797   FOR_EACH(i, 0, args.sequence_size) {
    798     if(i < args.sequence_size/2) {
    799       CHK(ssp_rng_get(rng) == ssp_rng_get(rng0));
    800     } else {
    801       CHK(ssp_rng_get(rng) == ssp_rng_get(rng1));
    802     }
    803     CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
    804     CHK(id == 63);
    805   }
    806 
    807   /* Fill the cache of the rng1 */
    808   CHK(ssp_rng_discard(rng0, 1013) == RES_OK);
    809   CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
    810   CHK(id == 63 + 203/*ceil(1013/(args.sequence_size*0.5))*/);
    811 
    812   /* Discard several sequences */
    813   CHK(ssp_rng_proxy_flush_sequences(proxy, 314) == RES_OK);
    814 
    815   /* Synchronize RNG with the current state of the proxy */
    816   CHK(ssp_rng_discard(rng, args.sequence_size*(203 + 314 - 1)) == RES_OK);
    817 
    818   /* Check RNG states */
    819   FOR_EACH(i, 0, args.sequence_size) {
    820     if(i < args.sequence_size/2) {
    821       CHK(ssp_rng_get(rng) == ssp_rng_get(rng0));
    822     } else {
    823       CHK(ssp_rng_get(rng) == ssp_rng_get(rng1));
    824     }
    825     CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
    826     CHK(id == 63 + 203 + 314);
    827   }
    828 
    829   /* Generate several RNs for the first RNG only to make under pressure the
    830    * cache stream of 'rng1'. The cache memory limit is 32 MB maximum and the
    831    * size of a Mersenne Twister RNG state is greater than 6 KB. Consquently,
    832    * ~5500 RNG states will exceed the cache stream, i.e. 5500*5 = 27500
    833    * random generations (since there is 5 RNs per bucket). Above this limit,
    834    * 'rng1' will not rely anymore on the proxy RNG to manage its state. */
    835   CHK(ssp_rng_discard(rng0, 30000) == RES_OK);
    836 
    837   /* Discard enough random numbers from rng1 to consume all cached RNG states,
    838    * and thus disable read cache usage */
    839   CHK(ssp_rng_discard(rng1, 30000) == RES_OK);
    840 
    841   CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK);
    842   CHK(id == 63+203+314+(30000*2)/args.sequence_size);
    843 
    844   /* Try to flush a sequence on a proxy whose a generator don't use cache */
    845   CHK(ssp_rng_proxy_flush_sequences(proxy, 1) == RES_OK);
    846 
    847   CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK);
    848   CHK(ssp_rng_ref_put(rng1) == RES_OK);
    849   CHK(ssp_rng_ref_put(rng0) == RES_OK);
    850   CHK(ssp_rng_ref_put(rng) == RES_OK);
    851 }
    852 
    853 int
    854 main(int argc, char** argv)
    855 {
    856   (void)argc, (void)argv;
    857   test_creation();
    858   test_creation2();
    859   test_rng_from_proxy();
    860   test_rng_from_proxy2();
    861   test_multi_proxies();
    862   test_proxy_from_rng();
    863   test_read();
    864   test_read_with_cached_states();
    865   test_write();
    866   test_cache();
    867   test_sequence();
    868   test_flush_sequence();
    869   CHK(mem_allocated_size() == 0);
    870   return 0;
    871 }