genetic_algorithm/strategy/
reporter.rs1use crate::genotype::Genotype;
10use crate::strategy::{StrategyConfig, StrategyReporter, StrategyState, STRATEGY_ACTIONS};
11use std::fmt::Arguments;
12use std::io::Write;
13use std::marker::PhantomData;
14
15#[derive(Clone)]
17pub struct Noop<G: Genotype>(pub PhantomData<G>);
18impl<G: Genotype> Default for Noop<G> {
19 fn default() -> Self {
20 Self(PhantomData)
21 }
22}
23impl<G: Genotype> Noop<G> {
24 pub fn new() -> Self {
25 Self::default()
26 }
27}
28impl<G: Genotype> StrategyReporter for Noop<G> {
29 type Genotype = G;
30}
31
32#[derive(Clone)]
34pub struct Duration<G: Genotype> {
35 pub buffer: Option<Vec<u8>>,
36 _phantom: PhantomData<G>,
37}
38impl<G: Genotype> Default for Duration<G> {
39 fn default() -> Self {
40 Self {
41 buffer: None,
42 _phantom: PhantomData,
43 }
44 }
45}
46impl<G: Genotype> Duration<G> {
47 pub fn new() -> Self {
48 Self::default()
49 }
50 pub fn new_with_buffer() -> Self {
51 Self {
52 buffer: Some(Vec::new()),
53 ..Default::default()
54 }
55 }
56 fn writeln(&mut self, args: Arguments<'_>) {
57 if let Some(buffer) = self.buffer.as_mut() {
58 buffer.write_fmt(args).unwrap_or(());
59 writeln!(buffer).unwrap_or(())
60 } else {
61 std::io::stdout().write_fmt(args).unwrap_or(());
62 println!()
63 }
64 }
65}
66impl<G: Genotype> StrategyReporter for Duration<G> {
67 type Genotype = G;
68
69 fn flush(&mut self, output: &mut Vec<u8>) {
70 if let Some(buffer) = self.buffer.as_mut() {
71 output.append(buffer);
72 }
73 }
74 fn on_enter<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
75 &mut self,
76 _genotype: &Self::Genotype,
77 state: &S,
78 config: &C,
79 ) {
80 self.writeln(format_args!(
81 "enter - {}, iteration: {}",
82 config.variant(),
83 state.current_iteration()
84 ));
85 }
86 fn on_exit<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
87 &mut self,
88 _genotype: &Self::Genotype,
89 state: &S,
90 config: &C,
91 ) {
92 self.writeln(format_args!(
93 "exit - {}, iteration: {}",
94 config.variant(),
95 state.current_iteration()
96 ));
97 STRATEGY_ACTIONS.iter().for_each(|action| {
98 if let Some(duration) = state.durations().get(action) {
99 self.writeln(format_args!(" {:?}: {:.3?}", action, duration));
100 }
101 });
102 self.writeln(format_args!(
103 " Total: {:.3?} ({:.0}% fitness)",
104 &state.total_duration(),
105 state.fitness_duration_rate() * 100.0
106 ));
107 }
108}
109
110#[derive(Clone)]
113pub struct Simple<G: Genotype> {
114 pub buffer: Option<Vec<u8>>,
115 pub period: usize,
116 pub show_genes: bool,
117 pub show_equal_fitness: bool,
118 _phantom: PhantomData<G>,
119}
120impl<G: Genotype> Default for Simple<G> {
121 fn default() -> Self {
122 Self {
123 buffer: None,
124 period: 1,
125 show_genes: false,
126 show_equal_fitness: false,
127 _phantom: PhantomData,
128 }
129 }
130}
131impl<G: Genotype> Simple<G> {
132 pub fn new(period: usize) -> Self {
133 Self {
134 period,
135 ..Default::default()
136 }
137 }
138 pub fn new_with_buffer(period: usize) -> Self {
139 Self {
140 buffer: Some(Vec::new()),
141 period,
142 ..Default::default()
143 }
144 }
145 pub fn new_with_flags(
146 period: usize,
147 buffered: bool,
148 show_genes: bool,
149 show_equal_fitness: bool,
150 ) -> Self {
151 Self {
152 period,
153 buffer: if buffered { Some(Vec::new()) } else { None },
154 show_genes,
155 show_equal_fitness,
156 ..Default::default()
157 }
158 }
159 fn writeln(&mut self, args: Arguments<'_>) {
160 if let Some(buffer) = self.buffer.as_mut() {
161 buffer.write_fmt(args).unwrap_or(());
162 writeln!(buffer).unwrap_or(())
163 } else {
164 std::io::stdout().write_fmt(args).unwrap_or(());
165 println!()
166 }
167 }
168}
169impl<G: Genotype> StrategyReporter for Simple<G> {
170 type Genotype = G;
171
172 fn flush(&mut self, output: &mut Vec<u8>) {
173 if let Some(buffer) = self.buffer.as_mut() {
174 output.append(buffer);
175 }
176 }
177 fn on_enter<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
178 &mut self,
179 genotype: &Self::Genotype,
180 state: &S,
181 config: &C,
182 ) {
183 let number_of_seed_genes = genotype.seed_genes_list().len();
184 if number_of_seed_genes > 0 {
185 self.writeln(format_args!(
186 "enter - {}, iteration: {}, number of seed genes: {}",
187 config.variant(),
188 state.current_iteration(),
189 number_of_seed_genes
190 ));
191 } else {
192 self.writeln(format_args!(
193 "enter - {}, iteration: {}",
194 config.variant(),
195 state.current_iteration()
196 ));
197 }
198 }
199 fn on_exit<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
200 &mut self,
201 _genotype: &Self::Genotype,
202 state: &S,
203 config: &C,
204 ) {
205 self.writeln(format_args!(
206 "exit - {}, iteration: {}",
207 config.variant(),
208 state.current_iteration()
209 ));
210 STRATEGY_ACTIONS.iter().for_each(|action| {
211 if let Some(duration) = state.durations().get(action) {
212 self.writeln(format_args!(" {:?}: {:.3?}", action, duration));
213 }
214 });
215 self.writeln(format_args!(
216 " Total: {:.3?} ({:.0}% fitness)",
217 &state.total_duration(),
218 state.fitness_duration_rate() * 100.0
219 ));
220 }
221
222 fn on_new_generation<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
223 &mut self,
224 _genotype: &Self::Genotype,
225 state: &S,
226 _config: &C,
227 ) {
228 if state.current_generation() % self.period == 0 {
229 self.writeln(format_args!(
230 "periodic - current_generation: {}, stale_generations: {}, best_generation: {}, scale_index: {:?}",
231 state.current_generation(),
232 state.stale_generations(),
233 state.best_generation(),
234 state.current_scale_index(),
235 ));
236 }
237 }
238
239 fn on_new_best_chromosome<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
240 &mut self,
241 genotype: &Self::Genotype,
242 state: &S,
243 _config: &C,
244 ) {
245 self.writeln(format_args!(
246 "new best - generation: {}, fitness_score: {:?}, scale_index: {:?}, genes: {:?}",
247 state.current_generation(),
248 state.best_fitness_score(),
249 state.current_scale_index(),
250 if self.show_genes {
251 Some(genotype.best_genes())
252 } else {
253 None
254 },
255 ));
256 }
257
258 fn on_new_best_chromosome_equal_fitness<S: StrategyState<Self::Genotype>, C: StrategyConfig>(
259 &mut self,
260 genotype: &Self::Genotype,
261 state: &S,
262 _config: &C,
263 ) {
264 if self.show_equal_fitness {
265 self.writeln(format_args!(
266 "equal best - generation: {}, fitness_score: {:?}, scale_index: {:?}, genes: {:?}",
267 state.current_generation(),
268 state.best_fitness_score(),
269 state.current_scale_index(),
270 if self.show_genes {
271 Some(genotype.best_genes())
272 } else {
273 None
274 },
275 ));
276 }
277 }
278}