scirs2_optimize/reinforcement_learning/
evolutionary_strategies.rs1use crate::error::OptimizeResult;
6use crate::result::OptimizeResults;
7use scirs2_core::ndarray::{Array1, ArrayView1};
8use scirs2_core::random::{rng, Rng};
9#[derive(Debug, Clone)]
14pub struct EvolutionaryStrategy {
15 pub population_size: usize,
17 pub population: Vec<Array1<f64>>,
19 pub fitness: Vec<f64>,
21 pub sigma: f64,
23}
24
25impl EvolutionaryStrategy {
26 pub fn new(population_size: usize, dimensions: usize, sigma: f64) -> Self {
28 let mut population = Vec::with_capacity(population_size);
29 for _ in 0..population_size {
30 let individual = Array1::from_shape_fn(dimensions, |_| {
31 scirs2_core::random::rng().random::<f64>() - 0.5
32 });
33 population.push(individual);
34 }
35
36 Self {
37 population_size,
38 population,
39 fitness: vec![f64::INFINITY; population_size],
40 sigma,
41 }
42 }
43
44 pub fn evaluate<F>(&mut self, objective: &F)
46 where
47 F: Fn(&ArrayView1<f64>) -> f64,
48 {
49 for (i, individual) in self.population.iter().enumerate() {
50 self.fitness[i] = objective(&individual.view());
51 }
52 }
53
54 pub fn evolve(&mut self) {
56 let mut indices: Vec<usize> = (0..self.population_size).collect();
58 indices.sort_by(|&a, &b| self.fitness[a].partial_cmp(&self.fitness[b]).unwrap());
59
60 let elite_size = self.population_size / 2;
61
62 for i in elite_size..self.population_size {
64 let parent_idx = indices[scirs2_core::random::rng().random_range(0..elite_size)];
65 let parent = &self.population[parent_idx];
66
67 let mut offspring = parent.clone();
69 for j in 0..offspring.len() {
70 offspring[j] += self.sigma * (scirs2_core::random::rng().random_range(-0.5..0.5));
71 }
72
73 self.population[i] = offspring;
74 }
75 }
76
77 pub fn get_best(&self) -> (Array1<f64>, f64) {
79 let mut best_idx = 0;
80 let mut best_fitness = self.fitness[0];
81
82 for (i, &fitness) in self.fitness.iter().enumerate() {
83 if fitness < best_fitness {
84 best_fitness = fitness;
85 best_idx = i;
86 }
87 }
88
89 (self.population[best_idx].clone(), best_fitness)
90 }
91}
92
93#[allow(dead_code)]
95pub fn evolutionary_optimize<F>(
96 objective: F,
97 initial_params: &ArrayView1<f64>,
98 num_generations: usize,
99) -> OptimizeResult<OptimizeResults<f64>>
100where
101 F: Fn(&ArrayView1<f64>) -> f64,
102{
103 let mut es = EvolutionaryStrategy::new(50, initial_params.len(), 0.1);
104
105 es.population[0] = initial_params.to_owned();
107
108 for _generation in 0..num_generations {
109 es.evaluate(&objective);
110 es.evolve();
111 }
112
113 let (best_params, best_fitness) = es.get_best();
114
115 Ok(OptimizeResults::<f64> {
116 x: best_params,
117 fun: best_fitness,
118 success: true,
119 nit: num_generations,
120 message: "Evolutionary strategy completed".to_string(),
121 jac: None,
122 hess: None,
123 constr: None,
124 nfev: num_generations * 50, njev: 0,
126 nhev: 0,
127 maxcv: 0,
128 status: 0,
129 })
130}
131
132#[allow(dead_code)]
133pub fn placeholder() {}