1#[macro_export]
2macro_rules! impl_integer {
3 ($($t:ty),*) => {
4 $(
5 impl Integer<$t> for $t {
6 const MIN: $t = <$t>::MIN;
7 const MAX: $t = <$t>::MAX;
8
9 fn from_i32(value: i32) -> $t {
10 value as $t
11 }
12 }
13 )*
14 };
15}
16
17#[macro_export]
18macro_rules! alters {
19 ($($struct_instance:expr),* $(,)?) => {
20 {
21 let mut vec: Vec<Box<dyn Alter<_>>> = Vec::new();
22 $(
23 vec.push(Box::new($struct_instance.alterer()));
24 )*
25 vec
26 }
27 };
28}
29
30#[macro_export]
46macro_rules! bench {
47 ($name:literal, $operation:expr) => {
48 let timer = std::time::Instant::now();
49 let result = $operation;
50 let elapsed = timer.elapsed();
51 println!("{:?} took {:?}", $name, elapsed);
52 result
53 };
54}
55
56#[macro_export]
57macro_rules! print_metrics {
58 ($metric_set:expr, [$($filter:expr),* $(,)?]) => {{
59 use std::collections::HashSet;
60 let filter_set: HashSet<&str> = vec![$($filter),*].into_iter().collect();
61
62 println!("=================================================== Metrics Summary ====================================================");
63
64 for metric_type in ["Operations", "Value", "Distribution", "Time"] {
66 for (name, metric) in $metric_set.iter() {
67 if !filter_set.contains(name) {
68 continue;
69 }
70 match (metric_type, metric) {
71 ("Operations", Metric::Operations(_, _, _)) => println!("{:?}", metric),
72 ("Value", Metric::Value(_, _)) => println!("{:?}", metric),
73 ("Distribution", Metric::Distribution(_, _)) => println!("{:?}", metric),
74 ("Time", Metric::Time(_, _)) => println!("{:?}", metric),
75 _ => {},
76 }
77 }
78 }
79 println!("========================================================================================================================");
80 }};
81 ($metric_set:expr) => {{
82 use std::time::Duration;
83
84 println!("=================================================== Metrics Summary ====================================================");
85
86 for (name, metric) in $metric_set.iter().filter(|(_, m)| matches!(m, Metric::Operations(_, _, _))) {
88 if let Metric::Operations(_, stat, time_stat) = metric {
89 println!(
90 "{:<20} | Mean: {:>8.3}, Min: {:>8.3}, Max: {:>8.3}, N: {:>3} | Avg Time: {:>9.3?}, Total Time: {:>9.3?}",
91 name,
92 stat.mean(),
93 stat.min(),
94 stat.max(),
95 stat.count(),
96 time_stat.mean(),
97 time_stat.sum(),
98 );
99 }
100 }
101
102 for (name, metric) in $metric_set.iter().filter(|(_, m)| matches!(m, Metric::Value(_, _, _))) {
104 if let Metric::Value(_, stat, dist) = metric {
105 println!(
106 "{:<20} | Mean: {:>8.3}, Min: {:>8.3}, Max: {:>8.3}, N: {:>3} | Dist. Mean: {:>8.3}, Dist. StdDev: {:>8.3}, Dist. Min: {:>8.3}, Dist. Max: {:>8.3}",
107 name,
108 stat.mean(),
109 stat.min(),
110 stat.max(),
111 stat.count(),
112 dist.mean(),
113 dist.standard_deviation(),
114 dist.min(),
115 dist.max(),
116
117 );
118 }
119 }
120
121 for (name, metric) in $metric_set.iter().filter(|(_, m)| matches!(m, Metric::Distribution(_, _))) {
123 if let Metric::Distribution(_, dist) = metric {
124 println!(
125 "{:<20} | Mean: {:>8.3}, StdDev: {:>8.3}, Min: {:>8.3}, Max: {:>8.3}, N: {:>3}",
126 name,
127 dist.mean(),
128 dist.standard_deviation(),
129 dist.min(),
130 dist.max(),
131 dist.count(),
132 );
133 }
134 }
135
136 for (name, metric) in $metric_set.iter().filter(|(_, m)| matches!(m, Metric::Time(_, _))) {
138 if let Metric::Time(_, stat) = metric {
139 println!(
140 "{:<20} | Avg Time: {:>9.3?}, Min Time: {:>9.3?}, Max Time: {:>9.3?}, N: {:>3} | Total Time: {:>9.3?}",
141 name,
142 stat.mean(),
143 stat.min(),
144 stat.max(),
145 stat.count(),
146 stat.sum(),
147 );
148 }
149 }
150
151 println!("========================================================================================================================");
152 }};
153}
154
155#[macro_export]
156macro_rules! metricset_to_string {
157 ($metric_set:expr) => {{
158 use std::collections::HashSet;
159 let mut result = String::new();
160
161 for (name, metric) in $metric_set.iter() {
162 result.push_str(&format!("{:?}\n", metric));
163 }
164 result
165 }};
166}
167
168#[macro_export]
169macro_rules! log_ctx {
170 ($ctx:expr) => {{
171 println!(
172 "[ Iteration {:<4} ] Score: {:>8.4}, Elapsed: {:.2?}",
173 $ctx.index(),
174 $ctx.score().as_f32(),
175 $ctx.time()
176 );
177 }};
178}
179
180#[macro_export]
181macro_rules! metric {
182 ($name:expr, $val:expr, $time:expr) => {{ Metric::new_operations($name, $val, $time) }};
183 ($name:expr, $val:expr) => {{
184 let mut metric = Metric::new_value($name);
185 metric.add_value($val);
186 metric
187 }};
188 ($name:expr, $dist:expr) => {{
189 let mut metric = Metric::new_distribution($name)
190 metric.add_distribution($dist);
191 metric
192 }};
193 ($name:expr, $time:expr) => {{
194 let mut metric = Metric::new_time($name);
195 metric.add_time($time);
196 metric
197 }};
198}
199
200#[macro_export]
201macro_rules! histogram {
202 ($title:expr, $data:expr) => {{
203 let max = $data.iter().cloned().fold(f32::MIN, f32::max);
204 let min = $data.iter().cloned().fold(f32::MAX, f32::min);
205 let bins = 10;
206 let step = (max - min) / bins as f32;
207 for i in 0..bins {
208 let lower = min + i as f32 * step;
209 let upper = lower + step;
210 let count = $data.iter().filter(|&&x| x >= lower && x < upper).count();
211 println!(" {:6.2} - {:6.2}: {}", lower, upper, "█".repeat(count));
212 }
213 }};
214}
215
216#[macro_export]
217macro_rules! dbg_ctx {
218 ($val:expr $(,)?) => {{
219 let tmp = &$val;
220 println!("[{}:{}] {} = {:?}", file!(), line!(), stringify!($val), tmp);
221 tmp
222 }};
223}
224
225#[macro_export]
226macro_rules! build_engine {
227 (
228 codec: $codec:expr,
229 fitness: $fitness_fn:expr,
230 settings: { $( $setting:ident $( : $value:expr )? ),* $(,)? }
231 ) => {{
232 let builder = GeneticEngine::builder().codec($codec).fitness_fn($fitness_fn);
233 $(
234 #[allow(unused_mut)]
235 let builder = crate::build_engine!(@apply_setting builder, $setting $(, $value)?);
236 )*
237 builder.build()
238 }};
239
240 (@apply_setting $builder:ident, $method:ident, $value:expr) => {
242 $builder.$method($value)
243 };
244 (@apply_setting $builder:ident, $method:ident) => {
245 $builder.$method()
246 };
247}
248
249#[macro_export]
250macro_rules! engine {
251 ($codec:expr, $fitness:expr) => {
252 GeneticEngine::builder().codec($codec).fitness_fn($fitness).build()
253 };
254 ($codec:expr, $fitness:expr, $($extra:tt)+) => {
255 GeneticEngine::builder().codec($codec).fitness_fn($fitness).$($extra)+.build()
256 };
257}
258
259#[macro_export]
260macro_rules! experiment {
261 (
262 repeat: $reps:expr,
263 $codec:expr,
264 $fitness:expr,
265 [$( $setting:ident ( $($value:expr),* ) ),* $(,)?],
266 $condition:expr
267 ) => {
268 (0..$reps)
269 .map(|_| {
270 let engine = GeneticEngine::builder()
271 .codec($codec)
272 .fitness_fn($fitness)
273 $( .$setting($($value),*) )*
274 .build();
275 engine.run($condition)
276 })
277 .collect::<Vec<_>>()
278 };
279}
280
281