problemreductions/rules/
partition_productionplanning.rs1use crate::models::misc::{Partition, ProductionPlanning};
4use crate::reduction;
5use crate::rules::traits::{ReduceTo, ReductionResult};
6
7#[derive(Debug, Clone)]
8pub struct ReductionPartitionToProductionPlanning {
9 target: ProductionPlanning,
10}
11
12impl ReductionResult for ReductionPartitionToProductionPlanning {
13 type Source = Partition;
14 type Target = ProductionPlanning;
15
16 fn target_problem(&self) -> &Self::Target {
17 &self.target
18 }
19
20 fn extract_solution(
21 &self,
22 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
23 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
24 crate::rules::traits::validate_target_witness(
25 self.target_problem(),
26 target_solution,
27 |value| value.0,
28 "target witness does not satisfy the target problem",
29 )?;
30
31 Ok(target_solution[..self.target.num_periods() - 1]
32 .iter()
33 .map(|&production| production > 0)
34 .collect())
35 }
36}
37
38#[crate::aggregate_reduction(identity)]
39impl crate::rules::AggregateReductionResult for ReductionPartitionToProductionPlanning {}
40
41#[reduction(
42 transform = {
43 exact { num_periods = "num_elements + 1", },
44 upper_bound {
45 max_capacity = "total_sum",
47 max_numeric_magnitude_bits = "max_numeric_magnitude_bits + num_elements",
48 },
49 },
50)]
51impl ReduceTo<ProductionPlanning> for Partition {
52 type Result = ReductionPartitionToProductionPlanning;
53
54 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
55 let half_floor = self.total_sum() / 2;
56 let half_ceil = half_floor + (self.total_sum() % 2);
57 let mut demands = vec![0; self.num_elements()];
58 demands.push(half_ceil);
59
60 let mut capacities = self.sizes().to_vec();
61 capacities.push(0);
62
63 let mut setup_costs = self.sizes().to_vec();
64 setup_costs.push(0);
65
66 let production_costs = vec![0; self.num_elements() + 1];
67 let inventory_costs = vec![0; self.num_elements() + 1];
68
69 let num_periods = self.num_elements() + 1;
70 Ok(ReductionPartitionToProductionPlanning {
71 target: ProductionPlanning::new(
72 num_periods,
73 demands,
74 capacities,
75 setup_costs,
76 production_costs,
77 inventory_costs,
78 half_floor,
79 ),
80 })
81 }
82}
83
84#[cfg(feature = "example-db")]
85pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
86 use crate::export::SolutionPair;
87
88 vec![crate::example_db::specs::RuleExampleSpec {
89 id: "partition_to_production_planning",
90 build: || {
91 crate::example_db::specs::rule_example_with_witness::<_, ProductionPlanning>(
92 Partition::new(vec![3, 5, 2, 4, 6]).unwrap(),
93 SolutionPair {
94 source_config: serde_json::json!(vec![false, false, false, true, true]),
95 target_config: serde_json::json!(vec![0, 0, 0, 4, 6, 0]),
96 },
97 )
98 },
99 }]
100}
101
102#[cfg(test)]
103#[path = "../unit_tests/rules/partition_productionplanning.rs"]
104mod tests;