problemreductions/models/misc/
resource_constrained_scheduling.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
8use crate::traits::Problem;
9use serde::{Deserialize, Serialize};
10
11inventory::submit! {
12 ProblemSchemaEntry {
13 name: "ResourceConstrainedScheduling",
14 display_name: "Resource Constrained Scheduling",
15 aliases: &[],
16 dimensions: &[],
17 module_path: module_path!(),
18 description: "Schedule unit-length tasks on m processors with resource constraints and a deadline",
19 fields: &[
20 FieldInfo { name: "num_processors", type_name: "usize", description: "Number of identical processors m" },
21 FieldInfo { name: "resource_bounds", type_name: "Vec<u64>", description: "Resource bound B_i for each resource i" },
22 FieldInfo { name: "resource_requirements", type_name: "Vec<Vec<u64>>", description: "R_i(t) for each task t and resource i (n x r matrix)" },
23 FieldInfo { name: "deadline", type_name: "u64", description: "Overall deadline D" },
24 ],
25 }
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct ResourceConstrainedScheduling {
61 num_processors: usize,
63 resource_bounds: Vec<u64>,
65 resource_requirements: Vec<Vec<u64>>,
67 deadline: u64,
69}
70
71impl ResourceConstrainedScheduling {
72 pub fn new(
80 num_processors: usize,
81 resource_bounds: Vec<u64>,
82 resource_requirements: Vec<Vec<u64>>,
83 deadline: u64,
84 ) -> Self {
85 assert!(deadline > 0, "deadline must be positive");
86 let r = resource_bounds.len();
87 for (t, row) in resource_requirements.iter().enumerate() {
88 assert_eq!(
89 row.len(),
90 r,
91 "task {t} has {} resource requirements, expected {r}",
92 row.len()
93 );
94 }
95 Self {
96 num_processors,
97 resource_bounds,
98 resource_requirements,
99 deadline,
100 }
101 }
102
103 pub fn num_tasks(&self) -> usize {
105 self.resource_requirements.len()
106 }
107
108 pub fn num_processors(&self) -> usize {
110 self.num_processors
111 }
112
113 pub fn resource_bounds(&self) -> &[u64] {
115 &self.resource_bounds
116 }
117
118 pub fn resource_requirements(&self) -> &[Vec<u64>] {
120 &self.resource_requirements
121 }
122
123 pub fn deadline(&self) -> u64 {
125 self.deadline
126 }
127
128 pub fn num_resources(&self) -> usize {
130 self.resource_bounds.len()
131 }
132}
133
134impl Problem for ResourceConstrainedScheduling {
135 const NAME: &'static str = "ResourceConstrainedScheduling";
136 type Value = crate::types::Or;
137
138 fn variant() -> Vec<(&'static str, &'static str)> {
139 crate::variant_params![]
140 }
141
142 fn dims(&self) -> Vec<usize> {
143 vec![self.deadline as usize; self.num_tasks()]
144 }
145
146 fn evaluate(&self, config: &[usize]) -> crate::types::Or {
147 crate::types::Or({
148 let n = self.num_tasks();
149 let d = self.deadline as usize;
150 let r = self.num_resources();
151
152 if config.len() != n {
154 return crate::types::Or(false);
155 }
156
157 if config.iter().any(|&slot| slot >= d) {
159 return crate::types::Or(false);
160 }
161
162 for u in 0..d {
164 let mut task_count = 0usize;
166 let mut resource_usage = vec![0u64; r];
167
168 for (t, &slot) in config.iter().enumerate() {
169 if slot == u {
170 task_count += 1;
171 for (usage, &req) in resource_usage
173 .iter_mut()
174 .zip(self.resource_requirements[t].iter())
175 {
176 *usage = usage.saturating_add(req);
177 }
178 }
179 }
180
181 if task_count > self.num_processors {
183 return crate::types::Or(false);
184 }
185
186 for (usage, bound) in resource_usage.iter().zip(self.resource_bounds.iter()) {
188 if usage > bound {
189 return crate::types::Or(false);
190 }
191 }
192 }
193
194 true
195 })
196 }
197}
198
199crate::declare_variants! {
200 default ResourceConstrainedScheduling => "deadline ^ num_tasks",
201}
202
203#[cfg(feature = "example-db")]
204pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
205 vec![crate::example_db::specs::ModelExampleSpec {
206 id: "resource_constrained_scheduling",
207 instance: Box::new(ResourceConstrainedScheduling::new(
209 3,
210 vec![20],
211 vec![vec![6], vec![7], vec![7], vec![6], vec![8], vec![6]],
212 2,
213 )),
214 optimal_config: vec![0, 0, 0, 1, 1, 1],
215 optimal_value: serde_json::json!(true),
216 }]
217}
218
219#[cfg(test)]
220#[path = "../../unit_tests/models/misc/resource_constrained_scheduling.rs"]
221mod tests;