problemreductions/models/graph/
degree_constrained_spanning_tree.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry, VariantDimension};
7use crate::topology::{Graph, SimpleGraph};
8use crate::traits::Problem;
9use crate::variant::VariantParam;
10use serde::{Deserialize, Serialize};
11use std::collections::VecDeque;
12
13inventory::submit! {
14 ProblemSchemaEntry {
15 name: "DegreeConstrainedSpanningTree",
16 display_name: "Degree-Constrained Spanning Tree",
17 aliases: &[],
18 dimensions: &[
19 VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph"]),
20 ],
21 module_path: module_path!(),
22 description: "Does G have a spanning tree with maximum vertex degree at most K?",
23 fields: &[
24 FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
25 FieldInfo { name: "max_degree", type_name: "usize", description: "max_degree: maximum allowed vertex degree K (>= 1)" },
26 ],
27 }
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
58#[serde(bound(deserialize = "G: serde::Deserialize<'de>"))]
59pub struct DegreeConstrainedSpanningTree<G> {
60 graph: G,
62 max_degree: usize,
64 edge_list: Vec<(usize, usize)>,
66}
67
68impl<G: Graph> DegreeConstrainedSpanningTree<G> {
69 pub fn new(graph: G, max_degree: usize) -> Self {
74 assert!(max_degree >= 1, "max_degree must be at least 1");
75 let edge_list = graph.edges();
76 Self {
77 graph,
78 max_degree,
79 edge_list,
80 }
81 }
82
83 pub fn graph(&self) -> &G {
85 &self.graph
86 }
87
88 pub fn max_degree(&self) -> usize {
90 self.max_degree
91 }
92
93 pub fn num_vertices(&self) -> usize {
95 self.graph.num_vertices()
96 }
97
98 pub fn num_edges(&self) -> usize {
100 self.graph.num_edges()
101 }
102
103 pub fn edge_list(&self) -> &[(usize, usize)] {
105 &self.edge_list
106 }
107}
108
109impl<G> Problem for DegreeConstrainedSpanningTree<G>
110where
111 G: Graph + VariantParam,
112{
113 const NAME: &'static str = "DegreeConstrainedSpanningTree";
114 type Value = crate::types::Or;
115
116 fn variant() -> Vec<(&'static str, &'static str)> {
117 crate::variant_params![G]
118 }
119
120 fn dims(&self) -> Vec<usize> {
121 vec![2; self.edge_list.len()]
122 }
123
124 fn evaluate(&self, config: &[usize]) -> crate::types::Or {
125 crate::types::Or({
126 let n = self.graph.num_vertices();
127 if config.len() != self.edge_list.len() {
128 return crate::types::Or(false);
129 }
130
131 let selected: Vec<(usize, usize)> = config
133 .iter()
134 .enumerate()
135 .filter(|(_, &v)| v == 1)
136 .map(|(i, _)| self.edge_list[i])
137 .collect();
138
139 if n == 0 {
141 return crate::types::Or(selected.is_empty());
142 }
143 if selected.len() != n - 1 {
144 return crate::types::Or(false);
145 }
146
147 let mut adj: Vec<Vec<usize>> = vec![Vec::new(); n];
149 let mut degree = vec![0usize; n];
150 for &(u, v) in &selected {
151 adj[u].push(v);
152 adj[v].push(u);
153 degree[u] += 1;
154 degree[v] += 1;
155 }
156
157 if degree.iter().any(|&d| d > self.max_degree) {
159 return crate::types::Or(false);
160 }
161
162 let mut visited = vec![false; n];
164 let mut queue = VecDeque::new();
165 visited[0] = true;
166 queue.push_back(0);
167 let mut count = 1;
168 while let Some(v) = queue.pop_front() {
169 for &u in &adj[v] {
170 if !visited[u] {
171 visited[u] = true;
172 count += 1;
173 queue.push_back(u);
174 }
175 }
176 }
177
178 count == n
179 })
180 }
181}
182
183crate::declare_variants! {
184 default DegreeConstrainedSpanningTree<SimpleGraph> => "2^num_vertices",
185}
186
187#[cfg(feature = "example-db")]
188pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
189 vec![crate::example_db::specs::ModelExampleSpec {
194 id: "degree_constrained_spanning_tree_simplegraph",
195 instance: Box::new(DegreeConstrainedSpanningTree::new(
196 SimpleGraph::new(
197 5,
198 vec![(0, 1), (0, 2), (0, 3), (1, 2), (1, 4), (2, 3), (3, 4)],
199 ),
200 2,
201 )),
202 optimal_config: vec![0, 1, 1, 1, 1, 0, 0],
203 optimal_value: serde_json::json!(true),
204 }]
205}
206
207#[cfg(test)]
208#[path = "../../unit_tests/models/graph/degree_constrained_spanning_tree.rs"]
209mod tests;