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(&self, target_solution: &[usize]) -> Vec<usize> {
39 (0..self.source_num_vars)
43 .map(|i| {
44 let y_selected = target_solution[2 * i] == 1;
45 if y_selected {
46 1
47 } else {
48 0
49 }
50 })
51 .collect()
52 }
53}
54
55fn digits_to_integer(digits: &[u8]) -> BigUint {
59 let mut value = BigUint::zero();
60 let ten = BigUint::from(10u8);
61 for &d in digits {
62 value = value * &ten + BigUint::from(d);
63 }
64 value
65}
66
67#[reduction(
68 overhead = { num_elements = "2 * num_vars + 2 * num_clauses" }
69)]
70impl ReduceTo<SubsetSum> for KSatisfiability<K3> {
71 type Result = Reduction3SATToSubsetSum;
72
73 fn reduce_to(&self) -> Self::Result {
74 let n = self.num_vars();
75 let m = self.num_clauses();
76 let num_digits = n + m;
77
78 let mut sizes = Vec::with_capacity(2 * n + 2 * m);
79
80 for i in 0..n {
82 let mut y_digits = vec![0u8; num_digits];
84 y_digits[i] = 1;
85 for (j, clause) in self.clauses().iter().enumerate() {
86 for &lit in &clause.literals {
87 let var_idx = (lit.unsigned_abs() as usize) - 1;
88 if var_idx == i && lit > 0 {
89 y_digits[n + j] = 1;
90 }
91 }
92 }
93 sizes.push(digits_to_integer(&y_digits));
94
95 let mut z_digits = vec![0u8; num_digits];
97 z_digits[i] = 1;
98 for (j, clause) in self.clauses().iter().enumerate() {
99 for &lit in &clause.literals {
100 let var_idx = (lit.unsigned_abs() as usize) - 1;
101 if var_idx == i && lit < 0 {
102 z_digits[n + j] = 1;
103 }
104 }
105 }
106 sizes.push(digits_to_integer(&z_digits));
107 }
108
109 for j in 0..m {
111 let mut g_digits = vec![0u8; num_digits];
113 g_digits[n + j] = 1;
114 sizes.push(digits_to_integer(&g_digits));
115
116 let mut h_digits = vec![0u8; num_digits];
118 h_digits[n + j] = 2;
119 sizes.push(digits_to_integer(&h_digits));
120 }
121
122 let mut target_digits = vec![0u8; num_digits];
124 for d in target_digits.iter_mut().take(n) {
125 *d = 1;
126 }
127 for d in target_digits.iter_mut().skip(n).take(m) {
128 *d = 4;
129 }
130 let target = digits_to_integer(&target_digits);
131
132 Reduction3SATToSubsetSum {
133 target: SubsetSum::new_unchecked(sizes, target),
134 source_num_vars: n,
135 }
136 }
137}
138
139#[cfg(feature = "example-db")]
140pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
141 use crate::export::SolutionPair;
142 use crate::models::formula::CNFClause;
143 use crate::models::misc::SubsetSum;
144
145 vec![crate::example_db::specs::RuleExampleSpec {
146 id: "ksatisfiability_to_subsetsum",
147 build: || {
148 let source = KSatisfiability::<K3>::new(
149 3,
150 vec![
151 CNFClause::new(vec![1, 2, 3]),
152 CNFClause::new(vec![-1, -2, 3]),
153 ],
154 );
155 crate::example_db::specs::rule_example_with_witness::<_, SubsetSum>(
156 source,
157 SolutionPair {
158 source_config: vec![0, 0, 1],
159 target_config: vec![0, 1, 0, 1, 1, 0, 1, 1, 1, 0],
160 },
161 )
162 },
163 }]
164}
165
166#[cfg(test)]
167#[path = "../unit_tests/rules/ksatisfiability_subsetsum.rs"]
168mod tests;