problemreductions/rules/
ilp_bool_ilp_i32.rs

1//! Natural embedding of binary ILP into general integer ILP.
2//!
3//! Every binary (0-1) variable is a valid non-negative integer variable.
4//! The constraints carry over unchanged. Additional upper-bound constraints
5//! (x_i <= 1) are added to preserve binary semantics.
6//!
7//! This is a same-name variant cast (ILP → ILP), so by convention it does not
8//! have an example file or a paper `reduction-rule` entry.
9
10use crate::models::algebraic::{LinearConstraint, ILP};
11use crate::reduction;
12use crate::rules::traits::{ReduceTo, ReductionResult};
13
14#[derive(Debug, Clone)]
15pub struct ReductionBinaryILPToIntILP {
16    target: ILP<i32>,
17}
18
19impl ReductionResult for ReductionBinaryILPToIntILP {
20    type Source = ILP<bool>;
21    type Target = ILP<i32>;
22
23    fn target_problem(&self) -> &ILP<i32> {
24        &self.target
25    }
26
27    fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
28        target_solution.to_vec()
29    }
30}
31
32#[reduction(overhead = {
33    num_vars = "num_vars",
34    num_constraints = "num_constraints + num_vars",
35})]
36impl ReduceTo<ILP<i32>> for ILP<bool> {
37    type Result = ReductionBinaryILPToIntILP;
38
39    fn reduce_to(&self) -> Self::Result {
40        let mut constraints = self.constraints.clone();
41        // Add x_i <= 1 for each variable to preserve binary domain
42        for i in 0..self.num_vars {
43            constraints.push(LinearConstraint::le(vec![(i, 1.0)], 1.0));
44        }
45        ReductionBinaryILPToIntILP {
46            target: ILP::<i32>::new(
47                self.num_vars,
48                constraints,
49                self.objective.clone(),
50                self.sense,
51            ),
52        }
53    }
54}
55
56#[cfg(test)]
57#[path = "../unit_tests/rules/ilp_bool_ilp_i32.rs"]
58mod tests;