ruvector_math/homology/
simplex.rs1use std::collections::{HashMap, HashSet};
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash)]
9pub struct Simplex {
10 pub vertices: Vec<usize>,
12}
13
14impl Simplex {
15 pub fn new(mut vertices: Vec<usize>) -> Self {
17 vertices.sort_unstable();
18 vertices.dedup();
19 Self { vertices }
20 }
21
22 pub fn vertex(v: usize) -> Self {
24 Self { vertices: vec![v] }
25 }
26
27 pub fn edge(v0: usize, v1: usize) -> Self {
29 Self::new(vec![v0, v1])
30 }
31
32 pub fn triangle(v0: usize, v1: usize, v2: usize) -> Self {
34 Self::new(vec![v0, v1, v2])
35 }
36
37 pub fn dim(&self) -> usize {
39 if self.vertices.is_empty() {
40 0
41 } else {
42 self.vertices.len() - 1
43 }
44 }
45
46 pub fn is_vertex(&self) -> bool {
48 self.vertices.len() == 1
49 }
50
51 pub fn is_edge(&self) -> bool {
53 self.vertices.len() == 2
54 }
55
56 pub fn faces(&self) -> Vec<Simplex> {
58 if self.vertices.len() <= 1 {
59 return vec![];
60 }
61
62 (0..self.vertices.len())
63 .map(|i| {
64 let face_verts: Vec<usize> = self
65 .vertices
66 .iter()
67 .enumerate()
68 .filter(|&(j, _)| j != i)
69 .map(|(_, &v)| v)
70 .collect();
71 Simplex::new(face_verts)
72 })
73 .collect()
74 }
75
76 pub fn is_face_of(&self, other: &Simplex) -> bool {
78 if self.vertices.len() >= other.vertices.len() {
79 return false;
80 }
81 self.vertices.iter().all(|v| other.vertices.contains(v))
82 }
83
84 pub fn shares_face_with(&self, other: &Simplex) -> bool {
86 let intersection: Vec<usize> = self
87 .vertices
88 .iter()
89 .filter(|v| other.vertices.contains(v))
90 .copied()
91 .collect();
92 !intersection.is_empty()
93 }
94}
95
96#[derive(Debug, Clone)]
98pub struct SimplicialComplex {
99 simplices: Vec<HashSet<Simplex>>,
101 max_dim: usize,
103}
104
105impl SimplicialComplex {
106 pub fn new() -> Self {
108 Self {
109 simplices: vec![HashSet::new()],
110 max_dim: 0,
111 }
112 }
113
114 pub fn from_simplices(simplices: Vec<Simplex>) -> Self {
116 let mut complex = Self::new();
117 for s in simplices {
118 complex.add(s);
119 }
120 complex
121 }
122
123 pub fn add(&mut self, simplex: Simplex) {
125 let dim = simplex.dim();
126
127 while self.simplices.len() <= dim {
129 self.simplices.push(HashSet::new());
130 }
131 self.max_dim = self.max_dim.max(dim);
132
133 self.add_with_faces(simplex);
135 }
136
137 fn add_with_faces(&mut self, simplex: Simplex) {
138 let dim = simplex.dim();
139
140 if self.simplices[dim].contains(&simplex) {
141 return; }
143
144 for face in simplex.faces() {
146 self.add_with_faces(face);
147 }
148
149 self.simplices[dim].insert(simplex);
151 }
152
153 pub fn contains(&self, simplex: &Simplex) -> bool {
155 let dim = simplex.dim();
156 if dim >= self.simplices.len() {
157 return false;
158 }
159 self.simplices[dim].contains(simplex)
160 }
161
162 pub fn simplices_of_dim(&self, d: usize) -> impl Iterator<Item = &Simplex> {
164 self.simplices.get(d).into_iter().flat_map(|s| s.iter())
165 }
166
167 pub fn all_simplices(&self) -> impl Iterator<Item = &Simplex> {
169 self.simplices.iter().flat_map(|s| s.iter())
170 }
171
172 pub fn count_dim(&self, d: usize) -> usize {
174 self.simplices.get(d).map(|s| s.len()).unwrap_or(0)
175 }
176
177 pub fn size(&self) -> usize {
179 self.simplices.iter().map(|s| s.len()).sum()
180 }
181
182 pub fn dimension(&self) -> usize {
184 self.max_dim
185 }
186
187 pub fn f_vector(&self) -> Vec<usize> {
189 self.simplices.iter().map(|s| s.len()).collect()
190 }
191
192 pub fn euler_characteristic(&self) -> i64 {
194 self.simplices
195 .iter()
196 .enumerate()
197 .map(|(d, s)| {
198 let sign = if d % 2 == 0 { 1 } else { -1 };
199 sign * s.len() as i64
200 })
201 .sum()
202 }
203
204 pub fn vertices(&self) -> HashSet<usize> {
206 self.simplices_of_dim(0)
207 .flat_map(|s| s.vertices.iter().copied())
208 .collect()
209 }
210
211 pub fn edges(&self) -> Vec<(usize, usize)> {
213 self.simplices_of_dim(1)
214 .filter_map(|s| {
215 if s.vertices.len() == 2 {
216 Some((s.vertices[0], s.vertices[1]))
217 } else {
218 None
219 }
220 })
221 .collect()
222 }
223}
224
225impl Default for SimplicialComplex {
226 fn default() -> Self {
227 Self::new()
228 }
229}
230
231#[cfg(test)]
232mod tests {
233 use super::*;
234
235 #[test]
236 fn test_simplex_creation() {
237 let vertex = Simplex::vertex(0);
238 assert_eq!(vertex.dim(), 0);
239
240 let edge = Simplex::edge(0, 1);
241 assert_eq!(edge.dim(), 1);
242
243 let triangle = Simplex::triangle(0, 1, 2);
244 assert_eq!(triangle.dim(), 2);
245 }
246
247 #[test]
248 fn test_simplex_faces() {
249 let triangle = Simplex::triangle(0, 1, 2);
250 let faces = triangle.faces();
251
252 assert_eq!(faces.len(), 3);
253 assert!(faces.contains(&Simplex::edge(0, 1)));
254 assert!(faces.contains(&Simplex::edge(0, 2)));
255 assert!(faces.contains(&Simplex::edge(1, 2)));
256 }
257
258 #[test]
259 fn test_simplicial_complex() {
260 let mut complex = SimplicialComplex::new();
261 complex.add(Simplex::triangle(0, 1, 2));
262
263 assert_eq!(complex.count_dim(0), 3);
265 assert_eq!(complex.count_dim(1), 3);
266 assert_eq!(complex.count_dim(2), 1);
267
268 assert_eq!(complex.euler_characteristic(), 1); }
270
271 #[test]
272 fn test_f_vector() {
273 let complex = SimplicialComplex::from_simplices(vec![
274 Simplex::triangle(0, 1, 2),
275 Simplex::triangle(1, 2, 3),
276 ]);
277
278 let f = complex.f_vector();
279 assert_eq!(f[0], 4); assert_eq!(f[1], 5); assert_eq!(f[2], 2); }
283
284 #[test]
285 fn test_is_face_of() {
286 let edge = Simplex::edge(0, 1);
287 let triangle = Simplex::triangle(0, 1, 2);
288
289 assert!(edge.is_face_of(&triangle));
290 assert!(!triangle.is_face_of(&edge));
291 }
292}