problemreductions/rules/
maximum2satisfiability_ilp.rs1use crate::models::algebraic::{LinearConstraint, ObjectiveSense, ILP};
11use crate::models::formula::Maximum2Satisfiability;
12use crate::reduction;
13use crate::rules::traits::{ReduceTo, ReductionResult};
14
15#[derive(Debug, Clone)]
17pub struct ReductionMaximum2SatisfiabilityToILP {
18 target: ILP<bool>,
19 num_vars: usize,
20}
21
22impl ReductionResult for ReductionMaximum2SatisfiabilityToILP {
23 type Source = Maximum2Satisfiability;
24 type Target = ILP<bool>;
25
26 fn target_problem(&self) -> &ILP<bool> {
27 &self.target
28 }
29
30 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
31 target_solution[..self.num_vars].to_vec()
32 }
33}
34
35#[reduction(
36 overhead = {
37 num_vars = "num_vars + num_clauses",
38 num_constraints = "num_clauses",
39 }
40)]
41impl ReduceTo<ILP<bool>> for Maximum2Satisfiability {
42 type Result = ReductionMaximum2SatisfiabilityToILP;
43
44 fn reduce_to(&self) -> Self::Result {
45 let n = self.num_vars();
46 let m = self.num_clauses();
47 let num_ilp_vars = n + m;
48
49 let constraints: Vec<LinearConstraint> = self
57 .clauses()
58 .iter()
59 .enumerate()
60 .map(|(j, clause)| {
61 let mut terms: Vec<(usize, f64)> = Vec::new();
62 let mut neg_count = 0i32;
63
64 terms.push((n + j, 1.0));
66
67 for &lit in &clause.literals {
68 let var_idx = lit.unsigned_abs() as usize - 1;
69 if lit > 0 {
70 terms.push((var_idx, -1.0));
72 } else {
73 terms.push((var_idx, 1.0));
75 neg_count += 1;
76 }
77 }
78
79 LinearConstraint::le(terms, neg_count as f64)
80 })
81 .collect();
82
83 let objective: Vec<(usize, f64)> = (0..m).map(|j| (n + j, 1.0)).collect();
85
86 let target = ILP::new(
87 num_ilp_vars,
88 constraints,
89 objective,
90 ObjectiveSense::Maximize,
91 );
92
93 ReductionMaximum2SatisfiabilityToILP {
94 target,
95 num_vars: n,
96 }
97 }
98}
99
100#[cfg(feature = "example-db")]
101pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
102 use crate::export::SolutionPair;
103 use crate::models::formula::CNFClause;
104
105 vec![crate::example_db::specs::RuleExampleSpec {
106 id: "maximum2satisfiability_to_ilp",
107 build: || {
108 let source = Maximum2Satisfiability::new(
109 4,
110 vec![
111 CNFClause::new(vec![1, 2]),
112 CNFClause::new(vec![1, -2]),
113 CNFClause::new(vec![-1, 3]),
114 CNFClause::new(vec![-1, -3]),
115 CNFClause::new(vec![2, 4]),
116 CNFClause::new(vec![-3, -4]),
117 CNFClause::new(vec![3, 4]),
118 ],
119 );
120 crate::example_db::specs::rule_example_with_witness::<_, ILP<bool>>(
131 source,
132 SolutionPair {
133 source_config: vec![1, 1, 0, 1],
134 target_config: vec![1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1],
135 },
136 )
137 },
138 }]
139}
140
141#[cfg(test)]
142#[path = "../unit_tests/rules/maximum2satisfiability_ilp.rs"]
143mod tests;