problemreductions/rules/
subsetsum_integerexpressionmembership.rs1use crate::models::misc::SubsetSum;
2use crate::models::misc::{IntExpr, IntegerExpressionMembership};
3use crate::reduction;
4use crate::rules::traits::{ReduceTo, ReductionResult};
5use num_traits::ToPrimitive;
6
7#[derive(Debug, Clone)]
8pub struct ReductionSubsetSumToIntegerExpressionMembership {
9 target: IntegerExpressionMembership,
10}
11
12impl ReductionResult for ReductionSubsetSumToIntegerExpressionMembership {
13 type Source = SubsetSum;
14 type Target = IntegerExpressionMembership;
15
16 fn target_problem(&self) -> &Self::Target {
17 &self.target
18 }
19
20 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
21 target_solution.to_vec()
24 }
25}
26
27fn build_expression(sizes: &[u64]) -> IntExpr {
36 assert!(
37 !sizes.is_empty(),
38 "SubsetSum must have at least one element"
39 );
40
41 let make_union = |s: u64| -> IntExpr {
42 IntExpr::Union(Box::new(IntExpr::Atom(1)), Box::new(IntExpr::Atom(s + 1)))
43 };
44
45 let mut expr = make_union(sizes[0]);
46 for &s in &sizes[1..] {
47 expr = IntExpr::Sum(Box::new(expr), Box::new(make_union(s)));
48 }
49 expr
50}
51
52#[reduction(overhead = {
53 num_union_nodes = "num_elements",
54})]
55impl ReduceTo<IntegerExpressionMembership> for SubsetSum {
56 type Result = ReductionSubsetSumToIntegerExpressionMembership;
57
58 fn reduce_to(&self) -> Self::Result {
59 let sizes: Vec<u64> = self
60 .sizes()
61 .iter()
62 .map(|size| size.to_u64().unwrap())
63 .collect();
64
65 let shift = u64::try_from(self.num_elements())
66 .expect("SubsetSum -> IntegerExpressionMembership requires num_elements to fit in u64");
67 let target = self.target().to_u64().unwrap().checked_add(shift).expect(
68 "SubsetSum -> IntegerExpressionMembership requires shifted target to fit in u64",
69 );
70
71 let expr = build_expression(&sizes);
72
73 ReductionSubsetSumToIntegerExpressionMembership {
74 target: IntegerExpressionMembership::new(expr, target),
75 }
76 }
77}
78
79#[cfg(feature = "example-db")]
80pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
81 use crate::export::SolutionPair;
82
83 vec![crate::example_db::specs::RuleExampleSpec {
84 id: "subsetsum_to_integerexpressionmembership",
85 build: || {
86 crate::example_db::specs::rule_example_with_witness::<_, IntegerExpressionMembership>(
87 SubsetSum::new(vec![1u32, 5, 6, 8], 11u32),
88 SolutionPair {
89 source_config: vec![0, 1, 1, 0],
90 target_config: vec![0, 1, 1, 0],
91 },
92 )
93 },
94 }]
95}
96
97#[cfg(test)]
98#[path = "../unit_tests/rules/subsetsum_integerexpressionmembership.rs"]
99mod tests;