problemreductions/models/misc/
optimum_communication_spanning_tree.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
9use crate::traits::Problem;
10use crate::types::Min;
11use serde::{Deserialize, Serialize};
12use std::collections::VecDeque;
13
14inventory::submit! {
15 ProblemSchemaEntry {
16 name: "OptimumCommunicationSpanningTree",
17 display_name: "Optimum Communication Spanning Tree",
18 aliases: &["OCST"],
19 dimensions: &[],
20 module_path: module_path!(),
21 description: "Find spanning tree minimizing total weighted communication cost",
22 fields: &[
23 FieldInfo { name: "num_vertices", type_name: "usize", description: "Number of vertices n" },
24 FieldInfo { name: "edge_weights", type_name: "Vec<Vec<i32>>", description: "Symmetric weight matrix w(i,j)" },
25 FieldInfo { name: "requirements", type_name: "Vec<Vec<i32>>", description: "Symmetric requirement matrix r(i,j)" },
26 ],
27 }
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
69pub struct OptimumCommunicationSpanningTree {
70 num_vertices: usize,
71 edge_weights: Vec<Vec<i32>>,
72 requirements: Vec<Vec<i32>>,
73}
74
75impl OptimumCommunicationSpanningTree {
76 pub fn new(edge_weights: Vec<Vec<i32>>, requirements: Vec<Vec<i32>>) -> Self {
88 let n = edge_weights.len();
89 assert!(n >= 2, "must have at least 2 vertices");
90 assert_eq!(
91 requirements.len(),
92 n,
93 "requirements matrix must have same size as edge_weights"
94 );
95
96 for (i, row) in edge_weights.iter().enumerate() {
97 assert_eq!(
98 row.len(),
99 n,
100 "edge_weights must be square: row {i} has length {} but expected {n}",
101 row.len()
102 );
103 assert_eq!(
104 row[i], 0,
105 "diagonal of edge_weights must be zero: edge_weights[{i}][{i}] = {}",
106 row[i]
107 );
108 }
109
110 for (i, row) in requirements.iter().enumerate() {
111 assert_eq!(
112 row.len(),
113 n,
114 "requirements must be square: row {i} has length {} but expected {n}",
115 row.len()
116 );
117 assert_eq!(
118 row[i], 0,
119 "diagonal of requirements must be zero: requirements[{i}][{i}] = {}",
120 row[i]
121 );
122 }
123
124 for i in 0..n {
126 for j in (i + 1)..n {
127 assert_eq!(
128 edge_weights[i][j], edge_weights[j][i],
129 "edge_weights must be symmetric: w[{i}][{j}]={} != w[{j}][{i}]={}",
130 edge_weights[i][j], edge_weights[j][i]
131 );
132 assert!(
133 edge_weights[i][j] >= 0,
134 "edge_weights must be non-negative: w[{i}][{j}]={}",
135 edge_weights[i][j]
136 );
137 assert_eq!(
138 requirements[i][j], requirements[j][i],
139 "requirements must be symmetric: r[{i}][{j}]={} != r[{j}][{i}]={}",
140 requirements[i][j], requirements[j][i]
141 );
142 assert!(
143 requirements[i][j] >= 0,
144 "requirements must be non-negative: r[{i}][{j}]={}",
145 requirements[i][j]
146 );
147 }
148 }
149
150 Self {
151 num_vertices: n,
152 edge_weights,
153 requirements,
154 }
155 }
156
157 pub fn num_vertices(&self) -> usize {
159 self.num_vertices
160 }
161
162 pub fn num_edges(&self) -> usize {
164 self.num_vertices * (self.num_vertices - 1) / 2
165 }
166
167 pub fn edge_weights(&self) -> &Vec<Vec<i32>> {
169 &self.edge_weights
170 }
171
172 pub fn requirements(&self) -> &Vec<Vec<i32>> {
174 &self.requirements
175 }
176
177 pub fn edges(&self) -> Vec<(usize, usize)> {
179 let n = self.num_vertices;
180 let mut edges = Vec::with_capacity(self.num_edges());
181 for i in 0..n {
182 for j in (i + 1)..n {
183 edges.push((i, j));
184 }
185 }
186 edges
187 }
188
189 pub fn edge_index(i: usize, j: usize, n: usize) -> usize {
191 debug_assert!(i < j && j < n);
192 i * n - i * (i + 1) / 2 + (j - i - 1)
193 }
194}
195
196fn is_valid_spanning_tree(n: usize, edges: &[(usize, usize)], config: &[usize]) -> bool {
198 if config.len() != edges.len() {
199 return false;
200 }
201
202 if config.iter().any(|&v| v > 1) {
204 return false;
205 }
206
207 let selected_count: usize = config.iter().sum();
209 if selected_count != n - 1 {
210 return false;
211 }
212
213 let mut adj: Vec<Vec<usize>> = vec![vec![]; n];
215 for (idx, &sel) in config.iter().enumerate() {
216 if sel == 1 {
217 let (u, v) = edges[idx];
218 adj[u].push(v);
219 adj[v].push(u);
220 }
221 }
222
223 let mut visited = vec![false; n];
224 let mut queue = VecDeque::new();
225 visited[0] = true;
226 queue.push_back(0);
227 while let Some(v) = queue.pop_front() {
228 for &u in &adj[v] {
229 if !visited[u] {
230 visited[u] = true;
231 queue.push_back(u);
232 }
233 }
234 }
235
236 visited.iter().all(|&v| v)
237}
238
239fn communication_cost(
244 n: usize,
245 edges: &[(usize, usize)],
246 config: &[usize],
247 edge_weights: &[Vec<i32>],
248 requirements: &[Vec<i32>],
249) -> i64 {
250 let mut adj: Vec<Vec<(usize, i32)>> = vec![vec![]; n];
252 for (idx, &sel) in config.iter().enumerate() {
253 if sel == 1 {
254 let (u, v) = edges[idx];
255 let w = edge_weights[u][v];
256 adj[u].push((v, w));
257 adj[v].push((u, w));
258 }
259 }
260
261 let mut total_cost: i64 = 0;
262
263 for src in 0..n {
265 let mut dist = vec![-1i64; n];
266 dist[src] = 0;
267 let mut queue = VecDeque::new();
268 queue.push_back(src);
269 while let Some(u) = queue.pop_front() {
270 for &(v, w) in &adj[u] {
271 if dist[v] < 0 {
272 dist[v] = dist[u] + w as i64;
273 queue.push_back(v);
274 }
275 }
276 }
277
278 for (dst, &d) in dist.iter().enumerate().skip(src + 1) {
280 total_cost += requirements[src][dst] as i64 * d;
281 }
282 }
283
284 total_cost
285}
286
287impl Problem for OptimumCommunicationSpanningTree {
288 const NAME: &'static str = "OptimumCommunicationSpanningTree";
289 type Value = Min<i64>;
290
291 fn variant() -> Vec<(&'static str, &'static str)> {
292 crate::variant_params![]
293 }
294
295 fn dims(&self) -> Vec<usize> {
296 vec![2; self.num_edges()]
297 }
298
299 fn evaluate(&self, config: &[usize]) -> Min<i64> {
300 let edges = self.edges();
301 if !is_valid_spanning_tree(self.num_vertices, &edges, config) {
302 return Min(None);
303 }
304 Min(Some(communication_cost(
305 self.num_vertices,
306 &edges,
307 config,
308 &self.edge_weights,
309 &self.requirements,
310 )))
311 }
312}
313
314crate::declare_variants! {
315 default OptimumCommunicationSpanningTree => "2^num_edges",
316}
317
318#[cfg(feature = "example-db")]
319pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
320 let edge_weights = vec![
328 vec![0, 1, 3, 2],
329 vec![1, 0, 2, 4],
330 vec![3, 2, 0, 1],
331 vec![2, 4, 1, 0],
332 ];
333 let requirements = vec![
334 vec![0, 2, 1, 3],
335 vec![2, 0, 1, 1],
336 vec![1, 1, 0, 2],
337 vec![3, 1, 2, 0],
338 ];
339 vec![crate::example_db::specs::ModelExampleSpec {
342 id: "optimum_communication_spanning_tree",
343 instance: Box::new(OptimumCommunicationSpanningTree::new(
344 edge_weights,
345 requirements,
346 )),
347 optimal_config: vec![1, 0, 1, 0, 0, 1],
348 optimal_value: serde_json::json!(20),
349 }]
350}
351
352#[cfg(test)]
353#[path = "../../unit_tests/models/misc/optimum_communication_spanning_tree.rs"]
354mod tests;