problemreductions/registry/
dyn_problem.rs1use serde::Serialize;
2use serde_json::Value;
3use std::any::Any;
4use std::collections::BTreeMap;
5use std::fmt;
6
7use crate::traits::{EvaluationError, Problem};
8use crate::types::SolutionAggregate;
9
10pub fn format_metric<T>(metric: &T) -> String
14where
15 T: fmt::Display,
16{
17 metric.to_string()
18}
19
20pub trait DynProblem: Any {
24 fn evaluate_dyn(&self, solution: &Value) -> Result<String, EvaluationError>;
26 fn evaluate_witness_dyn(&self, solution: &Value) -> Result<Option<String>, EvaluationError>;
29 fn evaluate_json(&self, solution: &Value) -> Result<Value, EvaluationError>;
31 fn serialize_json(&self) -> Value;
33 fn as_any(&self) -> &dyn Any;
35 fn problem_name(&self) -> &'static str;
37 fn variant_map(&self) -> BTreeMap<String, String>;
39 fn parameter_names_dyn(&self) -> &'static [&'static str];
41 fn parameters_dyn(&self) -> crate::types::ProblemParameters;
43}
44
45impl<T> DynProblem for T
46where
47 T: Problem + Serialize + 'static,
48 T::Solution: serde::de::DeserializeOwned,
49 T::Value: SolutionAggregate + fmt::Display + Serialize,
50{
51 fn evaluate_dyn(&self, solution: &Value) -> Result<String, EvaluationError> {
52 let solution = serde::Deserialize::deserialize(solution).map_err(|error| {
53 EvaluationError::InvalidConfiguration(format!("invalid solution JSON: {error}"))
54 })?;
55 Ok(format_metric(&self.evaluate(&solution)?))
56 }
57
58 fn evaluate_json(&self, solution: &Value) -> Result<Value, EvaluationError> {
59 let solution = serde::Deserialize::deserialize(solution).map_err(|error| {
60 EvaluationError::InvalidConfiguration(format!("invalid solution JSON: {error}"))
61 })?;
62 Ok(serde_json::to_value(self.evaluate(&solution)?).expect("serialize metric failed"))
63 }
64
65 fn evaluate_witness_dyn(&self, solution: &Value) -> Result<Option<String>, EvaluationError> {
66 let solution = serde::Deserialize::deserialize(solution).map_err(|error| {
67 EvaluationError::InvalidConfiguration(format!("invalid solution JSON: {error}"))
68 })?;
69 let value = self.evaluate(&solution)?;
70 Ok(T::Value::contributes_to_solution(&value, &value).then(|| format_metric(&value)))
71 }
72
73 fn serialize_json(&self) -> Value {
74 serde_json::to_value(self).expect("serialize failed")
75 }
76
77 fn as_any(&self) -> &dyn Any {
78 self
79 }
80
81 fn problem_name(&self) -> &'static str {
82 T::NAME
83 }
84
85 fn variant_map(&self) -> BTreeMap<String, String> {
86 crate::export::variant_to_map(T::variant())
87 }
88
89 fn parameter_names_dyn(&self) -> &'static [&'static str] {
90 T::parameter_names()
91 }
92
93 fn parameters_dyn(&self) -> crate::types::ProblemParameters {
94 self.parameters()
95 }
96}
97
98pub struct LoadedDynProblem {
100 inner: Box<dyn DynProblem>,
101}
102
103impl std::fmt::Debug for LoadedDynProblem {
104 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105 f.debug_struct("LoadedDynProblem")
106 .field("name", &self.inner.problem_name())
107 .finish()
108 }
109}
110
111impl LoadedDynProblem {
112 pub(crate) fn new(inner: Box<dyn DynProblem>) -> Self {
114 Self { inner }
115 }
116}
117
118impl std::ops::Deref for LoadedDynProblem {
119 type Target = dyn DynProblem;
120
121 fn deref(&self) -> &(dyn DynProblem + 'static) {
122 &*self.inner
123 }
124}