problemreductions/models/misc/
partition.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
8use crate::traits::Problem;
9use serde::{Deserialize, Serialize};
10
11inventory::submit! {
12 ProblemSchemaEntry {
13 name: "Partition",
14 display_name: "Partition",
15 aliases: &[],
16 dimensions: &[],
17 module_path: module_path!(),
18 description: "Determine whether a multiset of positive integers can be partitioned into two subsets of equal sum",
19 fields: &[
20 FieldInfo { name: "sizes", type_name: "Vec<u64>", description: "Positive integer size for each element" },
21 ],
22 }
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct Partition {
49 sizes: Vec<u64>,
50}
51
52impl Partition {
53 pub fn new(sizes: Vec<u64>) -> Self {
59 assert!(!sizes.is_empty(), "Partition requires at least one element");
60 assert!(
61 sizes.iter().all(|&s| s > 0),
62 "All sizes must be positive (> 0)"
63 );
64 Self { sizes }
65 }
66
67 pub fn sizes(&self) -> &[u64] {
69 &self.sizes
70 }
71
72 pub fn num_elements(&self) -> usize {
74 self.sizes.len()
75 }
76
77 pub fn total_sum(&self) -> u64 {
79 self.sizes.iter().sum()
80 }
81}
82
83impl Problem for Partition {
84 const NAME: &'static str = "Partition";
85 type Value = crate::types::Or;
86
87 fn variant() -> Vec<(&'static str, &'static str)> {
88 crate::variant_params![]
89 }
90
91 fn dims(&self) -> Vec<usize> {
92 vec![2; self.num_elements()]
93 }
94
95 fn evaluate(&self, config: &[usize]) -> crate::types::Or {
96 crate::types::Or({
97 if config.len() != self.num_elements() {
98 return crate::types::Or(false);
99 }
100 if config.iter().any(|&v| v >= 2) {
101 return crate::types::Or(false);
102 }
103 let selected_sum: u64 = config
104 .iter()
105 .enumerate()
106 .filter(|(_, &x)| x == 1)
107 .map(|(i, _)| self.sizes[i])
108 .sum();
109 selected_sum * 2 == self.total_sum()
110 })
111 }
112}
113
114crate::declare_variants! {
115 default Partition => "2^(num_elements / 2)",
116}
117
118#[cfg(feature = "example-db")]
119pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
120 vec![crate::example_db::specs::ModelExampleSpec {
121 id: "partition",
122 instance: Box::new(Partition::new(vec![3, 1, 1, 2, 2, 1])),
123 optimal_config: vec![1, 0, 0, 1, 0, 0],
124 optimal_value: serde_json::json!(true),
125 }]
126}
127
128#[cfg(test)]
129#[path = "../../unit_tests/models/misc/partition.rs"]
130mod tests;