1#![doc=include_str!("../../img/schrage_natural.svg")]
24#![doc=include_str!("../../img/Schrage.svg")]
28#![doc=include_str!("../../img/optimal.svg")]
32use crate::jobs::{Job, JobList, SchrageJobTable};
40use std::{cmp, vec};
41
42pub fn schrage(jobs: &JobList) -> SchrageJobTable {
83 let mut shortest_delivery_jobs = JobList::new(jobs.sorted_by_delivery_time());
86 let mut ready_to_run = JobList::new(Vec::new());
89 let mut t: u32 = 0;
91 let mut pi: JobList = JobList::new(Vec::new());
93
94 while !shortest_delivery_jobs.jobs.is_empty() || !ready_to_run.jobs.is_empty() {
96 while !shortest_delivery_jobs.jobs.is_empty()
98 && shortest_delivery_jobs.jobs[0].delivery_time <= t
99 {
100 ready_to_run
101 .jobs
102 .append(&mut vec![shortest_delivery_jobs.jobs[0]]);
103 shortest_delivery_jobs.jobs.remove(0);
104 }
105 if !ready_to_run.jobs.is_empty() {
107 let vec_by_processing_time = JobList {
108 jobs: ready_to_run.sorted_by_processing_time(),
109 };
110 let reversed: JobList = JobList {
111 jobs: vec_by_processing_time.jobs.into_iter().rev().collect(),
112 };
113 let cooldown_times: Vec<Job> = reversed.sorted_by_cooldown_time();
114
115 let max_cooldown_time = cooldown_times.last().unwrap();
116 let position = ready_to_run
117 .jobs
118 .iter()
119 .position(|&n| &n == max_cooldown_time)
120 .unwrap();
121 ready_to_run.jobs.remove(position);
122 pi.jobs.push(*max_cooldown_time);
124 t += max_cooldown_time.processing_time;
125 } else {
126 t = shortest_delivery_jobs.jobs[0].delivery_time;
129 }
130 }
131 SchrageJobTable { job_list: pi }
132}
133
134pub fn part_time_schrage(jobs: &JobList) -> u32 {
155 let mut shortest_delivery_jobs = JobList::new(jobs.sorted_by_delivery_time());
157 let mut ready_to_run = JobList::new(Vec::new());
159 let mut current_job = Job::new(0, 0, 0);
160 let mut t: u32 = 0;
161 let mut c_max: u32 = 0;
162 let mut pi: JobList = JobList { jobs: Vec::new() };
163
164 while !shortest_delivery_jobs.jobs.is_empty() || !ready_to_run.jobs.is_empty() {
165 while !shortest_delivery_jobs.jobs.is_empty()
166 && shortest_delivery_jobs.jobs[0].delivery_time <= t
167 {
168 ready_to_run
169 .jobs
170 .append(&mut vec![shortest_delivery_jobs.jobs[0]]);
171 let next_job = shortest_delivery_jobs.jobs.remove(0);
172
173 if next_job.cooldown_time > current_job.cooldown_time {
174 current_job.processing_time = t - next_job.delivery_time;
175 t = next_job.delivery_time;
176
177 if current_job.processing_time > 0 {
178 ready_to_run.jobs.append(&mut vec![current_job]);
179 ready_to_run.jobs = ready_to_run.sorted_by_delivery_time().clone();
180 }
181 }
182 }
183
184 if !ready_to_run.jobs.is_empty() {
185 let cooldown_times = ready_to_run.sorted_by_cooldown_time();
186 let max_cooldown_time = cooldown_times.last().unwrap();
187 let position = ready_to_run
188 .jobs
189 .iter()
190 .position(|&n| n.cooldown_time == max_cooldown_time.cooldown_time)
191 .unwrap();
192 current_job = ready_to_run.jobs.remove(position);
193
194 pi.jobs.push(*max_cooldown_time);
196 t += max_cooldown_time.processing_time;
197 c_max = cmp::max(t + max_cooldown_time.cooldown_time, c_max)
198 } else {
199 t = shortest_delivery_jobs.jobs[0].delivery_time;
200 }
201 }
202 c_max
203}
204
205#[cfg(test)]
206mod tests {
207 use crate::jobs::{Job, JobList};
208
209 use super::*;
210
211 #[test]
212 fn test_schrage_ex1() {
213 let expected_result = SchrageJobTable::new(JobList {
214 jobs: vec![
215 Job::new(0, 6, 17), Job::new(10, 5, 7), Job::new(13, 6, 26), Job::new(11, 7, 24), Job::new(20, 4, 21), Job::new(30, 3, 8), Job::new(30, 2, 0), ],
223 });
224 let js = SchrageJobTable::new(JobList {
225 jobs: vec![
226 Job::new(10, 5, 7), Job::new(13, 6, 26), Job::new(11, 7, 24), Job::new(20, 4, 21), Job::new(30, 3, 8), Job::new(0, 6, 17), Job::new(30, 2, 0), ],
234 });
235 let result = schrage(&js.job_list);
236 assert_eq!(result.job_list, expected_result.job_list);
237 assert_eq!(result.c_max(), 53);
238 }
239
240 #[test]
241 fn test_schrage_ex2() {
242 let expected_result = SchrageJobTable::new(JobList {
243 jobs: vec![
244 Job::new(1, 5, 9), Job::new(3, 6, 8), Job::new(1, 4, 6), Job::new(4, 5, 4), Job::new(7, 3, 3), Job::new(4, 7, 1), ],
251 });
252 let js = SchrageJobTable::new(JobList {
253 jobs: vec![
254 Job::new(1, 5, 9), Job::new(4, 5, 4), Job::new(1, 4, 6), Job::new(7, 3, 3), Job::new(3, 6, 8), Job::new(4, 7, 1), ],
261 });
262 let result = schrage(&js.job_list);
263 assert_eq!(result.job_list, expected_result.job_list);
264 assert_eq!(result.c_max(), 32);
265 }
266
267 #[test]
268 fn test_schrage_ex3() {
269 let expected_result = SchrageJobTable::new(JobList {
270 jobs: vec![
271 Job::new(15, 86, 700), Job::new(51, 52, 403), Job::new(144, 73, 536), Job::new(183, 17, 641), Job::new(226, 5, 629), Job::new(162, 80, 575), Job::new(103, 68, 470), Job::new(394, 34, 400), Job::new(35, 37, 386), Job::new(39, 38, 340), Job::new(162, 52, 241), Job::new(556, 23, 79), Job::new(567, 71, 618), Job::new(588, 45, 632), Job::new(598, 45, 200), Job::new(728, 18, 640), Job::new(715, 8, 93), Job::new(667, 80, 92), Job::new(57, 21, 76), Job::new(233, 68, 23), ],
292 });
293 let js = SchrageJobTable::new(JobList {
294 jobs: vec![
295 Job::new(162, 52, 241), Job::new(103, 68, 470), Job::new(39, 38, 340), Job::new(394, 34, 400), Job::new(15, 86, 700), Job::new(144, 73, 536), Job::new(51, 52, 403), Job::new(233, 68, 23), Job::new(183, 17, 641), Job::new(728, 18, 640), Job::new(667, 80, 92), Job::new(57, 21, 76), Job::new(35, 37, 386), Job::new(567, 71, 618), Job::new(226, 5, 629), Job::new(162, 80, 575), Job::new(588, 45, 632), Job::new(556, 23, 79), Job::new(715, 8, 93), Job::new(598, 45, 200), ],
316 });
317 let result = schrage(&js.job_list);
318 assert_eq!(result.job_list, expected_result.job_list);
319 assert_eq!(result.c_max(), 1399);
320 }
321
322 #[test]
323 fn test_schrage_ex4() {
324 let expected_result = SchrageJobTable::new(JobList {
325 jobs: vec![
326 Job::new(2, 20, 88), Job::new(5, 14, 125), Job::new(8, 16, 114), Job::new(9, 28, 94), Job::new(70, 4, 93), Job::new(71, 7, 71), Job::new(52, 1, 56), Job::new(52, 20, 56), Job::new(112, 22, 79), Job::new(90, 2, 13), ],
337 });
338 let js = SchrageJobTable::new(JobList {
339 jobs: vec![
340 Job::new(52, 1, 56), Job::new(70, 4, 93), Job::new(112, 22, 79), Job::new(5, 14, 125), Job::new(8, 16, 114), Job::new(71, 7, 71), Job::new(90, 2, 13), Job::new(2, 20, 88), Job::new(52, 20, 56), Job::new(9, 28, 94), ],
351 });
352 let result = schrage(&js.job_list);
353 assert_eq!(result.job_list, expected_result.job_list);
354 assert_eq!(result.c_max(), 213);
355 }
356
357 #[test]
358 fn test_sort() {
359 let js = JobList {
360 jobs: vec![
361 Job::new(0, 6, 17), Job::new(10, 5, 7), Job::new(13, 6, 26), Job::new(11, 7, 24), Job::new(20, 4, 21), Job::new(30, 3, 8), Job::new(30, 2, 0), ],
369 };
370 println!("Before sort: {}", js);
371 println!(
372 "After sort: {}",
373 JobList {
374 jobs: js.sorted_by_cooldown_time()
375 }
376 );
377 assert_eq!(true, true);
378 }
379
380 #[test]
381 fn test_part_time_schrage1() {
382 let js = JobList::new(vec![
383 Job::new(0, 27, 78),
384 Job::new(140, 7, 67),
385 Job::new(14, 36, 54),
386 Job::new(133, 76, 5),
387 ]);
388 let result = part_time_schrage(&js);
389 assert_eq!(result, 221)
390 }
391
392 #[test]
393 fn test_part_time_schrage2() {
394 let js = JobList::new(vec![
395 Job::new(8, 68, 984),
396 Job::new(747, 60, 1241),
397 Job::new(811, 78, 56),
398 Job::new(1760, 58, 1558),
399 Job::new(860, 16, 319),
400 Job::new(1549, 28, 927),
401 Job::new(1010, 96, 749),
402 Job::new(738, 37, 844),
403 Job::new(599, 20, 1170),
404 Job::new(446, 53, 1509),
405 Job::new(1363, 36, 19),
406 Job::new(1277, 14, 685),
407 Job::new(1574, 98, 1472),
408 Job::new(1886, 3, 1571),
409 Job::new(591, 21, 1587),
410 Job::new(714, 25, 1490),
411 Job::new(1881, 43, 1647),
412 Job::new(983, 62, 514),
413 Job::new(858, 8, 1215),
414 Job::new(634, 7, 587),
415 Job::new(784, 14, 1897),
416 Job::new(1893, 22, 1878),
417 Job::new(308, 89, 1039),
418 Job::new(1892, 91, 1815),
419 Job::new(1024, 75, 1602),
420 Job::new(1467, 59, 378),
421 Job::new(1830, 3, 1173),
422 Job::new(167, 25, 702),
423 Job::new(357, 3, 416),
424 Job::new(1739, 68, 71),
425 Job::new(1810, 58, 1220),
426 Job::new(453, 62, 393),
427 Job::new(462, 60, 22),
428 Job::new(332, 25, 1512),
429 Job::new(845, 96, 1176),
430 Job::new(522, 80, 513),
431 Job::new(1110, 61, 1854),
432 Job::new(484, 32, 570),
433 Job::new(545, 91, 274),
434 Job::new(64, 67, 74),
435 Job::new(90, 9, 1423),
436 Job::new(1013, 67, 1567),
437 Job::new(1509, 86, 878),
438 Job::new(238, 12, 285),
439 Job::new(1226, 23, 1767),
440 Job::new(83, 35, 22),
441 Job::new(626, 97, 63),
442 Job::new(6, 24, 707),
443 Job::new(507, 31, 1294),
444 Job::new(638, 98, 1528),
445 ]);
446 let result = part_time_schrage(&js);
447 assert_eq!(result, 3820);
448 }
449
450 #[test]
451 fn test_part_time_schrage3() {
452 let js = JobList::new(vec![
453 Job::new(162, 52, 241),
454 Job::new(103, 68, 470),
455 Job::new(39, 38, 340),
456 Job::new(394, 34, 400),
457 Job::new(15, 86, 700),
458 Job::new(144, 73, 536),
459 Job::new(51, 52, 403),
460 Job::new(233, 68, 23),
461 Job::new(183, 17, 641),
462 Job::new(728, 18, 640),
463 Job::new(667, 80, 92),
464 Job::new(57, 21, 76),
465 Job::new(35, 37, 386),
466 Job::new(567, 71, 618),
467 Job::new(226, 5, 629),
468 Job::new(162, 80, 575),
469 Job::new(588, 45, 632),
470 Job::new(556, 23, 79),
471 Job::new(715, 8, 93),
472 Job::new(598, 45, 200),
473 ]);
474 let result = part_time_schrage(&js);
475 assert_eq!(result, 1386);
476 }
477
478 #[test]
479 fn test_part_time_schrage4() {
480 let js = JobList::new(vec![
481 Job::new(219, 5, 276),
482 Job::new(84, 13, 103),
483 Job::new(336, 35, 146),
484 Job::new(271, 62, 264),
485 Job::new(120, 33, 303),
486 Job::new(299, 14, 328),
487 Job::new(106, 46, 91),
488 Job::new(181, 93, 97),
489 Job::new(263, 13, 168),
490 Job::new(79, 60, 235),
491 ]);
492 let result = part_time_schrage(&js);
493 assert_eq!(result, 641);
494 }
495}