///|
/// Tiny deterministic RNG used for sampling.
pub struct ReplayRng {
mut state : Int
}
///|
pub fn ReplayRng::new(seed : Int) -> ReplayRng {
{ state: if seed == 0 { 1 } else { seed } }
}
///|
pub fn ReplayRng::next_state(self : ReplayRng) -> Int {
// Small LCG, good enough for sampling order in tests and examples.
self.state = self.state * 1103515245 + 12345
self.state
}
///|
pub fn ReplayRng::next_index(self : ReplayRng, upper : Int) -> Int {
if upper <= 0 {
0
} else {
let raw = self.next_state()
let rem = raw % upper
if rem < 0 {
rem + upper
} else {
rem
}
}
}
///|
pub fn ReplayRng::next_unit(self : ReplayRng) -> Double {
let raw = self.next_state()
let normalized = if raw < 0 { -raw } else { raw }
(normalized % 1_000_000).to_double() / 1_000_000.0
}
///|
fn make_sequential_indices(size : Int) -> Array[Int] {
let indices : Array[Int] = []
let mut i = 0
while i < size {
indices.push(i)
i = i + 1
}
indices
}
///|
fn shuffle_prefix(
indices : Array[Int],
prefix_len : Int,
seed : Int,
) -> Array[Int] {
let rng = ReplayRng::new(seed)
let mut i = 0
while i < prefix_len {
let remaining = indices.length() - i
let j = i + rng.next_index(remaining)
let tmp = indices[i]
indices[i] = indices[j]
indices[j] = tmp
i = i + 1
}
indices
}
///|
fn normalize_positive(value : Double) -> Double {
if value < 0.0 {
-value
} else {
value
}
}