1use rand;
2use rand::Rng;
3
4use crate::blueprints::Blueprints;
5use crate::chromosome::EgpChromosome;
6use crate::component::Component;
7
8pub fn mutate(blueprints: &Blueprints, chromosome: &mut EgpChromosome) {
10 let mut rng = rand::thread_rng();
11
12 if rng.gen_range(0., 1.) < 0.5 {
13 mutate_activity(blueprints, chromosome);
14 } else {
15 let n_regulars: usize = chromosome.regular.iter().map(|group| group.len()).sum();
16
17 if rng.gen_range(0., 1.) < 1. / (n_regulars as f32) {
18 mutate_binding_site_output(blueprints, chromosome);
19 } else {
20 mutate_binding_site(blueprints, chromosome);
21 }
22 }
23}
24
25pub fn recombine(
31 blueprints: &Blueprints,
32 n_transfer: usize,
33 parent_a: &EgpChromosome,
34 parent_b: &EgpChromosome,
35) -> EgpChromosome {
36 let mut rng = rand::thread_rng();
37
38 if rng.gen_range(0., 1.) < 0.5 {
39 recombine_remove(blueprints, n_transfer, parent_a)
40 } else {
41 recombine_transfer(blueprints, n_transfer, parent_a, parent_b)
42 }
43}
44
45fn recombine_transfer(
46 blueprints: &Blueprints,
47 n_transfer: usize,
48 parent: &EgpChromosome,
49 donor: &EgpChromosome,
50) -> EgpChromosome {
51 let mut child = parent.clone();
52
53 let mut rng = rand::thread_rng();
54
55 let nonempty_group = nonempty_group(blueprints);
56 let group_len = donor.regular[nonempty_group].len();
57
58 let skip = rng.gen_range(0, group_len);
59
60 let mut n_transfer = if n_transfer < group_len {
61 n_transfer
62 } else {
63 group_len
64 };
65
66 for i in skip..group_len {
67 if n_transfer <= 0 {
68 break;
69 }
70
71 child.regular[nonempty_group].push(donor.regular[nonempty_group][i].clone());
72
73 n_transfer -= 1;
74 }
75
76 child
77}
78
79fn recombine_remove(
80 blueprints: &Blueprints,
81 n_remove: usize,
82 parent: &EgpChromosome,
83) -> EgpChromosome {
84 let mut child = parent.clone();
85
86 let mut rng = rand::thread_rng();
87
88 let nonempty_group = nonempty_group(blueprints);
89 let group_len = child.regular[nonempty_group].len();
90
91 let mut n_remove = if n_remove < group_len {
92 n_remove
93 } else {
94 group_len
95 };
96
97 let skip = rng.gen_range(0, group_len);
98
99 for i in skip..group_len {
100 if n_remove == 0 || i < child.regular[nonempty_group].len() {
101 break;
102 }
103
104 child.regular[nonempty_group].remove(i);
105
106 n_remove -= 1;
107 }
108
109 child
110}
111
112fn mutate_activity(blueprints: &Blueprints, chromosome: &mut EgpChromosome) {
113 let (group, member) = pick_group_and_member(blueprints);
114
115 let new_component = Component::from_blueprint(
116 &blueprints.regular[group][member],
117 blueprints.total_activities,
118 );
119
120 let n_compatible = chromosome.regular[group]
121 .iter()
122 .filter(|component| component.activity == new_component.activity)
123 .count();
124
125 if n_compatible == 0 {
126 return;
127 }
128
129 let mut rng = rand::thread_rng();
130
131 let to_replace = rng.gen_range(0, n_compatible);
132
133 let mut n_encountered = 0;
134
135 for i in 0..chromosome.regular[group].len() {
136 if chromosome.regular[group][i].activity == new_component.activity {
137 if to_replace == n_encountered {
138 chromosome.regular[group][i].activity = new_component.activity;
139 chromosome.regular[group][i].label = new_component.label.clone();
140 break;
141 }
142
143 n_encountered += 1;
144 }
145 }
146}
147
148fn mutate_binding_site(blueprints: &Blueprints, chromosome: &mut EgpChromosome) {
149 let mut rng = rand::thread_rng();
150
151 let nonempty_group = nonempty_group(blueprints);
152 let group_len = chromosome.regular[nonempty_group].len();
153
154 let component = &mut chromosome.regular[nonempty_group][rng.gen_range(0, group_len)];
155
156 let binding_site_index = rng.gen_range(0, component.binding_sites.len());
157 let dimension = rng.gen_range(0, blueprints.total_activities);
158
159 component.binding_sites[binding_site_index][dimension] = rng.gen::<f32>();
160}
161
162fn mutate_binding_site_output(blueprints: &Blueprints, chromosome: &mut EgpChromosome) {
163 let mut rng = rand::thread_rng();
164
165 let component = &mut chromosome.output;
166
167 let binding_site_index = rng.gen_range(0, component.binding_sites.len());
168 let dimension = rng.gen_range(0, blueprints.total_activities);
169
170 component.binding_sites[binding_site_index][dimension] = rng.gen::<f32>();
171}
172
173fn nonempty_group(blueprints: &Blueprints) -> usize {
174 let mut rng = rand::thread_rng();
175 let nonempty_groups = nonempty_groups(blueprints);
176 nonempty_groups[rng.gen_range(0, nonempty_groups.len())]
177}
178
179fn nonempty_groups(blueprints: &Blueprints) -> Vec<usize> {
180 blueprints
181 .regular
182 .iter()
183 .enumerate()
184 .filter(|(_group_index, group)| group.len() > 0)
185 .map(|(group_index, _group)| group_index)
186 .collect()
187}
188
189fn pick_group_and_member(blueprints: &Blueprints) -> (usize, usize) {
190 let mut rng = rand::thread_rng();
191
192 let group = nonempty_group(blueprints);
193 let member = rng.gen_range(0, blueprints.regular[group].len());
194
195 (group, member)
196}