conspire/geometry/ntree/defeature/
mod.rs1use 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}