problemreductions/models/
decision.rs1use crate::rules::{AggregateReductionResult, ReduceTo, ReduceToAggregate, ReductionResult};
4use crate::traits::Problem;
5use crate::types::{OptimizationValue, Or};
6use serde::de::DeserializeOwned;
7use serde::{Deserialize, Serialize};
8
9pub trait DecisionProblemMeta: Problem
11where
12 Self::Value: OptimizationValue,
13{
14 const DECISION_NAME: &'static str;
16}
17
18#[macro_export]
20macro_rules! decision_problem_meta {
21 ($inner:ty, $name:literal) => {
22 impl $crate::models::decision::DecisionProblemMeta for $inner {
23 const DECISION_NAME: &'static str = $name;
24 }
25 };
26}
27
28#[macro_export]
38macro_rules! register_decision_variant {
39 (
40 $inner:ty,
41 $name:literal,
42 $complexity:literal,
43 $aliases:expr,
44 $description:literal,
45 dims: [$($dim:expr),* $(,)?],
46 fields: [$($field:expr),* $(,)?],
47 size_getters: [$(($sg_name:literal, $sg_method:ident)),* $(,)?]
48 ) => {
49 $crate::declare_variants! {
50 default $crate::models::decision::Decision<$inner> => $complexity,
51 }
52
53 $crate::inventory::submit! {
54 $crate::registry::ProblemSchemaEntry {
55 name: $name,
56 display_name: $crate::register_decision_variant!(@display_name $name),
57 aliases: $aliases,
58 dimensions: &[$($dim),*],
59 module_path: module_path!(),
60 description: $description,
61 fields: &[$($field),*],
62 }
63 }
64
65 $crate::inventory::submit! {
67 $crate::rules::ReductionEntry {
68 source_name: $name,
69 target_name: <$inner as $crate::traits::Problem>::NAME,
70 source_variant_fn: <$crate::models::decision::Decision<$inner> as $crate::traits::Problem>::variant,
71 target_variant_fn: <$inner as $crate::traits::Problem>::variant,
72 overhead_fn: || $crate::rules::ReductionOverhead::identity(&[$($sg_name),*]),
73 module_path: module_path!(),
74 reduce_fn: Some(|any| {
75 let source = any
76 .downcast_ref::<$crate::models::decision::Decision<$inner>>()
77 .expect(concat!($name, " witness reduction source type mismatch"));
78 Box::new(
79 <$crate::models::decision::Decision<$inner> as $crate::rules::ReduceTo<$inner>>::reduce_to(source),
80 )
81 }),
82 reduce_aggregate_fn: Some(|any| {
83 let source = any
84 .downcast_ref::<$crate::models::decision::Decision<$inner>>()
85 .expect(concat!($name, " aggregate reduction source type mismatch"));
86 Box::new(
87 <$crate::models::decision::Decision<$inner> as $crate::rules::ReduceToAggregate<$inner>>::reduce_to_aggregate(source),
88 )
89 }),
90 capabilities: $crate::rules::EdgeCapabilities::both(),
91 overhead_eval_fn: |any| {
92 let source = any
93 .downcast_ref::<$crate::models::decision::Decision<$inner>>()
94 .expect(concat!($name, " overhead source type mismatch"));
95 $crate::types::ProblemSize::new(vec![
96 $(($sg_name, source.$sg_method())),*
97 ])
98 },
99 source_size_fn: |any| {
100 let source = any
101 .downcast_ref::<$crate::models::decision::Decision<$inner>>()
102 .expect(concat!($name, " size source type mismatch"));
103 $crate::types::ProblemSize::new(vec![
104 $(($sg_name, source.$sg_method()),)*
105 ("k", source.k()),
106 ])
107 },
108 }
109 }
110
111 $crate::inventory::submit! {
113 $crate::rules::ReductionEntry {
114 source_name: <$inner as $crate::traits::Problem>::NAME,
115 target_name: $name,
116 source_variant_fn: <$inner as $crate::traits::Problem>::variant,
117 target_variant_fn: <$crate::models::decision::Decision<$inner> as $crate::traits::Problem>::variant,
118 overhead_fn: || $crate::rules::ReductionOverhead::identity(&[$($sg_name),*]),
119 module_path: module_path!(),
120 reduce_fn: None,
121 reduce_aggregate_fn: None,
122 capabilities: $crate::rules::EdgeCapabilities::turing(),
123 overhead_eval_fn: |any| {
124 let source = any
125 .downcast_ref::<$inner>()
126 .expect(concat!($name, " turing overhead source type mismatch"));
127 $crate::types::ProblemSize::new(vec![
128 $(($sg_name, source.$sg_method())),*
129 ])
130 },
131 source_size_fn: |any| {
132 let source = any
133 .downcast_ref::<$inner>()
134 .expect(concat!($name, " turing size source type mismatch"));
135 $crate::types::ProblemSize::new(vec![
136 $(($sg_name, source.$sg_method())),*
137 ])
138 },
139 }
140 }
141 };
142 (@display_name "DecisionMinimumVertexCover") => {
143 "Decision Minimum Vertex Cover"
144 };
145 (@display_name "DecisionMinimumDominatingSet") => {
146 "Decision Minimum Dominating Set"
147 };
148 (@display_name "DecisionMaximumIndependentSet") => {
149 "Decision Maximum Independent Set"
150 };
151 (@display_name $name:literal) => {
152 $name
153 };
154}
155
156#[derive(Debug, Clone, Serialize, Deserialize)]
158pub struct Decision<P: Problem>
159where
160 P::Value: OptimizationValue,
161{
162 inner: P,
163 bound: <P::Value as OptimizationValue>::Inner,
164}
165
166impl<P: Problem> Decision<P>
167where
168 P::Value: OptimizationValue,
169{
170 pub fn new(inner: P, bound: <P::Value as OptimizationValue>::Inner) -> Self {
172 Self { inner, bound }
173 }
174
175 pub fn inner(&self) -> &P {
177 &self.inner
178 }
179
180 pub fn bound(&self) -> &<P::Value as OptimizationValue>::Inner {
182 &self.bound
183 }
184}
185
186impl<P> Problem for Decision<P>
187where
188 P: DecisionProblemMeta,
189 P::Value: OptimizationValue,
190{
191 const NAME: &'static str = P::DECISION_NAME;
192 type Value = Or;
193
194 fn dims(&self) -> Vec<usize> {
195 self.inner.dims()
196 }
197
198 fn evaluate(&self, config: &[usize]) -> Or {
199 Or(<P::Value as OptimizationValue>::meets_bound(
200 &self.inner.evaluate(config),
201 &self.bound,
202 ))
203 }
204
205 fn variant() -> Vec<(&'static str, &'static str)> {
206 P::variant()
207 }
208}
209
210#[derive(Debug, Clone)]
212pub struct DecisionToOptimizationResult<P>
213where
214 P: Problem,
215 P::Value: OptimizationValue,
216{
217 target: P,
218 bound: <P::Value as OptimizationValue>::Inner,
219}
220
221impl<P> AggregateReductionResult for DecisionToOptimizationResult<P>
222where
223 P: DecisionProblemMeta + 'static,
224 P::Value: OptimizationValue + Serialize + DeserializeOwned,
225{
226 type Source = Decision<P>;
227 type Target = P;
228
229 fn target_problem(&self) -> &Self::Target {
230 &self.target
231 }
232
233 fn extract_value(&self, target_value: P::Value) -> Or {
234 Or(<P::Value as OptimizationValue>::meets_bound(
235 &target_value,
236 &self.bound,
237 ))
238 }
239}
240
241impl<P> ReduceToAggregate<P> for Decision<P>
242where
243 P: DecisionProblemMeta + Clone + 'static,
244 P::Value: OptimizationValue + Serialize + DeserializeOwned,
245{
246 type Result = DecisionToOptimizationResult<P>;
247
248 fn reduce_to_aggregate(&self) -> Self::Result {
249 DecisionToOptimizationResult {
250 target: self.inner.clone(),
251 bound: self.bound.clone(),
252 }
253 }
254}
255
256#[derive(Debug, Clone)]
262pub struct DecisionToOptimizationWitnessResult<P>
263where
264 P: Problem,
265 P::Value: OptimizationValue,
266{
267 target: P,
268}
269
270impl<P> ReductionResult for DecisionToOptimizationWitnessResult<P>
271where
272 P: DecisionProblemMeta + 'static,
273 P::Value: OptimizationValue + Serialize + DeserializeOwned,
274{
275 type Source = Decision<P>;
276 type Target = P;
277
278 fn target_problem(&self) -> &Self::Target {
279 &self.target
280 }
281
282 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
283 target_solution.to_vec()
284 }
285}
286
287impl<P> ReduceTo<P> for Decision<P>
288where
289 P: DecisionProblemMeta + Clone + 'static,
290 P::Value: OptimizationValue + Serialize + DeserializeOwned,
291{
292 type Result = DecisionToOptimizationWitnessResult<P>;
293
294 fn reduce_to(&self) -> Self::Result {
295 DecisionToOptimizationWitnessResult {
296 target: self.inner.clone(),
297 }
298 }
299}
300
301#[cfg(test)]
302#[path = "../unit_tests/models/decision.rs"]
303mod tests;