Skip to main content

conspire/geometry/ntree/defeature/
mod.rs

1use crate::geometry::ntree::node::cell::Cell;
2use crate::geometry::ntree::node::slot::Slot;
3#[cfg(test)]
4mod test;
5
6use crate::geometry::ntree::{Orthotree, node::Kind, subdivide::insert_bit};
7use std::{
8    cmp::Reverse,
9    collections::{BinaryHeap, HashMap, HashSet},
10    hash::Hash,
11};
12
13impl<const D: usize, const L: usize, const M: usize, const N: usize, T, U, V>
14    Orthotree<D, L, M, N, T, U, V>
15where
16    T: Cell,
17    U: Slot,
18    V: Copy + Eq + Hash,
19{
20    pub fn defeature(&mut self, minimum: usize) {
21        loop {
22            let protruded = self.reduce_protrusions();
23            let clustered = self.reduce_clusters(minimum);
24            if !protruded && !clustered {
25                break;
26            }
27        }
28    }
29    fn reduce_protrusions(&mut self) -> bool {
30        let (leaves, pairs) = self.leaf_pairs();
31        let mut differing: HashMap<usize, HashMap<V, usize>> = HashMap::new();
32        for (a, b, weight) in pairs {
33            let (value_a, value_b) = (self.nodes[a].value.unwrap(), self.nodes[b].value.unwrap());
34            if value_a != value_b {
35                *differing.entry(a).or_default().entry(value_b).or_default() += weight;
36                *differing.entry(b).or_default().entry(value_a).or_default() += weight;
37            }
38        }
39        let mut reassignments: Vec<(usize, V)> = Vec::new();
40        for &leaf in &leaves {
41            let Some(neighbors) = differing.get(&leaf) else {
42                continue;
43            };
44            let length: usize = self.nodes[leaf].length.cells();
45            let facet_area = length.pow((D - 1) as u32);
46            let differing_area: usize = neighbors.values().sum();
47            if differing_area >= (M - 1) * facet_area {
48                let into = *neighbors.iter().max_by_key(|&(_, &area)| area).unwrap().0;
49                reassignments.push((leaf, into));
50            }
51        }
52        let changed = !reassignments.is_empty();
53        reassignments.into_iter().for_each(|(leaf, into)| {
54            self.nodes[leaf].value = Some(into);
55        });
56        changed
57    }
58    fn reduce_clusters(&mut self, minimum: usize) -> bool {
59        let count = self.len();
60        let mut parent: Vec<usize> = (0..count).collect();
61        let (leaves, pairs) = self.leaf_pairs();
62        let mut edges: Vec<(usize, usize, usize)> = Vec::new();
63        for (a, b, weight) in pairs {
64            if self.nodes[a].value == self.nodes[b].value {
65                union(&mut parent, a, b);
66            } else {
67                edges.push((a, b, weight));
68            }
69        }
70        let mut volume: HashMap<usize, usize> = HashMap::new();
71        let mut value: HashMap<usize, V> = HashMap::new();
72        for &leaf in &leaves {
73            let root = find(&mut parent, leaf);
74            let length: usize = self.nodes[leaf].length.cells();
75            *volume.entry(root).or_default() += length.pow(D as u32);
76            value
77                .entry(root)
78                .or_insert_with(|| self.nodes[leaf].value.unwrap());
79        }
80        let mut adjacency: HashMap<usize, HashMap<usize, usize>> = HashMap::new();
81        for (leaf, other, span) in edges {
82            let (a, b) = (find(&mut parent, leaf), find(&mut parent, other));
83            if a != b {
84                *adjacency.entry(a).or_default().entry(b).or_default() += span;
85                *adjacency.entry(b).or_default().entry(a).or_default() += span;
86            }
87        }
88        let mut queue: BinaryHeap<Reverse<(usize, usize)>> = volume
89            .iter()
90            .filter(|&(_, &size)| size < minimum)
91            .map(|(&root, &size)| Reverse((size, root)))
92            .collect();
93        let mut changed = false;
94        while let Some(Reverse((size, root))) = queue.pop() {
95            if value.get(&root).is_none_or(|_| volume[&root] != size) || size >= minimum {
96                continue;
97            }
98            let neighbors = match adjacency.get(&root) {
99                Some(map) if !map.is_empty() => map,
100                _ => continue,
101            };
102            changed = true;
103            let mut by_value: HashMap<V, usize> = HashMap::new();
104            for (other, &span) in neighbors {
105                *by_value.entry(value[other]).or_default() += span;
106            }
107            let into = *by_value.iter().max_by_key(|&(_, &span)| span).unwrap().0;
108            let group: Vec<usize> = neighbors
109                .keys()
110                .copied()
111                .filter(|other| value[other] == into)
112                .chain([root])
113                .collect();
114            group[..group.len() - 1]
115                .iter()
116                .for_each(|&other| union(&mut parent, root, other));
117            let root = find(&mut parent, root);
118            let merged_volume = group.iter().map(|node| volume[node]).sum();
119            let mut merged: HashMap<usize, usize> = HashMap::new();
120            for node in &group {
121                if let Some(map) = adjacency.remove(node) {
122                    for (other, span) in map {
123                        let other = find(&mut parent, other);
124                        if other != root {
125                            *merged.entry(other).or_default() += span;
126                        }
127                    }
128                }
129            }
130            group.iter().filter(|&&node| node != root).for_each(|node| {
131                volume.remove(node);
132                value.remove(node);
133            });
134            for other in merged.keys() {
135                let map = adjacency.get_mut(other).unwrap();
136                let span: usize = group.iter().filter_map(|node| map.remove(node)).sum();
137                map.insert(root, span);
138            }
139            volume.insert(root, merged_volume);
140            value.insert(root, into);
141            adjacency.insert(root, merged);
142            if merged_volume < minimum {
143                queue.push(Reverse((merged_volume, root)));
144            }
145        }
146        leaves.iter().for_each(|&leaf| {
147            self.nodes[leaf].value = Some(value[&find(&mut parent, leaf)]);
148        });
149        changed
150    }
151    fn leaf_pairs(&self) -> (Vec<usize>, Vec<(usize, usize, usize)>) {
152        let leaves: Vec<usize> = (0..self.len())
153            .filter(|&i| self.nodes[i].is_leaf() && self.nodes[i].value.is_some())
154            .collect();
155        let mut visited: HashSet<(usize, usize)> = HashSet::new();
156        let mut pairs: Vec<(usize, usize, usize)> = Vec::new();
157        for &leaf in &leaves {
158            let length: usize = self.nodes[leaf].length.cells();
159            for face in 0..M {
160                if let Some(neighbor) = self.nodes[leaf].facets[face] {
161                    let mut others = Vec::new();
162                    self.face_leaves(neighbor.slot(), face ^ 1, &mut others);
163                    for other in others {
164                        if self.nodes[other].value.is_some() {
165                            let key = if leaf < other {
166                                (leaf, other)
167                            } else {
168                                (other, leaf)
169                            };
170                            if visited.insert(key) {
171                                let span: usize = self.nodes[other].length.cells();
172                                pairs.push((leaf, other, length.min(span).pow((D - 1) as u32)));
173                            }
174                        }
175                    }
176                }
177            }
178        }
179        (leaves, pairs)
180    }
181    fn face_leaves(&self, index: usize, face: usize, out: &mut Vec<usize>) {
182        match &self.nodes[index].kind {
183            Kind::Leaf => out.push(index),
184            Kind::Tree(orthants) => {
185                let (axis, side) = (face >> 1, face & 1);
186                for i in 0..L {
187                    let child = orthants[insert_bit(i, axis, side)].slot();
188                    self.face_leaves(child, face, out);
189                }
190            }
191        }
192    }
193}
194
195fn find(parent: &mut [usize], mut i: usize) -> usize {
196    while parent[i] != i {
197        parent[i] = parent[parent[i]];
198        i = parent[i];
199    }
200    i
201}
202
203fn union(parent: &mut [usize], a: usize, b: usize) {
204    let (a, b) = (find(parent, a), find(parent, b));
205    if a != b {
206        parent[a] = b;
207    }
208}