ferrox/jobshop/
problem.rs1use serde::{Deserialize, Serialize};
2
3use converge_pack::{ExecutionIdentity, FactPayload};
4
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(deny_unknown_fields)]
8pub struct Operation {
9 pub machine_id: usize,
10 pub duration: i64,
11}
12
13#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
15#[serde(deny_unknown_fields)]
16pub struct Job {
17 pub id: usize,
18 pub name: String,
19 pub operations: Vec<Operation>,
21}
22
23#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
25#[serde(deny_unknown_fields)]
26pub struct JobShopRequest {
27 pub id: String,
28 pub jobs: Vec<Job>,
29 pub num_machines: usize,
30 #[serde(default = "default_time_limit")]
31 pub time_limit_seconds: f64,
32}
33
34impl FactPayload for JobShopRequest {
35 const FAMILY: &'static str = "ferrox.jobshop.request";
36 const VERSION: u16 = 1;
37}
38
39fn default_time_limit() -> f64 {
40 30.0
41}
42
43impl JobShopRequest {
44 pub fn horizon(&self) -> i64 {
46 self.jobs
47 .iter()
48 .flat_map(|j| j.operations.iter())
49 .map(|o| o.duration)
50 .sum()
51 }
52}
53
54#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
56#[serde(deny_unknown_fields)]
57pub struct ScheduledOp {
58 pub job_id: usize,
59 pub job_name: String,
60 pub machine_id: usize,
61 pub op_index: usize,
62 pub start: i64,
63 pub end: i64,
64}
65
66#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
68#[serde(deny_unknown_fields)]
69pub struct JobShopPlan {
70 pub request_id: String,
71 pub schedule: Vec<ScheduledOp>,
72 pub makespan: i64,
73 pub lower_bound: Option<i64>,
75 pub solver: String,
76 pub execution_identity: ExecutionIdentity,
77 pub status: String,
79 pub wall_time_seconds: f64,
80}
81
82impl FactPayload for JobShopPlan {
83 const FAMILY: &'static str = "ferrox.jobshop.plan";
84 const VERSION: u16 = 1;
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn horizon_zero_when_no_jobs() {
93 let r = JobShopRequest {
94 id: "r".into(),
95 jobs: vec![],
96 num_machines: 1,
97 time_limit_seconds: 1.0,
98 };
99 assert_eq!(r.horizon(), 0);
100 }
101
102 #[test]
103 fn horizon_sums_durations() {
104 let r = JobShopRequest {
105 id: "r".into(),
106 jobs: vec![Job {
107 id: 0,
108 name: "j".into(),
109 operations: vec![
110 Operation {
111 machine_id: 0,
112 duration: 4,
113 },
114 Operation {
115 machine_id: 1,
116 duration: 6,
117 },
118 ],
119 }],
120 num_machines: 2,
121 time_limit_seconds: 1.0,
122 };
123 assert_eq!(r.horizon(), 10);
124 }
125
126 #[test]
127 fn request_default_time_limit() {
128 let json = r#"{"id":"r","jobs":[],"num_machines":1}"#;
129 let r: JobShopRequest = serde_json::from_str(json).unwrap();
130 assert!((r.time_limit_seconds - 30.0).abs() < f64::EPSILON);
131 }
132}