Skip to main content

algebraeon_geometry/
boolean_operations.rs

1use super::*;
2use crate::simplex_overlap::simplex_interior_overlap;
3use crate::{
4    ambient_space::common_space,
5    convex_hull::ConvexHull,
6    partial_simplicial_complex::{LabelledPartialSimplicialComplex, PartialSimplicialComplex},
7    simplex::Simplex,
8    simplex_collection::{InteriorOrBoundarySimplexCollection, LabelledSimplexCollection},
9    simplicial_complex::{LabelledSimplicialComplex, SimplicialComplex},
10    simplicial_disjoint_union::{LabelledSimplicialDisjointUnion, SimplicialDisjointUnion},
11};
12use rayon::iter::{IntoParallelIterator, ParallelIterator};
13use std::collections::{HashMap, HashSet};
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16enum VennLabel {
17    Left,
18    Middle,
19    Right,
20}
21
22fn simplex_venn<'f, FS: OrderedRingSignature + FieldSignature>(
23    left_simplex: &Simplex<'f, FS>,
24    right_simplex: &Simplex<'f, FS>,
25) -> LabelledPartialSimplicialComplex<'f, FS, VennLabel>
26where
27    FS::Set: Hash,
28{
29    let ambient_space =
30        common_space(left_simplex.ambient_space(), right_simplex.ambient_space()).unwrap();
31
32    // optimization
33    if !simplex_interior_overlap(left_simplex, right_simplex) {
34        return LabelledPartialSimplicialComplex::<'f, FS, VennLabel>::new_labelled_unchecked(
35            ambient_space,
36            HashMap::from([
37                (left_simplex.clone(), VennLabel::Left),
38                (right_simplex.clone(), VennLabel::Right),
39            ]),
40        );
41    }
42
43    let overlap = ConvexHull::intersect(
44        &ConvexHull::from_simplex(left_simplex.clone()),
45        &ConvexHull::from_simplex(right_simplex.clone()),
46    );
47
48    // optimization
49    if overlap
50        .to_simplicial_complex()
51        .interior()
52        .simplexes()
53        .is_empty()
54    {
55        return LabelledPartialSimplicialComplex::<'f, FS, VennLabel>::new_labelled_unchecked(
56            ambient_space,
57            HashMap::from([
58                (left_simplex.clone(), VennLabel::Left),
59                (right_simplex.clone(), VennLabel::Right),
60            ]),
61        );
62    }
63
64    let mut self_ext = overlap.clone();
65    for pt in left_simplex.points() {
66        self_ext.extend_by_point(pt.clone());
67    }
68    let self_parts = self_ext.to_simplicial_complex().interior().into_simplexes();
69
70    let mut other_ext = overlap.clone();
71    for pt in right_simplex.points() {
72        other_ext.extend_by_point(pt.clone());
73    }
74    let other_parts = other_ext
75        .to_simplicial_complex()
76        .interior()
77        .into_simplexes();
78
79    let all_parts = self_parts.union(&other_parts);
80    LabelledPartialSimplicialComplex::<'f, FS, VennLabel>::new_labelled_unchecked(
81        ambient_space,
82        all_parts
83            .into_iter()
84            .map(|spx| {
85                let label = match (self_parts.contains(spx), other_parts.contains(spx)) {
86                    (true, false) => VennLabel::Left,
87                    (true, true) => VennLabel::Middle,
88                    (false, true) => VennLabel::Right,
89                    (false, false) => {
90                        unreachable!()
91                    }
92                };
93                (spx.clone(), label)
94            })
95            .collect(),
96    )
97}
98
99impl<'f, FS: OrderedRingSignature + FieldSignature, T: Eq + Clone + Send + Sync>
100    LabelledSimplicialDisjointUnion<'f, FS, T>
101where
102    FS::Set: Hash,
103{
104    pub(crate) fn subtract_raw<S: Eq + Clone + Send + Sync>(
105        &self,
106        other: &LabelledSimplicialDisjointUnion<'f, FS, S>,
107    ) -> LabelledSimplicialDisjointUnion<'f, FS, T> {
108        let ambient_space = common_space(self.ambient_space(), other.ambient_space()).unwrap();
109
110        Self::new_labelled_unchecked(
111            ambient_space,
112            self.labelled_simplexes()
113                .into_iter()
114                .collect::<Vec<_>>()
115                .into_par_iter()
116                .map(|(self_spx, self_spx_label)| {
117                    let mut self_leftover = HashSet::from([self_spx.clone()]);
118                    for other_spx in other.simplexes() {
119                        self_leftover = self_leftover
120                            .into_iter()
121                            .flat_map(|self_leftover_spx| {
122                                simplex_venn(&self_leftover_spx, other_spx)
123                                    .subset_by_label(&VennLabel::Left)
124                                    .into_simplexes()
125                            })
126                            .collect();
127                    }
128                    self_leftover
129                        .into_iter()
130                        .map(|spx| (spx, self_spx_label.clone()))
131                        .collect::<Vec<_>>()
132                })
133                .flatten()
134                .collect(),
135        )
136    }
137
138    pub(crate) fn intersect_raw<S: Eq + Clone + Send + Sync>(
139        &self,
140        other: &LabelledSimplicialDisjointUnion<'f, FS, S>,
141    ) -> LabelledSimplicialDisjointUnion<'f, FS, (T, S)> {
142        let ambient_space = common_space(self.ambient_space(), other.ambient_space()).unwrap();
143        LabelledSimplicialDisjointUnion::new_labelled_unchecked(ambient_space, {
144            let mut simplexes = HashMap::new();
145            for (self_spx, self_spx_label) in self.labelled_simplexes() {
146                for (other_spx, other_spx_label) in other.labelled_simplexes() {
147                    for spx in simplex_venn(self_spx, other_spx)
148                        .subset_by_label(&VennLabel::Middle)
149                        .into_simplexes()
150                    {
151                        simplexes.insert(spx, (self_spx_label.clone(), other_spx_label.clone()));
152                    }
153                }
154            }
155            simplexes
156        })
157    }
158
159    pub(crate) fn union_raw(&self, other: &Self) -> SimplicialDisjointUnion<'f, FS> {
160        let ambient_space = common_space(self.ambient_space(), other.ambient_space()).unwrap();
161        let mut simplexes = HashSet::new();
162        for spx in Self::subtract_raw(other, self).into_simplexes() {
163            simplexes.insert(spx);
164        }
165        for spx in self.simplexes() {
166            simplexes.insert(spx.clone());
167        }
168        Self::new_unchecked(ambient_space, simplexes)
169    }
170}
171
172pub trait Difference<Other> {
173    type Output;
174    fn difference(&self, other: &Other) -> Self::Output;
175}
176
177pub trait Intersect<Other> {
178    type Output;
179    fn intersect(&self, other: &Other) -> Self::Output;
180}
181
182pub trait Union<Other> {
183    type Output;
184    fn union(&self, other: &Other) -> Self::Output;
185}
186
187impl<
188    'f,
189    FS: OrderedRingSignature + FieldSignature,
190    T: Eq + Clone + Send + Sync,
191    S: Eq + Clone + Send + Sync,
192> Difference<LabelledSimplicialDisjointUnion<'f, FS, S>>
193    for LabelledSimplicialDisjointUnion<'f, FS, T>
194where
195    FS::Set: Hash,
196{
197    type Output = LabelledPartialSimplicialComplex<'f, FS, T>;
198
199    fn difference(&self, other: &LabelledSimplicialDisjointUnion<'f, FS, S>) -> Self::Output {
200        self.subtract_raw(other)
201            .refine_into_partial_simplicial_complex()
202            .simplify()
203    }
204}
205
206impl<
207    'f,
208    FS: OrderedRingSignature + FieldSignature,
209    T: Eq + Clone + Send + Sync,
210    S: Eq + Clone + Send + Sync,
211> Difference<LabelledPartialSimplicialComplex<'f, FS, S>>
212    for LabelledSimplicialDisjointUnion<'f, FS, T>
213where
214    FS::Set: Hash,
215{
216    type Output = LabelledPartialSimplicialComplex<'f, FS, T>;
217
218    fn difference(&self, other: &LabelledPartialSimplicialComplex<'f, FS, S>) -> Self::Output {
219        self.difference(&other.clone().into_simplicial_disjoint_union())
220    }
221}
222
223impl<
224    'f,
225    FS: OrderedRingSignature + FieldSignature,
226    T: Eq + Clone + Send + Sync,
227    S: Eq + Clone + Send + Sync,
228> Difference<LabelledSimplicialDisjointUnion<'f, FS, S>>
229    for LabelledPartialSimplicialComplex<'f, FS, T>
230where
231    FS::Set: Hash,
232{
233    type Output = LabelledPartialSimplicialComplex<'f, FS, T>;
234
235    fn difference(&self, other: &LabelledSimplicialDisjointUnion<'f, FS, S>) -> Self::Output {
236        self.clone()
237            .into_simplicial_disjoint_union()
238            .difference(other)
239    }
240}
241
242impl<
243    'f,
244    FS: OrderedRingSignature + FieldSignature,
245    T: Eq + Clone + Send + Sync,
246    S: Eq + Clone + Send + Sync,
247> Difference<LabelledPartialSimplicialComplex<'f, FS, S>>
248    for LabelledPartialSimplicialComplex<'f, FS, T>
249where
250    FS::Set: Hash,
251{
252    type Output = LabelledPartialSimplicialComplex<'f, FS, T>;
253
254    fn difference(&self, other: &LabelledPartialSimplicialComplex<'f, FS, S>) -> Self::Output {
255        self.clone()
256            .into_simplicial_disjoint_union()
257            .difference(&other.clone().into_simplicial_disjoint_union())
258    }
259}
260
261impl<
262    'f,
263    FS: OrderedRingSignature + FieldSignature,
264    T: Eq + Clone + Send + Sync,
265    S: Eq + Clone + Send + Sync,
266> Difference<LabelledSimplicialComplex<'f, FS, S>> for LabelledSimplicialDisjointUnion<'f, FS, T>
267where
268    FS::Set: Hash,
269{
270    type Output = LabelledPartialSimplicialComplex<'f, FS, T>;
271
272    fn difference(&self, other: &LabelledSimplicialComplex<'f, FS, S>) -> Self::Output {
273        self.difference(&other.clone().into_simplicial_disjoint_union())
274    }
275}
276
277impl<
278    'f,
279    FS: OrderedRingSignature + FieldSignature,
280    T: Eq + Clone + Send + Sync,
281    S: Eq + Clone + Send + Sync,
282> Difference<LabelledSimplicialComplex<'f, FS, S>> for LabelledPartialSimplicialComplex<'f, FS, T>
283where
284    FS::Set: Hash,
285{
286    type Output = LabelledPartialSimplicialComplex<'f, FS, T>;
287
288    fn difference(&self, other: &LabelledSimplicialComplex<'f, FS, S>) -> Self::Output {
289        self.clone()
290            .into_simplicial_disjoint_union()
291            .difference(&other.clone().into_simplicial_disjoint_union())
292    }
293}
294
295impl<
296    'f,
297    FS: OrderedRingSignature + FieldSignature,
298    T: Eq + Clone + Send + Sync,
299    S: Eq + Clone + Send + Sync,
300> Difference<LabelledSimplicialDisjointUnion<'f, FS, S>> for LabelledSimplicialComplex<'f, FS, T>
301where
302    FS::Set: Hash,
303{
304    type Output = LabelledPartialSimplicialComplex<'f, FS, T>;
305
306    fn difference(&self, other: &LabelledSimplicialDisjointUnion<'f, FS, S>) -> Self::Output {
307        self.clone()
308            .into_simplicial_disjoint_union()
309            .difference(other)
310    }
311}
312
313impl<
314    'f,
315    FS: OrderedRingSignature + FieldSignature,
316    T: Eq + Clone + Send + Sync,
317    S: Eq + Clone + Send + Sync,
318> Difference<LabelledPartialSimplicialComplex<'f, FS, S>> for LabelledSimplicialComplex<'f, FS, T>
319where
320    FS::Set: Hash,
321{
322    type Output = LabelledPartialSimplicialComplex<'f, FS, T>;
323
324    fn difference(&self, other: &LabelledPartialSimplicialComplex<'f, FS, S>) -> Self::Output {
325        self.clone()
326            .into_simplicial_disjoint_union()
327            .difference(&other.clone().into_simplicial_disjoint_union())
328    }
329}
330
331impl<
332    'f,
333    FS: OrderedRingSignature + FieldSignature,
334    T: Eq + Clone + Send + Sync,
335    S: Eq + Clone + Send + Sync,
336> Difference<LabelledSimplicialComplex<'f, FS, S>> for LabelledSimplicialComplex<'f, FS, T>
337where
338    FS::Set: Hash,
339{
340    type Output = LabelledPartialSimplicialComplex<'f, FS, T>;
341
342    fn difference(&self, other: &LabelledSimplicialComplex<'f, FS, S>) -> Self::Output {
343        self.clone()
344            .into_simplicial_disjoint_union()
345            .difference(&other.clone().into_simplicial_disjoint_union())
346    }
347}
348
349impl<'f, FS: OrderedRingSignature + FieldSignature> Intersect<SimplicialDisjointUnion<'f, FS>>
350    for SimplicialDisjointUnion<'f, FS>
351where
352    FS::Set: Hash,
353{
354    type Output = PartialSimplicialComplex<'f, FS>;
355
356    fn intersect(&self, other: &SimplicialDisjointUnion<'f, FS>) -> Self::Output {
357        self.intersect_raw(other)
358            .forget_labels()
359            .refine_into_partial_simplicial_complex()
360            .simplify()
361    }
362}
363
364impl<'f, FS: OrderedRingSignature + FieldSignature> Intersect<PartialSimplicialComplex<'f, FS>>
365    for SimplicialDisjointUnion<'f, FS>
366where
367    FS::Set: Hash,
368{
369    type Output = PartialSimplicialComplex<'f, FS>;
370
371    fn intersect(&self, other: &PartialSimplicialComplex<'f, FS>) -> Self::Output {
372        self.intersect(&other.clone().into_simplicial_disjoint_union())
373    }
374}
375
376impl<'f, FS: OrderedRingSignature + FieldSignature> Intersect<SimplicialDisjointUnion<'f, FS>>
377    for PartialSimplicialComplex<'f, FS>
378where
379    FS::Set: Hash,
380{
381    type Output = PartialSimplicialComplex<'f, FS>;
382
383    fn intersect(&self, other: &SimplicialDisjointUnion<'f, FS>) -> Self::Output {
384        self.clone()
385            .into_simplicial_disjoint_union()
386            .intersect(other)
387    }
388}
389
390impl<'f, FS: OrderedRingSignature + FieldSignature> Intersect<PartialSimplicialComplex<'f, FS>>
391    for PartialSimplicialComplex<'f, FS>
392where
393    FS::Set: Hash,
394{
395    type Output = PartialSimplicialComplex<'f, FS>;
396
397    fn intersect(&self, other: &PartialSimplicialComplex<'f, FS>) -> Self::Output {
398        self.clone()
399            .into_simplicial_disjoint_union()
400            .intersect(&other.clone().into_simplicial_disjoint_union())
401    }
402}
403
404impl<'f, FS: OrderedRingSignature + FieldSignature> Intersect<SimplicialDisjointUnion<'f, FS>>
405    for SimplicialComplex<'f, FS>
406where
407    FS::Set: Hash,
408{
409    type Output = PartialSimplicialComplex<'f, FS>;
410
411    fn intersect(&self, other: &SimplicialDisjointUnion<'f, FS>) -> Self::Output {
412        self.clone()
413            .into_simplicial_disjoint_union()
414            .intersect(other)
415    }
416}
417
418impl<'f, FS: OrderedRingSignature + FieldSignature> Intersect<PartialSimplicialComplex<'f, FS>>
419    for SimplicialComplex<'f, FS>
420where
421    FS::Set: Hash,
422{
423    type Output = PartialSimplicialComplex<'f, FS>;
424
425    fn intersect(&self, other: &PartialSimplicialComplex<'f, FS>) -> Self::Output {
426        self.clone()
427            .into_simplicial_disjoint_union()
428            .intersect(&other.clone().into_simplicial_disjoint_union())
429    }
430}
431
432impl<'f, FS: OrderedRingSignature + FieldSignature> Intersect<SimplicialComplex<'f, FS>>
433    for SimplicialDisjointUnion<'f, FS>
434where
435    FS::Set: Hash,
436{
437    type Output = PartialSimplicialComplex<'f, FS>;
438
439    fn intersect(&self, other: &SimplicialComplex<'f, FS>) -> Self::Output {
440        self.intersect(&other.clone().into_simplicial_disjoint_union())
441    }
442}
443
444impl<'f, FS: OrderedRingSignature + FieldSignature> Intersect<SimplicialComplex<'f, FS>>
445    for PartialSimplicialComplex<'f, FS>
446where
447    FS::Set: Hash,
448{
449    type Output = PartialSimplicialComplex<'f, FS>;
450
451    fn intersect(&self, other: &SimplicialComplex<'f, FS>) -> Self::Output {
452        self.clone()
453            .into_simplicial_disjoint_union()
454            .intersect(&other.clone().into_simplicial_disjoint_union())
455    }
456}
457
458impl<'f, FS: OrderedRingSignature + FieldSignature> Intersect<SimplicialComplex<'f, FS>>
459    for SimplicialComplex<'f, FS>
460where
461    FS::Set: Hash,
462{
463    type Output = SimplicialComplex<'f, FS>;
464
465    fn intersect(&self, other: &SimplicialComplex<'f, FS>) -> Self::Output {
466        self.clone()
467            .into_simplicial_disjoint_union()
468            .intersect(&other.clone().into_simplicial_disjoint_union())
469            .try_into_simplicial_complex()
470            .unwrap()
471    }
472}
473
474impl<'f, FS: OrderedRingSignature + FieldSignature> Union<SimplicialDisjointUnion<'f, FS>>
475    for SimplicialDisjointUnion<'f, FS>
476where
477    FS::Set: Hash,
478{
479    type Output = PartialSimplicialComplex<'f, FS>;
480
481    fn union(&self, other: &SimplicialDisjointUnion<'f, FS>) -> Self::Output {
482        self.union_raw(other)
483            .refine_into_partial_simplicial_complex()
484            .simplify()
485    }
486}
487
488impl<'f, FS: OrderedRingSignature + FieldSignature> Union<PartialSimplicialComplex<'f, FS>>
489    for SimplicialDisjointUnion<'f, FS>
490where
491    FS::Set: Hash,
492{
493    type Output = PartialSimplicialComplex<'f, FS>;
494
495    fn union(&self, other: &PartialSimplicialComplex<'f, FS>) -> Self::Output {
496        self.union(&other.clone().into_simplicial_disjoint_union())
497    }
498}
499
500impl<'f, FS: OrderedRingSignature + FieldSignature> Union<SimplicialDisjointUnion<'f, FS>>
501    for PartialSimplicialComplex<'f, FS>
502where
503    FS::Set: Hash,
504{
505    type Output = PartialSimplicialComplex<'f, FS>;
506
507    fn union(&self, other: &SimplicialDisjointUnion<'f, FS>) -> Self::Output {
508        self.clone().into_simplicial_disjoint_union().union(other)
509    }
510}
511
512impl<'f, FS: OrderedRingSignature + FieldSignature> Union<PartialSimplicialComplex<'f, FS>>
513    for PartialSimplicialComplex<'f, FS>
514where
515    FS::Set: Hash,
516{
517    type Output = PartialSimplicialComplex<'f, FS>;
518
519    fn union(&self, other: &PartialSimplicialComplex<'f, FS>) -> Self::Output {
520        self.clone()
521            .into_simplicial_disjoint_union()
522            .union(&other.clone().into_simplicial_disjoint_union())
523    }
524}
525
526impl<'f, FS: OrderedRingSignature + FieldSignature> Union<SimplicialDisjointUnion<'f, FS>>
527    for SimplicialComplex<'f, FS>
528where
529    FS::Set: Hash,
530{
531    type Output = PartialSimplicialComplex<'f, FS>;
532
533    fn union(&self, other: &SimplicialDisjointUnion<'f, FS>) -> Self::Output {
534        self.clone().into_simplicial_disjoint_union().union(other)
535    }
536}
537
538impl<'f, FS: OrderedRingSignature + FieldSignature> Union<PartialSimplicialComplex<'f, FS>>
539    for SimplicialComplex<'f, FS>
540where
541    FS::Set: Hash,
542{
543    type Output = PartialSimplicialComplex<'f, FS>;
544
545    fn union(&self, other: &PartialSimplicialComplex<'f, FS>) -> Self::Output {
546        self.clone()
547            .into_simplicial_disjoint_union()
548            .union(&other.clone().into_simplicial_disjoint_union())
549    }
550}
551
552impl<'f, FS: OrderedRingSignature + FieldSignature> Union<SimplicialComplex<'f, FS>>
553    for SimplicialDisjointUnion<'f, FS>
554where
555    FS::Set: Hash,
556{
557    type Output = PartialSimplicialComplex<'f, FS>;
558
559    fn union(&self, other: &SimplicialComplex<'f, FS>) -> Self::Output {
560        self.union(&other.clone().into_simplicial_disjoint_union())
561    }
562}
563
564impl<'f, FS: OrderedRingSignature + FieldSignature> Union<SimplicialComplex<'f, FS>>
565    for PartialSimplicialComplex<'f, FS>
566where
567    FS::Set: Hash,
568{
569    type Output = PartialSimplicialComplex<'f, FS>;
570
571    fn union(&self, other: &SimplicialComplex<'f, FS>) -> Self::Output {
572        self.clone()
573            .into_simplicial_disjoint_union()
574            .union(&other.clone().into_simplicial_disjoint_union())
575    }
576}
577
578impl<'f, FS: OrderedRingSignature + FieldSignature> Union<SimplicialComplex<'f, FS>>
579    for SimplicialComplex<'f, FS>
580where
581    FS::Set: Hash,
582{
583    type Output = SimplicialComplex<'f, FS>;
584
585    fn union(&self, other: &SimplicialComplex<'f, FS>) -> Self::Output {
586        self.clone()
587            .into_simplicial_disjoint_union()
588            .union(&other.clone().into_simplicial_disjoint_union())
589            .try_into_simplicial_complex()
590            .unwrap()
591    }
592}
593
594// impl<'f, FS: OrderedRingSignature + FieldSignature> SimplicialComplex<'f, FS>
595// where
596//     FS::Set: Hash,
597// {
598//     pub fn union_raw(&self, other: &Self) -> Self {
599//         LabelledSimplicialDisjointUnion::union_raw(&self.into(), &other.into())
600//             .refine_into_partial_simplicial_complex()
601//             .try_into_simplicial_complex()
602//             .unwrap()
603//     }
604
605//     pub fn union(&self, other: &Self) -> Self {
606//         self.union_raw(other).simplify()
607//     }
608
609//     pub fn intersect_raw(&self, other: &Self) -> Self {
610//         LabelledSimplicialDisjointUnion::intersect_raw(&self.into(), &other.into())
611//             .refine_into_partial_simplicial_complex()
612//             .into_forget_labels()
613//             .try_into_simplicial_complex()
614//             .unwrap()
615//     }
616
617//     pub fn intersect(&self, other: &Self) -> Self {
618//         self.intersect_raw(other).simplify()
619//     }
620// }
621
622/*
623 - Venn dju <T1> and dju <T2> to produce dju <(Option<T1>, Option<T2>)>
624 - Replace partial simplicial complex (psc) with labelled simplicial complex <bool>
625 - Intersect psc, psc -> psc
626 - Union psc, psc -> psc
627 - Subtract psc, psc -> psc
628 - Have a trait for a collection of labelled simplexes
629   - Labelled subset
630   - Filtered labelled subset
631   - Union -> PartialSimplicialComplex
632   - Intersection -> PartialSimplicialComplex
633   - Difference -> PartialSimplicialComplex
634 - Implement it for:
635   - SimplexUnion
636   - SimplexDisjointUnion
637   - SemiSimplicialComplex
638   - SimplicialComplex
639*/