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 category: crate::registry::ProblemCategory::Graph,
22 module_path: module_path!(),
23 description: "Does G have a spanning tree with maximum vertex degree at most K?",
24 fields: &[
25 FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
26 FieldInfo { name: "max_degree", type_name: "usize", description: "max_degree: maximum allowed vertex degree K (>= 1)" },
27 ],
28 }
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
59#[serde(bound(deserialize = "G: serde::Deserialize<'de>"))]
60pub struct DegreeConstrainedSpanningTree<G> {
61 graph: G,
63 max_degree: usize,
65 edge_list: Vec<(usize, usize)>,
67}
68
69impl<G: Graph> DegreeConstrainedSpanningTree<G> {
70 pub fn new(graph: G, max_degree: usize) -> Self {
75 assert!(max_degree >= 1, "max_degree must be at least 1");
76 let edge_list = graph.edges();
77 Self {
78 graph,
79 max_degree,
80 edge_list,
81 }
82 }
83
84 pub fn graph(&self) -> &G {
86 &self.graph
87 }
88
89 pub fn max_degree(&self) -> usize {
91 self.max_degree
92 }
93
94 pub fn num_vertices(&self) -> usize {
96 self.graph.num_vertices()
97 }
98
99 pub fn num_edges(&self) -> usize {
101 self.graph.num_edges()
102 }
103
104 pub fn edge_list(&self) -> &[(usize, usize)] {
106 &self.edge_list
107 }
108}
109
110impl<G> Problem for DegreeConstrainedSpanningTree<G>
111where
112 G: Graph + VariantParam,
113{
114 const NAME: &'static str = "DegreeConstrainedSpanningTree";
115 type Solution = Vec<bool>;
116 type Value = crate::types::Or;
117
118 crate::problem_parameters![("num_edges", num_edges), ("num_vertices", num_vertices),];
119
120 fn variant() -> Vec<(&'static str, &'static str)> {
121 crate::variant_params![G]
122 }
123
124 fn evaluate(
125 &self,
126 config: &Self::Solution,
127 ) -> Result<crate::types::Or, crate::traits::EvaluationError> {
128 Ok({
129 crate::types::Or({
130 let n = self.graph.num_vertices();
131 if config.len() != self.edge_list.len() {
132 return Err(crate::traits::EvaluationError::InvalidConfiguration(
133 "edge-selection length does not match the graph".into(),
134 ));
135 }
136
137 let selected: Vec<(usize, usize)> = config
139 .iter()
140 .enumerate()
141 .filter(|(_, &v)| v)
142 .map(|(i, _)| self.edge_list[i])
143 .collect();
144
145 if n == 0 {
147 return Ok(crate::types::Or(selected.is_empty()));
148 }
149 if selected.len() != n - 1 {
150 return Ok(crate::types::Or(false));
151 }
152
153 let mut adj: Vec<Vec<usize>> = vec![Vec::new(); n];
155 let mut degree = vec![0usize; n];
156 for &(u, v) in &selected {
157 adj[u].push(v);
158 adj[v].push(u);
159 degree[u] += 1;
160 degree[v] += 1;
161 }
162
163 if degree.iter().any(|&d| d > self.max_degree) {
165 return Ok(crate::types::Or(false));
166 }
167
168 let mut visited = vec![false; n];
170 let mut queue = VecDeque::new();
171 visited[0] = true;
172 queue.push_back(0);
173 let mut count = 1;
174 while let Some(v) = queue.pop_front() {
175 for &u in &adj[v] {
176 if !visited[u] {
177 visited[u] = true;
178 count += 1;
179 queue.push_back(u);
180 }
181 }
182 }
183
184 count == n
185 })
186 })
187 }
188}
189
190impl<G> crate::solvers::BruteForceProblem for DegreeConstrainedSpanningTree<G>
191where
192 G: Graph + VariantParam,
193{
194 fn dimensions(&self) -> Vec<usize> {
195 vec![2; self.edge_list.len()]
196 }
197}
198
199crate::declare_variants! {
200 default DegreeConstrainedSpanningTree<SimpleGraph> => "2^num_vertices",
201}
202
203crate::register_brute_force! {
204 DegreeConstrainedSpanningTree<SimpleGraph> decode |_, indices: Vec<usize>| crate::config::config_to_bits(&indices),
205}
206
207#[cfg(feature = "example-db")]
208pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
209 vec![crate::example_db::specs::ModelExampleSpec {
214 id: "degree_constrained_spanning_tree_simplegraph",
215 instance: Box::new(DegreeConstrainedSpanningTree::new(
216 SimpleGraph::new(
217 5,
218 vec![(0, 1), (0, 2), (0, 3), (1, 2), (1, 4), (2, 3), (3, 4)],
219 ),
220 2,
221 )),
222 optimal_config: serde_json::json!(vec![false, true, true, true, true, false, false]),
223 optimal_value: serde_json::json!(true),
224 }]
225}
226
227#[cfg(test)]
228#[path = "../../unit_tests/models/graph/degree_constrained_spanning_tree.rs"]
229mod tests;