optlib/particleswarm/velocitycalc/
mod.rs1use rand::distributions::{Distribution, Uniform};
2use rand::rngs::ThreadRng;
3
4use num::{Float, Num, NumCast};
5
6use crate::particleswarm::{Particle, VelocityCalculator, Swarm};
7
8pub struct ClassicVelocityCalculator<T> {
19 phi_personal: T,
20 phi_global: T,
21
22 random: ThreadRng,
23}
24
25impl<T> ClassicVelocityCalculator<T> {
26 pub fn new(phi_personal: T, phi_global: T) -> Self {
27 Self {
28 phi_personal,
29 phi_global,
30 random: rand::thread_rng(),
31 }
32 }
33}
34
35impl<T: NumCast + Num + Copy> VelocityCalculator<T> for ClassicVelocityCalculator<T> {
36 fn calc_new_velocity(&mut self, swarm: &Swarm<T>, particle: &Particle<T>) -> Vec<T> {
37 let dimension = particle.coordinates.len();
38 let global_best_particle = swarm.best_particle.as_ref().unwrap();
39 let global_best_solution = &global_best_particle.coordinates;
40
41 let between = Uniform::new_inclusive(0.0_f32, 1.0_f32);
42 let mut new_velocity = Vec::with_capacity(dimension);
43 for i in 0..dimension {
44 let r_personal = T::from(between.sample(&mut self.random)).unwrap();
45 let r_global = T::from(between.sample(&mut self.random)).unwrap();
46
47 let velocity_item = particle.velocity[i]
48 + self.phi_personal
49 * r_personal
50 * (particle.best_personal_coordinates[i] - particle.coordinates[i])
51 + self.phi_global * r_global * (global_best_solution[i] - particle.coordinates[i]);
52 new_velocity.push(velocity_item);
53 }
54
55 new_velocity
56 }
57}
58
59pub struct CanonicalVelocityCalculator<T> {
72 phi_personal: T,
73 phi_global: T,
74 xi: T,
75
76 random: ThreadRng,
77}
78
79impl<T: Float> CanonicalVelocityCalculator<T> {
80 pub fn new(phi_personal: T, phi_global: T, alpha: T) -> Self {
81 assert!(phi_personal + phi_global > T::from(4.0).unwrap());
82 assert!(alpha > T::zero());
83 assert!(alpha < T::one());
84
85 let phi = phi_global + phi_personal;
86 let xi = T::from(2.0).unwrap() * alpha / (phi - T::from(2.0).unwrap());
87 Self {
88 phi_personal,
89 phi_global,
90 xi,
91 random: rand::thread_rng(),
92 }
93 }
94}
95
96impl<T: NumCast + Num + Copy> VelocityCalculator<T> for CanonicalVelocityCalculator<T> {
97 fn calc_new_velocity(&mut self, swarm: &Swarm<T>, particle: &Particle<T>) -> Vec<T> {
98 let dimension = particle.coordinates.len();
99 let global_best_particle = swarm.best_particle.as_ref().unwrap();
100 let global_best_solution = &global_best_particle.coordinates;
101
102 let between = Uniform::new_inclusive(0.0_f32, 1.0_f32);
103 let mut new_velocity = Vec::with_capacity(dimension);
104 for i in 0..dimension {
105 let r_personal = T::from(between.sample(&mut self.random)).unwrap();
106 let r_global = T::from(between.sample(&mut self.random)).unwrap();
107
108 let velocity_item = self.xi
109 * (particle.velocity[i]
110 + self.phi_personal
111 * r_personal
112 * (particle.best_personal_coordinates[i] - particle.coordinates[i])
113 + self.phi_global
114 * r_global
115 * (global_best_solution[i] - particle.coordinates[i]));
116 new_velocity.push(velocity_item);
117 }
118
119 new_velocity
120 }
121}
122
123pub struct NegativeReinforcement<T> {
144 phi_best_personal: T,
145 phi_best_current: T,
146 phi_best_global: T,
147
148 phi_worst_personal: T,
149 phi_worst_current: T,
150 phi_worst_global: T,
151
152 xi: T,
153
154 random: ThreadRng,
155}
156impl<T> NegativeReinforcement<T> {
157 pub fn new(
158 phi_best_personal: T,
159 phi_best_current: T,
160 phi_best_global: T,
161 phi_worst_personal: T,
162 phi_worst_current: T,
163 phi_worst_global: T,
164 xi: T,
165 ) -> Self {
166 Self {
167 phi_best_personal,
168 phi_best_current,
169 phi_best_global,
170 phi_worst_personal,
171 phi_worst_current,
172 phi_worst_global,
173 xi,
174 random: rand::thread_rng(),
175 }
176 }
177}
178
179impl<T: NumCast + Num + Copy> VelocityCalculator<T> for NegativeReinforcement<T> {
180 fn calc_new_velocity(&mut self, swarm: &Swarm<T>, particle: &Particle<T>) -> Vec<T> {
181 let dimension = particle.coordinates.len();
182
183 let global_best_particle = swarm.best_particle.as_ref().unwrap();
184 let global_best_solution = &global_best_particle.coordinates;
185
186 let current_best_particle = swarm.get_current_best_particle().unwrap();
187 let current_best_solution = current_best_particle.coordinates;
188
189 let global_worst_particle = swarm.worst_particle.as_ref().unwrap();
190 let global_worst_solution = &global_worst_particle.coordinates;
191
192 let current_worst_particle = swarm.get_current_worst_particle().unwrap();
193 let current_worst_solution = current_worst_particle.coordinates;
194
195 let between = Uniform::new_inclusive(0.0, 1.0);
196 let mut new_velocity = Vec::with_capacity(dimension);
197 for i in 0..dimension {
198 let r_best_global = T::from(between.sample(&mut self.random)).unwrap();
199 let r_best_current = T::from(between.sample(&mut self.random)).unwrap();
200 let r_best_personal = T::from(between.sample(&mut self.random)).unwrap();
201
202 let r_worst_global = T::from(between.sample(&mut self.random)).unwrap();
203 let r_worst_current = T::from(between.sample(&mut self.random)).unwrap();
204 let r_worst_personal = T::from(between.sample(&mut self.random)).unwrap();
205
206 let v_best_personal = self.phi_best_personal
207 * r_best_personal
208 * (particle.best_personal_coordinates[i] - particle.coordinates[i]);
209 let v_best_current = self.phi_best_current
210 * r_best_current
211 * (current_best_solution[i] - particle.coordinates[i]);
212 let v_best_global = self.phi_best_global
213 * r_best_global
214 * (global_best_solution[i] - particle.coordinates[i]);
215
216 let v_worst_personal = self.phi_worst_personal
217 * r_worst_personal
218 * (particle.worst_personal_coordinates[i] - particle.coordinates[i]);
219 let v_worst_current = self.phi_worst_current
220 * r_worst_current
221 * (current_worst_solution[i] - particle.coordinates[i]);
222 let v_worst_global = self.phi_worst_global
223 * r_worst_global
224 * (global_worst_solution[i] - particle.coordinates[i]);
225
226 let velocity_item = self.xi
227 * (particle.velocity[i] + v_best_personal + v_best_current + v_best_global
228 - v_worst_personal
229 - v_worst_current
230 - v_worst_global);
231 new_velocity.push(velocity_item);
232 }
233
234 new_velocity
235 }
236}
237
238pub trait Inertia<T> {
240 fn get(&mut self, iteration: usize) -> T;
241}
242
243
244pub struct ConstInertia<T> {
246 w: T,
247}
248
249impl<T> ConstInertia<T> {
250 pub fn new(w: T) -> Self {
251 Self { w }
252 }
253}
254
255impl<T: Clone> Inertia<T> for ConstInertia<T> {
256 fn get(&mut self, _iteration: usize) -> T {
257 self.w.clone()
258 }
259}
260
261pub struct LinearInertia<T> {
263 w_min: T,
264 w_max: T,
265 t_max: usize,
266}
267
268impl<T: Float> LinearInertia<T> {
269 pub fn new(w_min: T, w_max: T, t_max: usize) -> Self {
270 Self {
271 w_min,
272 w_max,
273 t_max,
274 }
275 }
276}
277
278impl<T: Float> Inertia<T> for LinearInertia<T> {
279 fn get(&mut self, iteration: usize) -> T {
280 self.w_max
281 - (self.w_max - self.w_min) * T::from(iteration).unwrap() / T::from(self.t_max).unwrap()
282 }
283}
284
285pub struct InertiaVelocityCalculator<'a, T> {
296 phi_personal: T,
297 phi_global: T,
298 inertia: Box<dyn Inertia<T> + 'a>,
299
300 random: ThreadRng,
301}
302
303impl<'a, T> InertiaVelocityCalculator<'a, T> {
304 pub fn new(phi_personal: T, phi_global: T, inertia: Box<dyn Inertia<T> + 'a>) -> Self {
305 Self {
306 phi_personal,
307 phi_global,
308 inertia,
309 random: rand::thread_rng(),
310 }
311 }
312}
313
314impl<'a, T: NumCast + Num + Copy> VelocityCalculator<T> for InertiaVelocityCalculator<'a, T> {
315 fn calc_new_velocity(&mut self, swarm: &Swarm<T>, particle: &Particle<T>) -> Vec<T> {
316 let dimension = particle.coordinates.len();
317 let global_best_particle = swarm.best_particle.as_ref().unwrap();
318 let global_best_solution = &global_best_particle.coordinates;
319 let inertia_ratio = self.inertia.get(swarm.iteration);
320
321 let between = Uniform::new_inclusive(0.0_f32, 1.0_f32);
322 let mut new_velocity = Vec::with_capacity(dimension);
323 for i in 0..dimension {
324 let r_personal = T::from(between.sample(&mut self.random)).unwrap();
325 let r_global = T::from(between.sample(&mut self.random)).unwrap();
326
327 let velocity_item = inertia_ratio * particle.velocity[i]
328 + self.phi_personal
329 * r_personal
330 * (particle.best_personal_coordinates[i] - particle.coordinates[i])
331 + self.phi_global * r_global * (global_best_solution[i] - particle.coordinates[i]);
332 new_velocity.push(velocity_item);
333 }
334
335 new_velocity
336 }
337}