1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
use std::marker::PhantomData;
use crate::ga::{individual::IndividualTrait, GAMetadata};
use super::{Probe, ProbingPolicy};
/// ## PolicyDrivenProbe
///
/// Checks whether policy allows for logging and if so, delegates actual logging to wrapped probe
pub struct PolicyDrivenProbe<
IndividualT: IndividualTrait,
Pc: ProbingPolicy<IndividualT>,
Pr: Probe<IndividualT>,
> {
policy: Pc,
probe: Pr,
_phantom: PhantomData<IndividualT>, // FIXME: Is there a way to avoid it?
}
impl<IndividualT: IndividualTrait, Pc: ProbingPolicy<IndividualT>, Pr: Probe<IndividualT>>
PolicyDrivenProbe<IndividualT, Pc, Pr>
{
/// Returns new instance of [PolicyDrivenProbe]
///
/// ### Arguments
///
/// * `policy` - logging policy to apply
/// * `probe` - probe used to logging
pub fn new(policy: Pc, probe: Pr) -> Self {
Self {
policy,
probe,
_phantom: PhantomData,
}
}
}
impl<IndividualT: IndividualTrait, Pc: ProbingPolicy<IndividualT>, Pr: Probe<IndividualT>> Probe<IndividualT>
for PolicyDrivenProbe<IndividualT, Pc, Pr>
{
/// This method is called in the very beginning of genetic algorithm, even before
/// initial population is generated.
///
/// Delegates actual logging to wrapped `probe` only if `policy` returns `true`
///
/// ### Arguments
///
/// * `metadata` - Structure containing metadata information on genetic algorithm.
/// See [GAMetadata] for reference. When running this method only `start_time`
/// field has meaningful value.
fn on_start(&mut self, metadata: &GAMetadata) {
if self.policy.on_start(metadata) {
self.probe.on_start(metadata);
}
}
/// This method is called directly after initial populationn is created and fitness
/// of the individuals is evaluated
///
/// Delegates actual logging to wrapped `probe` only if `policy` returns `true`
///
/// ### Arguments
///
/// * `population` - Freshly generated population
fn on_initial_population_created(&mut self, population: &[IndividualT]) {
if self.policy.on_initial_population_created(population) {
self.probe.on_initial_population_created(population);
}
}
/// This method is called every time new best individual is found (irrespectively of generation)
///
/// Delegates actual logging to wrapped `probe` only if `policy` returns `true`
///
/// ### Arguments
///
/// * `metadata` - Structure containing metadata information on genetic algorithm.
/// See [GAMetadata] for reference.
/// * `individual` - New best individual
fn on_new_best(&mut self, metadata: &GAMetadata, individual: &IndividualT) {
if self.policy.on_new_best(metadata, individual) {
self.probe.on_new_best(metadata, individual);
}
}
/// This method is called every time a new generation is created (but not for initial population)
///
/// Delegates actual logging to wrapped `probe` only if `policy` returns `true`
///
/// ### Arguments
///
/// * `generation` - Newly created generation
fn on_new_generation(&mut self, metadata: &GAMetadata, generation: &[IndividualT]) {
if self.policy.on_new_generation(metadata, generation) {
self.probe.on_new_generation(metadata, generation);
}
}
/// This method is called once per generation with best individual in it
///
/// Delegates actual logging to wrapped `probe` only if `policy` returns `true`
///
/// ### Arguments
///
/// * `metadata` - Structure containing metadata information on genetic algorithm.
/// See [GAMetadata] for reference.
/// * `individual` - Best individual in current generation
fn on_best_fit_in_generation(&mut self, metadata: &GAMetadata, individual: &IndividualT) {
if self.policy.on_best_fit_in_generation(metadata, individual) {
self.probe.on_best_fit_in_generation(metadata, individual);
}
}
/// This method is called in the very begining of algorithm's main loop
///
/// Delegates actual logging to wrapped `probe` only if `policy` returns `true`
///
/// ### Arguments
///
/// * `metadata` - Structure containing metadata information on genetic algorithm.
/// See [GAMetadata] for reference.
fn on_iteration_start(&mut self, metadata: &GAMetadata) {
if self.policy.on_iteration_start(metadata) {
self.probe.on_iteration_start(metadata);
}
}
/// This method is called in the very end of algorithm's main loop, just before
/// termination conditions are evaluated
///
/// Delegates actual logging to wrapped `probe` only if `policy` returns `true`
///
/// ### Arguments
///
/// * `metadata` - Structure containing metadata information on genetic algorithm.
/// See [GAMetadata] for reference.
fn on_iteration_end(&mut self, metadata: &GAMetadata) {
if self.policy.on_iteration_end(metadata) {
self.probe.on_iteration_end(metadata);
}
}
/// This method is called after algorithm 's main loop is exited, just before the `run`
/// method returns
///
/// Delegates actual logging to wrapped `probe` only if `policy` returns `true`
///
/// ### Arguments
///
/// * `metadata` - Structure containing metadata information on genetic algorithm.
/// See [GAMetadata] for reference.
/// * `population` - Final population
/// * `best_individual` - Best individual found by algorithm
fn on_end(&mut self, metadata: &GAMetadata, population: &[IndividualT], best_individual: &IndividualT) {
if self.policy.on_end(metadata, population, best_individual) {
self.probe.on_end(metadata, population, best_individual);
}
}
}