use crate::Simulation;
use crate::SimulationParameters;
use rand::Rng;
pub type ObjectiveScore = f64;
pub fn monte_carlo_search(
mut simulation_parameters_generator: impl FnMut() -> SimulationParameters,
replications_limit: u32,
objective_function: impl Fn(&Simulation) -> ObjectiveScore,
) -> Option<Simulation> {
let mut approx_optimal_simulation: Option<Simulation> = None;
let mut high_score = ObjectiveScore::MIN;
for _ in 0..replications_limit {
let mut simulation = Simulation::new(simulation_parameters_generator());
simulation.run();
let score = objective_function(&simulation);
if score > high_score {
approx_optimal_simulation = Some(simulation.clone());
high_score = score;
}
}
approx_optimal_simulation
}
pub fn simulated_annealing_search(
initial_parameters_generator: impl Fn() -> SimulationParameters,
perturb_function: impl Fn(&SimulationParameters) -> SimulationParameters,
objective_function: impl Fn(&Simulation) -> ObjectiveScore,
summon_chaotic_flux: impl Fn(u32) -> f64,
replications_limit: u32,
) -> Option<SimulationParameters> {
let mut current_params = initial_parameters_generator();
let mut best_params = current_params.clone();
let mut current_world = Simulation::new(current_params.clone());
current_world.run();
let mut current_score = objective_function(¤t_world);
let mut best_score = current_score;
for chaotic_mana in (1..=replications_limit).rev() {
let k = replications_limit - chaotic_mana + 1;
let chaotic_flux = summon_chaotic_flux(k);
let new_params = perturb_function(¤t_params);
let mut parallel_world = Simulation::new(new_params.clone());
parallel_world.run();
let new_score = objective_function(¶llel_world);
let delta_goodness: f64 = current_score - new_score;
let explore_parallel_world = if delta_goodness < 0.0_f64 {
true
} else {
let acceptance_probability = (-delta_goodness / chaotic_flux).exp();
rand::rng().random_range(0.0..1.0) < acceptance_probability
};
if explore_parallel_world {
current_params = new_params;
current_score = new_score;
if current_score > best_score {
best_score = current_score;
best_params = current_params.clone();
}
}
}
Some(best_params)
}