problemreductions/rules/
ksatisfiability_subsetsum.rs1use crate::models::formula::KSatisfiability;
16use crate::models::misc::SubsetSum;
17use crate::reduction;
18use crate::rules::traits::{ReduceTo, ReductionResult};
19use crate::variant::K3;
20use num_bigint::BigUint;
21use num_traits::Zero;
22
23#[derive(Debug, Clone)]
25pub struct Reduction3SATToSubsetSum {
26 target: SubsetSum,
27 source_num_vars: usize,
28}
29
30impl ReductionResult for Reduction3SATToSubsetSum {
31 type Source = KSatisfiability<K3>;
32 type Target = SubsetSum;
33
34 fn target_problem(&self) -> &Self::Target {
35 &self.target
36 }
37
38 fn extract_solution(
39 &self,
40 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
41 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
42 crate::rules::traits::validate_target_witness(
43 self.target_problem(),
44 target_solution,
45 |value| value.0,
46 "target witness does not satisfy the target problem",
47 )?;
48
49 Ok({
50 (0..self.source_num_vars)
54 .map(|i| target_solution[2 * i])
55 .collect()
56 })
57 }
58}
59
60fn digits_to_integer(digits: &[u8]) -> BigUint {
64 let mut value = BigUint::zero();
65 let ten = BigUint::from(10u8);
66 for &d in digits {
67 value = value * &ten + BigUint::from(d);
68 }
69 value
70}
71
72#[crate::aggregate_reduction(identity)]
73impl crate::rules::AggregateReductionResult for Reduction3SATToSubsetSum {}
74
75#[reduction(transform = upper_bound {
78 num_elements = "2 * num_vars + 2 * num_clauses",
79 max_numeric_magnitude_bits = "4 * (num_vars + num_clauses) + 1",
80})]
81impl ReduceTo<SubsetSum> for KSatisfiability<K3> {
82 type Result = Reduction3SATToSubsetSum;
83
84 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
85 let n = self.num_vars();
86 let m = self.num_clauses();
87 let num_digits = n + m;
88
89 let mut sizes = Vec::with_capacity(2 * n + 2 * m);
90
91 for i in 0..n {
93 let mut y_digits = vec![0u8; num_digits];
95 y_digits[i] = 1;
96 for (j, clause) in self.clauses().iter().enumerate() {
97 for &lit in &clause.literals {
98 let var_idx = (lit.unsigned_abs() as usize) - 1;
99 if var_idx == i && lit > 0 {
100 y_digits[n + j] = 1;
101 }
102 }
103 }
104 sizes.push(digits_to_integer(&y_digits));
105
106 let mut z_digits = vec![0u8; num_digits];
108 z_digits[i] = 1;
109 for (j, clause) in self.clauses().iter().enumerate() {
110 for &lit in &clause.literals {
111 let var_idx = (lit.unsigned_abs() as usize) - 1;
112 if var_idx == i && lit < 0 {
113 z_digits[n + j] = 1;
114 }
115 }
116 }
117 sizes.push(digits_to_integer(&z_digits));
118 }
119
120 for j in 0..m {
122 let mut g_digits = vec![0u8; num_digits];
124 g_digits[n + j] = 1;
125 sizes.push(digits_to_integer(&g_digits));
126
127 let mut h_digits = vec![0u8; num_digits];
129 h_digits[n + j] = 2;
130 sizes.push(digits_to_integer(&h_digits));
131 }
132
133 let mut target_digits = vec![0u8; num_digits];
135 for d in target_digits.iter_mut().take(n) {
136 *d = 1;
137 }
138 for d in target_digits.iter_mut().skip(n).take(m) {
139 *d = 4;
140 }
141 let target = digits_to_integer(&target_digits);
142
143 Ok(Reduction3SATToSubsetSum {
144 target: SubsetSum::new_unchecked(sizes, target),
145 source_num_vars: n,
146 })
147 }
148}
149
150#[cfg(feature = "example-db")]
151pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
152 use crate::export::SolutionPair;
153 use crate::models::formula::CNFClause;
154 use crate::models::misc::SubsetSum;
155
156 vec![crate::example_db::specs::RuleExampleSpec {
157 id: "ksatisfiability_to_subsetsum",
158 build: || {
159 let source = KSatisfiability::<K3>::new(
160 3,
161 vec![
162 CNFClause::new(vec![1, 2, 3]),
163 CNFClause::new(vec![-1, -2, 3]),
164 ],
165 );
166 crate::example_db::specs::rule_example_with_witness::<_, SubsetSum>(
167 source,
168 SolutionPair {
169 source_config: serde_json::json!(vec![false, false, true]),
170 target_config: serde_json::json!(vec![
171 false, true, false, true, true, false, true, true, true, false
172 ]),
173 },
174 )
175 },
176 }]
177}
178
179#[cfg(test)]
180#[path = "../unit_tests/rules/ksatisfiability_subsetsum.rs"]
181mod tests;