metaheurustics/algorithm/
fa.rs1use ndarray::Array1;
2use rand::Rng;
3use std::f64;
4
5pub struct FireflyAlgorithm {
6 pub population_size: usize,
7 pub max_iterations: usize,
8 pub alpha: f64, pub beta0: f64, pub gamma: f64, }
12
13impl Default for FireflyAlgorithm {
14 fn default() -> Self {
15 FireflyAlgorithm {
16 population_size: 30,
17 max_iterations: 1000,
18 alpha: 0.2,
19 beta0: 1.0,
20 gamma: 1.0,
21 }
22 }
23}
24
25impl FireflyAlgorithm {
26 pub fn new(population_size: usize, max_iterations: usize) -> Self {
27 FireflyAlgorithm {
28 population_size,
29 max_iterations,
30 ..Default::default()
31 }
32 }
33
34 pub fn optimize<F>(&self, objective_fn: F, bounds: &[(f64, f64)]) -> Array1<f64>
35 where
36 F: Fn(&Array1<f64>) -> f64,
37 {
38 let dim = bounds.len();
39 let mut rng = rand::thread_rng();
40
41 let mut population: Vec<(Array1<f64>, f64)> = (0..self.population_size)
43 .map(|_| {
44 let position = Array1::from_vec(
45 bounds.iter()
46 .map(|(min, max)| rng.gen_range(*min..*max))
47 .collect()
48 );
49 let fitness = objective_fn(&position);
50 (position, fitness)
51 })
52 .collect();
53
54 let mut best_solution = population
55 .iter()
56 .min_by(|a, b| a.1.partial_cmp(&b.1).unwrap())
57 .unwrap()
58 .clone();
59
60 for _ in 0..self.max_iterations {
62 for i in 0..self.population_size {
64 for j in 0..self.population_size {
66 if population[j].1 < population[i].1 {
67 let r = (&population[i].0 - &population[j].0)
69 .mapv(|x| x * x)
70 .sum()
71 .sqrt();
72
73 let beta = self.beta0 * (-self.gamma * r * r).exp();
75
76 let mut new_position = Array1::zeros(dim);
78 for d in 0..dim {
79 let rand_step = rng.gen_range(-0.5..0.5);
80 new_position[d] = population[i].0[d] +
81 beta * (population[j].0[d] - population[i].0[d]) +
82 self.alpha * rand_step;
83
84 if new_position[d] < bounds[d].0 {
86 new_position[d] = bounds[d].0;
87 }
88 if new_position[d] > bounds[d].1 {
89 new_position[d] = bounds[d].1;
90 }
91 }
92
93 let new_fitness = objective_fn(&new_position);
94 if new_fitness < population[i].1 {
95 population[i] = (new_position, new_fitness);
96 }
97 }
98 }
99 }
100
101 if let Some(current_best) = population
103 .iter()
104 .min_by(|a, b| a.1.partial_cmp(&b.1).unwrap())
105 {
106 if current_best.1 < best_solution.1 {
107 best_solution = current_best.clone();
108 }
109 }
110 }
111
112 best_solution.0
113 }
114}