problemreductions/rules/
threepartition_sequencingwithreleasetimesanddeadlines.rs1use crate::models::misc::{SequencingWithReleaseTimesAndDeadlines, ThreePartition};
15use crate::reduction;
16use crate::rules::traits::{ReduceTo, ReductionResult};
17
18fn num_element_tasks(source: &ThreePartition) -> usize {
20 source.num_elements()
21}
22
23fn num_filler_tasks(source: &ThreePartition) -> usize {
25 source.num_groups() - 1
26}
27
28#[derive(Debug, Clone)]
30pub struct ReductionThreePartitionToSRTD {
31 target: SequencingWithReleaseTimesAndDeadlines,
32 num_element_tasks: usize,
34 bound: i64,
36}
37
38impl ReductionResult for ReductionThreePartitionToSRTD {
39 type Source = ThreePartition;
40 type Target = SequencingWithReleaseTimesAndDeadlines;
41
42 fn target_problem(&self) -> &Self::Target {
43 &self.target
44 }
45
46 fn extract_solution(
51 &self,
52 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
53 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
54 crate::rules::traits::validate_target_solution(self.target_problem(), target_solution)?;
55
56 Ok({
57 let mut current_time: i64 = 0;
59 let mut slot_assignment = vec![0usize; self.num_element_tasks];
60 let slot_width = self.bound.checked_add(1).ok_or_else(|| {
61 crate::rules::ExtractionError::invalid("slot width overflows i64")
62 })?; for &task in target_solution {
65 let start = current_time.max(self.target.release_times()[task]);
66 let finish = start
67 .checked_add(self.target.lengths()[task])
68 .ok_or_else(|| {
69 crate::rules::ExtractionError::invalid("task finish time overflows i64")
70 })?;
71 current_time = finish;
72
73 if task < self.num_element_tasks {
75 let slot = usize::try_from(start / slot_width).map_err(|_| {
76 crate::rules::ExtractionError::invalid(
77 "decoded task slot cannot be represented as usize",
78 )
79 })?;
80 slot_assignment[task] = slot;
81 }
82 }
83
84 slot_assignment
85 })
86 }
87}
88
89#[reduction(
90 transform = exact {
91 num_tasks = "num_elements + num_groups - 1",
92 },
93 unavailable = {
94 time_horizon = "the exact target parameter is not represented by this reduction's symbolic transform",
95 }
96)]
97impl ReduceTo<SequencingWithReleaseTimesAndDeadlines> for ThreePartition {
98 type Result = ReductionThreePartitionToSRTD;
99
100 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
101 let n_elem = num_element_tasks(self);
102 let n_fill = num_filler_tasks(self);
103 let m = self.num_groups();
104 let b = self.bound();
105 let overflow = |operation| {
106 crate::rules::ReductionError::integer_overflow::<
107 Self,
108 SequencingWithReleaseTimesAndDeadlines,
109 >(operation)
110 };
111 let total_tasks = n_elem
112 .checked_add(n_fill)
113 .ok_or_else(|| overflow("computing the target task count"))?;
114
115 let group_count =
117 i64::try_from(m).map_err(|_| overflow("converting the group count to i64"))?;
118 let slot_width = b
119 .checked_add(1)
120 .ok_or_else(|| overflow("computing the slot width"))?;
121 let horizon = group_count
122 .checked_mul(slot_width)
123 .and_then(|value| value.checked_sub(1))
124 .ok_or_else(|| overflow("computing the scheduling horizon"))?;
125
126 let mut lengths = Vec::with_capacity(total_tasks);
127 let mut release_times = Vec::with_capacity(total_tasks);
128 let mut deadlines = Vec::with_capacity(total_tasks);
129
130 for &size in self.sizes() {
132 lengths.push(size);
133 release_times.push(0);
134 deadlines.push(horizon);
135 }
136
137 for j in 0..n_fill {
139 let separator =
142 i64::try_from(j).map_err(|_| overflow("converting a filler-task index to i64"))?;
143 let next_separator = separator
144 .checked_add(1)
145 .ok_or_else(|| overflow("computing a filler-task index"))?;
146 let release = next_separator
147 .checked_mul(b)
148 .and_then(|value| value.checked_add(separator))
149 .ok_or_else(|| overflow("computing a filler-task release time"))?;
150 lengths.push(1);
151 release_times.push(release);
152 deadlines.push(
153 release
154 .checked_add(1)
155 .ok_or_else(|| overflow("computing a filler-task deadline"))?,
156 );
157 }
158
159 Ok(ReductionThreePartitionToSRTD {
160 target: SequencingWithReleaseTimesAndDeadlines::new(lengths, release_times, deadlines),
161 num_element_tasks: n_elem,
162 bound: b,
163 })
164 }
165}
166
167#[cfg(feature = "example-db")]
168pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
169 use crate::export::SolutionPair;
170
171 vec![crate::example_db::specs::RuleExampleSpec {
172 id: "threepartition_to_sequencingwithreleasetimesanddeadlines",
173 build: || {
174 crate::example_db::specs::rule_example_with_witness::<
193 _,
194 SequencingWithReleaseTimesAndDeadlines,
195 >(
196 ThreePartition::new(vec![4, 5, 6, 4, 6, 5], 15),
197 SolutionPair {
198 source_config: serde_json::json!(vec![0, 0, 0, 1, 1, 1]),
199 target_config: serde_json::json!(vec![0, 1, 2, 6, 3, 4, 5]),
200 },
201 )
202 },
203 }]
204}
205
206#[cfg(test)]
207#[path = "../unit_tests/rules/threepartition_sequencingwithreleasetimesanddeadlines.rs"]
208mod tests;