genetic_algorithm/strategy/evolve/
reporter.rs1use crate::extension::ExtensionEvent;
2use crate::genotype::EvolveGenotype;
3use crate::mutate::MutateEvent;
4use crate::strategy::{StrategyConfig, StrategyReporter, StrategyState, STRATEGY_ACTIONS};
5use std::fmt::Arguments;
6use std::io::Write;
7use std::marker::PhantomData;
8
9#[derive(Clone)]
51pub struct Simple<G: EvolveGenotype> {
52 pub buffer: Option<Vec<u8>>,
53 pub period: usize,
54 pub show_genes: bool,
55 pub show_equal_fitness: bool,
56 pub show_mutate_event: bool,
57 pub show_extension_event: bool,
58 number_of_mutate_events: usize,
59 number_of_extension_events: usize,
60 _phantom: PhantomData<G>,
61}
62impl<G: EvolveGenotype> Default for Simple<G> {
63 fn default() -> Self {
64 Self {
65 buffer: None,
66 period: 1,
67 show_genes: false,
68 show_equal_fitness: false,
69 show_mutate_event: false,
70 show_extension_event: false,
71 number_of_mutate_events: 0,
72 number_of_extension_events: 0,
73 _phantom: PhantomData,
74 }
75 }
76}
77impl<G: EvolveGenotype> Simple<G> {
78 pub fn new(period: usize) -> Self {
79 Self {
80 period,
81 ..Default::default()
82 }
83 }
84 pub fn new_with_buffer(period: usize) -> Self {
85 Self {
86 buffer: Some(Vec::new()),
87 period,
88 ..Default::default()
89 }
90 }
91 pub fn new_with_flags(
92 period: usize,
93 buffered: bool,
94 show_genes: bool,
95 show_equal_fitness: bool,
96 show_mutate_event: bool,
97 show_extension_event: bool,
98 ) -> Self {
99 Self {
100 buffer: if buffered { Some(Vec::new()) } else { None },
101 period,
102 show_genes,
103 show_equal_fitness,
104 show_mutate_event,
105 show_extension_event,
106 ..Default::default()
107 }
108 }
109 fn writeln(&mut self, args: Arguments<'_>) {
110 if let Some(buffer) = self.buffer.as_mut() {
111 buffer.write_fmt(args).unwrap_or(());
112 writeln!(buffer).unwrap_or(())
113 } else {
114 std::io::stdout().write_fmt(args).unwrap_or(());
115 println!()
116 }
117 }
118}
119impl<G: EvolveGenotype> StrategyReporter for Simple<G> {
120 type Genotype = G;
121
122 fn flush(&mut self, output: &mut Vec<u8>) {
123 if let Some(buffer) = self.buffer.as_mut() {
124 output.append(buffer);
125 }
126 }
127 fn on_enter<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
128 &mut self,
129 genotype: &Self::Genotype,
130 state: &S,
131 config: &C,
132 ) {
133 let number_of_seed_genes = genotype.seed_genes_list().len();
134 if number_of_seed_genes > 0 {
135 self.writeln(format_args!(
136 "enter - {}, iteration: {}, number of seed genes: {}",
137 config.variant(),
138 state.current_iteration(),
139 number_of_seed_genes
140 ));
141 } else {
142 self.writeln(format_args!(
143 "enter - {}, iteration: {}",
144 config.variant(),
145 state.current_iteration()
146 ));
147 }
148 }
149 fn on_exit<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
150 &mut self,
151 _genotype: &Self::Genotype,
152 state: &S,
153 config: &C,
154 ) {
155 let fitness_report = if let Some((hits, misses, ratio)) =
156 config.fitness_cache().map(|c| c.hit_miss_stats())
157 {
158 format!(
159 "({:.0}% fitness, cache hits/misses/ratio: {}/{}/{:.2})",
160 state.fitness_duration_rate() * 100.0,
161 hits,
162 misses,
163 ratio
164 )
165 } else {
166 format!("({:.0}% fitness)", state.fitness_duration_rate() * 100.0)
167 };
168
169 self.writeln(format_args!(
170 "exit - {}, iteration: {}",
171 config.variant(),
172 state.current_iteration()
173 ));
174 STRATEGY_ACTIONS.iter().for_each(|action| {
175 if let Some(duration) = state.durations().get(action) {
176 self.writeln(format_args!(" {:?}: {:.3?}", action, duration));
177 }
178 });
179 self.writeln(format_args!(
180 " Total: {:.3?} {}",
181 &state.total_duration(),
182 fitness_report
183 ));
184 }
185
186 fn on_new_generation<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
188 &mut self,
189 _genotype: &Self::Genotype,
190 state: &S,
191 config: &C,
192 ) {
193 if state.current_generation() % self.period == 0 {
194 let number_of_extension_events = self.number_of_extension_events;
195 let fitness_cache_hit_miss_ratio = config.fitness_cache().map(|c| c.hit_miss_stats().2);
196
197 self.writeln(format_args!(
198 "periodic - current_generation: {}, stale_generations: {}, best_generation: {}, scale_index: {:?}, population_cardinality: {:?}, current_population_size: {}, fitness_cache_hit_miss_ratio: {:.2?}, #extension_events: {}",
199 state.current_generation(),
200 state.stale_generations(),
201 state.best_generation(),
202 state.current_scale_index(),
203 state.population_cardinality(),
204 state.population_as_ref().size(),
205 fitness_cache_hit_miss_ratio,
206 number_of_extension_events,
207 ));
208 self.number_of_mutate_events = 0;
209 self.number_of_extension_events = 0;
210 }
211 }
212
213 fn on_new_best_chromosome<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
214 &mut self,
215 genotype: &Self::Genotype,
216 state: &S,
217 _config: &C,
218 ) {
219 self.writeln(format_args!(
220 "new best - generation: {}, fitness_score: {:?}, scale_index: {:?}, genes: {:?}",
221 state.current_generation(),
222 state.best_fitness_score(),
223 state.current_scale_index(),
224 if self.show_genes {
225 Some(genotype.best_genes())
226 } else {
227 None
228 },
229 ));
230 }
231
232 fn on_new_best_chromosome_equal_fitness<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
233 &mut self,
234 genotype: &Self::Genotype,
235 state: &S,
236 _config: &C,
237 ) {
238 if self.show_equal_fitness {
239 self.writeln(format_args!(
240 "equal best - generation: {}, fitness_score: {:?}, scale_index: {:?}, genes: {:?}",
241 state.current_generation(),
242 state.best_fitness_score(),
243 state.current_scale_index(),
244 if self.show_genes {
245 Some(genotype.best_genes())
246 } else {
247 None
248 },
249 ));
250 }
251 }
252
253 fn on_extension_event<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
254 &mut self,
255 event: ExtensionEvent,
256 _genotype: &Self::Genotype,
257 state: &S,
258 _config: &C,
259 ) {
260 self.number_of_extension_events += 1;
261 if self.show_extension_event {
262 match event {
263 ExtensionEvent::MassDeduplication(message) => self.writeln(format_args!(
264 "extension event - mass deduplication - generation {} - {}",
265 state.current_generation(),
266 message
267 )),
268 ExtensionEvent::MassDegeneration(message) => self.writeln(format_args!(
269 "extension event - mass degeneration - generation {} - {}",
270 state.current_generation(),
271 message
272 )),
273 ExtensionEvent::MassExtinction(message) => self.writeln(format_args!(
274 "extension event - mass extinction - generation {} - {}",
275 state.current_generation(),
276 message
277 )),
278 ExtensionEvent::MassGenesis(message) => self.writeln(format_args!(
279 "extension event - mass genesis - generation {} - {}",
280 state.current_generation(),
281 message
282 )),
283 }
284 }
285 }
286
287 fn on_mutate_event<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
288 &mut self,
289 event: MutateEvent,
290 _genotype: &Self::Genotype,
291 state: &S,
292 _config: &C,
293 ) {
294 self.number_of_mutate_events += 1;
295 if self.show_mutate_event {
296 match event {
297 MutateEvent::ChangeMutationProbability(message) => self.writeln(format_args!(
298 "mutate event - change mutation probability - generation {} - {}",
299 state.current_generation(),
300 message
301 )),
302 }
303 }
304 }
305}