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