problemreductions/rules/
ksatisfiability_kclique.rs1use crate::models::formula::KSatisfiability;
10use crate::models::graph::KClique;
11use crate::reduction;
12use crate::rules::traits::{ReduceTo, ReductionResult};
13use crate::topology::SimpleGraph;
14use crate::variant::K3;
15
16#[derive(Debug, Clone)]
18pub struct Reduction3SATToKClique {
19 target: KClique<SimpleGraph>,
20 literal_assignments: Vec<(usize, bool)>,
21 source_num_vars: usize,
22}
23
24impl ReductionResult for Reduction3SATToKClique {
25 type Source = KSatisfiability<K3>;
26 type Target = KClique<SimpleGraph>;
27
28 fn target_problem(&self) -> &Self::Target {
29 &self.target
30 }
31
32 fn extract_solution(
33 &self,
34 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
35 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
36 crate::rules::traits::validate_target_witness(
37 self.target_problem(),
38 target_solution,
39 |value| value.0,
40 "target selection is not a clique meeting the threshold",
41 )?;
42 let mut assignment = vec![false; self.source_num_vars];
44 for (&selected, &(variable, positive)) in target_solution[..self.literal_assignments.len()]
45 .iter()
46 .zip(&self.literal_assignments)
47 {
48 if selected {
49 assignment[variable] = positive;
50 }
51 }
52 Ok(assignment)
53 }
54}
55
56#[crate::aggregate_reduction(identity)]
57impl crate::rules::AggregateReductionResult for Reduction3SATToKClique {}
58
59#[reduction(
60 transform = upper_bound {
61 num_vertices = "3 * num_clauses + 1",
62 k = "num_clauses + 1",
63 num_edges = "9 * num_clauses^2 + 3 * num_clauses",
64 }
65)]
66impl ReduceTo<KClique<SimpleGraph>> for KSatisfiability<K3> {
67 type Result = Reduction3SATToKClique;
68
69 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
70 let (num_vertices, k) =
71 clique_sizes(self.num_clauses(), self.clauses().iter().map(|c| c.len()))?;
72 let positions: Vec<_> = self
75 .clauses()
76 .iter()
77 .enumerate()
78 .flat_map(|(clause, c)| {
79 c.variables()
80 .into_iter()
81 .zip(&c.literals)
82 .map(move |(var, &lit)| (clause, var, lit > 0))
83 })
84 .collect();
85 let mut edges = Vec::new();
86 for (u, &(cu, vu, pu)) in positions.iter().enumerate() {
87 for (v, &(cv, vv, pv)) in positions.iter().enumerate().skip(u + 1) {
88 if cu != cv && (vu != vv || pu == pv) {
89 edges.push((u, v));
90 }
91 }
92 }
93 let anchor = positions.len();
94 edges.extend((0..anchor).map(|v| (v, anchor)));
95 let target = KClique::new(SimpleGraph::new(num_vertices, edges), k);
96 Ok(Reduction3SATToKClique {
97 target,
98 literal_assignments: positions.into_iter().map(|(_, v, p)| (v, p)).collect(),
99 source_num_vars: self.num_vars(),
100 })
101 }
102}
103
104fn clique_sizes(
106 m: usize,
107 lengths: impl IntoIterator<Item = usize>,
108) -> Result<(usize, usize), crate::rules::ReductionError> {
109 let overflow = || {
110 crate::rules::ReductionError::integer_overflow::<KSatisfiability<K3>, KClique<SimpleGraph>>(
111 "counting SAT clique occurrences and auxiliary vertices",
112 )
113 };
114 let t = lengths
115 .into_iter()
116 .try_fold(0usize, |sum, len| sum.checked_add(len))
117 .ok_or_else(overflow)?;
118 let vertices = t.max(m).checked_add(1).ok_or_else(overflow)?;
119 Ok((vertices, m + 1))
121}
122
123#[cfg(feature = "example-db")]
124pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
125 use crate::export::SolutionPair;
126 use crate::models::formula::CNFClause;
127
128 vec![crate::example_db::specs::RuleExampleSpec {
129 id: "ksatisfiability_to_kclique",
130 build: || {
131 let source = KSatisfiability::<K3>::new(
133 3,
134 vec![
135 CNFClause::new(vec![1, 2, 3]),
136 CNFClause::new(vec![-1, -2, 3]),
137 ],
138 );
139 crate::example_db::specs::rule_example_with_witness::<_, KClique<SimpleGraph>>(
144 source,
145 SolutionPair {
146 source_config: serde_json::json!(vec![false, false, true]),
147 target_config: serde_json::json!(vec![
148 false, false, true, true, false, false, true
149 ]),
150 },
151 )
152 },
153 }]
154}
155
156#[cfg(test)]
157#[path = "../unit_tests/rules/ksatisfiability_kclique.rs"]
158mod tests;