1use std::collections::{HashMap, HashSet};
2
3use super::*;
4
5#[derive(Clone)]
6pub struct SCSpxInfo<
7 FS: OrderedRingStructure + FieldStructure,
8 SP: Borrow<AffineSpace<FS>> + Clone,
9 T: Eq + Clone,
10> {
11 inv_bdry: HashSet<Simplex<FS, SP>>,
12 label: T,
13}
14
15impl<FS: OrderedRingStructure + FieldStructure, SP: Borrow<AffineSpace<FS>> + Clone, T: Eq + Clone>
16 std::fmt::Debug for SCSpxInfo<FS, SP, T>
17{
18 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19 f.debug_struct("SCSpxInfo")
20 .field("inv_bdry", &self.inv_bdry)
21 .finish()
22 }
23}
24
25#[derive(Clone)]
26pub struct LabelledSimplicialComplex<
27 FS: OrderedRingStructure + FieldStructure,
28 SP: Borrow<AffineSpace<FS>> + Clone,
29 T: Eq + Clone,
30> {
31 ambient_space: SP,
32 simplexes: HashMap<Simplex<FS, SP>, SCSpxInfo<FS, SP, T>>,
33}
34
35pub type SimplicialComplex<FS, SP> = LabelledSimplicialComplex<FS, SP, ()>;
36
37impl<FS: OrderedRingStructure + FieldStructure, SP: Borrow<AffineSpace<FS>> + Clone, T: Eq + Clone>
38 std::fmt::Debug for LabelledSimplicialComplex<FS, SP, T>
39{
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 f.debug_struct("SimplicialComplex")
42 .field("simplexes", &self.simplexes)
43 .finish()
44 }
45}
46
47impl<FS: OrderedRingStructure + FieldStructure, SP: Borrow<AffineSpace<FS>> + Clone, T: Eq + Clone>
48 LabelledSimplexCollection<FS, SP, T> for LabelledSimplicialComplex<FS, SP, T>
49where
50 FS::Set: Hash,
51{
52 type WithLabel<S: Eq + Clone> = LabelledSimplicialComplex<FS, SP, S>;
53 type SubsetType = LabelledPartialSimplicialComplex<FS, SP, T>;
54
55 fn new_labelled(
56 ambient_space: SP,
57 simplexes: HashMap<Simplex<FS, SP>, T>,
58 ) -> Result<Self, &'static str> {
59 for simplex in simplexes.keys() {
60 assert_eq!(simplex.ambient_space().borrow(), ambient_space.borrow());
61 if simplex.points().len() == 0 {
62 return Err("Simplicial complex musn't contain the null simplex");
63 }
64 }
65
66 let mut simplexes = simplexes
67 .into_iter()
68 .map(|(spx, label)| {
69 (
70 spx,
71 SCSpxInfo {
72 inv_bdry: HashSet::new(),
73 label,
74 },
75 )
76 })
77 .collect::<HashMap<_, _>>();
78
79 for simplex in simplexes.keys().map(|s| s.clone()).collect::<Vec<_>>() {
80 for bdry_spx in simplex.proper_sub_simplices_not_null() {
81 match simplexes.get_mut(&bdry_spx) {
82 Some(entry) => {
83 entry.inv_bdry.insert(simplex.clone());
84 }
85 None => {
86 return Err("Simplicial complex must be closed under taking boundaries");
87 }
88 }
89 }
90 }
91
92 Ok(Self {
93 ambient_space,
94 simplexes,
95 })
96 }
97
98 fn new_labelled_unchecked(ambient_space: SP, simplexes: HashMap<Simplex<FS, SP>, T>) -> Self {
99 Self::new_labelled(ambient_space, simplexes).unwrap()
100 }
101
102 fn ambient_space(&self) -> SP {
103 self.ambient_space.clone()
104 }
105
106 fn labelled_simplexes(&self) -> HashMap<&Simplex<FS, SP>, &T> {
107 self.simplexes
108 .iter()
109 .map(|(spx, info)| (spx, &info.label))
110 .collect()
111 }
112
113 fn into_labelled_simplexes(self) -> HashMap<Simplex<FS, SP>, T> {
114 self.simplexes
115 .into_iter()
116 .map(|(spx, info)| (spx, info.label))
117 .collect()
118 }
119
120 fn into_partial_simplicial_complex(self) -> LabelledPartialSimplicialComplex<FS, SP, T> {
121 LabelledPartialSimplicialComplex::new_labelled_unchecked(
122 self.ambient_space,
123 self.simplexes
124 .into_iter()
125 .map(|(spx, info)| (spx, info.label))
126 .collect(),
127 )
128 }
129}
130
131impl<FS: OrderedRingStructure + FieldStructure, SP: Borrow<AffineSpace<FS>> + Clone, T: Eq + Clone>
132 LabelledSimplicialComplex<FS, SP, T>
133where
134 FS::Set: Hash,
135{
136 fn check(&self) {
137 let mut inv_bdry_map = HashMap::new();
138 for spx in self.simplexes.keys() {
139 inv_bdry_map.insert(spx.clone(), HashSet::new());
140 }
141
142 for (spx, _info) in &self.simplexes {
143 for bdry_spx in spx.proper_sub_simplices_not_null() {
144 assert!(self.simplexes.contains_key(&bdry_spx));
145 inv_bdry_map.get_mut(&bdry_spx).unwrap().insert(spx.clone());
146 }
147 }
148
149 for (spx, info) in &self.simplexes {
150 assert_eq!(&info.inv_bdry, inv_bdry_map.get(spx).unwrap());
151 }
152
153 LabelledSimplicialDisjointUnion::new_labelled_unchecked(
155 self.ambient_space(),
156 self.simplexes
157 .iter()
158 .map(|(spx, info)| (spx.clone(), info.label.clone()))
159 .collect(),
160 )
161 .check();
162 }
163}
164
165impl<FS: OrderedRingStructure + FieldStructure, SP: Borrow<AffineSpace<FS>> + Clone>
166 SimplicialComplex<FS, SP>
167where
168 FS::Set: Hash,
169{
170 pub fn interior_and_boundary(
171 &self,
172 ) -> LabelledSimplicialComplex<FS, SP, InteriorBoundaryLabel> {
173 let n = self.ambient_space().borrow().affine_dimension();
181
182 let mut simplexes = HashMap::new();
183
184 let mut all = self.simplexes.keys().cloned().collect::<Vec<_>>();
185 all.sort_unstable_by_key(|s| std::cmp::Reverse(s.n())); for simplex in all {
187 let r = simplex.n();
188 if r == n {
189 simplexes.insert(simplex, InteriorBoundaryLabel::Interior);
191 } else {
192 let inv_bdry = &self.simplexes.get(&simplex).unwrap().inv_bdry;
193 if r == n - 1 {
194 match inv_bdry.len() {
197 0 | 1 => {
198 simplexes.insert(simplex, InteriorBoundaryLabel::Boundary);
199 }
200 2 => {
201 simplexes.insert(simplex, InteriorBoundaryLabel::Interior);
202 }
203 _ => panic!(
204 "rank n-1 simplex should be in the boundary of at most 2 rank n simplices"
205 ),
206 }
207 } else {
208 debug_assert!(r < n - 1);
210 if inv_bdry.is_empty() {
211 simplexes.insert(simplex, InteriorBoundaryLabel::Boundary);
212 } else {
213 if inv_bdry
214 .iter()
215 .all(|b| simplexes.get(b).unwrap() == &InteriorBoundaryLabel::Interior)
216 {
217 simplexes.insert(simplex, InteriorBoundaryLabel::Interior);
218 } else {
219 simplexes.insert(simplex, InteriorBoundaryLabel::Boundary);
220 }
221 }
222 }
223 }
224 }
225
226 LabelledSimplicialComplex::new_labelled(self.ambient_space(), simplexes).unwrap()
227 }
228
229 pub fn interior(&self) -> PartialSimplicialComplex<FS, SP> {
230 self.interior_and_boundary()
231 .subset_by_label(&InteriorBoundaryLabel::Interior)
232 }
233
234 pub fn boundary(&self) -> SimplicialComplex<FS, SP> {
235 self.interior_and_boundary()
236 .subset_by_label(&InteriorBoundaryLabel::Boundary)
237 .try_as_simplicial_complex()
238 .unwrap()
239 }
240}
241
242fn simplify_in_region<
254 FS: OrderedRingStructure + FieldStructure,
255 SP: Borrow<AffineSpace<FS>> + Clone,
256>(
257 space: SP,
258 boundary_facets: Vec<OrientedSimplex<FS, SP>>,
259) -> Option<Vec<Simplex<FS, SP>>>
260where
261 FS::Set: Hash,
262{
263 for spx in &boundary_facets {
264 debug_assert_eq!(spx.ambient_space().borrow(), space.borrow());
265 }
266
267 let mut boundary_points: HashMap<Vector<FS, SP>, Vec<usize>> = HashMap::new();
268 for (idx, spx) in boundary_facets.iter().enumerate() {
269 for pt in spx.simplex().points() {
270 if boundary_points.contains_key(pt) {
271 boundary_points.get_mut(pt).unwrap().push(idx);
272 } else {
273 boundary_points.insert(pt.clone(), vec![idx]);
274 }
275 }
276 }
277
278 for (boundary_point, adjacent_facets) in boundary_points {
279 let mut nonadjacent_facets = (0..boundary_facets.len()).collect::<HashSet<_>>();
280 for idx in &adjacent_facets {
281 nonadjacent_facets.remove(idx);
282 }
283
284 if nonadjacent_facets.iter().all(|idx| {
285 match boundary_facets[*idx].classify_point(&boundary_point) {
286 OrientationSide::Positive => false,
287 OrientationSide::Neutral => false,
288 OrientationSide::Negative => true,
289 }
290 }) {
291 let mut nonadjacent_simplexes = HashSet::new();
292 for idx in nonadjacent_facets {
293 for spx in boundary_facets[idx].simplex().sub_simplices_not_null() {
294 nonadjacent_simplexes.insert(spx);
295 }
296 }
297 for idx in adjacent_facets {
298 for spx in boundary_facets[idx].simplex().sub_simplices_not_null() {
299 nonadjacent_simplexes.remove(&spx);
300 }
301 }
302
303 let filler = nonadjacent_simplexes
304 .into_iter()
305 .map(|spx| {
306 let mut points = spx.points().clone();
307 points.push(boundary_point.clone());
308 Simplex::new(spx.ambient_space().clone(), points).unwrap()
309 })
310 .collect();
311
312 return Some(filler);
313 }
314 }
315 None
316}
317
318impl<FS: OrderedRingStructure + FieldStructure, SP: Borrow<AffineSpace<FS>> + Clone, T: Eq + Clone>
319 LabelledSimplicialComplex<FS, SP, T>
320where
321 FS::Set: Hash,
322{
323 pub fn simplify(mut self) -> Self {
324 let mut pts_todo = HashSet::new();
333 for simplex in self.simplexes.keys() {
334 for pt in simplex.points() {
335 pts_todo.insert(pt.clone());
336 }
337 }
338
339 while !pts_todo.is_empty() {
340 let pt = {
341 let mut pts_todo_iter = pts_todo.into_iter();
342 let pt = pts_todo_iter.next().unwrap();
343 pts_todo = pts_todo_iter.collect();
344 pt
345 };
346
347 let pt_spx = Simplex::new(self.ambient_space(), vec![pt.clone()]).unwrap();
348 let (star, link) = {
349 let mut star = self.simplexes.get(&pt_spx).unwrap().inv_bdry.clone();
350 star.insert(pt_spx.clone());
351
352 let mut nbd = HashSet::new();
353 for spx in &star {
354 for bdry in spx.sub_simplices_not_null() {
355 nbd.insert(bdry);
356 }
357 }
358
359 let mut link = nbd.clone();
360 for spx in &star {
361 link.remove(spx);
362 }
363
364 debug_assert_eq!(star.len() + link.len(), nbd.len());
365 for link_spx in &link {
366 debug_assert!(self.simplexes.contains_key(&link_spx));
367 }
368
369 (star, link)
370 };
371
372 let link_points = {
373 let mut link_points: Vec<Vector<FS, SP>> = vec![];
374 for spx in &link {
375 for p in spx.points() {
376 link_points.push(p.clone());
377 }
378 }
379 link_points
380 };
381
382 let nbd_points = {
383 let mut nbd_points = link_points.clone();
384 nbd_points.push(pt.clone());
385 nbd_points
386 };
387
388 let nbd_affine_subspace = EmbeddedAffineSubspace::new_affine_span_linearly_dependent(
389 self.ambient_space(),
390 nbd_points.iter().collect(),
391 );
392
393 let nbd_points_img = nbd_points
394 .iter()
395 .map(|pt| nbd_affine_subspace.unembed_point(pt).unwrap())
396 .collect::<Vec<_>>();
397 let pt_img = nbd_affine_subspace.unembed_point(&pt).unwrap();
398 let pt_img_spx =
399 Simplex::new(nbd_affine_subspace.embedded_space(), vec![pt_img.clone()]).unwrap();
400 let star_img = star
401 .iter()
402 .map(|s| nbd_affine_subspace.unembed_simplex(s).unwrap())
403 .collect::<HashSet<_>>();
404 let link_img = link
405 .iter()
406 .map(|s| nbd_affine_subspace.unembed_simplex(s).unwrap())
407 .collect::<HashSet<_>>();
408
409 let nbd = LabelledSimplicialComplex::<FS, AffineSpace<FS>, T>::new(
410 nbd_affine_subspace.embedded_space(),
411 {
412 let mut simplexes = HashSet::new();
413 simplexes.extend(star_img.clone());
414 simplexes.extend(link_img.clone());
415 simplexes
416 },
417 )
418 .unwrap();
419 let nbd_interior = nbd.interior().into_simplexes();
420
421 if !nbd_interior.contains(&pt_img_spx) {
422 let boundary_img = star_img
447 .iter()
448 .filter(|spx| !nbd_interior.contains(&spx))
449 .collect::<HashSet<_>>();
450
451 let boundary = boundary_img
452 .iter()
453 .map(|spx| nbd_affine_subspace.embed_simplex(spx))
454 .collect::<Vec<_>>();
455 let semistar = {
456 let mut semistar = star.clone();
457 for spx in &boundary {
458 semistar.remove(spx);
459 }
460 semistar
461 };
462 debug_assert_eq!(boundary.len() + semistar.len(), star.len());
463 if let (Some(boundary_label), Some(semistar_label)) = (
464 self.common_label(boundary.iter()).cloned(),
465 self.common_label(semistar.iter()).cloned(),
466 ) {
467 let mut boundary_img_points = HashSet::new();
468 for spx in &boundary_img {
469 for p in spx.points() {
470 boundary_img_points.insert(p);
471 }
472 }
473 let nbd_boundary_affine_subspace =
474 EmbeddedAffineSubspace::new_affine_span_linearly_dependent(
475 nbd_affine_subspace.embedded_space(),
476 boundary_img_points.into_iter().collect(),
477 );
478 debug_assert!(
479 nbd_boundary_affine_subspace
480 .embedded_space()
481 .affine_dimension()
482 <= nbd_affine_subspace.embedded_space().affine_dimension()
483 );
484 if nbd_boundary_affine_subspace
485 .embedded_space()
486 .affine_dimension()
487 + 1
488 == nbd_affine_subspace.embedded_space().affine_dimension()
489 {
490 let ref_point_img = {
491 let mut ref_point_img = None;
492 for pt in &nbd_points_img {
493 if nbd_boundary_affine_subspace.unembed_point(pt).is_none() {
494 ref_point_img = Some(pt.clone());
495 break;
496 }
497 }
498 ref_point_img.unwrap()
499 };
500 let oriented_hyperplane = OrientedSimplex::new_with_negative_point(
501 nbd_boundary_affine_subspace.ambient_space(),
502 nbd_boundary_affine_subspace.get_embedding_points().clone(),
503 &ref_point_img,
504 )
505 .unwrap();
506 for pt in &nbd_points_img {
507 debug_assert!(
508 oriented_hyperplane.classify_point(pt) != OrientationSide::Positive
509 );
510 }
511
512 let rim_img = {
513 let mut rim_img = HashSet::new();
514 for spx in &boundary_img {
515 for bspx in spx.sub_simplices_not_null() {
516 rim_img.insert(bspx);
517 }
518 }
519 for spx in &boundary_img {
520 rim_img.remove(spx);
521 }
522 rim_img
523 };
524
525 let pt_img_img =
526 nbd_boundary_affine_subspace.unembed_point(&pt_img).unwrap();
527
528 let rim_img_img = rim_img
529 .iter()
530 .map(|spx| {
531 OrientedSimplex::new_with_negative_point(
532 nbd_boundary_affine_subspace.embedded_space(),
533 nbd_boundary_affine_subspace
534 .unembed_simplex(spx)
535 .unwrap()
536 .points()
537 .clone(),
538 &pt_img_img,
539 )
540 .unwrap()
541 })
542 .collect::<Vec<_>>();
543
544 if let Some(new_boundary_img_img) = simplify_in_region(
545 nbd_boundary_affine_subspace.embedded_space(),
546 rim_img_img,
547 ) {
548 let new_boundary_img = new_boundary_img_img
549 .iter()
550 .map(|spx| nbd_boundary_affine_subspace.embed_simplex(spx))
551 .collect::<Vec<_>>();
552
553 let sphere_img = {
554 let mut sphere_img = vec![];
555 for spx in &new_boundary_img {
556 if spx.n() + 1
557 == nbd_affine_subspace.embedded_space().affine_dimension()
558 {
559 sphere_img.push(
560 OrientedSimplex::new_with_negative_point(
561 nbd_affine_subspace.embedded_space(),
562 spx.points().clone(),
563 &ref_point_img,
564 )
565 .unwrap(),
566 );
567 }
568 }
569 for spx in &link_img {
570 if spx.n() + 1
571 == nbd_affine_subspace.embedded_space().affine_dimension()
572 {
573 sphere_img.push(
574 OrientedSimplex::new_with_negative_point(
575 nbd_affine_subspace.embedded_space(),
576 spx.points().clone(),
577 &pt_img,
578 )
579 .unwrap(),
580 );
581 }
582 }
583 sphere_img
584 };
585
586 if let Some(new_star_img) =
587 simplify_in_region(nbd_affine_subspace.embedded_space(), sphere_img)
588 {
589 self.remove_simplexes_unchecked(star.into_iter().collect());
590 self.add_simplexes_unchecked(
591 new_boundary_img
592 .into_iter()
593 .map(|spx_img| nbd_affine_subspace.embed_simplex(&spx_img))
594 .collect(),
595 &boundary_label,
596 );
597 self.add_simplexes_unchecked(
598 new_star_img
599 .into_iter()
600 .map(|spx_img| nbd_affine_subspace.embed_simplex(&spx_img))
601 .collect(),
602 &semistar_label,
603 );
604 pts_todo.extend(link_points);
605 }
606 }
607 }
608 }
609 } else {
610 if let Some(star_label) = self.common_label(star.iter()).cloned() {
634 let boundary = link_img
635 .iter()
636 .filter(|spx| {
637 let n = spx.n();
638 let a = nbd_affine_subspace.embedded_space().affine_dimension();
639 if n >= a {
640 unreachable!()
641 } else if n + 1 == a {
642 true
643 } else {
644 debug_assert!(n + 1 < a);
645 false
646 }
647 })
648 .map(|spx| {
649 OrientedSimplex::new_with_negative_point(
650 nbd_affine_subspace.embedded_space(),
651 spx.points().clone(),
652 &pt_img,
653 )
654 .unwrap()
655 })
656 .collect();
657
658 if let Some(new_star_img) =
659 simplify_in_region(nbd_affine_subspace.embedded_space(), boundary)
660 {
661 self.remove_simplexes_unchecked(star.into_iter().collect());
662 self.add_simplexes_unchecked(
663 new_star_img
664 .into_iter()
665 .map(|spx_img| nbd_affine_subspace.embed_simplex(&spx_img))
666 .collect(),
667 &star_label,
668 );
669 pts_todo.extend(link_points);
670 }
671 }
672 }
673 }
674
675 #[cfg(debug_assertions)]
676 self.check();
677
678 self
679 }
680
681 fn remove_simplexes_unchecked(&mut self, simplexes: Vec<Simplex<FS, SP>>) {
700 for spx in &simplexes {
701 for bdry_spx in spx.proper_sub_simplices_not_null() {
702 match self.simplexes.get_mut(&bdry_spx) {
703 Some(info) => {
704 info.inv_bdry.remove(spx);
705 }
706 None => {}
707 }
708 }
709 }
710 for spx in &simplexes {
711 self.simplexes.remove(spx);
712 }
713 }
714
715 fn remove_simplexes(&mut self, simplexes: Vec<Simplex<FS, SP>>) {
716 self.remove_simplexes_unchecked(simplexes);
717 #[cfg(debug_assertions)]
718 self.check();
719 }
720
721 fn add_simplexes_unchecked(&mut self, simplexes: Vec<Simplex<FS, SP>>, label: &T) {
725 for spx in &simplexes {
726 self.simplexes.insert(
727 spx.clone(),
728 SCSpxInfo {
729 inv_bdry: HashSet::new(),
730 label: label.clone(),
731 },
732 );
733 }
734 for spx in &simplexes {
735 for bdry_spx in spx.proper_sub_simplices_not_null() {
736 self.simplexes
737 .get_mut(&bdry_spx)
738 .unwrap()
739 .inv_bdry
740 .insert(spx.clone());
741 }
742 }
743 }
744
745 fn add_simplexes(&mut self, simplexes: Vec<Simplex<FS, SP>>, label: &T) {
746 self.add_simplexes_unchecked(simplexes, label);
747 #[cfg(debug_assertions)]
748 self.check();
749 }
750}