1use crate::models::formula::Satisfiability;
12use crate::models::graph::MaximumIndependentSet;
13use crate::reduction;
14use crate::rules::traits::{ReduceTo, ReductionResult};
15use crate::topology::SimpleGraph;
16use crate::types::One;
17
18#[derive(Debug, Clone, PartialEq, Eq)]
20pub struct BoolVar {
21 pub name: usize,
23 pub neg: bool,
25}
26
27impl BoolVar {
28 pub fn new(name: usize, neg: bool) -> Self {
30 Self { name, neg }
31 }
32
33 pub fn from_literal(lit: i32) -> Self {
36 let name = lit.unsigned_abs() as usize - 1; let neg = lit < 0;
38 Self { name, neg }
39 }
40
41 pub fn is_complement(&self, other: &BoolVar) -> bool {
43 self.name == other.name && self.neg != other.neg
44 }
45}
46
47#[derive(Debug, Clone)]
55pub struct ReductionSATToIS {
56 target: MaximumIndependentSet<SimpleGraph, One>,
58 literals: Vec<BoolVar>,
60 num_source_variables: usize,
62 num_clauses: usize,
64}
65
66impl ReductionResult for ReductionSATToIS {
67 type Source = Satisfiability;
68 type Target = MaximumIndependentSet<SimpleGraph, One>;
69
70 fn target_problem(&self) -> &Self::Target {
71 &self.target
72 }
73
74 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
80 let mut assignment = vec![0usize; self.num_source_variables];
81 let mut covered = vec![false; self.num_source_variables];
82
83 for (vertex_idx, &selected) in target_solution.iter().enumerate() {
84 if selected == 1 {
85 let literal = &self.literals[vertex_idx];
86 assignment[literal.name] = if literal.neg { 0 } else { 1 };
89 covered[literal.name] = true;
90 }
91 }
92
93 assignment
96 }
97}
98
99impl ReductionSATToIS {
100 pub fn num_clauses(&self) -> usize {
102 self.num_clauses
103 }
104
105 pub fn literals(&self) -> &[BoolVar] {
107 &self.literals
108 }
109}
110
111#[reduction(
112 overhead = {
113 num_vertices = "num_literals",
114 num_edges = "num_literals^2",
115 }
116)]
117impl ReduceTo<MaximumIndependentSet<SimpleGraph, One>> for Satisfiability {
118 type Result = ReductionSATToIS;
119
120 fn reduce_to(&self) -> Self::Result {
121 let mut literals: Vec<BoolVar> = Vec::new();
122 let mut edges: Vec<(usize, usize)> = Vec::new();
123 let mut vertex_count = 0;
124
125 for clause in self.clauses() {
128 let clause_start = vertex_count;
129
130 for &lit in &clause.literals {
132 literals.push(BoolVar::from_literal(lit));
133 vertex_count += 1;
134 }
135
136 for i in clause_start..vertex_count {
138 for j in (i + 1)..vertex_count {
139 edges.push((i, j));
140 }
141 }
142 }
143
144 for i in 0..vertex_count {
148 for j in (i + 1)..vertex_count {
149 if literals[i].is_complement(&literals[j]) {
150 edges.push((i, j));
151 }
152 }
153 }
154
155 let target = MaximumIndependentSet::new(
156 SimpleGraph::new(vertex_count, edges),
157 vec![One; vertex_count],
158 );
159
160 ReductionSATToIS {
161 target,
162 literals,
163 num_source_variables: self.num_vars(),
164 num_clauses: self.num_clauses(),
165 }
166 }
167}
168
169#[cfg(feature = "example-db")]
170pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
171 use crate::export::SolutionPair;
172 use crate::models::formula::CNFClause;
173
174 fn sat_seven_clause_example() -> Satisfiability {
175 Satisfiability::new(
176 5,
177 vec![
178 CNFClause::new(vec![1, 2, -3]),
179 CNFClause::new(vec![-1, 3, 4]),
180 CNFClause::new(vec![2, -4, 5]),
181 CNFClause::new(vec![-2, 3, -5]),
182 CNFClause::new(vec![1, -3, 5]),
183 CNFClause::new(vec![-1, -2, 4]),
184 CNFClause::new(vec![3, -4, -5]),
185 ],
186 )
187 }
188
189 vec![crate::example_db::specs::RuleExampleSpec {
190 id: "satisfiability_to_maximumindependentset",
191 build: || {
192 crate::example_db::specs::rule_example_with_witness::<
193 _,
194 MaximumIndependentSet<SimpleGraph, One>,
195 >(
196 sat_seven_clause_example(),
197 SolutionPair {
198 source_config: vec![1, 1, 1, 1, 0],
199 target_config: vec![
200 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0,
201 ],
202 },
203 )
204 },
205 }]
206}
207
208#[cfg(test)]
209#[path = "../unit_tests/rules/sat_maximumindependentset.rs"]
210mod tests;