problemreductions/topology/
hypergraph.rs1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
25pub struct HyperGraph {
26 num_vertices: usize,
27 edges: Vec<Vec<usize>>,
28}
29
30impl HyperGraph {
31 pub fn new(num_vertices: usize, edges: Vec<Vec<usize>>) -> Self {
37 for edge in &edges {
38 for &v in edge {
39 assert!(v < num_vertices, "vertex index {} out of bounds (max {})", v, num_vertices - 1);
40 }
41 }
42 Self { num_vertices, edges }
43 }
44
45 pub fn empty(num_vertices: usize) -> Self {
47 Self {
48 num_vertices,
49 edges: Vec::new(),
50 }
51 }
52
53 pub fn num_vertices(&self) -> usize {
55 self.num_vertices
56 }
57
58 pub fn num_edges(&self) -> usize {
60 self.edges.len()
61 }
62
63 pub fn edges(&self) -> &[Vec<usize>] {
65 &self.edges
66 }
67
68 pub fn edge(&self, index: usize) -> Option<&Vec<usize>> {
70 self.edges.get(index)
71 }
72
73 pub fn has_edge(&self, edge: &[usize]) -> bool {
75 let mut sorted = edge.to_vec();
76 sorted.sort();
77 self.edges.iter().any(|e| {
78 let mut e_sorted = e.clone();
79 e_sorted.sort();
80 e_sorted == sorted
81 })
82 }
83
84 pub fn neighbors(&self, v: usize) -> Vec<usize> {
86 let mut neighbors = Vec::new();
87 for edge in &self.edges {
88 if edge.contains(&v) {
89 for &u in edge {
90 if u != v && !neighbors.contains(&u) {
91 neighbors.push(u);
92 }
93 }
94 }
95 }
96 neighbors
97 }
98
99 pub fn degree(&self, v: usize) -> usize {
101 self.edges.iter().filter(|edge| edge.contains(&v)).count()
102 }
103
104 pub fn edges_containing(&self, v: usize) -> Vec<&Vec<usize>> {
106 self.edges.iter().filter(|edge| edge.contains(&v)).collect()
107 }
108
109 pub fn add_edge(&mut self, edge: Vec<usize>) {
115 for &v in &edge {
116 assert!(v < self.num_vertices, "vertex index {} out of bounds", v);
117 }
118 self.edges.push(edge);
119 }
120
121 pub fn max_edge_size(&self) -> usize {
123 self.edges.iter().map(|e| e.len()).max().unwrap_or(0)
124 }
125
126 pub fn is_regular_graph(&self) -> bool {
128 self.edges.iter().all(|e| e.len() == 2)
129 }
130
131 pub fn to_graph_edges(&self) -> Option<Vec<(usize, usize)>> {
134 if !self.is_regular_graph() {
135 return None;
136 }
137 Some(
138 self.edges
139 .iter()
140 .map(|e| (e[0], e[1]))
141 .collect()
142 )
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149
150 #[test]
151 fn test_hypergraph_basic() {
152 let hg = HyperGraph::new(4, vec![vec![0, 1, 2], vec![2, 3]]);
153 assert_eq!(hg.num_vertices(), 4);
154 assert_eq!(hg.num_edges(), 2);
155 }
156
157 #[test]
158 fn test_hypergraph_empty() {
159 let hg = HyperGraph::empty(5);
160 assert_eq!(hg.num_vertices(), 5);
161 assert_eq!(hg.num_edges(), 0);
162 }
163
164 #[test]
165 fn test_hypergraph_neighbors() {
166 let hg = HyperGraph::new(4, vec![vec![0, 1, 2], vec![2, 3]]);
167 let neighbors = hg.neighbors(2);
168 assert!(neighbors.contains(&0));
169 assert!(neighbors.contains(&1));
170 assert!(neighbors.contains(&3));
171 assert!(!neighbors.contains(&2)); }
173
174 #[test]
175 fn test_hypergraph_has_edge() {
176 let hg = HyperGraph::new(4, vec![vec![0, 1, 2]]);
177 assert!(hg.has_edge(&[0, 1, 2]));
178 assert!(hg.has_edge(&[2, 1, 0])); assert!(!hg.has_edge(&[0, 1]));
180 assert!(!hg.has_edge(&[0, 1, 3]));
181 }
182
183 #[test]
184 fn test_hypergraph_degree() {
185 let hg = HyperGraph::new(4, vec![vec![0, 1, 2], vec![2, 3]]);
186 assert_eq!(hg.degree(0), 1);
187 assert_eq!(hg.degree(2), 2);
188 assert_eq!(hg.degree(3), 1);
189 }
190
191 #[test]
192 fn test_hypergraph_edges_containing() {
193 let hg = HyperGraph::new(4, vec![vec![0, 1, 2], vec![2, 3]]);
194 let edges = hg.edges_containing(2);
195 assert_eq!(edges.len(), 2);
196 }
197
198 #[test]
199 fn test_hypergraph_add_edge() {
200 let mut hg = HyperGraph::empty(4);
201 hg.add_edge(vec![0, 1]);
202 hg.add_edge(vec![1, 2, 3]);
203 assert_eq!(hg.num_edges(), 2);
204 }
205
206 #[test]
207 fn test_hypergraph_max_edge_size() {
208 let hg = HyperGraph::new(4, vec![vec![0, 1], vec![0, 1, 2, 3]]);
209 assert_eq!(hg.max_edge_size(), 4);
210 }
211
212 #[test]
213 fn test_hypergraph_is_regular_graph() {
214 let regular = HyperGraph::new(3, vec![vec![0, 1], vec![1, 2]]);
215 assert!(regular.is_regular_graph());
216
217 let not_regular = HyperGraph::new(4, vec![vec![0, 1, 2]]);
218 assert!(!not_regular.is_regular_graph());
219 }
220
221 #[test]
222 fn test_hypergraph_to_graph_edges() {
223 let hg = HyperGraph::new(3, vec![vec![0, 1], vec![1, 2]]);
224 let edges = hg.to_graph_edges();
225 assert!(edges.is_some());
226 let edges = edges.unwrap();
227 assert_eq!(edges.len(), 2);
228 }
229
230 #[test]
231 fn test_hypergraph_get_edge() {
232 let hg = HyperGraph::new(4, vec![vec![0, 1, 2], vec![2, 3]]);
233 assert_eq!(hg.edge(0), Some(&vec![0, 1, 2]));
234 assert_eq!(hg.edge(1), Some(&vec![2, 3]));
235 assert_eq!(hg.edge(2), None);
236 }
237
238 #[test]
239 #[should_panic(expected = "vertex index 5 out of bounds")]
240 fn test_hypergraph_invalid_vertex() {
241 HyperGraph::new(4, vec![vec![0, 5]]);
242 }
243
244 #[test]
245 #[should_panic(expected = "vertex index 4 out of bounds")]
246 fn test_hypergraph_add_invalid_edge() {
247 let mut hg = HyperGraph::empty(4);
248 hg.add_edge(vec![0, 4]);
249 }
250}