use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
use std::cell::RefCell;
thread_local! {
static QCRYPTO_RNG: RefCell<ChaCha8Rng> = RefCell::new(ChaCha8Rng::from_os_rng());
}
pub fn set_global_seed(seed: u64) {
QCRYPTO_RNG.with(|rng| {
*rng.borrow_mut() = ChaCha8Rng::seed_from_u64(seed);
});
}
pub fn random_bool(p: f64) -> bool {
QCRYPTO_RNG.with(|rng| rng.borrow_mut().random_bool(p))
}
pub fn random_f64() -> f64 {
QCRYPTO_RNG.with(|rng| rng.borrow_mut().random())
}
pub fn random_f64_range(min: f64, max: f64) -> f64 {
QCRYPTO_RNG.with(|rng| rng.borrow_mut().random_range(min..max))
}
pub fn shuffle_slice<T>(slice: &mut [T]) {
QCRYPTO_RNG.with(|rng| {
rand::seq::SliceRandom::shuffle(slice, &mut *rng.borrow_mut());
});
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_set_global_seed_deterministic() {
set_global_seed(42);
let val1 = random_f64();
set_global_seed(42);
let val2 = random_f64();
assert_eq!(val1, val2);
}
#[test]
fn test_random_bool() {
set_global_seed(123);
assert!(random_bool(1.0));
assert!(!random_bool(0.0));
}
#[test]
fn test_random_f64() {
let val = random_f64();
assert!(val >= 0.0 && val < 1.0);
}
#[test]
fn test_random_f64_range() {
let min = 1.5;
let max = 3.5;
for _ in 0..1000 {
let val = random_f64_range(min, max);
assert!(val >= min && val < max);
}
set_global_seed(999);
let val1 = random_f64_range(min, max);
set_global_seed(999);
let val2 = random_f64_range(min, max);
assert_eq!(val1, val2);
}
#[test]
fn test_shuffle_slice() {
set_global_seed(42);
let mut data1 = vec![1, 2, 3, 4, 5];
shuffle_slice(&mut data1);
set_global_seed(42);
let mut data2 = vec![1, 2, 3, 4, 5];
shuffle_slice(&mut data2);
assert_eq!(data1, data2);
assert_ne!(data1, vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_measurement_determinism_with_seed() {
use crate::{Gate, Measurement, QuantumState};
let create_superposition = || {
let mut state = QuantumState::new(3); state.apply(&Gate::h(), &[0]).unwrap();
state.apply(&Gate::h(), &[1]).unwrap();
state.apply(&Gate::h(), &[2]).unwrap();
state
};
set_global_seed(42);
let mut state1 = create_superposition();
let m1_q0 = state1.measure(&Measurement::z_basis(), &[0]).unwrap();
let m1_q1 = state1.measure(&Measurement::z_basis(), &[1]).unwrap();
let m1_q2 = state1.measure(&Measurement::z_basis(), &[2]).unwrap();
set_global_seed(42);
let mut state2 = create_superposition();
let m2_q0 = state2.measure(&Measurement::z_basis(), &[0]).unwrap();
let m2_q1 = state2.measure(&Measurement::z_basis(), &[1]).unwrap();
let m2_q2 = state2.measure(&Measurement::z_basis(), &[2]).unwrap();
assert_eq!(m1_q0.value, m2_q0.value);
assert_eq!(m1_q1.value, m2_q1.value);
assert_eq!(m1_q2.value, m2_q2.value);
}
}