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