problemreductions/rules/
schedulingwithindividualdeadlines_ilp.rs1use crate::models::algebraic::{LinearConstraint, ObjectiveSense, ILP};
15use crate::models::misc::SchedulingWithIndividualDeadlines;
16use crate::reduction;
17use crate::rules::ilp_helpers::one_hot_decode_rows;
18use crate::rules::traits::{ReduceTo, ReductionResult};
19
20#[derive(Debug, Clone)]
25pub struct ReductionSWIDToILP {
26 target: ILP<bool>,
27 num_tasks: usize,
28 max_deadline: usize,
29}
30
31impl ReductionResult for ReductionSWIDToILP {
32 type Source = SchedulingWithIndividualDeadlines;
33 type Target = ILP<bool>;
34
35 fn target_problem(&self) -> &ILP<bool> {
36 &self.target
37 }
38
39 fn extract_solution(
43 &self,
44 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
45 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
46 crate::rules::traits::validate_target_witness(
47 self.target_problem(),
48 target_solution,
49 |value| value.value.is_some(),
50 "target ILP assignment is infeasible",
51 )?;
52
53 one_hot_decode_rows(target_solution, self.num_tasks, self.max_deadline, 0)
54 }
55}
56
57#[crate::aggregate_reduction(ilp_feasibility)]
58impl crate::rules::AggregateReductionResult for ReductionSWIDToILP {}
59
60#[reduction(transform = {
61 exact {
62 num_vars = "num_tasks * max_deadline",
63 num_constraints = "num_tasks + max_deadline + num_precedences + 1",
64 },
65 upper_bound {
66 max_constraint_magnitude_bits = "num_tasks + max_deadline + 1",
67 num_nonzeros = "(num_tasks * max_deadline) * (num_tasks + max_deadline + num_precedences + 1)",
68 },
69})]
70impl ReduceTo<ILP<bool>> for SchedulingWithIndividualDeadlines {
71 type Result = ReductionSWIDToILP;
72
73 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
74 let n = self.num_tasks();
75 let max_d = usize::try_from(self.max_deadline()).map_err(|_| {
76 crate::rules::ReductionError::integer_overflow::<
77 SchedulingWithIndividualDeadlines,
78 ILP<bool>,
79 >("validated deadline must fit usize")
80 })?;
81 let num_vars = n * max_d;
82
83 let var = |j: usize, t: usize| j * max_d + t;
84 let processor_count = Self::exact_i64(
85 self.num_processors().min(n),
86 "encoding the processor capacity",
87 )?;
88
89 let mut constraints = Vec::new();
90
91 for j in 0..n {
93 let dj = usize::try_from(self.deadlines()[j]).map_err(|_| {
94 crate::rules::ReductionError::integer_overflow::<
95 SchedulingWithIndividualDeadlines,
96 ILP<bool>,
97 >("validated deadline must fit usize")
98 })?;
99 let terms: Vec<(usize, i64)> = (0..dj).map(|t| (var(j, t), 1)).collect();
100 constraints.push(LinearConstraint::eq(terms, 1));
101 }
102
103 let unused_slots = self
105 .deadlines()
106 .iter()
107 .enumerate()
108 .flat_map(|(j, &deadline)| {
109 (usize::try_from(deadline).expect("validated deadline fits usize")..max_d)
110 .map(move |t| (var(j, t), 1))
111 })
112 .collect();
113 constraints.push(LinearConstraint::eq(unused_slots, 0));
114
115 for t in 0..max_d {
117 let terms: Vec<(usize, i64)> = (0..n).map(|j| (var(j, t), 1)).collect();
118 constraints.push(LinearConstraint::le(terms, processor_count));
119 }
120
121 for &(i, j) in self.precedences() {
123 let di = usize::try_from(self.deadlines()[i]).map_err(|_| {
124 crate::rules::ReductionError::integer_overflow::<
125 SchedulingWithIndividualDeadlines,
126 ILP<bool>,
127 >("validated deadline must fit usize")
128 })?;
129 let dj = usize::try_from(self.deadlines()[j]).map_err(|_| {
130 crate::rules::ReductionError::integer_overflow::<
131 SchedulingWithIndividualDeadlines,
132 ILP<bool>,
133 >("validated deadline must fit usize")
134 })?;
135 let mut terms: Vec<(usize, i64)> = Vec::new();
136 for t in 0..dj {
137 terms.push((var(j, t), Self::exact_i64(t, "encoding a time slot")?));
138 }
139 for t in 0..di {
140 terms.push((var(i, t), -Self::exact_i64(t, "encoding a time slot")?));
141 }
142 constraints.push(LinearConstraint::ge(terms, 1));
143 }
144
145 Ok(ReductionSWIDToILP {
146 target: ILP::new(num_vars, constraints, vec![], ObjectiveSense::Minimize)
147 .map_err(Self::target_construction)?,
148 num_tasks: n,
149 max_deadline: max_d,
150 })
151 }
152}
153
154#[cfg(feature = "example-db")]
155pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
156 vec![crate::example_db::specs::RuleExampleSpec {
157 id: "schedulingwithindividualdeadlines_to_ilp",
158 build: || {
159 let source = SchedulingWithIndividualDeadlines::new(3, 2, vec![2, 2, 3], vec![(0, 2)]);
161 crate::example_db::specs::rule_example_via_ilp::<_, bool>(source)
162 },
163 }]
164}
165
166#[cfg(test)]
167#[path = "../unit_tests/rules/schedulingwithindividualdeadlines_ilp.rs"]
168mod tests;