problemreductions/rules/
partition_subsetsum.rs1use crate::models::misc::{Partition, SubsetSum};
8use crate::reduction;
9use crate::rules::traits::{ReduceTo, ReductionResult};
10use num_bigint::{BigUint, ToBigUint};
11
12#[derive(Debug, Clone)]
14pub struct ReductionPartitionToSubsetSum {
15 target: SubsetSum,
16 source_n: usize,
19}
20
21impl ReductionResult for ReductionPartitionToSubsetSum {
22 type Source = Partition;
23 type Target = SubsetSum;
24
25 fn target_problem(&self) -> &Self::Target {
26 &self.target
27 }
28
29 fn extract_solution(
30 &self,
31 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
32 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
33 crate::rules::traits::validate_target_witness(
34 self.target_problem(),
35 target_solution,
36 |value| value.0,
37 "target witness does not satisfy the target problem",
38 )?;
39
40 if target_solution.len() != self.source_n {
41 return Err(crate::rules::ExtractionError::invalid(format!(
42 "expected {} subset-selection values, got {}",
43 self.source_n,
44 target_solution.len()
45 )));
46 }
47 Ok(target_solution.to_vec())
48 }
49}
50
51#[crate::aggregate_reduction(identity)]
52impl crate::rules::AggregateReductionResult for ReductionPartitionToSubsetSum {}
53
54#[reduction(
56 transform = upper_bound {
57 max_numeric_magnitude_bits = "max_numeric_magnitude_bits + num_elements",
58 num_elements = "num_elements",
59 })]
60impl ReduceTo<SubsetSum> for Partition {
61 type Result = ReductionPartitionToSubsetSum;
62
63 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
64 let total = self.total_sum();
65 let source_n = self.num_elements();
66
67 Ok(if total % 2 != 0 {
68 ReductionPartitionToSubsetSum {
71 target: SubsetSum::new_unchecked(vec![], BigUint::from(1u32)),
72 source_n,
73 }
74 } else {
75 let sizes: Vec<BigUint> = self
76 .sizes()
77 .iter()
78 .map(|&size| {
79 size.to_biguint()
80 .expect("validated nonnegative Partition size")
81 })
82 .collect();
83 let target_val = (total / 2)
84 .to_biguint()
85 .expect("validated nonnegative Partition total");
86 ReductionPartitionToSubsetSum {
87 target: SubsetSum::new_unchecked(sizes, target_val),
88 source_n,
89 }
90 })
91 }
92}
93
94#[cfg(feature = "example-db")]
95pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
96 use crate::export::SolutionPair;
97
98 vec![crate::example_db::specs::RuleExampleSpec {
99 id: "partition_to_subsetsum",
100 build: || {
101 crate::example_db::specs::rule_example_with_witness::<_, SubsetSum>(
102 Partition::new(vec![3, 1, 1, 2, 2, 1]).unwrap(),
103 SolutionPair {
104 source_config: serde_json::json!(vec![true, false, false, true, false, false]),
105 target_config: serde_json::json!(vec![true, false, false, true, false, false]),
106 },
107 )
108 },
109 }]
110}
111
112#[cfg(test)]
113#[path = "../unit_tests/rules/partition_subsetsum.rs"]
114mod tests;