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(
31 &self,
32 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
33 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
34 crate::rules::traits::validate_target_solution(self.target_problem(), target_solution)?;
35
36 Ok(target_solution[..self.num_vars]
37 .iter()
38 .map(|&value| value == 1)
39 .collect())
40 }
41}
42
43#[reduction(
44 transform = exact {
45 num_vars = "num_vars + num_clauses",
46 num_constraints = "num_clauses",
47 },
48 unavailable = {
49 num_nonzeros = "the exact target parameter is not represented by this reduction's symbolic transform",
50 }
51)]
52impl ReduceTo<ILP<bool>> for Maximum2Satisfiability {
53 type Result = ReductionMaximum2SatisfiabilityToILP;
54
55 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
56 let n = self.num_vars();
57 let m = self.num_clauses();
58 let num_ilp_vars = n + m;
59
60 let constraints: Vec<LinearConstraint> = self
68 .clauses()
69 .iter()
70 .enumerate()
71 .map(|(j, clause)| {
72 let mut terms: Vec<(usize, i64)> = Vec::new();
73 let mut neg_count = 0;
74
75 terms.push((n + j, 1));
77
78 for &lit in &clause.literals {
79 let var_idx = lit.unsigned_abs() as usize - 1;
80 if lit > 0 {
81 terms.push((var_idx, -1));
83 } else {
84 terms.push((var_idx, 1));
86 neg_count += 1;
87 }
88 }
89
90 LinearConstraint::le(terms, neg_count)
91 })
92 .collect();
93
94 let objective: Vec<(usize, i64)> = (0..m).map(|j| (n + j, 1)).collect();
96
97 let target = ILP::new(
98 num_ilp_vars,
99 constraints,
100 objective,
101 ObjectiveSense::Maximize,
102 )
103 .map_err(<Self as ReduceTo<ILP<bool>>>::target_construction)?;
104
105 Ok(ReductionMaximum2SatisfiabilityToILP {
106 target,
107 num_vars: n,
108 })
109 }
110}
111
112#[cfg(feature = "example-db")]
113pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
114 use crate::export::SolutionPair;
115 use crate::models::formula::CNFClause;
116
117 vec![crate::example_db::specs::RuleExampleSpec {
118 id: "maximum2satisfiability_to_ilp",
119 build: || {
120 let source = Maximum2Satisfiability::new(
121 4,
122 vec![
123 CNFClause::new(vec![1, 2]),
124 CNFClause::new(vec![1, -2]),
125 CNFClause::new(vec![-1, 3]),
126 CNFClause::new(vec![-1, -3]),
127 CNFClause::new(vec![2, 4]),
128 CNFClause::new(vec![-3, -4]),
129 CNFClause::new(vec![3, 4]),
130 ],
131 );
132 crate::example_db::specs::rule_example_with_witness::<_, ILP<bool>>(
143 source,
144 SolutionPair {
145 source_config: serde_json::json!(vec![true, true, false, true]),
146 target_config: serde_json::json!(vec![1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1]),
147 },
148 )
149 },
150 }]
151}
152
153#[cfg(test)]
154#[path = "../unit_tests/rules/maximum2satisfiability_ilp.rs"]
155mod tests;