problemreductions/rules/
sequencingtominimizetardytaskweight_ilp.rs1use crate::models::algebraic::{LinearConstraint, ObjectiveSense, ILP};
8use crate::models::misc::SequencingToMinimizeTardyTaskWeight;
9use crate::reduction;
10use crate::rules::ilp_helpers::one_hot_decode;
11use crate::rules::traits::{ReduceTo, ReductionResult};
12
13#[derive(Debug, Clone)]
15pub struct ReductionSTMTTWToILP {
16 target: ILP<bool>,
17 num_tasks: usize,
18}
19
20impl ReductionResult for ReductionSTMTTWToILP {
21 type Source = SequencingToMinimizeTardyTaskWeight;
22 type Target = ILP<bool>;
23
24 fn target_problem(&self) -> &ILP<bool> {
25 &self.target
26 }
27
28 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
29 let n = self.num_tasks;
30 one_hot_decode(target_solution, n, n, 0)
34 }
35}
36
37#[reduction(overhead = {
38 num_vars = "num_tasks * num_tasks + num_tasks",
39 num_constraints = "2 * num_tasks + num_tasks * num_tasks",
40})]
41impl ReduceTo<ILP<bool>> for SequencingToMinimizeTardyTaskWeight {
42 type Result = ReductionSTMTTWToILP;
43
44 fn reduce_to(&self) -> Self::Result {
45 let n = self.num_tasks();
46 let num_x_vars = n * n;
47 let num_vars = num_x_vars + n;
48 let total_length: u64 = self.lengths().iter().copied().sum();
49 let big_m = total_length as f64;
50
51 let x_var = |j: usize, p: usize| -> usize { j * n + p };
52 let u_var = |j: usize| -> usize { num_x_vars + j };
53
54 let mut constraints = Vec::new();
55
56 for j in 0..n {
58 let terms: Vec<(usize, f64)> = (0..n).map(|p| (x_var(j, p), 1.0)).collect();
59 constraints.push(LinearConstraint::eq(terms, 1.0));
60 }
61
62 for p in 0..n {
64 let terms: Vec<(usize, f64)> = (0..n).map(|j| (x_var(j, p), 1.0)).collect();
65 constraints.push(LinearConstraint::eq(terms, 1.0));
66 }
67
68 let lengths = self.lengths();
73 for j in 0..n {
74 for p in 0..n {
75 let mut terms: Vec<(usize, f64)> = Vec::new();
76 terms.push((x_var(j, p), big_m));
77 for pp in 0..p {
78 for (jj, &len) in lengths.iter().enumerate() {
79 terms.push((x_var(jj, pp), len as f64));
80 }
81 }
82 terms.push((u_var(j), -big_m));
83 let rhs = self.deadlines()[j] as f64 - lengths[j] as f64 + big_m;
84 constraints.push(LinearConstraint::le(terms, rhs));
85 }
86 }
87
88 let weights = self.weights();
90 let objective: Vec<(usize, f64)> = (0..n).map(|j| (u_var(j), weights[j] as f64)).collect();
91
92 ReductionSTMTTWToILP {
93 target: ILP::new(num_vars, constraints, objective, ObjectiveSense::Minimize),
94 num_tasks: n,
95 }
96 }
97}
98
99#[cfg(feature = "example-db")]
100pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
101 vec![crate::example_db::specs::RuleExampleSpec {
102 id: "sequencingtominimizetardytaskweight_to_ilp",
103 build: || {
104 let source = SequencingToMinimizeTardyTaskWeight::new(
105 vec![3, 2, 4, 1, 2],
106 vec![5, 3, 7, 2, 4],
107 vec![6, 4, 10, 2, 8],
108 );
109 crate::example_db::specs::rule_example_via_ilp::<_, bool>(source)
110 },
111 }]
112}
113
114#[cfg(test)]
115#[path = "../unit_tests/rules/sequencingtominimizetardytaskweight_ilp.rs"]
116mod tests;