1use super::*;
2use crate::{
3 affine_subspace::EmbeddedAffineSubspace,
4 ambient_space::AffineSpace,
5 oriented_simplex::{OrientationSide, OrientedSimplex},
6 partial_simplicial_complex::{LabelledPartialSimplicialComplex, PartialSimplicialComplex},
7 simplex::Simplex,
8 simplex_collection::{
9 InteriorOrBoundary, InteriorOrBoundarySimplexCollection, LabelledSimplexCollection,
10 },
11 simplicial_disjoint_union::LabelledSimplicialDisjointUnion,
12 vector::Vector,
13};
14use std::collections::{HashMap, HashSet};
15
16#[derive(Clone)]
17pub struct SCSpxInfo<'f, FS: OrderedRingSignature + FieldSignature, T: Eq + Clone + Send + Sync> {
18 inv_bdry: HashSet<Simplex<'f, FS>>,
19 label: T,
20}
21
22impl<'f, FS: OrderedRingSignature + FieldSignature, T: Eq + Clone + Send + Sync> std::fmt::Debug
23 for SCSpxInfo<'f, FS, T>
24{
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 f.debug_struct("SCSpxInfo")
27 .field("inv_bdry", &self.inv_bdry)
28 .finish()
29 }
30}
31
32#[derive(Clone)]
33pub struct LabelledSimplicialComplex<
34 'f,
35 FS: OrderedRingSignature + FieldSignature,
36 T: Eq + Clone + Send + Sync,
37> {
38 ambient_space: AffineSpace<'f, FS>,
39 simplexes: HashMap<Simplex<'f, FS>, SCSpxInfo<'f, FS, T>>,
40}
41
42pub type SimplicialComplex<'f, FS> = LabelledSimplicialComplex<'f, FS, ()>;
43
44impl<'f, FS: OrderedRingSignature + FieldSignature, T: Eq + Clone + Send + Sync> std::fmt::Debug
45 for LabelledSimplicialComplex<'f, FS, T>
46{
47 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48 f.debug_struct("SimplicialComplex")
49 .field("simplexes", &self.simplexes)
50 .finish()
51 }
52}
53
54impl<'f, FS: OrderedRingSignature + FieldSignature, T: Eq + Clone + Send + Sync>
55 LabelledSimplexCollection<'f, FS, T> for LabelledSimplicialComplex<'f, FS, T>
56where
57 FS::Set: Hash,
58{
59 type WithLabel<S: Eq + Clone + Send + Sync> = LabelledSimplicialComplex<'f, FS, S>;
60 type SubsetType = LabelledPartialSimplicialComplex<'f, FS, T>;
61
62 fn try_new_labelled(
63 ambient_space: AffineSpace<'f, FS>,
64 simplexes: HashMap<Simplex<'f, FS>, T>,
65 ) -> Result<Self, &'static str> {
66 for simplex in simplexes.keys() {
67 assert_eq!(simplex.ambient_space(), ambient_space);
68 if simplex.points().is_empty() {
69 return Err("Simplicial complex musn't contain the null simplex");
70 }
71 }
72
73 let mut simplexes = simplexes
74 .into_iter()
75 .map(|(spx, label)| {
76 (
77 spx,
78 SCSpxInfo {
79 inv_bdry: HashSet::new(),
80 label,
81 },
82 )
83 })
84 .collect::<HashMap<_, _>>();
85
86 for simplex in simplexes.keys().cloned().collect::<Vec<_>>() {
87 for bdry_spx in simplex.proper_sub_simplices_not_null() {
88 match simplexes.get_mut(&bdry_spx) {
89 Some(entry) => {
90 entry.inv_bdry.insert(simplex.clone());
91 }
92 None => {
93 return Err("Simplicial complex must be closed under taking boundaries");
94 }
95 }
96 }
97 }
98
99 Ok(Self {
100 ambient_space,
101 simplexes,
102 })
103 }
104
105 fn new_labelled_unchecked(
106 ambient_space: AffineSpace<'f, FS>,
107 simplexes: HashMap<Simplex<'f, FS>, T>,
108 ) -> Self {
109 Self::try_new_labelled(ambient_space, simplexes).unwrap()
110 }
111
112 fn ambient_space(&self) -> AffineSpace<'f, FS> {
113 self.ambient_space
114 }
115
116 fn labelled_simplexes(&self) -> HashMap<&Simplex<'f, FS>, &T> {
117 self.simplexes
118 .iter()
119 .map(|(spx, info)| (spx, &info.label))
120 .collect()
121 }
122
123 fn into_labelled_simplexes(self) -> HashMap<Simplex<'f, FS>, T> {
124 self.simplexes
125 .into_iter()
126 .map(|(spx, info)| (spx, info.label))
127 .collect()
128 }
129
130 fn into_partial_simplicial_complex(self) -> LabelledPartialSimplicialComplex<'f, FS, T> {
131 LabelledPartialSimplicialComplex::new_labelled_unchecked(
132 self.ambient_space,
133 self.simplexes
134 .into_iter()
135 .map(|(spx, info)| (spx, info.label))
136 .collect(),
137 )
138 }
139
140 fn to_partial_simplicial_complex(&self) -> LabelledPartialSimplicialComplex<'f, FS, T> {
141 self.clone().into_partial_simplicial_complex()
142 }
143
144 fn into_simplicial_disjoint_union(self) -> LabelledSimplicialDisjointUnion<'f, FS, T> {
145 LabelledSimplicialDisjointUnion::new_labelled_unchecked(
146 self.ambient_space,
147 self.simplexes
148 .into_iter()
149 .map(|(spx, info)| (spx, info.label))
150 .collect(),
151 )
152 }
153
154 fn to_simplicial_disjoint_union(&self) -> LabelledSimplicialDisjointUnion<'f, FS, T> {
155 self.clone().into_simplicial_disjoint_union()
156 }
157}
158
159impl<'f, FS: OrderedRingSignature + FieldSignature, T: Eq + Clone + Send + Sync>
160 LabelledSimplicialComplex<'f, FS, T>
161where
162 FS::Set: Hash,
163{
164 #[allow(unused)]
165 pub(crate) fn check(&self) {
166 let mut inv_bdry_map = HashMap::new();
167 for spx in self.simplexes.keys() {
168 inv_bdry_map.insert(spx.clone(), HashSet::new());
169 }
170
171 for spx in self.simplexes.keys() {
172 for bdry_spx in spx.proper_sub_simplices_not_null() {
173 assert!(self.simplexes.contains_key(&bdry_spx));
174 inv_bdry_map.get_mut(&bdry_spx).unwrap().insert(spx.clone());
175 }
176 }
177
178 for (spx, info) in &self.simplexes {
179 assert_eq!(&info.inv_bdry, inv_bdry_map.get(spx).unwrap());
180 }
181
182 LabelledSimplicialDisjointUnion::new_labelled_unchecked(
184 self.ambient_space(),
185 self.simplexes
186 .iter()
187 .map(|(spx, info)| (spx.clone(), info.label.clone()))
188 .collect(),
189 )
190 .check();
191 }
192}
193
194impl<'f, FS: OrderedRingSignature + FieldSignature> SimplicialComplex<'f, FS>
195where
196 FS::Set: Hash,
197{
198 pub fn interior_and_boundary(&self) -> LabelledSimplicialComplex<'f, FS, InteriorOrBoundary> {
199 let n = self.ambient_space().affine_dimension();
207
208 let mut simplexes = HashMap::new();
209
210 let mut all = self.simplexes.keys().cloned().collect::<Vec<_>>();
211 all.sort_unstable_by_key(|s| std::cmp::Reverse(s.n())); for simplex in all {
213 let r = simplex.n();
214 if r == n {
215 simplexes.insert(simplex, InteriorOrBoundary::Interior);
217 } else {
218 let inv_bdry = &self.simplexes.get(&simplex).unwrap().inv_bdry;
219 if r == n - 1 {
220 match inv_bdry.len() {
223 0 | 1 => {
224 simplexes.insert(simplex, InteriorOrBoundary::Boundary);
225 }
226 2 => {
227 simplexes.insert(simplex, InteriorOrBoundary::Interior);
228 }
229 _ => panic!(
230 "rank n-1 simplex should be in the boundary of at most 2 rank n simplices"
231 ),
232 }
233 } else {
234 debug_assert!(r < n - 1);
236 if inv_bdry.is_empty() {
237 simplexes.insert(simplex, InteriorOrBoundary::Boundary);
238 } else if inv_bdry
239 .iter()
240 .all(|b| simplexes.get(b).unwrap() == &InteriorOrBoundary::Interior)
241 {
242 simplexes.insert(simplex, InteriorOrBoundary::Interior);
243 } else {
244 simplexes.insert(simplex, InteriorOrBoundary::Boundary);
245 }
246 }
247 }
248 }
249
250 LabelledSimplicialComplex::try_new_labelled(self.ambient_space(), simplexes).unwrap()
251 }
252
253 pub(crate) fn interior_raw(&self) -> PartialSimplicialComplex<'f, FS> {
254 self.interior_and_boundary().interior()
255 }
256
257 pub fn interior(&self) -> PartialSimplicialComplex<'f, FS> {
258 self.interior_raw().simplify()
259 }
260
261 pub(crate) fn boundary_raw(&self) -> SimplicialComplex<'f, FS> {
262 self.interior_and_boundary()
263 .boundary()
264 .try_into_simplicial_complex()
265 .unwrap()
266 }
267
268 pub fn boundary(&self) -> SimplicialComplex<'f, FS> {
269 self.boundary_raw().simplify()
270 }
271}
272
273fn simplify_in_region<'f, FS: OrderedRingSignature + FieldSignature, T: Eq + Clone + Send + Sync>(
288 space: AffineSpace<'f, FS>,
289 boundary_facets: Vec<OrientedSimplex<'f, FS>>,
290 labelled_interior: HashMap<Simplex<'f, FS>, T>,
291) -> Option<HashMap<Simplex<'f, FS>, T>>
292where
293 FS::Set: Hash,
294{
295 let labelled_interior =
296 LabelledSimplicialDisjointUnion::new_labelled_unchecked(space, labelled_interior);
297
298 let interior_uniform_label = {
299 let labels = labelled_interior
300 .labelled_simplexes()
301 .into_values()
302 .collect::<Vec<_>>();
303 let first = *labels.first()?;
304 if labels.iter().all(|label| *label == first) {
305 Some(first)
306 } else {
307 None
308 }
309 };
310
311 for spx in &boundary_facets {
312 debug_assert_eq!(spx.ambient_space(), space);
313 }
314
315 let mut boundary_points: HashMap<Vector<'f, FS>, Vec<usize>> = HashMap::new();
316 for (idx, spx) in boundary_facets.iter().enumerate() {
317 for pt in spx.simplex().points() {
318 if boundary_points.contains_key(pt) {
319 boundary_points.get_mut(pt).unwrap().push(idx);
320 } else {
321 boundary_points.insert(pt.clone(), vec![idx]);
322 }
323 }
324 }
325
326 'BOUNDARY_LOOP: for (boundary_point, adjacent_facets) in boundary_points {
327 let mut nonadjacent_facets = (0..boundary_facets.len()).collect::<HashSet<_>>();
328 for idx in &adjacent_facets {
329 nonadjacent_facets.remove(idx);
330 }
331
332 if nonadjacent_facets.iter().all(|idx| {
333 match boundary_facets[*idx].classify_point(&boundary_point) {
334 OrientationSide::Positive | OrientationSide::Neutral => false,
335 OrientationSide::Negative => true,
336 }
337 }) {
338 let mut nonadjacent_simplexes = HashSet::new();
339 for idx in nonadjacent_facets {
340 for spx in boundary_facets[idx].simplex().sub_simplices_not_null() {
341 nonadjacent_simplexes.insert(spx);
342 }
343 }
344 for idx in adjacent_facets {
345 for spx in boundary_facets[idx].simplex().sub_simplices_not_null() {
346 nonadjacent_simplexes.remove(&spx);
347 }
348 }
349
350 let labelled_new_interior = LabelledSimplicialDisjointUnion::new_labelled_unchecked(
351 space,
352 nonadjacent_simplexes
353 .into_iter()
354 .enumerate()
355 .map(|(i, spx)| {
356 (
357 {
358 let mut points = spx.points().clone();
359 points.push(boundary_point.clone());
360 spx.ambient_space().simplex(points).unwrap()
361 },
362 i,
363 )
364 })
365 .collect(),
366 );
367
368 let filler = if let Some(interior_label) = interior_uniform_label {
369 labelled_new_interior.apply_label_function(|_| interior_label.clone())
370 } else {
371 let interior_intersection = LabelledSimplicialDisjointUnion::intersect_raw(
372 &labelled_interior,
373 &labelled_new_interior,
374 );
375
376 debug_assert!(
377 LabelledSimplicialDisjointUnion::subtract_raw(
378 &labelled_interior,
379 &labelled_new_interior,
380 )
381 .labelled_simplexes()
382 .is_empty()
383 );
384
385 debug_assert!(
386 LabelledSimplicialDisjointUnion::subtract_raw(
387 &labelled_new_interior,
388 &labelled_interior,
389 )
390 .labelled_simplexes()
391 .is_empty()
392 );
393
394 let mut i_to_label_map = HashMap::new();
395 for (_, (label, i)) in interior_intersection.labelled_simplexes() {
396 match i_to_label_map.entry(i) {
397 std::collections::hash_map::Entry::Occupied(occupied_entry) => {
398 if *occupied_entry.get() != label {
399 continue 'BOUNDARY_LOOP;
400 }
401 }
402 std::collections::hash_map::Entry::Vacant(vacant_entry) => {
403 vacant_entry.insert(label);
404 }
405 }
406 }
407
408 labelled_new_interior
409 .apply_label_function(|label| (*i_to_label_map.get(label).unwrap()).clone())
410 };
411
412 return Some(filler.into_labelled_simplexes());
413 }
414 }
415 None
416}
417
418impl<'f, FS: OrderedRingSignature + FieldSignature, T: Eq + Clone + Send + Sync>
419 LabelledSimplicialComplex<'f, FS, T>
420where
421 FS::Set: Hash,
422{
423 pub fn simplify(mut self) -> Self {
424 let mut pts_todo = HashSet::new();
433 for simplex in self.simplexes.keys() {
434 for pt in simplex.points() {
435 pts_todo.insert(pt.clone());
436 }
437 }
438
439 while !pts_todo.is_empty() {
440 let pt = {
441 let mut pts_todo_iter = pts_todo.into_iter();
442 let pt = pts_todo_iter.next().unwrap();
443 pts_todo = pts_todo_iter.collect();
444 pt
445 };
446
447 let pt_spx = self.ambient_space().simplex(vec![pt.clone()]).unwrap();
448 let (star, link) = {
449 let mut star = self.simplexes.get(&pt_spx).unwrap().inv_bdry.clone();
450 star.insert(pt_spx.clone());
451
452 let mut nbd = HashSet::new();
453 for spx in &star {
454 for bdry in spx.sub_simplices_not_null() {
455 nbd.insert(bdry);
456 }
457 }
458
459 let mut link = nbd.clone();
460 for spx in &star {
461 link.remove(spx);
462 }
463
464 debug_assert_eq!(star.len() + link.len(), nbd.len());
465 for link_spx in &link {
466 debug_assert!(self.simplexes.contains_key(link_spx));
467 }
468
469 (star, link)
470 };
471
472 let link_points = {
473 let mut link_points: Vec<Vector<'f, FS>> = vec![];
474 for spx in &link {
475 for p in spx.points() {
476 link_points.push(p.clone());
477 }
478 }
479 link_points
480 };
481
482 let nbd_points = {
483 let mut nbd_points = link_points.clone();
484 nbd_points.push(pt.clone());
485 nbd_points
486 };
487
488 let nbd_affine_subspace = EmbeddedAffineSubspace::new_affine_span(
489 self.ambient_space(),
490 nbd_points.iter().collect(),
491 );
492
493 let nbd_points_img = nbd_points
494 .iter()
495 .map(|pt| nbd_affine_subspace.unembed_point(pt).unwrap())
496 .collect::<Vec<_>>();
497
498 let pt_img = nbd_affine_subspace.unembed_point(&pt).unwrap();
499 let pt_img_spx = nbd_affine_subspace
500 .embedded_space()
501 .simplex(vec![pt_img.clone()])
502 .unwrap();
503
504 let star_img = star
505 .iter()
506 .map(|s| {
507 (
508 nbd_affine_subspace.unembed_simplex(s).unwrap(),
509 self.simplexes.get(s).unwrap().label.clone(),
510 )
511 })
512 .collect::<HashMap<_, _>>();
513
514 let link_img = link
515 .iter()
516 .map(|s| nbd_affine_subspace.unembed_simplex(s).unwrap())
517 .collect::<HashSet<_>>();
518
519 let nbd = LabelledSimplicialComplex::<'f, FS, T>::try_new(
520 nbd_affine_subspace.embedded_space(),
521 {
522 let mut simplexes = HashSet::new();
523 simplexes.extend(star_img.keys().cloned());
524 simplexes.extend(link_img.clone());
525 simplexes
526 },
527 )
528 .unwrap();
529 let nbd_interior = nbd.interior_raw().into_simplexes();
530
531 if !nbd_interior.contains(&pt_img_spx) {
532 let boundary_img = star_img
557 .iter()
558 .filter(|(spx, _)| !nbd_interior.contains(spx))
559 .collect::<HashMap<_, _>>();
560 let semistar_img = star_img
561 .iter()
562 .filter(|(spx, _)| nbd_interior.contains(spx))
563 .collect::<HashMap<_, _>>();
564
565 let boundary = boundary_img
566 .keys()
567 .map(|spx| nbd_affine_subspace.embed_simplex(spx))
568 .collect::<Vec<_>>();
569 let semistar = semistar_img
570 .keys()
571 .map(|spx| nbd_affine_subspace.embed_simplex(spx))
572 .collect::<Vec<_>>();
573
574 debug_assert_eq!(boundary.len() + semistar.len(), star.len());
575
576 let mut boundary_img_points = HashSet::new();
577 for spx in boundary_img.keys() {
578 for p in spx.points() {
579 boundary_img_points.insert(p);
580 }
581 }
582 let nbd_boundary_affine_subspace = EmbeddedAffineSubspace::new_affine_span(
583 nbd_affine_subspace.embedded_space(),
584 boundary_img_points.into_iter().collect(),
585 );
586 debug_assert!(
587 nbd_boundary_affine_subspace
588 .embedded_space()
589 .affine_dimension()
590 <= nbd_affine_subspace.embedded_space().affine_dimension()
591 );
592 if nbd_boundary_affine_subspace
593 .embedded_space()
594 .affine_dimension()
595 + 1
596 == nbd_affine_subspace.embedded_space().affine_dimension()
597 {
598 let ref_point_img = {
599 let mut ref_point_img = None;
600 for pt in &nbd_points_img {
601 if nbd_boundary_affine_subspace.unembed_point(pt).is_none() {
602 ref_point_img = Some(pt.clone());
603 break;
604 }
605 }
606 ref_point_img.unwrap()
607 };
608 let oriented_hyperplane = OrientedSimplex::new_with_negative_point(
609 nbd_boundary_affine_subspace.ambient_space(),
610 nbd_boundary_affine_subspace.get_embedding_points().clone(),
611 &ref_point_img,
612 )
613 .unwrap();
614 for pt in &nbd_points_img {
615 debug_assert!(
616 oriented_hyperplane.classify_point(pt) != OrientationSide::Positive
617 );
618 }
619
620 let rim_img = {
621 let mut rim_img = HashSet::new();
622 for spx in boundary_img.keys() {
623 for bspx in spx.sub_simplices_not_null() {
624 rim_img.insert(bspx);
625 }
626 }
627 for spx in boundary_img.keys() {
628 rim_img.remove(spx);
629 }
630 rim_img
631 };
632
633 let pt_img_img = nbd_boundary_affine_subspace.unembed_point(&pt_img).unwrap();
634
635 let rim_img_img = rim_img
636 .iter()
637 .map(|spx| {
638 OrientedSimplex::new_with_negative_point(
639 nbd_boundary_affine_subspace.embedded_space(),
640 nbd_boundary_affine_subspace
641 .unembed_simplex(spx)
642 .unwrap()
643 .points()
644 .clone(),
645 &pt_img_img,
646 )
647 .unwrap()
648 })
649 .collect::<Vec<_>>();
650
651 let boundary_img_img = boundary_img
652 .iter()
653 .map(|(spx, label)| {
654 (
655 nbd_boundary_affine_subspace.unembed_simplex(spx).unwrap(),
656 *label,
657 )
658 })
659 .collect::<Vec<_>>();
660
661 if let Some(new_boundary_img_img) = simplify_in_region(
662 nbd_boundary_affine_subspace.embedded_space(),
663 rim_img_img,
664 boundary_img_img
665 .iter()
666 .map(|(spx, label)| (spx.clone(), (*label).clone()))
667 .collect(),
668 ) {
669 let new_boundary_img = new_boundary_img_img
670 .iter()
671 .map(|(spx, label)| {
672 (nbd_boundary_affine_subspace.embed_simplex(spx), label)
673 })
674 .collect::<Vec<_>>();
675
676 let sphere_img = {
677 let mut sphere_img = vec![];
678 for (spx, _) in &new_boundary_img {
679 if spx.n() + 1
680 == nbd_affine_subspace.embedded_space().affine_dimension()
681 {
682 sphere_img.push(
683 OrientedSimplex::new_with_negative_point(
684 nbd_affine_subspace.embedded_space(),
685 spx.points().clone(),
686 &ref_point_img,
687 )
688 .unwrap(),
689 );
690 }
691 }
692 for spx in &link_img {
693 if spx.n() + 1
694 == nbd_affine_subspace.embedded_space().affine_dimension()
695 {
696 sphere_img.push(
697 OrientedSimplex::new_with_negative_point(
698 nbd_affine_subspace.embedded_space(),
699 spx.points().clone(),
700 &pt_img,
701 )
702 .unwrap(),
703 );
704 }
705 }
706 sphere_img
707 };
708
709 if let Some(new_star_img) = simplify_in_region(
710 nbd_affine_subspace.embedded_space(),
711 sphere_img,
712 semistar_img
713 .into_iter()
714 .map(|(spx, label)| (spx.clone(), label.clone()))
715 .collect(),
716 ) {
717 self.remove_simplexes_unchecked(star.into_iter().collect());
718 self.add_simplexes_unchecked(
719 new_boundary_img
720 .into_iter()
721 .map(|(spx_img, label)| {
722 (nbd_affine_subspace.embed_simplex(&spx_img), label.clone())
723 })
724 .collect(),
725 );
726 self.add_simplexes_unchecked(
727 new_star_img
728 .into_iter()
729 .map(|(spx_img, label)| {
730 (nbd_affine_subspace.embed_simplex(&spx_img), label.clone())
731 })
732 .collect(),
733 );
734 pts_todo.extend(link_points);
735 }
736 }
737 }
738 } else {
739 let boundary_img = link_img
763 .iter()
764 .filter(|spx| {
765 let n = spx.n();
766 let a = nbd_affine_subspace.embedded_space().affine_dimension();
767 if n >= a {
768 unreachable!()
769 } else if n + 1 == a {
770 true
771 } else {
772 debug_assert!(n + 1 < a);
773 false
774 }
775 })
776 .map(|spx| {
777 OrientedSimplex::new_with_negative_point(
778 nbd_affine_subspace.embedded_space(),
779 spx.points().clone(),
780 &pt_img,
781 )
782 .unwrap()
783 })
784 .collect();
785
786 if let Some(new_star_img) = simplify_in_region(
787 nbd_affine_subspace.embedded_space(),
788 boundary_img,
789 star_img
790 .iter()
791 .map(|(spx, label)| (spx.clone(), label.clone()))
792 .collect(),
793 ) {
794 self.remove_simplexes_unchecked(star.into_iter().collect());
795 self.add_simplexes_unchecked(
796 new_star_img
797 .into_iter()
798 .map(|(spx_img, label)| {
799 (nbd_affine_subspace.embed_simplex(&spx_img), label)
800 })
801 .collect(),
802 );
803 pts_todo.extend(link_points);
804 }
805 }
806 }
807
808 #[cfg(debug_assertions)]
809 self.check();
810
811 self
812 }
813
814 fn remove_simplexes_unchecked(&mut self, simplexes: Vec<Simplex<'f, FS>>) {
817 for spx in &simplexes {
818 for bdry_spx in spx.proper_sub_simplices_not_null() {
819 if let Some(info) = self.simplexes.get_mut(&bdry_spx) {
820 info.inv_bdry.remove(spx);
821 }
822 }
823 }
824 for spx in &simplexes {
825 self.simplexes.remove(spx);
826 }
827 }
828
829 pub fn remove_simplexes(&mut self, simplexes: Vec<Simplex<'f, FS>>) {
830 self.remove_simplexes_unchecked(simplexes);
831 #[cfg(debug_assertions)]
832 self.check();
833 }
834
835 fn add_simplexes_unchecked(&mut self, simplexes: Vec<(Simplex<'f, FS>, T)>) {
839 for (spx, label) in &simplexes {
840 self.simplexes.insert(
841 spx.clone(),
842 SCSpxInfo {
843 inv_bdry: HashSet::new(),
844 label: label.clone(),
845 },
846 );
847 }
848 for (spx, _) in simplexes {
849 for bdry_spx in spx.proper_sub_simplices_not_null() {
850 self.simplexes
851 .get_mut(&bdry_spx)
852 .unwrap()
853 .inv_bdry
854 .insert(spx.clone());
855 }
856 }
857 }
858
859 pub fn add_simplexes(&mut self, simplexes: Vec<(Simplex<'f, FS>, T)>) {
860 self.add_simplexes_unchecked(simplexes);
861 #[cfg(debug_assertions)]
862 self.check();
863 }
864}