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_solution(self.target_problem(), target_solution)?;
47
48 one_hot_decode_rows(target_solution, self.num_tasks, self.max_deadline, 0)
49 }
50}
51
52#[reduction(
53 transform = exact {
54 num_vars = "num_tasks * max_deadline",
55 num_constraints = "num_tasks + max_deadline + num_precedences + 1",
56 },
57 unavailable = {
58 num_nonzeros = "the exact target parameter is not represented by this reduction's symbolic transform",
59 }
60)]
61impl ReduceTo<ILP<bool>> for SchedulingWithIndividualDeadlines {
62 type Result = ReductionSWIDToILP;
63
64 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
65 let n = self.num_tasks();
66 let max_d = usize::try_from(self.max_deadline()).map_err(|_| {
67 crate::rules::ReductionError::integer_overflow::<
68 SchedulingWithIndividualDeadlines,
69 ILP<bool>,
70 >("validated deadline must fit usize")
71 })?;
72 let num_vars = n * max_d;
73
74 let var = |j: usize, t: usize| j * max_d + t;
75 let processor_count =
76 Self::exact_i64(self.num_processors(), "encoding the processor capacity")?;
77
78 let mut constraints = Vec::new();
79
80 for j in 0..n {
82 let dj = usize::try_from(self.deadlines()[j]).map_err(|_| {
83 crate::rules::ReductionError::integer_overflow::<
84 SchedulingWithIndividualDeadlines,
85 ILP<bool>,
86 >("validated deadline must fit usize")
87 })?;
88 let terms: Vec<(usize, i64)> = (0..dj).map(|t| (var(j, t), 1)).collect();
89 constraints.push(LinearConstraint::eq(terms, 1));
90 }
91
92 let unused_slots = self
94 .deadlines()
95 .iter()
96 .enumerate()
97 .flat_map(|(j, &deadline)| {
98 (usize::try_from(deadline).expect("validated deadline fits usize")..max_d)
99 .map(move |t| (var(j, t), 1))
100 })
101 .collect();
102 constraints.push(LinearConstraint::eq(unused_slots, 0));
103
104 for t in 0..max_d {
106 let terms: Vec<(usize, i64)> = (0..n).map(|j| (var(j, t), 1)).collect();
107 constraints.push(LinearConstraint::le(terms, processor_count));
108 }
109
110 for &(i, j) in self.precedences() {
112 let di = usize::try_from(self.deadlines()[i]).map_err(|_| {
113 crate::rules::ReductionError::integer_overflow::<
114 SchedulingWithIndividualDeadlines,
115 ILP<bool>,
116 >("validated deadline must fit usize")
117 })?;
118 let dj = usize::try_from(self.deadlines()[j]).map_err(|_| {
119 crate::rules::ReductionError::integer_overflow::<
120 SchedulingWithIndividualDeadlines,
121 ILP<bool>,
122 >("validated deadline must fit usize")
123 })?;
124 let mut terms: Vec<(usize, i64)> = Vec::new();
125 for t in 0..dj {
126 terms.push((var(j, t), Self::exact_i64(t, "encoding a time slot")?));
127 }
128 for t in 0..di {
129 terms.push((var(i, t), -Self::exact_i64(t, "encoding a time slot")?));
130 }
131 constraints.push(LinearConstraint::ge(terms, 1));
132 }
133
134 Ok(ReductionSWIDToILP {
135 target: ILP::new(num_vars, constraints, vec![], ObjectiveSense::Minimize)
136 .map_err(Self::target_construction)?,
137 num_tasks: n,
138 max_deadline: max_d,
139 })
140 }
141}
142
143#[cfg(feature = "example-db")]
144pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
145 vec![crate::example_db::specs::RuleExampleSpec {
146 id: "schedulingwithindividualdeadlines_to_ilp",
147 build: || {
148 let source = SchedulingWithIndividualDeadlines::new(3, 2, vec![2, 2, 3], vec![(0, 2)]);
150 crate::example_db::specs::rule_example_via_ilp::<_, bool>(source)
151 },
152 }]
153}
154
155#[cfg(test)]
156#[path = "../unit_tests/rules/schedulingwithindividualdeadlines_ilp.rs"]
157mod tests;