mod statistics;
pub use statistics::{Gap, Statistics};
use std::{
fmt::Debug,
time::{Duration, Instant},
};
use typed_builder::TypedBuilder;
use crate::core::{solver, Evaluation, Problem, Solver, StopCriterion};
#[derive(Debug, TypedBuilder)]
pub struct Batch<P, B, S, SC, H>
where
P: Problem,
SC: StopCriterion<P> + Clone,
B: FnMut(usize, usize) -> S,
S: Solver<SC, H, P = P>,
H: solver::IterHook<P> + Clone,
{
base_seed: usize,
executions: usize,
solver: B,
stop_criterion: SC,
hook: H,
}
impl<P, B, S, SC, H> Batch<P, B, S, SC, H>
where
P: Problem,
SC: StopCriterion<P> + Clone,
B: FnMut(usize, usize) -> S,
S: Solver<SC, H, P = P>,
H: solver::IterHook<P> + Clone,
{
pub fn run(mut self) -> Option<BatchResult<P, H>> {
let executions = (1..=self.executions as usize)
.flat_map(|exec_number| {
let start = Instant::now();
let mut hook = self.hook.clone();
let evaluation = {
let mut solver = (self.solver)(self.base_seed, exec_number);
solver.solve(&mut self.stop_criterion.clone(), &mut hook)?
};
let duration = start.elapsed();
Some(Execution {
number: exec_number,
evaluation,
duration,
hook,
})
})
.collect::<Vec<_>>();
if executions.is_empty() {
None
} else {
Some(BatchResult {
executions,
base_seed: self.base_seed,
})
}
}
}
pub struct BatchResult<P: Problem, H> {
base_seed: usize,
executions: Vec<Execution<P, H>>,
}
pub struct Execution<P: Problem, H> {
number: usize,
evaluation: Evaluation<P>,
duration: Duration,
hook: H,
}
impl<P: Problem, H> Execution<P, H> {
pub fn number(&self) -> usize {
self.number
}
pub fn evaluation(&self) -> &Evaluation<P> {
&self.evaluation
}
pub fn duration(&self) -> Duration {
self.duration
}
pub fn hook(&self) -> &H {
&self.hook
}
}
impl<P, H> Debug for Execution<P, H>
where
P::Value: Debug,
P: Problem,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Execution")
.field("number", &self.number)
.field("solution value", &self.evaluation.value())
.field("duration", &self.duration)
.finish()
}
}
impl<P: Problem, H> BatchResult<P, H> {
pub fn executions(&self) -> &[Execution<P, H>] {
&self.executions
}
pub fn base_seed(&self) -> usize {
self.base_seed
}
}
impl<P, H> Debug for BatchResult<P, H>
where
P: Problem + Debug,
P::Solution: Debug,
P::Value: Debug,
H: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BatchResult")
.field("base seed", &self.base_seed)
.field("evaluations", &self.executions)
.finish()
}
}