problemreductions/rules/
threedimensionalmatching_minimumweightdecoding.rs1use crate::models::algebraic::MinimumWeightDecoding;
24use crate::models::set::ThreeDimensionalMatching;
25use crate::reduction;
26use crate::rules::traits::{ReduceTo, ReductionResult};
27
28#[derive(Debug, Clone)]
30pub struct ReductionThreeDimensionalMatchingToMinimumWeightDecoding {
31 target: MinimumWeightDecoding,
32 source_num_triples: usize,
36 source_universe_size: usize,
37}
38
39impl ReductionResult for ReductionThreeDimensionalMatchingToMinimumWeightDecoding {
40 type Source = ThreeDimensionalMatching;
41 type Target = MinimumWeightDecoding;
42
43 fn target_problem(&self) -> &Self::Target {
44 &self.target
45 }
46
47 fn extract_solution(
51 &self,
52 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
53 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
54 crate::rules::traits::validate_target_witness(
55 self.target_problem(),
56 target_solution,
57 |value| crate::rules::AggregateReductionResult::extract_value(self, value).0,
58 "target witness does not certify a YES answer for the source",
59 )?;
60 if target_solution.len() != self.target.num_cols() {
61 return Err(crate::rules::ExtractionError::invalid(format!(
62 "expected {} target codeword bits, got {}",
63 self.target.num_cols(),
64 target_solution.len()
65 )));
66 }
67
68 Ok(target_solution[..self.source_num_triples].to_vec())
69 }
70}
71
72#[crate::aggregate_reduction]
73impl crate::rules::AggregateReductionResult
74 for ReductionThreeDimensionalMatchingToMinimumWeightDecoding
75{
76 type Source = ThreeDimensionalMatching;
77 type Target = MinimumWeightDecoding;
78
79 fn target_problem(&self) -> &Self::Target {
80 &self.target
81 }
82
83 fn extract_value(&self, value: crate::types::Min<i64>) -> crate::types::Or {
84 crate::types::Or(
85 value
86 .0
87 .is_some_and(|count| i128::from(count) == self.source_universe_size as i128),
88 )
89 }
90}
91
92#[reduction(
93 transform = exact {
94 num_rows = "3 * universe_size",
95 num_cols = "num_triples",
96 })]
97impl ReduceTo<MinimumWeightDecoding> for ThreeDimensionalMatching {
98 type Result = ReductionThreeDimensionalMatchingToMinimumWeightDecoding;
99
100 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
101 let q = self.universe_size();
102 let m = self.num_triples();
103
104 if q == 0 || m == 0 {
105 return Ok(ReductionThreeDimensionalMatchingToMinimumWeightDecoding {
112 source_universe_size: q,
113 target: MinimumWeightDecoding::new(vec![vec![true]], vec![false]),
114 source_num_triples: m,
115 });
116 }
117
118 let num_rows = 3 * q;
121 let mut matrix = vec![vec![false; m]; num_rows];
122 for (j, &(a, b, c)) in self.triples().iter().enumerate() {
123 matrix[a][j] = true;
124 matrix[q + b][j] = true;
125 matrix[2 * q + c][j] = true;
126 }
127 let syndrome = vec![true; num_rows];
128
129 Ok(ReductionThreeDimensionalMatchingToMinimumWeightDecoding {
130 source_universe_size: q,
131 target: MinimumWeightDecoding::new(matrix, syndrome),
132 source_num_triples: m,
133 })
134 }
135}
136
137#[cfg(feature = "example-db")]
138pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
139 use crate::export::SolutionPair;
140
141 vec![crate::example_db::specs::RuleExampleSpec {
142 id: "threedimensionalmatching_to_minimumweightdecoding",
143 build: || {
144 crate::example_db::specs::rule_example_with_witness::<_, MinimumWeightDecoding>(
148 ThreeDimensionalMatching::new(2, vec![(0, 0, 0), (1, 1, 1), (0, 1, 0), (1, 0, 1)]),
149 SolutionPair {
150 source_config: serde_json::json!(vec![true, true, false, false]),
151 target_config: serde_json::json!(vec![true, true, false, false]),
152 },
153 )
154 },
155 }]
156}
157
158#[cfg(test)]
159#[path = "../unit_tests/rules/threedimensionalmatching_minimumweightdecoding.rs"]
160mod tests;