1use super::{clamp, sample, Evaluator, Optimizer};
17use crate::problem::Problem;
18use crate::rng::Rng;
19use crate::solution::{Report, Solution};
20use crate::termination::Termination;
21
22#[derive(Debug, Clone, Copy)]
24pub struct Pso {
25 pub swarm_size: usize,
27 pub inertia: f64,
29 pub cognitive: f64,
31 pub social: f64,
33 pub seed: u64,
35}
36
37impl Default for Pso {
38 fn default() -> Self {
39 Pso {
40 swarm_size: 30,
41 inertia: 0.7298,
42 cognitive: 1.49618,
43 social: 1.49618,
44 seed: 42,
45 }
46 }
47}
48
49impl Optimizer for Pso {
50 fn with_seed(&self, seed: u64) -> Self {
51 Pso { seed, ..*self }
52 }
53
54 fn optimize(&self, problem: &dyn Problem, term: &Termination) -> Report {
56 crate::problem::validate(problem).unwrap_or_else(|e| panic!("Pso: invalid problem: {e}"));
57 let bounds = problem.bounds();
58 let dim = bounds.len();
59 let n = self.swarm_size.max(2);
60 let mut rng = Rng::new(self.seed);
61
62 let vmax: Vec<f64> = bounds.iter().map(|&(lo, hi)| hi - lo).collect();
64
65 let first_x = sample(bounds, &mut rng);
68 let first_v = finite_or_worst(problem.objective(&first_x));
69 let mut ev = Evaluator::new(
70 problem,
71 term,
72 Solution {
73 x: first_x.clone(),
74 value: first_v,
75 },
76 );
77
78 let mut pos: Vec<Vec<f64>> = Vec::with_capacity(n);
79 let mut vel: Vec<Vec<f64>> = Vec::with_capacity(n);
80 let mut pbest_x: Vec<Vec<f64>> = Vec::with_capacity(n);
81 let mut pbest_f: Vec<f64> = Vec::with_capacity(n);
82
83 vel.push(init_velocity(&first_x, bounds, &mut rng));
85 pbest_x.push(first_x.clone());
86 pbest_f.push(first_v);
87 pos.push(first_x);
88
89 for _ in 1..n {
90 let x = sample(bounds, &mut rng);
91 let v = init_velocity(&x, bounds, &mut rng);
92 let f = if ev.done() {
93 f64::INFINITY
94 } else {
95 finite_or_worst(ev.eval(&x))
96 };
97 pbest_x.push(x.clone());
98 pbest_f.push(f);
99 pos.push(x);
100 vel.push(v);
101 }
102
103 while !ev.done() {
104 for i in 0..n {
105 if ev.done() {
106 break;
107 }
108 let gbest = ev.best.x.clone();
110 for d in 0..dim {
111 let (lo, hi) = bounds[d];
112 let r1 = rng.uniform();
113 let r2 = rng.uniform();
114 let mut v = self.inertia * vel[i][d]
115 + self.cognitive * r1 * (pbest_x[i][d] - pos[i][d])
116 + self.social * r2 * (gbest[d] - pos[i][d]);
117 v = clamp(v, -vmax[d], vmax[d]);
118
119 let mut x = pos[i][d] + v;
120 if x < lo {
121 x = lo;
122 v = 0.0;
123 } else if x > hi {
124 x = hi;
125 v = 0.0;
126 }
127 vel[i][d] = v;
128 pos[i][d] = x;
129 }
130
131 let f = finite_or_worst(ev.eval(&pos[i]));
132 if f < pbest_f[i] {
133 pbest_f[i] = f;
134 pbest_x[i].copy_from_slice(&pos[i]);
135 }
136 }
137 }
138
139 ev.finish()
140 }
141}
142
143#[inline]
144fn finite_or_worst(v: f64) -> f64 {
145 if v.is_finite() {
146 v
147 } else {
148 f64::INFINITY
149 }
150}
151
152fn init_velocity(x: &[f64], bounds: &[(f64, f64)], rng: &mut Rng) -> Vec<f64> {
155 bounds
156 .iter()
157 .zip(x)
158 .map(|(&(lo, hi), &xi)| 0.5 * (rng.uniform_in(lo, hi) - xi))
159 .collect()
160}