problemreductions/models/misc/
sequencing_to_minimize_weighted_tardiness.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
9use crate::traits::Problem;
10use serde::{Deserialize, Serialize};
11
12inventory::submit! {
13 ProblemSchemaEntry {
14 name: "SequencingToMinimizeWeightedTardiness",
15 display_name: "Sequencing to Minimize Weighted Tardiness",
16 aliases: &[],
17 dimensions: &[],
18 module_path: module_path!(),
19 description: "Schedule jobs on one machine so total weighted tardiness is at most K",
20 fields: &[
21 FieldInfo { name: "lengths", type_name: "Vec<u64>", description: "Processing times l_j for each job" },
22 FieldInfo { name: "weights", type_name: "Vec<u64>", description: "Tardiness weights w_j for each job" },
23 FieldInfo { name: "deadlines", type_name: "Vec<u64>", description: "Deadlines d_j for each job" },
24 FieldInfo { name: "bound", type_name: "u64", description: "Upper bound K on total weighted tardiness" },
25 ],
26 }
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct SequencingToMinimizeWeightedTardiness {
60 lengths: Vec<u64>,
61 weights: Vec<u64>,
62 deadlines: Vec<u64>,
63 bound: u64,
64}
65
66impl SequencingToMinimizeWeightedTardiness {
67 pub fn new(lengths: Vec<u64>, weights: Vec<u64>, deadlines: Vec<u64>, bound: u64) -> Self {
73 assert_eq!(
74 lengths.len(),
75 weights.len(),
76 "weights length must equal lengths length"
77 );
78 assert_eq!(
79 lengths.len(),
80 deadlines.len(),
81 "deadlines length must equal lengths length"
82 );
83 Self {
84 lengths,
85 weights,
86 deadlines,
87 bound,
88 }
89 }
90
91 pub fn lengths(&self) -> &[u64] {
93 &self.lengths
94 }
95
96 pub fn weights(&self) -> &[u64] {
98 &self.weights
99 }
100
101 pub fn deadlines(&self) -> &[u64] {
103 &self.deadlines
104 }
105
106 pub fn bound(&self) -> u64 {
108 self.bound
109 }
110
111 pub fn num_tasks(&self) -> usize {
113 self.lengths.len()
114 }
115
116 fn decode_schedule(&self, config: &[usize]) -> Option<Vec<usize>> {
117 super::decode_lehmer(config, self.num_tasks())
118 }
119
120 fn schedule_weighted_tardiness(&self, schedule: &[usize]) -> Option<u64> {
121 let mut completion_time = 0u128;
122 let mut total = 0u128;
123 for &job in schedule {
124 completion_time += u128::from(self.lengths[job]);
125 let tardiness = completion_time.saturating_sub(u128::from(self.deadlines[job]));
126 total += tardiness * u128::from(self.weights[job]);
127 }
128 u64::try_from(total).ok()
129 }
130
131 pub fn total_weighted_tardiness(&self, config: &[usize]) -> Option<u64> {
136 let schedule = self.decode_schedule(config)?;
137 self.schedule_weighted_tardiness(&schedule)
138 }
139}
140
141impl Problem for SequencingToMinimizeWeightedTardiness {
142 const NAME: &'static str = "SequencingToMinimizeWeightedTardiness";
143 type Value = crate::types::Or;
144
145 fn variant() -> Vec<(&'static str, &'static str)> {
146 crate::variant_params![]
147 }
148
149 fn dims(&self) -> Vec<usize> {
150 super::lehmer_dims(self.num_tasks())
151 }
152
153 fn evaluate(&self, config: &[usize]) -> crate::types::Or {
154 crate::types::Or({
155 self.total_weighted_tardiness(config)
156 .is_some_and(|total| total <= self.bound)
157 })
158 }
159}
160
161crate::declare_variants! {
162 default SequencingToMinimizeWeightedTardiness => "factorial(num_tasks)",
163}
164
165#[cfg(feature = "example-db")]
166pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
167 vec![crate::example_db::specs::ModelExampleSpec {
168 id: "sequencing_to_minimize_weighted_tardiness",
169 instance: Box::new(SequencingToMinimizeWeightedTardiness::new(
170 vec![3, 4, 2, 5, 3],
171 vec![2, 3, 1, 4, 2],
172 vec![5, 8, 4, 15, 10],
173 13,
174 )),
175 optimal_config: vec![0, 0, 2, 1, 0],
176 optimal_value: serde_json::json!(true),
177 }]
178}
179
180#[cfg(test)]
181#[path = "../../unit_tests/models/misc/sequencing_to_minimize_weighted_tardiness.rs"]
182mod tests;