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)]
60pub struct SequencingWithReleaseTimesAndDeadlines {
61 lengths: Vec<i64>,
62 release_times: Vec<i64>,
63 deadlines: Vec<i64>,
64}
65
66impl SequencingWithReleaseTimesAndDeadlines {
67 pub fn new(lengths: Vec<i64>, release_times: Vec<i64>, deadlines: Vec<i64>) -> Self {
73 assert_eq!(lengths.len(), release_times.len());
74 assert_eq!(lengths.len(), deadlines.len());
75 assert!(
76 lengths.iter().all(|&length| length >= 0),
77 "task lengths must be nonnegative"
78 );
79 assert!(
80 release_times.iter().all(|&release| release >= 0),
81 "release times must be nonnegative"
82 );
83 assert!(
84 deadlines.iter().all(|&deadline| deadline >= 0),
85 "deadlines must be nonnegative"
86 );
87 Self {
88 lengths,
89 release_times,
90 deadlines,
91 }
92 }
93
94 pub fn lengths(&self) -> &[i64] {
96 &self.lengths
97 }
98
99 pub fn release_times(&self) -> &[i64] {
101 &self.release_times
102 }
103
104 pub fn deadlines(&self) -> &[i64] {
106 &self.deadlines
107 }
108
109 pub fn num_tasks(&self) -> usize {
111 self.lengths.len()
112 }
113
114 pub fn time_horizon(&self) -> i64 {
116 self.deadlines.iter().copied().max().unwrap_or(0)
117 }
118}
119
120impl Problem for SequencingWithReleaseTimesAndDeadlines {
121 const NAME: &'static str = "SequencingWithReleaseTimesAndDeadlines";
122 type Solution = Vec<usize>;
123 type Value = crate::types::Or;
124
125 crate::problem_parameters![("num_tasks", num_tasks), ("time_horizon", time_horizon),];
126
127 fn variant() -> Vec<(&'static str, &'static str)> {
128 crate::variant_params![]
129 }
130
131 fn evaluate(
132 &self,
133 config: &Self::Solution,
134 ) -> Result<crate::types::Or, crate::traits::EvaluationError> {
135 let n = self.num_tasks();
136 if config.len() != n {
137 return Err(crate::traits::EvaluationError::InvalidConfiguration(
138 "schedule length does not match the tasks".into(),
139 ));
140 }
141 if config.iter().any(|&task| task >= n) {
142 return Err(crate::traits::EvaluationError::InvalidConfiguration(
143 "schedule contains an out-of-range task".into(),
144 ));
145 }
146 Ok({
147 crate::types::Or({
148 let Some(schedule) = super::decode_permutation(config, self.num_tasks()) else {
149 return Ok(crate::types::Or(false));
150 };
151
152 let mut current_time: i64 = 0;
154 for &task in &schedule {
155 let start = current_time.max(self.release_times[task]);
156 let finish = start + self.lengths[task];
157 if finish > self.deadlines[task] {
158 return Ok(crate::types::Or(false));
159 }
160 current_time = finish;
161 }
162
163 true
164 })
165 })
166 }
167}
168
169impl crate::solvers::BruteForceProblem for SequencingWithReleaseTimesAndDeadlines {
170 fn dimensions(&self) -> Vec<usize> {
171 super::lehmer_dims(self.num_tasks())
172 }
173}
174
175crate::declare_variants! {
176 default SequencingWithReleaseTimesAndDeadlines => "2^num_tasks * num_tasks",
177}
178
179crate::register_brute_force! {
180 SequencingWithReleaseTimesAndDeadlines decode |problem: &SequencingWithReleaseTimesAndDeadlines, indices: Vec<usize>| super::decode_lehmer(&indices, problem.num_tasks()).expect("enumerated Lehmer digits are valid"),
181}
182
183#[cfg(feature = "example-db")]
184pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
185 vec![crate::example_db::specs::ModelExampleSpec {
186 id: "sequencing_with_release_times_and_deadlines",
187 instance: Box::new(SequencingWithReleaseTimesAndDeadlines::new(
191 vec![3, 2, 4, 1, 2],
192 vec![0, 1, 5, 0, 8],
193 vec![5, 6, 10, 3, 12],
194 )),
195 optimal_config: serde_json::json!(vec![3, 0, 1, 2, 4]),
196 optimal_value: serde_json::json!(true),
197 }]
198}
199
200#[cfg(test)]
201#[path = "../../unit_tests/models/misc/sequencing_with_release_times_and_deadlines.rs"]
202mod tests;