problemreductions/topology/
unit_disk_graph.rs1use super::graph::Graph;
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
33pub struct UnitDiskGraph {
34 positions: Vec<(f64, f64)>,
36 radius: f64,
38 edges: Vec<(usize, usize)>,
40}
41
42impl UnitDiskGraph {
43 pub fn new(positions: Vec<(f64, f64)>, radius: f64) -> Self {
50 let n = positions.len();
51 let mut edges = Vec::new();
52
53 for i in 0..n {
55 for j in (i + 1)..n {
56 if Self::distance(&positions[i], &positions[j]) <= radius {
57 edges.push((i, j));
58 }
59 }
60 }
61
62 Self {
63 positions,
64 radius,
65 edges,
66 }
67 }
68
69 pub fn unit(positions: Vec<(f64, f64)>) -> Self {
71 Self::new(positions, 1.0)
72 }
73
74 fn distance(p1: &(f64, f64), p2: &(f64, f64)) -> f64 {
76 let dx = p1.0 - p2.0;
77 let dy = p1.1 - p2.1;
78 (dx * dx + dy * dy).sqrt()
79 }
80
81 pub fn num_vertices(&self) -> usize {
83 self.positions.len()
84 }
85
86 pub fn num_edges(&self) -> usize {
88 self.edges.len()
89 }
90
91 pub fn radius(&self) -> f64 {
93 self.radius
94 }
95
96 pub fn position(&self, v: usize) -> Option<(f64, f64)> {
98 self.positions.get(v).copied()
99 }
100
101 pub fn positions(&self) -> &[(f64, f64)] {
103 &self.positions
104 }
105
106 pub fn edges(&self) -> &[(usize, usize)] {
108 &self.edges
109 }
110
111 pub fn has_edge(&self, u: usize, v: usize) -> bool {
113 let (u, v) = if u < v { (u, v) } else { (v, u) };
114 self.edges.contains(&(u, v))
115 }
116
117 pub fn vertex_distance(&self, u: usize, v: usize) -> Option<f64> {
119 match (self.positions.get(u), self.positions.get(v)) {
120 (Some(p1), Some(p2)) => Some(Self::distance(p1, p2)),
121 _ => None,
122 }
123 }
124
125 pub fn neighbors(&self, v: usize) -> Vec<usize> {
127 self.edges
128 .iter()
129 .filter_map(|&(u1, u2)| {
130 if u1 == v {
131 Some(u2)
132 } else if u2 == v {
133 Some(u1)
134 } else {
135 None
136 }
137 })
138 .collect()
139 }
140
141 pub fn degree(&self, v: usize) -> usize {
143 self.neighbors(v).len()
144 }
145
146 pub fn bounding_box(&self) -> Option<((f64, f64), (f64, f64))> {
148 if self.positions.is_empty() {
149 return None;
150 }
151
152 let min_x = self
153 .positions
154 .iter()
155 .map(|p| p.0)
156 .fold(f64::INFINITY, f64::min);
157 let max_x = self
158 .positions
159 .iter()
160 .map(|p| p.0)
161 .fold(f64::NEG_INFINITY, f64::max);
162 let min_y = self
163 .positions
164 .iter()
165 .map(|p| p.1)
166 .fold(f64::INFINITY, f64::min);
167 let max_y = self
168 .positions
169 .iter()
170 .map(|p| p.1)
171 .fold(f64::NEG_INFINITY, f64::max);
172
173 Some(((min_x, min_y), (max_x, max_y)))
174 }
175
176 pub fn grid(rows: usize, cols: usize, spacing: f64, radius: f64) -> Self {
185 let mut positions = Vec::with_capacity(rows * cols);
186 for r in 0..rows {
187 for c in 0..cols {
188 positions.push((c as f64 * spacing, r as f64 * spacing));
189 }
190 }
191 Self::new(positions, radius)
192 }
193}
194
195impl Graph for UnitDiskGraph {
196 const NAME: &'static str = "UnitDiskGraph";
197
198 fn num_vertices(&self) -> usize {
199 self.positions.len()
200 }
201
202 fn num_edges(&self) -> usize {
203 self.edges.len()
204 }
205
206 fn edges(&self) -> Vec<(usize, usize)> {
207 self.edges.clone()
208 }
209
210 fn has_edge(&self, u: usize, v: usize) -> bool {
211 let (u, v) = if u < v { (u, v) } else { (v, u) };
212 self.edges.contains(&(u, v))
213 }
214
215 fn neighbors(&self, v: usize) -> Vec<usize> {
216 self.edges
217 .iter()
218 .filter_map(|&(u1, u2)| {
219 if u1 == v {
220 Some(u2)
221 } else if u2 == v {
222 Some(u1)
223 } else {
224 None
225 }
226 })
227 .collect()
228 }
229}
230
231use super::graph::SimpleGraph;
232use crate::impl_variant_param;
233impl_variant_param!(UnitDiskGraph, "graph", parent: SimpleGraph,
234 cast: |g| SimpleGraph::new(g.num_vertices(), Graph::edges(g)));
235
236#[cfg(test)]
237#[path = "../unit_tests/topology/unit_disk_graph.rs"]
238mod tests;