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_solution(self.target_problem(), target_solution)?;
43
44 Ok({
45 (0..self.source_num_vars)
49 .map(|i| target_solution[2 * i])
50 .collect()
51 })
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 transform = upper_bound { 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) -> Result<Self::Result, crate::rules::ReductionError> {
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 Ok(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: serde_json::json!(vec![false, false, true]),
159 target_config: serde_json::json!(vec![
160 false, true, false, true, true, false, true, true, true, false
161 ]),
162 },
163 )
164 },
165 }]
166}
167
168#[cfg(test)]
169#[path = "../unit_tests/rules/ksatisfiability_subsetsum.rs"]
170mod tests;