math_audio_optimisation/
mutant_current_to_pbest1.rs1use ndarray::{Array1, Array2, Zip};
8use rand::Rng;
9
10use crate::distinct_indices::distinct_indices;
11use crate::external_archive::ExternalArchive;
12
13pub(crate) fn mutant_current_to_pbest1<R: Rng + ?Sized>(
22 i: usize,
23 pop: &Array2<f64>,
24 sorted_indices: &[usize],
25 p_best_size: usize,
26 archive: Option<&ExternalArchive>,
27 f: f64,
28 rng: &mut R,
29) -> Array1<f64> {
30 let npop = pop.nrows();
31
32 let pbest_idx = if p_best_size >= npop {
33 sorted_indices[0]
34 } else {
35 sorted_indices[rng.random_range(0..p_best_size)]
36 };
37
38 let r1 = distinct_indices(i, 1, npop, rng)[0];
39
40 let r2 = if let Some(arch) = archive {
41 if !arch.is_empty() && rng.random::<f64>() < 0.5 {
42 if let Some(sol) = arch.random_select(rng) {
43 sol.clone()
44 } else {
45 let available: Vec<usize> =
46 (0..npop).filter(|&idx| idx != i && idx != r1).collect();
47 if available.is_empty() {
48 pop.row(r1).to_owned()
49 } else {
50 pop.row(available[rng.random_range(0..available.len())])
51 .to_owned()
52 }
53 }
54 } else {
55 let available: Vec<usize> = (0..npop).filter(|&idx| idx != i && idx != r1).collect();
56 if available.is_empty() {
57 pop.row(r1).to_owned()
58 } else {
59 pop.row(available[rng.random_range(0..available.len())])
60 .to_owned()
61 }
62 }
63 } else {
64 let available: Vec<usize> = (0..npop).filter(|&idx| idx != i && idx != r1).collect();
65 if available.is_empty() {
66 pop.row(r1).to_owned()
67 } else {
68 pop.row(available[rng.random_range(0..available.len())])
69 .to_owned()
70 }
71 };
72
73 Zip::from(pop.row(i))
74 .and(pop.row(pbest_idx))
75 .and(pop.row(r1))
76 .and(r2.view())
77 .map_collect(|&curr, &pbest, &x1, &x2| curr + f * (pbest - curr) + f * (x1 - x2))
78}
79
80#[inline]
83pub(crate) fn compute_pbest_size(p: f64, npop: usize) -> usize {
84 ((p * npop as f64).ceil() as usize).max(1).min(npop)
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90 use ndarray::array;
91
92 #[test]
93 fn test_pbest_size() {
94 assert_eq!(compute_pbest_size(0.1, 100), 10);
95 assert_eq!(compute_pbest_size(0.1, 50), 5);
96 assert_eq!(compute_pbest_size(0.1, 10), 1);
97 assert_eq!(compute_pbest_size(0.5, 10), 5);
98 }
99
100 #[test]
101 fn test_mutant_basic() {
102 let pop = array![[0.0, 0.0], [1.0, 1.0], [2.0, 2.0], [3.0, 3.0]];
103 let sorted_indices = vec![3, 2, 1, 0];
104
105 let mut rng = rand::rng();
106 let mutant = mutant_current_to_pbest1(0, &pop, &sorted_indices, 2, None, 0.5, &mut rng);
107
108 assert_eq!(mutant.len(), 2);
109 }
110}