problemreductions/models/graph/
isomorphic_spanning_tree.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: "IsomorphicSpanningTree",
16 display_name: "Isomorphic Spanning Tree",
17 aliases: &[],
18 dimensions: &[
19 VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph"]),
20 ],
21 module_path: module_path!(),
22 description: "Does graph G contain a spanning tree isomorphic to tree T?",
23 fields: &[
24 FieldInfo { name: "graph", type_name: "G", description: "The host graph G" },
25 FieldInfo { name: "tree", type_name: "SimpleGraph", description: "The target tree T (must be a tree with |V(T)| = |V(G)|)" },
26 ],
27 }
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
57#[serde(bound(deserialize = "G: serde::Deserialize<'de>"))]
58pub struct IsomorphicSpanningTree<G> {
59 graph: G,
60 tree: SimpleGraph,
61}
62
63impl<G: Graph> IsomorphicSpanningTree<G> {
64 pub fn new(graph: G, tree: SimpleGraph) -> Self {
71 let n = graph.num_vertices();
72 assert_eq!(
73 n,
74 tree.num_vertices(),
75 "graph and tree must have the same number of vertices"
76 );
77 assert_eq!(
78 tree.num_edges(),
79 n.saturating_sub(1),
80 "tree must have exactly n-1 edges"
81 );
82 assert!(is_connected(&tree), "tree must be connected");
83 Self { graph, tree }
84 }
85
86 pub fn graph(&self) -> &G {
88 &self.graph
89 }
90
91 pub fn tree(&self) -> &SimpleGraph {
93 &self.tree
94 }
95
96 pub fn num_vertices(&self) -> usize {
98 self.graph.num_vertices()
99 }
100
101 pub fn num_edges(&self) -> usize {
103 self.graph.num_edges()
104 }
105
106 pub fn tree_edges(&self) -> Vec<(usize, usize)> {
108 self.tree.edges()
109 }
110}
111
112impl<G> Problem for IsomorphicSpanningTree<G>
113where
114 G: Graph + VariantParam,
115{
116 const NAME: &'static str = "IsomorphicSpanningTree";
117 type Value = crate::types::Or;
118
119 fn variant() -> Vec<(&'static str, &'static str)> {
120 crate::variant_params![G]
121 }
122
123 fn dims(&self) -> Vec<usize> {
124 vec![self.graph.num_vertices(); self.graph.num_vertices()]
125 }
126
127 fn evaluate(&self, config: &[usize]) -> crate::types::Or {
128 crate::types::Or(is_valid_isomorphic_spanning_tree(
129 &self.graph,
130 &self.tree,
131 config,
132 ))
133 }
134}
135
136fn is_valid_isomorphic_spanning_tree<G: Graph>(
137 graph: &G,
138 tree: &SimpleGraph,
139 config: &[usize],
140) -> bool {
141 let n = graph.num_vertices();
142 if config.len() != n {
143 return false;
144 }
145
146 let mut seen = vec![false; n];
147 for &v in config {
148 if v >= n || seen[v] {
149 return false;
150 }
151 seen[v] = true;
152 }
153
154 tree.edges()
155 .into_iter()
156 .all(|(u, v)| graph.has_edge(config[u], config[v]))
157}
158
159fn is_connected(graph: &SimpleGraph) -> bool {
160 let n = graph.num_vertices();
161 if n == 0 {
162 return true;
163 }
164
165 let mut visited = vec![false; n];
166 let mut queue = std::collections::VecDeque::new();
167 visited[0] = true;
168 queue.push_back(0);
169 let mut count = 1;
170
171 while let Some(v) = queue.pop_front() {
172 for u in graph.neighbors(v) {
173 if !visited[u] {
174 visited[u] = true;
175 count += 1;
176 queue.push_back(u);
177 }
178 }
179 }
180
181 count == n
182}
183
184#[cfg(feature = "example-db")]
185pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
186 vec![crate::example_db::specs::ModelExampleSpec {
187 id: "isomorphic_spanning_tree",
188 instance: Box::new(IsomorphicSpanningTree::new(
189 SimpleGraph::new(4, vec![(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]),
190 SimpleGraph::new(4, vec![(0, 1), (0, 2), (0, 3)]),
191 )),
192 optimal_config: vec![0, 1, 2, 3],
193 optimal_value: serde_json::json!(true),
194 }]
195}
196
197crate::declare_variants! {
198 default IsomorphicSpanningTree<SimpleGraph> => "2^num_vertices",
199}
200
201#[cfg(test)]
202#[path = "../../unit_tests/models/graph/isomorphic_spanning_tree.rs"]
203mod tests;