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_witness(
55 self.target_problem(),
56 target_solution,
57 |value| value.0,
58 "target witness does not satisfy the target problem",
59 )?;
60
61 Ok({
62 let mut current_time: i64 = 0;
64 let mut slot_assignment = vec![0usize; self.num_element_tasks];
65 let slot_width = self.bound.checked_add(1).ok_or_else(|| {
66 crate::rules::ExtractionError::invalid("slot width overflows i64")
67 })?; for &task in target_solution {
70 let start = current_time.max(self.target.release_times()[task]);
71 let finish = start
72 .checked_add(self.target.lengths()[task])
73 .ok_or_else(|| {
74 crate::rules::ExtractionError::invalid("task finish time overflows i64")
75 })?;
76 current_time = finish;
77
78 if task < self.num_element_tasks {
80 let slot = usize::try_from(start / slot_width).map_err(|_| {
81 crate::rules::ExtractionError::invalid(
82 "decoded task slot cannot be represented as usize",
83 )
84 })?;
85 slot_assignment[task] = slot;
86 }
87 }
88
89 slot_assignment
90 })
91 }
92}
93
94#[crate::aggregate_reduction(identity)]
95impl crate::rules::AggregateReductionResult for ReductionThreePartitionToSRTD {}
96
97#[reduction(
98 transform = {
99 exact {
101 num_tasks = "num_elements + num_groups - 1",
102 time_horizon = "num_groups * (bound + 1) - 1",
103 },
104 upper_bound { time_horizon_bits = "max_numeric_magnitude_bits + num_groups + 1", },
105 },
106)]
107impl ReduceTo<SequencingWithReleaseTimesAndDeadlines> for ThreePartition {
108 type Result = ReductionThreePartitionToSRTD;
109
110 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
111 let n_elem = num_element_tasks(self);
112 let n_fill = num_filler_tasks(self);
113 let m = self.num_groups();
114 let b = self.bound();
115 let overflow = |operation| {
116 crate::rules::ReductionError::integer_overflow::<
117 Self,
118 SequencingWithReleaseTimesAndDeadlines,
119 >(operation)
120 };
121 let total_tasks = n_elem
122 .checked_add(n_fill)
123 .ok_or_else(|| overflow("computing the target task count"))?;
124
125 let group_count =
127 i64::try_from(m).map_err(|_| overflow("converting the group count to i64"))?;
128 let slot_width = b
129 .checked_add(1)
130 .ok_or_else(|| overflow("computing the slot width"))?;
131 let horizon = group_count
132 .checked_mul(slot_width)
133 .and_then(|value| value.checked_sub(1))
134 .ok_or_else(|| overflow("computing the scheduling horizon"))?;
135
136 let mut lengths = Vec::with_capacity(total_tasks);
137 let mut release_times = Vec::with_capacity(total_tasks);
138 let mut deadlines = Vec::with_capacity(total_tasks);
139
140 for &size in self.sizes() {
142 lengths.push(size);
143 release_times.push(0);
144 deadlines.push(horizon);
145 }
146
147 for j in 0..n_fill {
149 let separator =
152 i64::try_from(j).map_err(|_| overflow("converting a filler-task index to i64"))?;
153 let next_separator = separator
154 .checked_add(1)
155 .ok_or_else(|| overflow("computing a filler-task index"))?;
156 let release = next_separator
157 .checked_mul(b)
158 .and_then(|value| value.checked_add(separator))
159 .ok_or_else(|| overflow("computing a filler-task release time"))?;
160 lengths.push(1);
161 release_times.push(release);
162 deadlines.push(
163 release
164 .checked_add(1)
165 .ok_or_else(|| overflow("computing a filler-task deadline"))?,
166 );
167 }
168
169 Ok(ReductionThreePartitionToSRTD {
170 target: SequencingWithReleaseTimesAndDeadlines::new(lengths, release_times, deadlines),
171 num_element_tasks: n_elem,
172 bound: b,
173 })
174 }
175}
176
177#[cfg(feature = "example-db")]
178pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
179 use crate::export::SolutionPair;
180
181 vec![crate::example_db::specs::RuleExampleSpec {
182 id: "threepartition_to_sequencingwithreleasetimesanddeadlines",
183 build: || {
184 crate::example_db::specs::rule_example_with_witness::<
203 _,
204 SequencingWithReleaseTimesAndDeadlines,
205 >(
206 ThreePartition::new(vec![4, 5, 6, 4, 6, 5], 15),
207 SolutionPair {
208 source_config: serde_json::json!(vec![0, 0, 0, 1, 1, 1]),
209 target_config: serde_json::json!(vec![0, 1, 2, 6, 3, 4, 5]),
210 },
211 )
212 },
213 }]
214}
215
216#[cfg(test)]
217#[path = "../unit_tests/rules/threepartition_sequencingwithreleasetimesanddeadlines.rs"]
218mod tests;