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 aggregate_witness_evaluation(
26 &self,
27 value: &Value,
28 ) -> Result<Option<String>, EvaluationError>;
29 fn evaluate_dyn(&self, solution: &Value) -> Result<String, EvaluationError>;
31 fn evaluate_witness_dyn(&self, solution: &Value) -> Result<Option<String>, EvaluationError>;
34 fn evaluate_json(&self, solution: &Value) -> Result<Value, EvaluationError>;
36 fn serialize_json(&self) -> Value;
38 fn as_any(&self) -> &dyn Any;
40 fn problem_name(&self) -> &'static str;
42 fn variant_map(&self) -> BTreeMap<String, String>;
44 fn parameter_names_dyn(&self) -> &'static [&'static str];
46 fn parameters_dyn(&self) -> crate::types::ProblemParameters;
48}
49
50impl<T> DynProblem for T
51where
52 T: Problem + Serialize + 'static,
53 T::Solution: serde::de::DeserializeOwned,
54 T::Value: SolutionAggregate + fmt::Display + Serialize,
55{
56 fn aggregate_witness_evaluation(
57 &self,
58 value: &Value,
59 ) -> Result<Option<String>, EvaluationError> {
60 let value: T::Value = serde::Deserialize::deserialize(value).map_err(|error| {
61 EvaluationError::InvalidConfiguration(format!("invalid aggregate JSON: {error}"))
62 })?;
63 Ok(T::Value::contributes_to_solution(&value, &value).then(|| format_metric(&value)))
64 }
65 fn evaluate_dyn(&self, solution: &Value) -> Result<String, EvaluationError> {
66 let solution = serde::Deserialize::deserialize(solution).map_err(|error| {
67 EvaluationError::InvalidConfiguration(format!("invalid solution JSON: {error}"))
68 })?;
69 Ok(format_metric(&self.evaluate(&solution)?))
70 }
71
72 fn evaluate_json(&self, solution: &Value) -> Result<Value, EvaluationError> {
73 let solution = serde::Deserialize::deserialize(solution).map_err(|error| {
74 EvaluationError::InvalidConfiguration(format!("invalid solution JSON: {error}"))
75 })?;
76 serde_json::to_value(self.evaluate(&solution)?).map_err(|error| {
77 EvaluationError::InvalidConfiguration(format!("cannot serialize evaluation: {error}"))
78 })
79 }
80
81 fn evaluate_witness_dyn(&self, solution: &Value) -> Result<Option<String>, EvaluationError> {
82 let solution = serde::Deserialize::deserialize(solution).map_err(|error| {
83 EvaluationError::InvalidConfiguration(format!("invalid solution JSON: {error}"))
84 })?;
85 let value = self.evaluate(&solution)?;
86 Ok(T::Value::contributes_to_solution(&value, &value).then(|| format_metric(&value)))
87 }
88
89 fn serialize_json(&self) -> Value {
90 serde_json::to_value(self).expect("serialize failed")
91 }
92
93 fn as_any(&self) -> &dyn Any {
94 self
95 }
96
97 fn problem_name(&self) -> &'static str {
98 T::NAME
99 }
100
101 fn variant_map(&self) -> BTreeMap<String, String> {
102 crate::export::variant_to_map(T::variant())
103 }
104
105 fn parameter_names_dyn(&self) -> &'static [&'static str] {
106 T::parameter_names()
107 }
108
109 fn parameters_dyn(&self) -> crate::types::ProblemParameters {
110 self.parameters()
111 }
112}
113
114pub struct LoadedDynProblem {
116 inner: Box<dyn DynProblem>,
117}
118
119impl std::fmt::Debug for LoadedDynProblem {
120 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121 f.debug_struct("LoadedDynProblem")
122 .field("name", &self.inner.problem_name())
123 .finish()
124 }
125}
126
127impl LoadedDynProblem {
128 pub(crate) fn new(inner: Box<dyn DynProblem>) -> Self {
130 Self { inner }
131 }
132}
133
134impl std::ops::Deref for LoadedDynProblem {
135 type Target = dyn DynProblem;
136
137 fn deref(&self) -> &(dyn DynProblem + 'static) {
138 &*self.inner
139 }
140}