problemreductions/rules/
feasibleregisterassignment_ilp.rs1use crate::models::algebraic::{Bounded, IntegerVariable, LinearConstraint, ObjectiveSense, ILP};
4use crate::models::misc::FeasibleRegisterAssignment;
5use crate::reduction;
6use crate::rules::ilp_helpers::{bounded_order_comparison, ranks_to_positions};
7use crate::rules::traits::{ReduceTo, ReductionResult};
8
9#[derive(Debug, Clone)]
10pub struct ReductionFeasibleRegisterAssignmentToILP {
11 target: ILP<i64, i64, Bounded>,
12 num_vertices: usize,
13}
14
15impl ReductionResult for ReductionFeasibleRegisterAssignmentToILP {
16 type Source = FeasibleRegisterAssignment;
17 type Target = ILP<i64, i64, Bounded>;
18
19 fn target_problem(&self) -> &ILP<i64, i64, Bounded> {
20 &self.target
21 }
22
23 fn extract_solution(
24 &self,
25 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
26 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
27 crate::rules::traits::validate_target_witness(
28 self.target_problem(),
29 target_solution,
30 |value| value.value.is_some(),
31 "target ILP assignment is infeasible",
32 )?;
33
34 Ok(ranks_to_positions(&target_solution[..self.num_vertices]))
35 }
36}
37
38#[crate::aggregate_reduction(ilp_feasibility)]
39impl crate::rules::AggregateReductionResult for ReductionFeasibleRegisterAssignmentToILP {}
40
41#[reduction(transform = {
42 exact {
43 num_vars = "num_vertices + num_same_register_pairs",
44 },
45 upper_bound {
46 num_constraints = "num_vertices * num_arcs + 2 * num_same_register_pairs",
47 num_nonzeros = "3 * num_vertices * num_arcs + 6 * num_same_register_pairs",
48 max_constraint_magnitude_bits = "num_vertices + 1",
49 },
50})]
51impl ReduceTo<ILP<i64, i64, Bounded>> for FeasibleRegisterAssignment {
52 type Result = ReductionFeasibleRegisterAssignmentToILP;
53
54 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
55 let n = self.num_vertices();
56 let pairs: Vec<_> = (0..n)
57 .flat_map(|u| ((u + 1)..n).map(move |v| (u, v)))
58 .filter(|&(u, v)| self.assignment()[u] == self.assignment()[v])
59 .collect();
60 let num_vars = n.checked_add(pairs.len()).ok_or_else(|| {
61 crate::rules::ReductionError::integer_overflow::<Self, ILP<i64, i64, Bounded>>(
62 "counting register assignment variables",
63 )
64 })?;
65 let big_m = Self::exact_i64(n, "encoding the schedule order")?;
66 let last_position = big_m.saturating_sub(1).max(0);
67 let mut variables = vec![
68 IntegerVariable::new(Some(0), Some(last_position))
69 .map_err(Self::target_construction)?;
70 n
71 ];
72 variables.resize(num_vars, IntegerVariable::binary());
73 let mut constraints = Vec::new();
74 let mut dependents = vec![Vec::new(); n];
75 for &(dependent, dependency) in self.arcs() {
76 constraints.push(LinearConstraint::ge(
77 vec![(dependent, 1), (dependency, -1)],
78 1,
79 ));
80 dependents[dependency].push(dependent);
81 }
82 for (index, &(u, v)) in pairs.iter().enumerate() {
83 let selector = n + index;
84 constraints.extend(bounded_order_comparison(u, v, selector, big_m));
85 for &w in &dependents[u] {
88 if w != v {
89 constraints.push(LinearConstraint::ge(
90 vec![(v, 1), (w, -1), (selector, -big_m)],
91 1 - big_m,
92 ));
93 }
94 }
95 for &w in &dependents[v] {
96 if w != u {
97 constraints.push(LinearConstraint::ge(
98 vec![(u, 1), (w, -1), (selector, big_m)],
99 1,
100 ));
101 }
102 }
103 }
104 let target = ILP::with_variables(variables, constraints, vec![], ObjectiveSense::Minimize)
105 .map_err(Self::target_construction)?;
106 crate::rules::ilp_helpers::validate_bounded_constraint_arithmetic::<Self>(&target)?;
107
108 Ok(ReductionFeasibleRegisterAssignmentToILP {
109 target,
110 num_vertices: n,
111 })
112 }
113}
114
115#[cfg(feature = "example-db")]
116pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
117 vec![crate::example_db::specs::RuleExampleSpec {
118 id: "feasibleregisterassignment_to_ilp",
119 build: || {
120 let source = FeasibleRegisterAssignment::new(
121 4,
122 vec![(0, 1), (0, 2), (1, 3)],
123 2,
124 vec![0, 1, 0, 0],
125 );
126 crate::example_db::specs::rule_example_via_bounded_ilp::<_>(source)
127 },
128 }]
129}
130
131#[cfg(test)]
132#[path = "../unit_tests/rules/feasibleregisterassignment_ilp.rs"]
133mod tests;