problemreductions/rules/
partition_openshopscheduling.rs1use crate::models::decision::Decision;
4use crate::models::misc::{OpenShopScheduling, Partition};
5use crate::reduction;
6use crate::rules::traits::{ReduceTo, ReductionResult};
7
8#[derive(Debug, Clone)]
9pub struct ReductionPartitionToOpenShopScheduling {
10 target: Decision<OpenShopScheduling>,
11}
12
13impl ReductionResult for ReductionPartitionToOpenShopScheduling {
14 type Source = Partition;
15 type Target = Decision<OpenShopScheduling>;
16
17 fn target_problem(&self) -> &Self::Target {
18 &self.target
19 }
20
21 fn extract_solution(
22 &self,
23 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
24 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
25 crate::rules::traits::validate_target_witness(
26 self.target_problem(),
27 target_solution,
28 |value| value.0,
29 "target schedule does not certify a balanced partition",
30 )?;
31
32 Ok({
33 let num_elements = self.target.inner().num_jobs() - 1;
34 let mut source_config = vec![false; num_elements];
35 let m = self.target.inner().num_machines();
36 let start_times = target_solution
37 .chunks_exact(m)
38 .map(|times| {
39 times
40 .iter()
41 .map(|&time| {
42 i64::try_from(time).map_err(|_| {
43 crate::rules::ExtractionError::invalid(
44 "target schedule time does not fit i64",
45 )
46 })
47 })
48 .collect::<Result<Vec<_>, _>>()
49 })
50 .collect::<Result<Vec<_>, _>>()?;
51 let special_job = num_elements;
52 let half_sum = self.target.inner().processing_times()[special_job][0];
53
54 let middle_machine = (0..m)
56 .find(|&machine| start_times[special_job][machine] == half_sum)
57 .ok_or_else(|| {
58 crate::rules::ExtractionError::invalid(
59 "target schedule has no machine at the partition boundary",
60 )
61 })?;
62 let pivot = start_times[special_job][middle_machine];
63
64 for (job, slot) in source_config.iter_mut().enumerate() {
65 let completion = start_times[job][middle_machine]
66 .checked_add(self.target.inner().processing_times()[job][middle_machine])
67 .ok_or_else(|| {
68 crate::rules::ExtractionError::invalid("target schedule time overflows i64")
69 })?;
70 if completion <= pivot {
71 *slot = true;
72 }
73 }
74
75 source_config
76 })
77 }
78}
79
80#[crate::aggregate_reduction(identity)]
81impl crate::rules::AggregateReductionResult for ReductionPartitionToOpenShopScheduling {}
82
83#[reduction(
84 transform = {
85 exact {
86 num_jobs = "num_elements + 1",
87 num_machines = "3",
88 },
89 upper_bound {
90 schedule_horizon = "9 * total_sum / 2",
92 schedule_horizon_bits = "max_numeric_magnitude_bits + num_elements + 3",
93 },
94 },
95)]
96impl ReduceTo<Decision<OpenShopScheduling>> for Partition {
97 type Result = ReductionPartitionToOpenShopScheduling;
98
99 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
100 let half_sum = self.total_sum() / 2;
101 let mut processing_times: Vec<Vec<i64>> =
102 self.sizes().iter().map(|&size| vec![size; 3]).collect();
103 processing_times.push(vec![half_sum; 3]);
104
105 let target = OpenShopScheduling::try_new(3, processing_times)
106 .map_err(<Self as ReduceTo<Decision<OpenShopScheduling>>>::target_construction)?;
107 let feasible_makespan = 3 * half_sum;
109 Ok(ReductionPartitionToOpenShopScheduling {
110 target: Decision::new(target, feasible_makespan),
111 })
112 }
113}
114
115#[cfg(feature = "example-db")]
116pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
117 use crate::export::SolutionPair;
118
119 vec![crate::example_db::specs::RuleExampleSpec {
120 id: "partition_to_open_shop_scheduling",
121 build: || {
122 crate::example_db::specs::rule_example_with_witness::<_, Decision<OpenShopScheduling>>(
123 Partition::new(vec![1, 2, 3]).unwrap(),
124 SolutionPair {
125 source_config: serde_json::json!(vec![true, true, false]),
126 target_config: serde_json::json!(vec![0, 5, 6, 1, 3, 7, 6, 0, 3, 3, 6, 0]),
127 },
128 )
129 },
130 }]
131}
132
133#[cfg(test)]
134#[path = "../unit_tests/rules/partition_openshopscheduling.rs"]
135mod tests;