problemreductions/rules/
setsplitting_ilp.rs1use crate::models::algebraic::{LinearConstraint, ObjectiveSense, ILP};
13use crate::models::set::SetSplitting;
14use crate::reduction;
15use crate::rules::traits::{ReduceTo, ReductionResult};
16
17#[derive(Debug, Clone)]
19pub struct ReductionSetSplittingToILP {
20 target: ILP<bool>,
21}
22
23impl ReductionResult for ReductionSetSplittingToILP {
24 type Source = SetSplitting;
25 type Target = ILP<bool>;
26
27 fn target_problem(&self) -> &ILP<bool> {
28 &self.target
29 }
30
31 fn extract_solution(
32 &self,
33 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
34 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
35 crate::rules::traits::validate_target_solution(self.target_problem(), target_solution)?;
36
37 Ok(target_solution.iter().map(|&value| value == 1).collect())
38 }
39}
40
41#[reduction(
42 transform = exact {
43 num_vars = "universe_size",
44 num_constraints = "2 * num_subsets",
45 },
46 unavailable = {
47 num_nonzeros = "the exact target parameter is not represented by this reduction's symbolic transform",
48 }
49)]
50impl ReduceTo<ILP<bool>> for SetSplitting {
51 type Result = ReductionSetSplittingToILP;
52
53 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
54 let num_vars = self.universe_size();
55 let mut constraints = Vec::new();
56
57 for subset in self.subsets() {
58 let terms: Vec<(usize, i64)> = subset.iter().map(|&e| (e, 1)).collect();
59 let k = <Self as ReduceTo<ILP<bool>>>::exact_i64(
60 subset.len() - 1,
61 "encoding the split-set cardinality",
62 )?;
63
64 constraints.push(LinearConstraint::ge(terms.clone(), 1));
66
67 constraints.push(LinearConstraint::le(terms, k));
69 }
70
71 let target = ILP::new(num_vars, constraints, vec![], ObjectiveSense::Minimize)
72 .map_err(<Self as ReduceTo<ILP<bool>>>::target_construction)?;
73 Ok(ReductionSetSplittingToILP { target })
74 }
75}
76
77#[cfg(feature = "example-db")]
78pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
79 vec![crate::example_db::specs::RuleExampleSpec {
80 id: "setsplitting_to_ilp",
81 build: || {
82 let source = SetSplitting::new(
83 6,
84 vec![vec![0, 1, 2], vec![2, 3, 4], vec![0, 4, 5], vec![1, 3, 5]],
85 );
86 crate::example_db::specs::rule_example_via_ilp::<_, bool>(source)
87 },
88 }]
89}
90
91#[cfg(test)]
92#[path = "../unit_tests/rules/setsplitting_ilp.rs"]
93mod tests;