problemreductions/models/misc/
sequencing_with_release_times_and_deadlines.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
9use crate::traits::Problem;
10use serde::{Deserialize, Serialize};
11
12inventory::submit! {
13 ProblemSchemaEntry {
14 name: "SequencingWithReleaseTimesAndDeadlines",
15 display_name: "Sequencing with Release Times and Deadlines",
16 aliases: &[],
17 dimensions: &[],
18 category: crate::registry::ProblemCategory::Misc,
19 module_path: module_path!(),
20 description: "Single-machine scheduling feasibility: can all tasks be scheduled within their release-deadline windows without overlap?",
21 fields: &[
22 FieldInfo { name: "lengths", type_name: "Vec<i64>", description: "Processing time l(t) for each task (positive)" },
23 FieldInfo { name: "release_times", type_name: "Vec<i64>", description: "Release time r(t) for each task (non-negative)" },
24 FieldInfo { name: "deadlines", type_name: "Vec<i64>", description: "Deadline d(t) for each task (positive)" },
25 ],
26 }
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
60#[serde(try_from = "SequencingWithReleaseTimesAndDeadlinesData")]
61pub struct SequencingWithReleaseTimesAndDeadlines {
62 lengths: Vec<i64>,
63 release_times: Vec<i64>,
64 deadlines: Vec<i64>,
65}
66
67#[derive(Deserialize)]
68struct SequencingWithReleaseTimesAndDeadlinesData {
69 lengths: Vec<i64>,
70 release_times: Vec<i64>,
71 deadlines: Vec<i64>,
72}
73
74impl TryFrom<SequencingWithReleaseTimesAndDeadlinesData>
75 for SequencingWithReleaseTimesAndDeadlines
76{
77 type Error = crate::registry::ConstructionError;
78 fn try_from(data: SequencingWithReleaseTimesAndDeadlinesData) -> Result<Self, Self::Error> {
79 Self::try_new(data.lengths, data.release_times, data.deadlines)
80 }
81}
82
83impl SequencingWithReleaseTimesAndDeadlines {
84 pub fn new(lengths: Vec<i64>, release_times: Vec<i64>, deadlines: Vec<i64>) -> Self {
90 Self::try_new(lengths, release_times, deadlines).unwrap_or_else(|error| panic!("{error}"))
91 }
92
93 fn try_new(
94 lengths: Vec<i64>,
95 release_times: Vec<i64>,
96 deadlines: Vec<i64>,
97 ) -> Result<Self, crate::registry::ConstructionError> {
98 if lengths.len() != release_times.len() {
99 return Err("lengths and release_times must have the same length".into());
100 }
101 if lengths.len() != deadlines.len() {
102 return Err("lengths and deadlines must have the same length".into());
103 }
104 if lengths.iter().any(|&length| length < 0) {
105 return Err("task lengths must be nonnegative".into());
106 }
107 if release_times.iter().any(|&release| release < 0) {
108 return Err("release times must be nonnegative".into());
109 }
110 if deadlines.iter().any(|&deadline| deadline < 0) {
111 return Err("deadlines must be nonnegative".into());
112 }
113 Ok(Self {
114 lengths,
115 release_times,
116 deadlines,
117 })
118 }
119
120 pub fn lengths(&self) -> &[i64] {
122 &self.lengths
123 }
124
125 pub fn release_times(&self) -> &[i64] {
127 &self.release_times
128 }
129
130 pub fn deadlines(&self) -> &[i64] {
132 &self.deadlines
133 }
134
135 pub fn num_tasks(&self) -> usize {
137 self.lengths.len()
138 }
139
140 pub fn time_horizon(&self) -> i64 {
142 self.deadlines.iter().copied().max().unwrap_or(0)
143 }
144
145 pub fn time_horizon_bits(&self) -> u64 {
147 crate::types::max_numeric_magnitude_bits([self.time_horizon()])
148 }
149}
150
151impl Problem for SequencingWithReleaseTimesAndDeadlines {
152 const NAME: &'static str = "SequencingWithReleaseTimesAndDeadlines";
153 type Solution = Vec<usize>;
154 type Value = crate::types::Or;
155
156 crate::problem_parameters![
157 ("num_tasks", num_tasks),
158 ("time_horizon", time_horizon),
159 ("time_horizon_bits", time_horizon_bits),
160 ];
161
162 fn variant() -> Vec<(&'static str, &'static str)> {
163 crate::variant_params![]
164 }
165
166 fn evaluate(
167 &self,
168 config: &Self::Solution,
169 ) -> Result<crate::types::Or, crate::traits::EvaluationError> {
170 let n = self.num_tasks();
171 if config.len() != n {
172 return Err(crate::traits::EvaluationError::InvalidConfiguration(
173 "schedule length does not match the tasks".into(),
174 ));
175 }
176 if config.iter().any(|&task| task >= n) {
177 return Err(crate::traits::EvaluationError::InvalidConfiguration(
178 "schedule contains an out-of-range task".into(),
179 ));
180 }
181 Ok({
182 crate::types::Or({
183 let Some(schedule) = super::decode_permutation(config, self.num_tasks()) else {
184 return Ok(crate::types::Or(false));
185 };
186
187 let mut current_time: i64 = 0;
189 for &task in &schedule {
190 let start = current_time.max(self.release_times[task]);
191 let finish = start + self.lengths[task];
192 if finish > self.deadlines[task] {
193 return Ok(crate::types::Or(false));
194 }
195 current_time = finish;
196 }
197
198 true
199 })
200 })
201 }
202}
203
204impl crate::solvers::BruteForceProblem for SequencingWithReleaseTimesAndDeadlines {
205 fn dimensions(&self) -> Vec<usize> {
206 super::lehmer_dims(self.num_tasks())
207 }
208}
209
210crate::declare_variants! {
211 default SequencingWithReleaseTimesAndDeadlines => "2^num_tasks * num_tasks",
212}
213
214crate::register_brute_force! {
215 SequencingWithReleaseTimesAndDeadlines decode |problem: &SequencingWithReleaseTimesAndDeadlines, indices: Vec<usize>| super::decode_lehmer(&indices, problem.num_tasks()).expect("enumerated Lehmer digits are valid"),
216}
217
218#[cfg(feature = "example-db")]
219pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
220 vec![crate::example_db::specs::ModelExampleSpec {
221 id: "sequencing_with_release_times_and_deadlines",
222 instance: Box::new(SequencingWithReleaseTimesAndDeadlines::new(
226 vec![3, 2, 4, 1, 2],
227 vec![0, 1, 5, 0, 8],
228 vec![5, 6, 10, 3, 12],
229 )),
230 optimal_config: serde_json::json!(vec![3, 0, 1, 2, 4]),
231 optimal_value: serde_json::json!(true),
232 }]
233}
234
235#[cfg(test)]
236#[path = "../../unit_tests/models/misc/sequencing_with_release_times_and_deadlines.rs"]
237mod tests;