From 2b2783f300c41a68626ebe922a7556209160e4ee Mon Sep 17 00:00:00 2001
From: STEVAN Antoine <antoine.stevan@isae-supaero.fr>
Date: Mon, 27 May 2024 11:12:24 +0000
Subject: [PATCH] Rand (dragoon/komodo!113)

- add `--prng-seed: u8` to fix the random number generator seed

## example
by running the following snippet, we get
- `first.123.png` and `second.123.png` with `--prng-seed 123` which are the same
- `first.111.png` and `second.111.png` with `--prng-seed 111` which are the same
- `first.111.png` and `first.123.png` are different

```bash
use ./scripts/inbreeding

const OPTS = {
    nb_bytes: (10 * 1_024),
    k: 10,
    n: 20,
    nb_scenarii: 10,
    nb_measurements: 10,
    measurement_schedule: 1,
    measurement_schedule_start: 0,
    max_t: 50,
    strategies: [
        "single:1",
        "double:0.5:1:2",
        "single:2"
        "double:0.5:2:3",
        "single:3"
        "single:5"
        "single:10",
    ],
    environment: "random-fixed:0.5:1",
}

inbreeding build

inbreeding run --options $OPTS --prng-seed 123 --output /tmp/first.123.nuon
inbreeding plot /tmp/first.123.nuon --options { k: $OPTS.k } --save /tmp/first.123.png

inbreeding run --options $OPTS --prng-seed 123 --output /tmp/second.123.nuon
inbreeding plot /tmp/second.123.nuon --options { k: $OPTS.k } --save /tmp/second.123.png

inbreeding run --options $OPTS --prng-seed 111 --output /tmp/first.111.nuon
inbreeding plot /tmp/first.111.nuon --options { k: $OPTS.k } --save /tmp/first.111.png

inbreeding run --options $OPTS --prng-seed 111 --output /tmp/second.111.nuon
inbreeding plot /tmp/second.111.nuon --options { k: $OPTS.k } --save /tmp/second.111.png
```

| seed | first | second |
| ---- | ----- | ------ |
| 123  | ![first.123](/uploads/6b09bf94ca7019e200a47e1a53adc533/first.123.png) | ![second.123](/uploads/fa77c1be84d6279f71cbfe3064c83242/second.123.png) |
| 111  | ![first.111](/uploads/bd31a0832825ecbef48178b2e8689a6f/first.111.png) | ![second.111](/uploads/e1c00e0a6765e82388a3c7142847bbab/second.111.png) |
---
 examples/inbreeding/environment.rs |  6 +++---
 examples/inbreeding/mod.rs         | 11 ++++++++---
 examples/inbreeding/strategy.rs    |  4 ++--
 scripts/inbreeding/run.nu          |  5 ++++-
 4 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/examples/inbreeding/environment.rs b/examples/inbreeding/environment.rs
index ff223dfd..2b1feaeb 100644
--- a/examples/inbreeding/environment.rs
+++ b/examples/inbreeding/environment.rs
@@ -1,4 +1,4 @@
-use rand::{seq::SliceRandom, RngCore};
+use rand::{seq::SliceRandom, Rng, RngCore};
 
 #[derive(Debug, PartialEq)]
 pub(super) enum Environment {
@@ -20,13 +20,13 @@ impl Environment {
         match self {
             Environment::Fixed { n } => things.iter().take(things.len() - n),
             Environment::RandomFixed { p, n } => {
-                if rand::random::<f64>() > *p {
+                if rng.gen::<f64>() > *p {
                     return things;
                 }
                 things.iter().take(things.len() - n)
             }
             Environment::RandomDynamic { p, q } => {
-                if rand::random::<f64>() > *p {
+                if rng.gen::<f64>() > *p {
                     return things;
                 }
                 things
diff --git a/examples/inbreeding/mod.rs b/examples/inbreeding/mod.rs
index cc2f524d..730e8f24 100644
--- a/examples/inbreeding/mod.rs
+++ b/examples/inbreeding/mod.rs
@@ -41,14 +41,14 @@ use komodo::{
     fec::{self, Shard},
     linalg::Matrix,
 };
-use rand::{rngs::ThreadRng, seq::SliceRandom, thread_rng, Rng, RngCore};
+use rand::{rngs::StdRng, seq::SliceRandom, Rng, RngCore, SeedableRng};
 
 mod environment;
 mod strategy;
 
 use crate::{environment::Environment, strategy::Strategy};
 
-fn random_bytes(n: usize, rng: &mut ThreadRng) -> Vec<u8> {
+fn random_bytes(n: usize, rng: &mut impl RngCore) -> Vec<u8> {
     (0..n).map(|_| rng.gen::<u8>()).collect()
 }
 
@@ -222,6 +222,9 @@ struct Cli {
     measurement_schedule: usize,
     #[arg(long)]
     measurement_schedule_start: usize,
+
+    #[arg(long)]
+    prng_seed: u8,
 }
 
 fn main() {
@@ -235,7 +238,9 @@ fn main() {
         exit(1);
     }
 
-    let mut rng = thread_rng();
+    let mut seed: [u8; 32] = [0; 32];
+    seed[0] = cli.prng_seed;
+    let mut rng = StdRng::from_seed(seed);
 
     let bytes = random_bytes(cli.nb_bytes, &mut rng);
 
diff --git a/examples/inbreeding/strategy.rs b/examples/inbreeding/strategy.rs
index 0bc12642..f8f8143e 100644
--- a/examples/inbreeding/strategy.rs
+++ b/examples/inbreeding/strategy.rs
@@ -1,4 +1,4 @@
-use rand::{seq::SliceRandom, RngCore};
+use rand::{seq::SliceRandom, Rng, RngCore};
 
 #[derive(Debug, PartialEq)]
 pub(super) enum Strategy {
@@ -14,7 +14,7 @@ impl Strategy {
         let nb_to_take = match self {
             Self::Single { n } => *n,
             Self::Double { p, n, m } => {
-                if rand::random::<f64>() < *p {
+                if rng.gen::<f64>() < *p {
                     *n
                 } else {
                     *m
diff --git a/scripts/inbreeding/run.nu b/scripts/inbreeding/run.nu
index d6cdc509..bf665af1 100644
--- a/scripts/inbreeding/run.nu
+++ b/scripts/inbreeding/run.nu
@@ -14,7 +14,8 @@ export def main [
         max_t: int,
         strategies: list<string>,
         environment: string,
-    >
+    >,
+    --prng-seed: int = 0,
 ] {
     if $baseline {
         ^$BIN ...[
@@ -26,6 +27,7 @@ export def main [
             --measurement-schedule-start $options.measurement_schedule_start
             -t $options.max_t
             --test-case end-to-end
+            --prng-seed $prng_seed
         ] | lines | into float | save --force baseline.nuon
 
         print "baseline saved to `baseline.nuon`"
@@ -44,6 +46,7 @@ export def main [
                 --test-case recoding
                 --strategy $s
                 --environment $options.environment
+                --prng-seed $prng_seed
             ]
                 | lines
                 | parse "{t}, {diversity}"
-- 
GitLab