optimum/analysis/
batch.rs1mod statistics;
4
5pub use statistics::{Gap, Statistics};
6
7use std::{
8 fmt::Debug,
9 time::{Duration, Instant},
10};
11
12use typed_builder::TypedBuilder;
13
14use crate::core::{solver, Evaluation, Problem, Solver, StopCriterion};
15
16#[derive(Debug, TypedBuilder)]
19pub struct Batch<P, B, S, SC, H>
20where
21 P: Problem,
22 SC: StopCriterion<P> + Clone,
23 B: FnMut(usize, usize) -> S,
24 S: Solver<SC, H, P = P>,
25 H: solver::IterHook<P> + Clone,
26{
27 base_seed: usize,
28 executions: usize,
29 solver: B,
30 stop_criterion: SC,
31 hook: H,
32}
33
34impl<P, B, S, SC, H> Batch<P, B, S, SC, H>
35where
36 P: Problem,
37 SC: StopCriterion<P> + Clone,
38 B: FnMut(usize, usize) -> S,
39 S: Solver<SC, H, P = P>,
40 H: solver::IterHook<P> + Clone,
41{
42 pub fn run(mut self) -> Option<BatchResult<P, H>> {
59 let executions = (1..=self.executions as usize)
60 .flat_map(|exec_number| {
61 let start = Instant::now();
62
63 let mut hook = self.hook.clone();
64 let evaluation = {
65 let mut solver = (self.solver)(self.base_seed, exec_number);
66 solver.solve(&mut self.stop_criterion.clone(), &mut hook)?
67 };
68
69 let duration = start.elapsed();
70
71 Some(Execution {
72 number: exec_number,
73 evaluation,
74 duration,
75 hook,
76 })
77 })
78 .collect::<Vec<_>>();
79
80 if executions.is_empty() {
81 None
82 } else {
83 Some(BatchResult {
84 executions,
85 base_seed: self.base_seed,
86 })
87 }
88 }
89}
90
91pub struct BatchResult<P: Problem, H> {
93 base_seed: usize,
94 executions: Vec<Execution<P, H>>,
95}
96
97pub struct Execution<P: Problem, H> {
101 number: usize,
102 evaluation: Evaluation<P>,
103 duration: Duration,
104 hook: H,
105}
106
107impl<P: Problem, H> Execution<P, H> {
108 pub fn number(&self) -> usize {
110 self.number
111 }
112
113 pub fn evaluation(&self) -> &Evaluation<P> {
115 &self.evaluation
116 }
117
118 pub fn duration(&self) -> Duration {
120 self.duration
121 }
122
123 pub fn hook(&self) -> &H {
125 &self.hook
126 }
127}
128
129impl<P, H> Debug for Execution<P, H>
130where
131 P::Value: Debug,
132 P: Problem,
133{
134 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135 f.debug_struct("Execution")
136 .field("number", &self.number)
137 .field("solution value", &self.evaluation.value())
138 .field("duration", &self.duration)
139 .finish()
140 }
141}
142
143impl<P: Problem, H> BatchResult<P, H> {
144 pub fn executions(&self) -> &[Execution<P, H>] {
146 &self.executions
147 }
148
149 pub fn base_seed(&self) -> usize {
151 self.base_seed
152 }
153}
154
155impl<P, H> Debug for BatchResult<P, H>
156where
157 P: Problem + Debug,
158 P::Solution: Debug,
159 P::Value: Debug,
160 H: Debug,
161{
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 f.debug_struct("BatchResult")
164 .field("base seed", &self.base_seed)
165 .field("evaluations", &self.executions)
166 .finish()
167 }
168}