problemreductions/models/graph/
rooted_tree_arrangement.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: "RootedTreeArrangement",
16 display_name: "Rooted Tree Arrangement",
17 aliases: &[],
18 dimensions: &[
19 VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph"]),
20 ],
21 module_path: module_path!(),
22 description: "Find a rooted-tree embedding of a graph with bounded total edge stretch",
23 fields: &[
24 FieldInfo { name: "graph", type_name: "G", description: "The undirected graph G=(V,E)" },
25 FieldInfo { name: "bound", type_name: "usize", description: "Upper bound K on total tree stretch" },
26 ],
27 }
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
31#[serde(bound(deserialize = "G: serde::Deserialize<'de>"))]
32pub struct RootedTreeArrangement<G> {
33 graph: G,
34 bound: usize,
35}
36
37#[derive(Debug, Clone)]
38struct TreeInfo {
39 depth: Vec<usize>,
40}
41
42impl<G: Graph> RootedTreeArrangement<G> {
43 pub fn new(graph: G, bound: usize) -> Self {
44 Self { graph, bound }
45 }
46
47 pub fn graph(&self) -> &G {
48 &self.graph
49 }
50
51 pub fn bound(&self) -> usize {
52 self.bound
53 }
54
55 pub fn num_vertices(&self) -> usize {
56 self.graph.num_vertices()
57 }
58
59 pub fn num_edges(&self) -> usize {
60 self.graph.num_edges()
61 }
62
63 pub fn is_valid_solution(&self, config: &[usize]) -> bool {
64 matches!(self.total_edge_stretch(config), Some(stretch) if stretch <= self.bound)
65 }
66
67 pub fn total_edge_stretch(&self, config: &[usize]) -> Option<usize> {
68 let n = self.graph.num_vertices();
69 if n == 0 {
70 return config.is_empty().then_some(0);
71 }
72
73 let (parent, mapping) = self.split_config(config)?;
74 let tree = analyze_parent_array(parent)?;
75 if !is_valid_permutation(mapping) {
76 return None;
77 }
78
79 let mut total = 0usize;
80 for (u, v) in self.graph.edges() {
81 let tree_u = mapping[u];
82 let tree_v = mapping[v];
83 if !are_ancestor_comparable(parent, tree_u, tree_v) {
84 return None;
85 }
86 total += tree.depth[tree_u].abs_diff(tree.depth[tree_v]);
87 }
88
89 Some(total)
90 }
91
92 fn split_config<'a>(&self, config: &'a [usize]) -> Option<(&'a [usize], &'a [usize])> {
93 let n = self.graph.num_vertices();
94 (config.len() == 2 * n).then(|| config.split_at(n))
95 }
96}
97
98impl<G> Problem for RootedTreeArrangement<G>
99where
100 G: Graph + VariantParam,
101{
102 const NAME: &'static str = "RootedTreeArrangement";
103 type Value = crate::types::Or;
104
105 fn variant() -> Vec<(&'static str, &'static str)> {
106 crate::variant_params![G]
107 }
108
109 fn dims(&self) -> Vec<usize> {
110 let n = self.graph.num_vertices();
111 vec![n; 2 * n]
112 }
113
114 fn evaluate(&self, config: &[usize]) -> crate::types::Or {
115 crate::types::Or(self.is_valid_solution(config))
116 }
117}
118
119fn analyze_parent_array(parent: &[usize]) -> Option<TreeInfo> {
120 let n = parent.len();
121 if n == 0 {
122 return Some(TreeInfo { depth: vec![] });
123 }
124
125 if parent.iter().any(|&p| p >= n) {
126 return None;
127 }
128
129 let roots = parent
130 .iter()
131 .enumerate()
132 .filter_map(|(node, &p)| (node == p).then_some(node))
133 .collect::<Vec<_>>();
134 if roots.len() != 1 {
135 return None;
136 }
137 let root = roots[0];
138
139 let mut state = vec![0u8; n];
140 let mut depth = vec![0usize; n];
141
142 fn visit(
143 node: usize,
144 root: usize,
145 parent: &[usize],
146 state: &mut [u8],
147 depth: &mut [usize],
148 ) -> Option<usize> {
149 match state[node] {
150 1 => return None,
151 2 => return Some(depth[node]),
152 _ => {}
153 }
154
155 state[node] = 1;
156 let d = if node == root {
157 0
158 } else {
159 let next = parent[node];
160 if next == node {
161 return None;
162 }
163 visit(next, root, parent, state, depth)? + 1
164 };
165 depth[node] = d;
166 state[node] = 2;
167 Some(d)
168 }
169
170 for node in 0..n {
171 visit(node, root, parent, &mut state, &mut depth)?;
172 }
173
174 Some(TreeInfo { depth })
175}
176
177fn is_valid_permutation(mapping: &[usize]) -> bool {
178 let n = mapping.len();
179 let mut seen = vec![false; n];
180 for &image in mapping {
181 if image >= n || seen[image] {
182 return false;
183 }
184 seen[image] = true;
185 }
186 true
187}
188
189fn is_ancestor(parent: &[usize], ancestor: usize, descendant: usize) -> bool {
190 let mut current = descendant;
191 loop {
192 if current == ancestor {
193 return true;
194 }
195 let next = parent[current];
196 if next == current {
197 return false;
198 }
199 current = next;
200 }
201}
202
203fn are_ancestor_comparable(parent: &[usize], u: usize, v: usize) -> bool {
204 is_ancestor(parent, u, v) || is_ancestor(parent, v, u)
205}
206
207crate::declare_variants! {
208 default RootedTreeArrangement<SimpleGraph> => "2^num_vertices",
209}
210
211#[cfg(feature = "example-db")]
212pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
213 vec![crate::example_db::specs::ModelExampleSpec {
214 id: "rooted_tree_arrangement_simplegraph",
215 instance: Box::new(RootedTreeArrangement::new(
216 SimpleGraph::new(4, vec![(0, 1), (0, 2), (1, 2), (2, 3)]),
217 5,
218 )),
219 optimal_config: vec![0, 0, 1, 2, 0, 1, 2, 3],
220 optimal_value: serde_json::json!(true),
221 }]
222}
223
224#[cfg(test)]
225#[path = "../../unit_tests/models/graph/rooted_tree_arrangement.rs"]
226mod tests;