1extern crate rand;
6use rand::distributions::{Distribution, Uniform};
7use std::fmt::Display;
9use std::time::Instant;
10
11#[cfg(feature = "parallel")]
12use rayon::iter::{IntoParallelRefMutIterator, ParallelIterator};
13
14use crate::common::*;
15use crate::core::eoa::{InitializationMode, EOA};
16use crate::core::genome::Genome;
17use crate::core::optimization_result::OptimizationResult;
18use crate::core::parameters::Parameters;
19use crate::core::problem::Problem;
20
21#[derive(Debug)]
28pub struct IEO<'a, T: Problem> {
29 pub problem: &'a mut T,
30 pub params: &'a IEOparams<'a>,
31}
32
33impl<'a, T: Problem> IEO<'a, T> {
34 pub fn new(settings: &'a IEOparams, problem: &'a mut T) -> Self {
35 IEO {
36 problem,
37 params: settings,
38 }
39 }
40}
41
42impl<'a, T: Problem> EOA for IEO<'a, T> {
43 fn run(&mut self) -> OptimizationResult {
44 let chronos = Instant::now();
45
46 match self.params.check() {
50 Err(error) => OptimizationResult::get_none(error),
51 Ok(()) => {
52 let dim = self.params.get_problem_dimension();
53 let particles_no = self.params.get_population_size();
54 let max_iter = self.params.get_max_iterations();
55
56 let ub = self.params.get_upper_bounds();
57
58 let lb = self.params.get_lower_bounds();
59
60 let a1: f64 = self.params.a1;
64 let a2: f64 = self.params.a2;
65 let gp: f64 = self.params.gp;
66 let nu: f64 = f64::min(self.params.pool_size_rate, 1.0);
67 let mut iter = 0;
69 let v: f64 = 1.0;
70
71 let mut ceq1_fit: f64 = f64::MAX;
73 let mut ceq1: Genome = Genome::new(particles_no + 1, dim);
76
77 let mut fitness = vec![0.0f64; particles_no];
78 let mut fit_old = vec![0.0f64; particles_no];
79 let mut c_old = vec![vec![0.0f64; dim]; particles_no];
80
81 let mut lambda = vec![0.0f64; dim];
82 let mut r = vec![0.0f64; dim];
83 let mut r1 = vec![0.0f64; dim];
84 let mut r2 = vec![0.0f64; dim];
85 let mut ceq = vec![0.0f64; dim];
86 let mut f = vec![0.0f64; dim];
87 let mut _gcp: f64 = 0.0;
88 let mut rng = rand::thread_rng();
91 let mut convergence_curve = vec![0.0f64; max_iter];
94 let mut _index: usize = 0;
95 let mut _g0: f64 = 0.0;
96 let mut _g: f64 = 0.0;
97
98 let mut c: Vec<Genome> =
101 self.initialize(self.params, InitializationMode::RealUniform);
102
103 while iter < max_iter {
105 for i in 0..c.len() {
107 for j in 0..dim {
108 if c[i].genes[j] < lb[j] {
109 c[i].genes[j] = lb[j];
110 }
111
112 if c[i].genes[j] > ub[j] {
113 c[i].genes[j] = ub[j];
114 }
115 }
116 }
117
118 #[cfg(not(feature = "parallel"))]
121 for i in 0..particles_no {
122 fitness[i] = self.problem.objectivefunction(&mut c[i].genes);
123 c[i].fitness = Some(fitness[i]);
124 }
126
127 #[cfg(feature = "parallel")]
130 {
131 c.par_iter_mut().for_each(|g| {
132 g.fitness = Some(self.problem.objectivefunction(&g.genes))
133 });
134 for i in 0..particles_no {
135 match c[i].fitness {
136 None => fitness[i] = f64::MAX,
137 Some(fit) => fitness[i] = fit,
138 };
139 }
140 }
142 if iter == 0 {
147 copy_vector(&fitness, &mut fit_old);
148 copy_matrix(&c, &mut c_old);
149 }
150
151 for i in 0..particles_no {
152 if fit_old[i] < fitness[i] {
153 fitness[i] = fit_old[i];
154 copy_vector2genome(&c_old[i], &mut c[i]);
155 }
156 }
157
158 copy_matrix(&c, &mut c_old);
159 copy_vector(&fitness, &mut fit_old);
160
161 let jpool: usize =
166 (nu * particles_no as f64 * (1.0 - (iter as f64 / max_iter as f64))).ceil()
167 as usize;
168
169 let mut c_pool = vec![vec![0.0f64; dim]; jpool + 1];
171
172 let interval = Uniform::from(0..jpool);
174
175 let mut ind: Vec<usize> = (0..particles_no).collect();
177 ind.sort_by(|&a, &b| fitness[a].total_cmp(&fitness[b]));
178
179 for i in 0..jpool {
180 for j in 0..dim {
181 c_pool[i][j] = c[ind[i]].genes[j];
182 }
183 }
184
185 if ceq1_fit > fitness[ind[0]] {
187 ceq1_fit = fitness[ind[0]];
188 copy_vector2genome(&c[ind[0]].genes, &mut ceq1);
189 ceq1.fitness = Some(ceq1_fit);
190 }
191
192 let mut sum_value: f64 = 0.0;
195 for j in 0..dim {
196 for i in 0..jpool {
197 sum_value += c_pool[i][j];
198 }
199 c_pool[jpool][j] = sum_value / jpool as f64;
200 sum_value = 0.0;
201 }
202
203 let tmpt = (iter / max_iter) as f64;
205 let t: f64 = (1.0 - tmpt).powf(a2 * tmpt);
206
207 for i in 0..particles_no {
208 randomize(&mut lambda);
209
210 randomize(&mut r); _index = interval.sample(&mut rng);
216 copy_vector(&c_pool[_index], &mut ceq);
217 for j in 0..dim {
220 f[j] = a1
221 * f64::signum(r[j] - 0.5)
222 * (f64::exp(-1.0 * lambda[j] * t) - 1.0);
223 }
224
225 randomize(&mut r1);
227 randomize(&mut r2);
228
229 for j in 0..dim {
230 if r2[j] > gp {
232 _gcp = 0.5 * r1[j];
233 } else {
234 _gcp = 0.0f64;
235 }
236
237 _g0 = _gcp * (ceq[j] - lambda[j] * c[i].genes[j]);
239
240 _g = _g0 * f[j];
242
243 c[i].genes[j] = ceq[j]
245 + (c[i].genes[j] - ceq[j]) * f[j]
246 + (_g / (lambda[j] * v)) * (1.0 - f[j]);
247 }
248 }
249
250 convergence_curve[iter] = ceq1_fit;
254 iter += 1;
255
256 #[cfg(feature = "report")]
257 println!("Iter : {}, Best-fit : {}", iter, ceq1_fit);
258 }
259
260 let duration = chronos.elapsed();
262 let result = OptimizationResult {
263 best_genome: Some(ceq1),
264 best_fitness: Some(ceq1_fit),
265 convergence_trend: Some(convergence_curve),
266 computation_time: Some(duration),
267 err_report: None,
268 };
269 return result;
270 }
271 }
272 }
273}
274#[derive(Debug, Clone)]
276pub struct IEOparams<'a> {
277 pub population_size: usize,
279
280 pub problem_dimension: usize,
282
283 pub max_iterations: usize,
285
286 pub lower_bounds: &'a [f64],
288
289 pub upper_bounds: &'a [f64],
291
292 pub a1: f64,
294 pub a2: f64,
296 pub gp: f64,
298 pub pool_size_rate: f64,
300}
301
302#[allow(dead_code)]
303impl<'a> IEOparams<'a> {
304 pub fn new(
305 p_size: usize,
306 dim: usize,
307 max_iter: usize,
308 lb: &'a [f64],
309 ub: &'a [f64],
310 a1: f64,
311 a2: f64,
312 gp: f64,
313 pool_size_rate: f64,
314 ) -> Result<IEOparams<'a>, String> {
315 let params = IEOparams {
316 population_size: p_size,
317 problem_dimension: dim,
318 max_iterations: max_iter,
319 lower_bounds: lb,
320 upper_bounds: ub,
321 a1,
322 a2,
323 gp,
324 pool_size_rate,
325 };
326
327 match params.check() {
328 Err(error) => Err(error),
329 Ok(()) => Ok(params),
330 }
331 }
332}
333
334impl<'a> Parameters for IEOparams<'a> {
335 fn get_population_size(&self) -> usize {
336 self.population_size
337 }
338
339 fn get_problem_dimension(&self) -> usize {
340 self.problem_dimension
341 }
342
343 fn get_max_iterations(&self) -> usize {
344 self.max_iterations
345 }
346
347 fn get_lower_bounds(&self) -> Vec<f64> {
348 self.lower_bounds.to_vec()
349 }
350
351 fn get_upper_bounds(&self) -> Vec<f64> {
352 self.upper_bounds.to_vec()
353 }
354}
355
356impl<'a> Default for IEOparams<'a> {
357 fn default() -> Self {
378 IEOparams {
379 population_size: 10,
380 problem_dimension: 3,
381 max_iterations: 100,
382 lower_bounds: &[-100.0f64, -100.0, -100.0],
383 upper_bounds: &[100.0f64, 100.0, 100.0],
384 a1: 2.0f64,
385 a2: 1.0f64,
386 gp: 0.5f64,
387 pool_size_rate: 0.2,
388 }
389 }
390}
391
392impl<'a> Display for IEOparams<'a> {
393 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
394 write!(
395 f,
396 "Pop.Size: {}, Problem dim.: {}, Max.Iter: {}, a1: {}, a2: {}, GP: {}, Pool Size Rate:{}, LB: {:?}, UB: {:?}",
397 self.population_size,
398 self.problem_dimension,
399 self.max_iterations,
400 self.a1,
401 self.a2,
402 self.gp,
403 self.pool_size_rate,
404 self.get_lower_bounds(),
405 self.get_upper_bounds()
406 )
407 }
408}
409
410#[cfg(test)]
411mod ieo_params_tests {
412 use super::*;
413
414 #[test]
415 fn test_ub_slice() {
416 let d: usize = 5;
417 let n: usize = 10;
418 let k: usize = 100;
419
420 let ub = vec![1.0f64, 2.0, 3.0, 4.0, 5.0];
421 let lb = ub.clone();
422
423 let params = IEOparams {
424 population_size: n,
425 max_iterations: k,
426 problem_dimension: d,
427 lower_bounds: lb.as_slice(),
428 upper_bounds: ub.as_slice(),
429 a1: 2.0f64,
430 a2: 1.0f64,
431 gp: 0.5f64,
432 pool_size_rate: 0.0625,
433 };
434
435 let sl_ub = vec![1.0f64, 2.0, 3.0, 4.0, 5.0];
436 let slice_ub = sl_ub.as_slice();
437
438 assert_eq!(params.upper_bounds, slice_ub);
439 }
440
441 #[test]
442 fn test_default_fn() {
443 let p = IEOparams::default();
444 assert_eq!(p.a1, 2.0f64);
445 assert_eq!(p.a2, 1.0f64);
446 assert_eq!(p.gp, 0.50f64);
447 }
448
449 #[test]
450 fn eoparams_unwrap_or_default_test_1() {
451 let _ub = vec![1.0f64, 2.0, 3.0, 4.0, 5.0];
452 let _lb = vec![-1.0f64, -2.0, -3.0, -4.0, -5.0];
453
454 let p = IEOparams::new(
455 10,
456 10,
457 100,
458 _lb.as_slice(),
459 _ub.as_slice(),
460 0.5,
461 0.5,
462 0.5,
463 0.2,
464 )
465 .unwrap_or_default();
466 assert_eq!(p.a1, 2.0f64);
467 assert_eq!(p.a2, 1.0f64);
468 assert_eq!(p.gp, 0.50f64);
469 }
470
471 #[test]
472 fn eoparams_unwrap_or_default_test_2() {
473 let _ub = vec![1.0f64, 2.0, 3.0, 4.0, 5.0];
474 let _lb = vec![-1.0f64, -2.0, -3.0, -4.0, -5.0];
475
476 let p = IEOparams::new(
477 10,
478 5,
479 100,
480 _lb.as_slice(),
481 _ub.as_slice(),
482 0.5,
483 0.5,
484 0.5,
485 0.2,
486 )
487 .unwrap_or_default();
488 assert_eq!(p.a1, 0.50f64);
489 assert_eq!(p.a2, 0.50f64);
490 assert_eq!(p.gp, 0.50f64);
491 }
492}