problemreductions/rules/
minimumvertexcover_ensemblecomputation.rs1use crate::models::graph::MinimumVertexCover;
16use crate::models::misc::EnsembleComputation;
17use crate::reduction;
18use crate::rules::traits::{ReduceTo, ReductionResult};
19use crate::topology::{Graph, SimpleGraph};
20use crate::types::One;
21
22#[derive(Debug, Clone)]
24pub struct ReductionVCToEC {
25 target: EnsembleComputation,
26 num_vertices: usize,
28}
29
30impl ReductionResult for ReductionVCToEC {
31 type Source = MinimumVertexCover<SimpleGraph, One>;
32 type Target = EnsembleComputation;
33
34 fn target_problem(&self) -> &Self::Target {
35 &self.target
36 }
37
38 fn extract_solution(
44 &self,
45 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
46 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
47 let value =
48 crate::rules::traits::validate_target_solution(self.target_problem(), target_solution)?;
49 let crate::types::Min(Some(length)) = value else {
50 return Err(crate::rules::ExtractionError::invalid(
51 "target configuration does not encode a valid ensemble computation",
52 ));
53 };
54 let meaningful_steps = usize::try_from(length).map_err(|_| {
55 crate::rules::ExtractionError::invalid(
56 "ensemble operation count cannot be represented as usize",
57 )
58 })?;
59 let mut cover = vec![false; self.num_vertices];
60 let universe_size = self.target.universe_size();
61 for &[left, right] in target_solution
62 .as_chunks::<2>()
63 .0
64 .iter()
65 .take(meaningful_steps)
66 {
67 if left < universe_size && right < universe_size {
68 cover[left.min(right)] = true;
72 }
73 }
74 Ok(cover)
75 }
76}
77
78#[reduction(
79 transform = upper_bound {
80 universe_size = "num_vertices + 1",
81 num_subsets = "num_edges",
82 budget = "num_vertices + num_edges + 1",
83 }
84)]
85impl ReduceTo<EnsembleComputation> for MinimumVertexCover<SimpleGraph, One> {
86 type Result = ReductionVCToEC;
87
88 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
89 let num_vertices = self.graph().num_vertices();
90 let edges = self.graph().edges();
91 let num_edges = edges.len();
92 let a0 = num_vertices; let overflow = || {
96 crate::rules::ReductionError::integer_overflow::<Self, EnsembleComputation>(
97 "computing ensemble universe, budget, or operand dimensions",
98 )
99 };
100 let universe_size = num_vertices.checked_add(1).ok_or_else(overflow)?;
101
102 let subsets: Vec<Vec<usize>> = edges.iter().map(|&(u, v)| vec![a0, u, v]).collect();
104
105 let budget = num_vertices
108 .checked_add(num_edges)
109 .ok_or_else(overflow)?
110 .max(1);
111 universe_size.checked_add(budget).ok_or_else(overflow)?;
112 budget.checked_mul(2).ok_or_else(overflow)?;
113
114 let target = EnsembleComputation::try_new(universe_size, subsets, budget)
115 .map_err(crate::rules::ReductionError::construction::<Self, EnsembleComputation>)?;
116
117 Ok(ReductionVCToEC {
118 target,
119 num_vertices,
120 })
121 }
122}
123
124#[cfg(feature = "example-db")]
125pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
126 use crate::export::SolutionPair;
127
128 vec![crate::example_db::specs::RuleExampleSpec {
129 id: "minimumvertexcover_to_ensemblecomputation",
130 build: || {
131 let source = MinimumVertexCover::new(SimpleGraph::new(2, vec![(0, 1)]), vec![One; 2]);
137
138 let target_config = vec![
143 2, 0, 1, 3, 2, 1, ];
147 let source_config = vec![true, false];
150
151 crate::example_db::specs::rule_example_with_witness::<_, EnsembleComputation>(
152 source,
153 SolutionPair {
154 source_config: serde_json::to_value(source_config)
155 .expect("solution serialization must succeed"),
156 target_config: serde_json::to_value(target_config)
157 .expect("solution serialization must succeed"),
158 },
159 )
160 },
161 }]
162}
163
164#[cfg(test)]
165#[path = "../unit_tests/rules/minimumvertexcover_ensemblecomputation.rs"]
166mod tests;