solverforge_solver/builder/context/
candidate_metric.rs1use std::fmt;
2use std::sync::Arc;
3
4use crate::stats::CandidateTraceIdentity;
5
6pub trait RuntimeCandidateMetric<S>: Send + Sync {
13 fn measure(&self, solution: &S, candidate: &CandidateTraceIdentity) -> f64;
14}
15
16pub struct RuntimeCandidateMetricBinding<S> {
17 name: Arc<str>,
18 metric: Arc<dyn RuntimeCandidateMetric<S>>,
19}
20
21impl<S> RuntimeCandidateMetricBinding<S> {
22 pub fn new(
23 name: impl Into<Arc<str>>,
24 metric: Arc<dyn RuntimeCandidateMetric<S>>,
25 ) -> Result<Self, String> {
26 let name = name.into();
27 if name.is_empty() {
28 return Err("candidate metric name must not be empty".to_string());
29 }
30 Ok(Self { name, metric })
31 }
32
33 pub fn name(&self) -> &str {
34 self.name.as_ref()
35 }
36
37 pub fn measure(&self, solution: &S, candidate: &CandidateTraceIdentity) -> f64 {
38 self.metric.measure(solution, candidate)
39 }
40}
41
42impl<S> Clone for RuntimeCandidateMetricBinding<S> {
43 fn clone(&self) -> Self {
44 Self {
45 name: Arc::clone(&self.name),
46 metric: Arc::clone(&self.metric),
47 }
48 }
49}
50
51impl<S> fmt::Debug for RuntimeCandidateMetricBinding<S> {
52 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
53 formatter
54 .debug_struct("RuntimeCandidateMetricBinding")
55 .field("name", &self.name)
56 .finish_non_exhaustive()
57 }
58}
59
60pub struct RuntimeCandidateMetricRegistry<S> {
61 metrics: Vec<RuntimeCandidateMetricBinding<S>>,
62}
63
64impl<S> Clone for RuntimeCandidateMetricRegistry<S> {
65 fn clone(&self) -> Self {
66 Self {
67 metrics: self.metrics.clone(),
68 }
69 }
70}
71
72impl<S> fmt::Debug for RuntimeCandidateMetricRegistry<S> {
73 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
74 formatter
75 .debug_list()
76 .entries(self.metrics.iter().map(RuntimeCandidateMetricBinding::name))
77 .finish()
78 }
79}
80
81impl<S> RuntimeCandidateMetricRegistry<S> {
82 pub fn new(metrics: Vec<RuntimeCandidateMetricBinding<S>>) -> Result<Self, String> {
83 for (index, metric) in metrics.iter().enumerate() {
84 if metrics[..index]
85 .iter()
86 .any(|existing| existing.name() == metric.name())
87 {
88 return Err(format!(
89 "candidate metric `{}` is declared more than once",
90 metric.name()
91 ));
92 }
93 }
94 Ok(Self { metrics })
95 }
96
97 pub fn get(&self, name: &str) -> Option<&RuntimeCandidateMetricBinding<S>> {
98 self.metrics.iter().find(|metric| metric.name() == name)
99 }
100}
101
102impl<S> Default for RuntimeCandidateMetricRegistry<S> {
103 fn default() -> Self {
104 Self {
105 metrics: Vec::new(),
106 }
107 }
108}