✨🧪⬆➕ workspace, varo: Implement RNG with ChaCha8 and add optimization function
- Updated `Cargo.toml` and `Cargo.lock` to downgrade `rand_core` to 0.6.4 and add `rand_chacha` dependency with `serde1` feature. - Implemented `Rng` struct wrapping `ChaCha8Rng` with seed initialization, stream selection, and number generation methods. - Added `rng_new`, `rng_from_seed`, `rng_set_stream`, `rng_next_u32`, `rng_next_u64`, `rng_fill_bytes`, `rng_gen_f32`, and `rng_gen_gaussian` functions. - Made `value` field in `Score` and `values` field in `OptimizationResult` public. - Implemented `Distribution::sample` method that generates Gaussian numbers when moments are available. - Added `From<f32>` implementation for `Score`. - Implemented `optimize` function that evaluates candidates using cloned RNG streams and returns sorted results. - Added integration test `test_optimize` that verifies optimization sorting behavior.
This commit is contained in:
parent
5614cfe95f
commit
db531c8c73
5 changed files with 103 additions and 27 deletions
|
@ -1,18 +1,52 @@
|
|||
use rand_core::SeedableRng;
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::f32::consts::PI;
|
||||
use vanth_derive::Vanth;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, Vanth)]
|
||||
pub struct Rng {
|
||||
// TODO: RNG
|
||||
inner: ChaCha8Rng,
|
||||
}
|
||||
|
||||
impl Rng {
|
||||
// TODO
|
||||
pub fn rng_new() -> Rng {
|
||||
Rng { inner: ChaCha8Rng::from_seed([0u8; 32]) }
|
||||
}
|
||||
|
||||
pub fn rng_from_seed(seed: [u8; 32]) -> Rng {
|
||||
Rng { inner: ChaCha8Rng::from_seed(seed) }
|
||||
}
|
||||
|
||||
pub fn rng_set_stream(rng: &mut Rng, stream: u64) {
|
||||
rng.inner.set_stream(stream);
|
||||
}
|
||||
|
||||
pub fn rng_next_u32(rng: &mut Rng) -> u32 {
|
||||
rng.inner.next_u32()
|
||||
}
|
||||
|
||||
pub fn rng_next_u64(rng: &mut Rng) -> u64 {
|
||||
rng.inner.next_u64()
|
||||
}
|
||||
|
||||
pub fn rng_fill_bytes(rng: &mut Rng, dest: &mut [u8]) {
|
||||
rng.inner.fill_bytes(dest)
|
||||
}
|
||||
|
||||
pub fn rng_gen_f32(rng: &mut Rng) -> f32 {
|
||||
rng_next_u32(rng) as f32 / u32::MAX as f32
|
||||
}
|
||||
|
||||
pub fn rng_gen_gaussian(rng: &mut Rng, mean: f32, std_dev: f32) -> f32 {
|
||||
let u = rng_gen_f32(rng);
|
||||
let v = rng_gen_f32(rng);
|
||||
let s = (-2.0 * (1.0 - u).ln()).sqrt();
|
||||
let angle = 2.0 * PI * v;
|
||||
mean + std_dev * s * angle.cos()
|
||||
}
|
||||
|
||||
pub trait Varo {
|
||||
/// Produce a random
|
||||
/// Produce a random instance of `Self` using the provided RNG.
|
||||
fn next(digest: &mut Rng) -> Self;
|
||||
}
|
||||
|
||||
|
@ -23,27 +57,41 @@ pub struct Distribution {
|
|||
}
|
||||
|
||||
impl Distribution {
|
||||
pub fn sample(digest: &mut Rng) -> f32 {
|
||||
todo!()
|
||||
pub fn sample(&self, digest: &mut Rng) -> f32 {
|
||||
if self.moments.len() >= 2 {
|
||||
rng_gen_gaussian(digest, self.moments[0], self.moments[1].sqrt())
|
||||
} else {
|
||||
rng_gen_f32(digest)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, Vanth)]
|
||||
pub struct Score {
|
||||
value: f32,
|
||||
pub value: f32,
|
||||
}
|
||||
|
||||
impl From<f32> for Score {
|
||||
fn from(value: f32) -> Self {
|
||||
Score { value }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, Vanth)]
|
||||
pub struct OptimizationResult {
|
||||
/// List of pairs of evaluation score and Rng used to generate the value.
|
||||
values: Vec<(Rng, f32)>
|
||||
pub values: Vec<(Rng, f32)>
|
||||
}
|
||||
|
||||
pub fn optimize<T: Varo>(evaluator: impl Fn(T) -> Score, rng: &mut Rng, rounds: u32) -> OptimizationResult {
|
||||
// TODO:
|
||||
// `for i in 0..rounds`: create a clone of `rng` and feed it `i`.
|
||||
// Call T::next() and pass it to the evaluator.
|
||||
// Return a sorted list, highest scores first.
|
||||
|
||||
todo!()
|
||||
let mut values: Vec<(Rng, f32)> = Vec::with_capacity(rounds as usize);
|
||||
for i in 0..rounds {
|
||||
let mut child = rng.clone();
|
||||
rng_set_stream(&mut child, i as u64);
|
||||
let t = T::next(&mut child);
|
||||
let score = evaluator(t).value;
|
||||
values.push((child, score));
|
||||
}
|
||||
values.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
|
||||
OptimizationResult { values }
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue