problemreductions/models/misc/
sequencing_with_deadlines_and_set_up_times.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
9use crate::traits::Problem;
10use crate::types::Or;
11use serde::{Deserialize, Serialize};
12
13inventory::submit! {
14 ProblemSchemaEntry {
15 name: "SequencingWithDeadlinesAndSetUpTimes",
16 display_name: "Sequencing with Deadlines and Set-Up Times",
17 aliases: &[],
18 dimensions: &[],
19 module_path: module_path!(),
20 description: "Determine whether all tasks can be scheduled on a single machine by their deadlines given compiler-switch setup penalties",
21 fields: &[
22 FieldInfo { name: "lengths", type_name: "Vec<u64>", description: "Processing time for each task" },
23 FieldInfo { name: "deadlines", type_name: "Vec<u64>", description: "Deadline d(t) for each task" },
24 FieldInfo { name: "compilers", type_name: "Vec<usize>", description: "Compiler index k(t) for each task" },
25 FieldInfo { name: "setup_times", type_name: "Vec<u64>", description: "Setup time s(c) charged when switching to compiler c" },
26 ],
27 }
28}
29
30#[derive(Debug, Clone, Serialize)]
45pub struct SequencingWithDeadlinesAndSetUpTimes {
46 lengths: Vec<u64>,
47 deadlines: Vec<u64>,
48 compilers: Vec<usize>,
49 setup_times: Vec<u64>,
50}
51
52#[derive(Deserialize)]
53struct SequencingWithDeadlinesAndSetUpTimesSerde {
54 lengths: Vec<u64>,
55 deadlines: Vec<u64>,
56 compilers: Vec<usize>,
57 setup_times: Vec<u64>,
58}
59
60impl SequencingWithDeadlinesAndSetUpTimes {
61 fn validate(
62 lengths: &[u64],
63 deadlines: &[u64],
64 compilers: &[usize],
65 setup_times: &[u64],
66 ) -> Result<(), String> {
67 if lengths.len() != deadlines.len() {
68 return Err("lengths length must equal deadlines length".to_string());
69 }
70 if lengths.len() != compilers.len() {
71 return Err("lengths length must equal compilers length".to_string());
72 }
73 if lengths.contains(&0) {
74 return Err("task lengths must be positive".to_string());
75 }
76 let num_compilers = setup_times.len();
77 for &c in compilers {
78 if c >= num_compilers {
79 return Err(format!(
80 "compiler index {c} is out of range for setup_times of length {num_compilers}"
81 ));
82 }
83 }
84 Ok(())
85 }
86
87 pub fn new(
93 lengths: Vec<u64>,
94 deadlines: Vec<u64>,
95 compilers: Vec<usize>,
96 setup_times: Vec<u64>,
97 ) -> Self {
98 Self::validate(&lengths, &deadlines, &compilers, &setup_times)
99 .unwrap_or_else(|err| panic!("{err}"));
100 Self {
101 lengths,
102 deadlines,
103 compilers,
104 setup_times,
105 }
106 }
107
108 pub fn num_tasks(&self) -> usize {
110 self.lengths.len()
111 }
112
113 pub fn num_compilers(&self) -> usize {
115 self.setup_times.len()
116 }
117
118 pub fn lengths(&self) -> &[u64] {
120 &self.lengths
121 }
122
123 pub fn deadlines(&self) -> &[u64] {
125 &self.deadlines
126 }
127
128 pub fn compilers(&self) -> &[usize] {
130 &self.compilers
131 }
132
133 pub fn setup_times(&self) -> &[u64] {
135 &self.setup_times
136 }
137
138 fn all_deadlines_met(&self, schedule: &[usize]) -> bool {
142 let mut elapsed: u64 = 0;
143 let mut prev_compiler: Option<usize> = None;
144 for &task in schedule {
145 if let Some(prev) = prev_compiler {
147 if prev != self.compilers[task] {
148 elapsed = elapsed
149 .checked_add(self.setup_times[self.compilers[task]])
150 .expect("elapsed time overflowed u64");
151 }
152 }
153 elapsed = elapsed
154 .checked_add(self.lengths[task])
155 .expect("elapsed time overflowed u64");
156 if elapsed > self.deadlines[task] {
157 return false;
158 }
159 prev_compiler = Some(self.compilers[task]);
160 }
161 true
162 }
163}
164
165impl TryFrom<SequencingWithDeadlinesAndSetUpTimesSerde> for SequencingWithDeadlinesAndSetUpTimes {
166 type Error = String;
167
168 fn try_from(value: SequencingWithDeadlinesAndSetUpTimesSerde) -> Result<Self, Self::Error> {
169 Self::validate(
170 &value.lengths,
171 &value.deadlines,
172 &value.compilers,
173 &value.setup_times,
174 )?;
175 Ok(Self {
176 lengths: value.lengths,
177 deadlines: value.deadlines,
178 compilers: value.compilers,
179 setup_times: value.setup_times,
180 })
181 }
182}
183
184impl<'de> Deserialize<'de> for SequencingWithDeadlinesAndSetUpTimes {
185 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
186 where
187 D: serde::Deserializer<'de>,
188 {
189 let value = SequencingWithDeadlinesAndSetUpTimesSerde::deserialize(deserializer)?;
190 Self::try_from(value).map_err(serde::de::Error::custom)
191 }
192}
193
194impl Problem for SequencingWithDeadlinesAndSetUpTimes {
195 const NAME: &'static str = "SequencingWithDeadlinesAndSetUpTimes";
196 type Value = Or;
197
198 fn variant() -> Vec<(&'static str, &'static str)> {
199 crate::variant_params![]
200 }
201
202 fn dims(&self) -> Vec<usize> {
203 let n = self.num_tasks();
204 vec![n; n]
205 }
206
207 fn evaluate(&self, config: &[usize]) -> Or {
208 let n = self.num_tasks();
209 let Some(schedule) = super::decode_permutation(config, n) else {
210 return Or(false);
211 };
212 Or(self.all_deadlines_met(&schedule))
213 }
214}
215
216crate::declare_variants! {
217 default SequencingWithDeadlinesAndSetUpTimes => "factorial(num_tasks)",
218}
219
220#[cfg(feature = "example-db")]
221pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
222 vec![crate::example_db::specs::ModelExampleSpec {
223 id: "sequencing_with_deadlines_and_set_up_times",
224 instance: Box::new(SequencingWithDeadlinesAndSetUpTimes::new(
233 vec![2, 3, 1, 2, 2],
234 vec![4, 11, 3, 16, 7],
235 vec![0, 1, 0, 1, 0],
236 vec![1, 2],
237 )),
238 optimal_config: vec![2, 0, 4, 1, 3],
239 optimal_value: serde_json::json!(true),
240 }]
241}
242
243#[cfg(test)]
244#[path = "../../unit_tests/models/misc/sequencing_with_deadlines_and_set_up_times.rs"]
245mod tests;