Skip to main content

problemreductions/rules/
partition_cosineproductintegration.rs

1//! Reduction from Partition to CosineProductIntegration.
2//!
3//! Given a Partition instance with sizes `[s_1, ..., s_n]`, construct a
4//! CosineProductIntegration instance with coefficients `[s_1, ..., s_n]`
5//! (cast from `u64` to `i64`).
6//!
7//! A balanced partition exists iff a balanced sign assignment exists:
8//! subset A has sum = total/2 iff the sign vector `ε_i = +1` for `i ∈ A`,
9//! `ε_i = -1` for `i ∉ A` satisfies `∑ ε_i s_i = 0`.
10//!
11//! Solution extraction is the identity mapping.
12
13use crate::models::misc::{CosineProductIntegration, Partition};
14use crate::reduction;
15use crate::rules::traits::{ReduceTo, ReductionResult};
16
17/// Result of reducing Partition to CosineProductIntegration.
18#[derive(Debug, Clone)]
19pub struct ReductionPartitionToCPI {
20    target: CosineProductIntegration,
21}
22
23impl ReductionResult for ReductionPartitionToCPI {
24    type Source = Partition;
25    type Target = CosineProductIntegration;
26
27    fn target_problem(&self) -> &Self::Target {
28        &self.target
29    }
30
31    fn extract_solution(
32        &self,
33        target_solution: &<Self::Target as crate::traits::Problem>::Solution,
34    ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
35        crate::rules::traits::validate_target_solution(self.target_problem(), target_solution)?;
36
37        Ok(target_solution.to_vec())
38    }
39}
40
41#[reduction(
42    transform = exact {
43        num_coefficients = "num_elements",
44    })]
45impl ReduceTo<CosineProductIntegration> for Partition {
46    type Result = ReductionPartitionToCPI;
47
48    fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
49        let coefficients = self.sizes().to_vec();
50        Ok(ReductionPartitionToCPI {
51            target: CosineProductIntegration::new(coefficients),
52        })
53    }
54}
55
56#[cfg(feature = "example-db")]
57pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
58    use crate::export::SolutionPair;
59
60    vec![crate::example_db::specs::RuleExampleSpec {
61        id: "partition_to_cosineproductintegration",
62        build: || {
63            // sizes [3, 1, 1, 2, 2, 1]: partition {3,2,1}={6} and {1,2,1}={4}? No...
64            // Actually [3,1,1,2,2,1] sum=10, need sum=5 each.
65            // config [1,0,0,1,0,0] → selected={3,2}=5, rest={1,1,2,1}=5 ✓
66            // sign assignment: bit=1→−, bit=0→+ : (+3,−1,−1,+2,−2,−1) = 3-1-1+2-2-1=0? No, 3-1-1+2-2-1=0. Yes!
67            // Wait: config [1,0,0,1,0,0] means elements 0,3 in subset 1.
68            // For CPI: bit 1 means −a_i. So −3+1+1−2+2+1 = 0. Yes!
69            crate::example_db::specs::rule_example_with_witness::<_, CosineProductIntegration>(
70                Partition::new(vec![3, 1, 1, 2, 2, 1]).unwrap(),
71                SolutionPair {
72                    source_config: serde_json::json!(vec![true, false, false, true, false, false]),
73                    target_config: serde_json::json!(vec![true, false, false, true, false, false]),
74                },
75            )
76        },
77    }]
78}
79
80#[cfg(test)]
81#[path = "../unit_tests/rules/partition_cosineproductintegration.rs"]
82mod tests;