algebraeon_geometry/simplexes/
simplicial_disjoint_union.rs

1use std::collections::{HashMap, HashSet};
2
3use super::*;
4
5#[derive(Clone)]
6pub struct LabelledSimplicialDisjointUnion<
7    FS: OrderedRingStructure + FieldStructure,
8    SP: Borrow<AffineSpace<FS>> + Clone,
9    T: Eq + Clone,
10> where
11    FS::Set: Hash,
12{
13    ambient_space: SP,
14    simplexes: HashMap<Simplex<FS, SP>, T>,
15}
16
17pub type SimplicialDisjointUnion<FS, SP> = LabelledSimplicialDisjointUnion<FS, SP, ()>;
18
19impl<
20        FS: OrderedRingStructure + FieldStructure,
21        SP: Borrow<AffineSpace<FS>> + Clone,
22        T: Eq + Clone,
23    > From<&LabelledSimplicialComplex<FS, SP, T>> for LabelledSimplicialDisjointUnion<FS, SP, T>
24where
25    FS::Set: Hash,
26{
27    fn from(sc: &LabelledSimplicialComplex<FS, SP, T>) -> Self {
28        Self {
29            ambient_space: sc.ambient_space(),
30            simplexes: sc
31                .labelled_simplexes()
32                .into_iter()
33                .map(|(spx, label)| (spx.clone(), label.clone()))
34                .collect(),
35        }
36    }
37}
38
39impl<
40        FS: OrderedRingStructure + FieldStructure,
41        SP: Borrow<AffineSpace<FS>> + Clone,
42        T: Eq + Clone,
43    > From<&LabelledPartialSimplicialComplex<FS, SP, T>>
44    for LabelledSimplicialDisjointUnion<FS, SP, T>
45where
46    FS::Set: Hash,
47{
48    fn from(sc: &LabelledPartialSimplicialComplex<FS, SP, T>) -> Self {
49        Self {
50            ambient_space: sc.ambient_space(),
51            simplexes: sc
52                .labelled_simplexes()
53                .into_iter()
54                .map(|(s, label)| (s.clone(), label.clone()))
55                .collect(),
56        }
57    }
58}
59
60impl<
61        FS: OrderedRingStructure + FieldStructure,
62        SP: Borrow<AffineSpace<FS>> + Clone,
63        T: Eq + Clone,
64    > LabelledSimplexCollection<FS, SP, T> for LabelledSimplicialDisjointUnion<FS, SP, T>
65where
66    FS::Set: Hash,
67{
68    type WithLabel<S: Eq + Clone> = LabelledSimplicialDisjointUnion<FS, SP, S>;
69    type SubsetType = LabelledSimplicialDisjointUnion<FS, SP, T>;
70
71    fn new_labelled(
72        ambient_space: SP,
73        simplexes: HashMap<Simplex<FS, SP>, T>,
74    ) -> Result<Self, &'static str> {
75        //todo: check simplexes are disjoint
76        Ok(Self {
77            ambient_space,
78            simplexes,
79        })
80    }
81
82    fn new_labelled_unchecked(ambient_space: SP, simplexes: HashMap<Simplex<FS, SP>, T>) -> Self {
83        Self {
84            ambient_space,
85            simplexes,
86        }
87    }
88
89    fn ambient_space(&self) -> SP {
90        self.ambient_space.clone()
91    }
92
93    fn labelled_simplexes(&self) -> HashMap<&Simplex<FS, SP>, &T> {
94        self.simplexes.iter().collect()
95    }
96
97    fn into_labelled_simplexes(self) -> HashMap<Simplex<FS, SP>, T> {
98        self.simplexes
99    }
100
101    fn into_partial_simplicial_complex(self) -> LabelledPartialSimplicialComplex<FS, SP, T> {
102        self.refine_to_partial_simplicial_complex()
103    }
104}
105
106impl<
107        FS: OrderedRingStructure + FieldStructure,
108        SP: Borrow<AffineSpace<FS>> + Clone,
109        T: Eq + Clone,
110    > LabelledSimplicialDisjointUnion<FS, SP, T>
111where
112    FS::Set: Hash,
113{
114    pub(super) fn check(&self) {
115        for (spx_a, _label_a) in &self.simplexes {
116            for (spx_b, _label_b) in &self.simplexes {
117                let bdry_a = spx_a
118                    .sub_simplices_not_null()
119                    .into_iter()
120                    .collect::<HashSet<_>>();
121                let bdry_b = spx_b
122                    .sub_simplices_not_null()
123                    .into_iter()
124                    .collect::<HashSet<_>>();
125                if !bdry_a.contains(spx_b) && !bdry_b.contains(spx_a) {
126                    let overlap = ConvexHull::intersect(
127                        &ConvexHull::from_simplex(spx_a.clone()),
128                        &ConvexHull::from_simplex(spx_b.clone()),
129                    );
130
131                    if !(overlap.affine_span_dimension() < spx_a.n()
132                        && overlap.affine_span_dimension() < spx_b.n())
133                    {
134                        println!("spx_a = {:?}", spx_a);
135                        println!("spx_b = {:?}", spx_b);
136                        panic!("simplicial complex simplex overlap");
137                    }
138                }
139            }
140        }
141    }
142
143    pub fn refine_to_partial_simplicial_complex(
144        mut self,
145    ) -> LabelledPartialSimplicialComplex<FS, SP, T> {
146        let ambient_space = self.ambient_space();
147
148        //maintain a list of pairs of simplexes which may intersect on their boundary
149        let mut pairs_todo: HashMap<Simplex<FS, SP>, HashSet<Simplex<FS, SP>>> = HashMap::new();
150        let simplexes = self.simplexes().into_iter().collect::<Vec<_>>();
151        for i in 0..simplexes.len() {
152            for j in 0..simplexes.len() {
153                if i != j {
154                    let spx_i = simplexes[i];
155                    let spx_j = simplexes[j];
156                    pairs_todo
157                        .entry(spx_i.clone())
158                        .or_insert(HashSet::new())
159                        .insert(spx_j.clone());
160                }
161            }
162        }
163
164        while !pairs_todo.is_empty() {
165            let spx1 = pairs_todo.keys().into_iter().next().unwrap().clone();
166            match pairs_todo.get(&spx1).unwrap().iter().next().cloned() {
167                None => {
168                    pairs_todo.remove(&spx1);
169                }
170                Some(spx2) => {
171                    //The pair (spx1, spx2) no longer needs to be checked
172                    pairs_todo.get_mut(&spx1).unwrap().remove(&spx2);
173                    pairs_todo.get_mut(&spx2).unwrap().remove(&spx1);
174
175                    debug_assert_ne!(spx1, spx2);
176                    debug_assert!(self.simplexes.contains_key(&spx1));
177                    debug_assert!(self.simplexes.contains_key(&spx2));
178
179                    let overlap = ConvexHull::intersect(
180                        &ConvexHull::from_simplex(spx1.clone()),
181                        &ConvexHull::from_simplex(spx2.clone()),
182                    );
183
184                    if !overlap.is_empty() {
185                        if match Simplex::new(
186                            ambient_space.clone(),
187                            overlap.defining_points().into_iter().collect(),
188                        ) {
189                            Ok(overlap_spx) => {
190                                let spx1_points = spx1.points().into_iter().collect::<HashSet<_>>();
191                                let spx2_points = spx2.points().into_iter().collect::<HashSet<_>>();
192                                !overlap_spx
193                                    .points()
194                                    .into_iter()
195                                    .all(|pt| spx1_points.contains(pt) && spx2_points.contains(pt))
196                            }
197                            Err(_) => true,
198                        } {
199                            //there is a bad overlap between spx1 and spx2
200                            let mut spx1_replacement = overlap.clone();
201                            for pt in spx1.points() {
202                                spx1_replacement.extend_by_point(pt.clone());
203                            }
204                            let mut spx2_replacement = overlap.clone();
205                            for pt in spx2.points() {
206                                spx2_replacement.extend_by_point(pt.clone());
207                            }
208
209                            //remove any pairs containing spx1 or spx2
210                            let mut spx1_paired = vec![];
211                            for spx in pairs_todo.get(&spx1).unwrap_or(&HashSet::new()).clone() {
212                                debug_assert_ne!(spx, spx1);
213                                debug_assert_ne!(spx, spx2);
214                                debug_assert!(self.simplexes.contains_key(&spx));
215                                pairs_todo
216                                    .get_mut(&spx)
217                                    .unwrap_or(&mut HashSet::new())
218                                    .remove(&spx1);
219                                spx1_paired.push(spx);
220                            }
221                            pairs_todo.remove(&spx1);
222
223                            let mut spx2_paired = vec![];
224                            for spx in pairs_todo.get(&spx2).unwrap_or(&HashSet::new()).clone() {
225                                debug_assert_ne!(spx, spx1);
226                                debug_assert_ne!(spx, spx2);
227                                debug_assert!(self.simplexes.contains_key(&spx));
228                                pairs_todo
229                                    .get_mut(&spx)
230                                    .unwrap_or(&mut HashSet::new())
231                                    .remove(&spx2);
232                                spx2_paired.push(spx);
233                            }
234                            pairs_todo.remove(&spx2);
235
236                            // //pairs should now be in a valid state again
237                            // for (a, bs) in &pairs_todo {
238                            //     debug_assert!(self.simplexes.contains(a));
239                            //     for b in bs {
240                            //         debug_assert!(self.simplexes.contains(b));
241                            //     }
242                            // }
243
244                            let spx1_label = self.simplexes.get(&spx1).unwrap().clone();
245                            let spx2_label = self.simplexes.get(&spx2).unwrap().clone();
246
247                            //remove spx1 and spx2
248                            self.simplexes.remove(&spx1);
249                            self.simplexes.remove(&spx2);
250
251                            //add the refinements of spx1 and spx2 and update the pairs todo
252                            for spx1_repl in spx1_replacement
253                                .as_simplicial_complex()
254                                .subset_by_label(&InteriorBoundaryLabel::Interior)
255                                .into_simplexes()
256                            {
257                                for spx in &spx1_paired {
258                                    pairs_todo
259                                        .entry(spx1_repl.clone())
260                                        .or_insert(HashSet::new())
261                                        .insert(spx.clone());
262                                    pairs_todo
263                                        .entry(spx.clone())
264                                        .or_insert(HashSet::new())
265                                        .insert(spx1_repl.clone());
266                                }
267                                self.simplexes.insert(spx1_repl, spx1_label.clone());
268                            }
269
270                            for spx2_repl in spx2_replacement
271                                .as_simplicial_complex()
272                                .subset_by_label(&InteriorBoundaryLabel::Interior)
273                                .into_simplexes()
274                            {
275                                for spx in &spx2_paired {
276                                    pairs_todo
277                                        .entry(spx2_repl.clone())
278                                        .or_insert(HashSet::new())
279                                        .insert(spx.clone());
280                                    pairs_todo
281                                        .entry(spx.clone())
282                                        .or_insert(HashSet::new())
283                                        .insert(spx2_repl.clone());
284                                }
285                                self.simplexes.insert(spx2_repl, spx2_label.clone());
286                            }
287                        }
288                    }
289                }
290            }
291        }
292
293        LabelledPartialSimplicialComplex::new_labelled_unchecked(ambient_space, self.simplexes)
294    }
295}