From 666f5dac4eba920a1ba17042f3f14a316dbbf00d Mon Sep 17 00:00:00 2001
From: "a.stevan" <antoine.stevan@isae-supaero.fr>
Date: Tue, 28 May 2024 17:27:18 +0200
Subject: [PATCH 1/2] add `random` to `inbreeding` to draw elements

---
 bins/inbreeding/src/main.rs   |  1 +
 bins/inbreeding/src/random.rs | 25 +++++++++++++++++++++++++
 2 files changed, 26 insertions(+)
 create mode 100644 bins/inbreeding/src/random.rs

diff --git a/bins/inbreeding/src/main.rs b/bins/inbreeding/src/main.rs
index 71beb012..212b0cae 100644
--- a/bins/inbreeding/src/main.rs
+++ b/bins/inbreeding/src/main.rs
@@ -12,6 +12,7 @@ use komodo::{
 use rand::{rngs::StdRng, seq::SliceRandom, Rng, RngCore, SeedableRng};
 
 mod environment;
+mod random;
 mod strategy;
 
 use crate::{environment::Environment, strategy::Strategy};
diff --git a/bins/inbreeding/src/random.rs b/bins/inbreeding/src/random.rs
new file mode 100644
index 00000000..8593049f
--- /dev/null
+++ b/bins/inbreeding/src/random.rs
@@ -0,0 +1,25 @@
+use rand::{Rng, RngCore};
+use std::collections::HashSet;
+
+fn draw_unique_indices(n: usize, vec_len: usize, rng: &mut impl RngCore) -> HashSet<usize> {
+    let mut indices = HashSet::new();
+
+    while indices.len() < n {
+        let idx = rng.gen_range(0..vec_len);
+        indices.insert(idx);
+    }
+
+    indices
+}
+
+pub(super) fn draw_unique_elements<T: Clone>(
+    things: &[T],
+    n: usize,
+    rng: &mut impl RngCore,
+) -> Vec<T> {
+    let mut res = vec![];
+    for i in draw_unique_indices(n, things.len(), rng) {
+        res.push(things[i].clone());
+    }
+    res
+}
-- 
GitLab


From 57c7e9b1b7da5817e1ab7cde869c6cd8f7206031 Mon Sep 17 00:00:00 2001
From: "a.stevan" <antoine.stevan@isae-supaero.fr>
Date: Tue, 28 May 2024 17:27:43 +0200
Subject: [PATCH 2/2] use `draw_unique_elements` to draw shards

---
 bins/inbreeding/src/environment.rs | 27 ++++++++++++---------------
 bins/inbreeding/src/main.rs        |  8 +++-----
 bins/inbreeding/src/strategy.rs    |  9 ++++-----
 3 files changed, 19 insertions(+), 25 deletions(-)

diff --git a/bins/inbreeding/src/environment.rs b/bins/inbreeding/src/environment.rs
index 2b1feaeb..11357823 100644
--- a/bins/inbreeding/src/environment.rs
+++ b/bins/inbreeding/src/environment.rs
@@ -1,4 +1,6 @@
-use rand::{seq::SliceRandom, Rng, RngCore};
+use rand::{Rng, RngCore};
+
+use crate::random::draw_unique_elements;
 
 #[derive(Debug, PartialEq)]
 pub(super) enum Environment {
@@ -14,28 +16,23 @@ impl Environment {
     /// `update(things, rng)` is `things` with some elements potentially removed according to the
     /// [`Environment`] type
     pub(super) fn update<T: Clone>(&self, things: &[T], rng: &mut impl RngCore) -> Vec<T> {
-        let mut things = things.to_vec();
-        things.shuffle(rng);
-
-        match self {
-            Environment::Fixed { n } => things.iter().take(things.len() - n),
+        let nb_to_take = match self {
+            Environment::Fixed { n } => things.len() - n,
             Environment::RandomFixed { p, n } => {
                 if rng.gen::<f64>() > *p {
-                    return things;
+                    return things.to_vec();
                 }
-                things.iter().take(things.len() - n)
+                things.len() - n
             }
             Environment::RandomDynamic { p, q } => {
                 if rng.gen::<f64>() > *p {
-                    return things;
+                    return things.to_vec();
                 }
-                things
-                    .iter()
-                    .take((things.len() as f64 * (1.0 - q)) as usize)
+                (things.len() as f64 * (1.0 - q)) as usize
             }
-        }
-        .cloned()
-        .collect()
+        };
+
+        draw_unique_elements(things, nb_to_take, rng)
     }
 
     pub(super) fn from_str(s: &str) -> Result<Self, String> {
diff --git a/bins/inbreeding/src/main.rs b/bins/inbreeding/src/main.rs
index 212b0cae..51f2d08b 100644
--- a/bins/inbreeding/src/main.rs
+++ b/bins/inbreeding/src/main.rs
@@ -9,7 +9,8 @@ use komodo::{
     fec::{self, Shard},
     linalg::Matrix,
 };
-use rand::{rngs::StdRng, seq::SliceRandom, Rng, RngCore, SeedableRng};
+use rand::{rngs::StdRng, Rng, RngCore, SeedableRng};
+use random::draw_unique_elements;
 
 mod environment;
 mod random;
@@ -39,16 +40,13 @@ fn measure_inbreeding<F: PrimeField>(
     sty: &ProgressStyle,
     rng: &mut impl RngCore,
 ) -> f64 {
-    let mut s: Vec<_> = shards.to_vec();
     let mut count = 0;
 
     let pb = mp.add(ProgressBar::new(nb_measurements as u64));
     pb.set_style(sty.clone());
     pb.set_message("measure");
     for _ in 0..nb_measurements {
-        // get any k of the shards
-        s.shuffle(rng);
-        if fec::decode(s.iter().take(k).cloned().collect()).is_ok() {
+        if fec::decode(draw_unique_elements(shards, k, rng)).is_ok() {
             count += 1;
         }
         pb.inc(1);
diff --git a/bins/inbreeding/src/strategy.rs b/bins/inbreeding/src/strategy.rs
index f8f8143e..ffe57360 100644
--- a/bins/inbreeding/src/strategy.rs
+++ b/bins/inbreeding/src/strategy.rs
@@ -1,4 +1,6 @@
-use rand::{seq::SliceRandom, Rng, RngCore};
+use rand::{Rng, RngCore};
+
+use crate::random::draw_unique_elements;
 
 #[derive(Debug, PartialEq)]
 pub(super) enum Strategy {
@@ -8,9 +10,6 @@ pub(super) enum Strategy {
 
 impl Strategy {
     pub(super) fn draw<T: Clone>(&self, things: &[T], rng: &mut impl RngCore) -> Vec<T> {
-        let mut things = things.to_vec();
-        things.shuffle(rng);
-
         let nb_to_take = match self {
             Self::Single { n } => *n,
             Self::Double { p, n, m } => {
@@ -22,7 +21,7 @@ impl Strategy {
             }
         };
 
-        things.iter().take(nb_to_take).cloned().collect()
+        draw_unique_elements(things, nb_to_take, rng)
     }
 
     pub(super) fn from_str(s: &str) -> Result<Self, String> {
-- 
GitLab