problemreductions/rules/
maximum2satisfiability_maxcut.rs1use crate::models::formula::Maximum2Satisfiability;
15use crate::models::graph::MaxCut;
16use crate::reduction;
17use crate::rules::traits::{ReduceTo, ReductionResult};
18use crate::topology::SimpleGraph;
19use std::collections::BTreeMap;
20
21#[derive(Debug, Clone)]
23pub struct ReductionMaximum2SatisfiabilityToMaxCut {
24 target: MaxCut<SimpleGraph, i32>,
25 source_num_vars: usize,
26}
27
28impl ReductionResult for ReductionMaximum2SatisfiabilityToMaxCut {
29 type Source = Maximum2Satisfiability;
30 type Target = MaxCut<SimpleGraph, i32>;
31
32 fn target_problem(&self) -> &Self::Target {
33 &self.target
34 }
35
36 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
37 let reference_side = target_solution[0];
38 (0..self.source_num_vars)
39 .map(|i| usize::from(target_solution[i + 1] == reference_side))
40 .collect()
41 }
42}
43
44fn add_edge_weight(weights: &mut BTreeMap<(usize, usize), i32>, u: usize, v: usize, delta: i32) {
45 let edge = if u < v { (u, v) } else { (v, u) };
46 *weights.entry(edge).or_insert(0) += delta;
47}
48
49fn literal_polarity(lit: i32) -> i32 {
50 if lit > 0 {
51 1
52 } else {
53 -1
54 }
55}
56
57#[reduction(
58 overhead = {
59 num_vertices = "num_vars + 1",
60 num_edges = "num_vars + num_clauses",
61 }
62)]
63impl ReduceTo<MaxCut<SimpleGraph, i32>> for Maximum2Satisfiability {
64 type Result = ReductionMaximum2SatisfiabilityToMaxCut;
65
66 fn reduce_to(&self) -> Self::Result {
67 let mut accumulated = BTreeMap::new();
68
69 for clause in self.clauses() {
70 let literals = &clause.literals;
71 let (lit_a, lit_b) = (literals[0], literals[1]);
72 let var_a = lit_a.unsigned_abs() as usize;
73 let var_b = lit_b.unsigned_abs() as usize;
74 let sigma_a = literal_polarity(lit_a);
75 let sigma_b = literal_polarity(lit_b);
76
77 add_edge_weight(&mut accumulated, 0, var_a, -sigma_a);
78 add_edge_weight(&mut accumulated, 0, var_b, -sigma_b);
79 if var_a != var_b {
80 add_edge_weight(&mut accumulated, var_a, var_b, sigma_a * sigma_b);
81 }
82 }
83
84 let (edges, weights): (Vec<_>, Vec<_>) = accumulated
85 .into_iter()
86 .filter(|(_, weight)| *weight != 0)
87 .unzip();
88
89 let target = MaxCut::new(SimpleGraph::new(self.num_vars() + 1, edges), weights);
90
91 ReductionMaximum2SatisfiabilityToMaxCut {
92 target,
93 source_num_vars: self.num_vars(),
94 }
95 }
96}
97
98#[cfg(feature = "example-db")]
99pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
100 use crate::export::SolutionPair;
101 use crate::models::formula::CNFClause;
102
103 vec![crate::example_db::specs::RuleExampleSpec {
104 id: "maximum2satisfiability_to_maxcut",
105 build: || {
106 let source = Maximum2Satisfiability::new(
107 3,
108 vec![
109 CNFClause::new(vec![1, 2]),
110 CNFClause::new(vec![-1, 3]),
111 CNFClause::new(vec![2, -3]),
112 CNFClause::new(vec![-1, -2]),
113 CNFClause::new(vec![1, 3]),
114 ],
115 );
116 crate::example_db::specs::rule_example_with_witness::<_, MaxCut<SimpleGraph, i32>>(
117 source,
118 SolutionPair {
119 source_config: vec![0, 1, 1],
121 target_config: vec![0, 1, 0, 0],
124 },
125 )
126 },
127 }]
128}
129
130#[cfg(test)]
131#[path = "../unit_tests/rules/maximum2satisfiability_maxcut.rs"]
132mod tests;