problemreductions/models/graph/
partition_into_forests.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry, VariantDimension};
8use crate::topology::{Graph, SimpleGraph};
9use crate::traits::Problem;
10use crate::variant::VariantParam;
11use serde::{Deserialize, Serialize};
12
13inventory::submit! {
14 ProblemSchemaEntry {
15 name: "PartitionIntoForests",
16 display_name: "Partition into Forests",
17 aliases: &[],
18 dimensions: &[
19 VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph"]),
20 ],
21 module_path: module_path!(),
22 description: "Partition vertices into K classes each inducing an acyclic subgraph",
23 fields: &[
24 FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
25 FieldInfo { name: "num_forests", type_name: "usize", description: "num_forests: number of forest classes K (>= 1)" },
26 ],
27 }
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
56#[serde(bound(deserialize = "G: serde::Deserialize<'de>"))]
57pub struct PartitionIntoForests<G> {
58 graph: G,
60 num_forests: usize,
62}
63
64impl<G: Graph> PartitionIntoForests<G> {
65 pub fn new(graph: G, num_forests: usize) -> Self {
70 assert!(num_forests >= 1, "num_forests must be at least 1");
71 Self { graph, num_forests }
72 }
73
74 pub fn graph(&self) -> &G {
76 &self.graph
77 }
78
79 pub fn num_forests(&self) -> usize {
81 self.num_forests
82 }
83
84 pub fn num_vertices(&self) -> usize {
86 self.graph.num_vertices()
87 }
88
89 pub fn num_edges(&self) -> usize {
91 self.graph.num_edges()
92 }
93}
94
95impl<G> Problem for PartitionIntoForests<G>
96where
97 G: Graph + VariantParam,
98{
99 const NAME: &'static str = "PartitionIntoForests";
100 type Value = crate::types::Or;
101
102 fn variant() -> Vec<(&'static str, &'static str)> {
103 crate::variant_params![G]
104 }
105
106 fn dims(&self) -> Vec<usize> {
107 vec![self.num_forests; self.graph.num_vertices()]
108 }
109
110 fn evaluate(&self, config: &[usize]) -> crate::types::Or {
111 crate::types::Or(is_valid_forest_partition(
112 &self.graph,
113 self.num_forests,
114 config,
115 ))
116 }
117}
118
119fn is_valid_forest_partition<G: Graph>(graph: &G, num_forests: usize, config: &[usize]) -> bool {
121 let n = graph.num_vertices();
122
123 if config.len() != n {
125 return false;
126 }
127 if config.iter().any(|&c| c >= num_forests) {
128 return false;
129 }
130
131 let mut parent: Vec<usize> = (0..n).collect();
135
136 fn find(parent: &mut Vec<usize>, x: usize) -> usize {
137 if parent[x] != x {
138 parent[x] = find(parent, parent[x]);
139 }
140 parent[x]
141 }
142
143 for (u, v) in graph.edges() {
144 if config[u] != config[v] {
145 continue;
147 }
148 let ru = find(&mut parent, u);
150 let rv = find(&mut parent, v);
151 if ru == rv {
152 return false; }
154 parent[ru] = rv; }
156
157 true
158}
159
160crate::declare_variants! {
161 default PartitionIntoForests<SimpleGraph> => "num_forests^num_vertices",
162}
163
164#[cfg(feature = "example-db")]
165pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
166 vec![crate::example_db::specs::ModelExampleSpec {
167 id: "partition_into_forests_simplegraph",
168 instance: Box::new(PartitionIntoForests::new(
169 SimpleGraph::new(
170 6,
171 vec![(0, 1), (1, 2), (2, 0), (2, 3), (3, 4), (4, 5), (5, 3)],
172 ),
173 2,
174 )),
175 optimal_config: vec![0, 1, 1, 0, 1, 1],
178 optimal_value: serde_json::json!(true),
179 }]
180}
181
182#[cfg(test)]
183#[path = "../../unit_tests/models/graph/partition_into_forests.rs"]
184mod tests;