Skip to main content

ark/tree/
mod.rs

1
2pub mod signed;
3
4use std::cmp;
5
6/// The max radix of this tree is 4.
7const RADIX: usize = 4;
8
9#[derive(Debug, Clone)]
10pub struct Node {
11	idx: u32,
12	parent: Option<u32>,
13	children: [Option<u32>; RADIX],
14	/// Exclusive range of leaves, allowed to revolve back to 0.
15	leaves: (u32, u32),
16	nb_tree_leaves: u32,
17	level: u32,
18}
19
20impl Node {
21	// Tree construction arithmetic on bounded leaf indices and a small RADIX.
22	#[allow(clippy::arithmetic_side_effects)]
23	fn new_leaf(idx: usize, nb_tree_leaves: usize) -> Node {
24		let idx = u32::try_from(idx).expect("leaf index fits in u32");
25		let nb_tree_leaves = u32::try_from(nb_tree_leaves).expect("leaf count fits in u32");
26		Node {
27			idx,
28			parent: None,
29			children: [None; RADIX],
30			leaves: (idx, (idx+1) % nb_tree_leaves),
31			nb_tree_leaves,
32			level: 0,
33		}
34	}
35
36	pub fn idx(&self) -> usize {
37		self.idx as usize
38	}
39
40	/// The index among internal nodes, starting after the leaves
41	///
42	/// Panics if this node is a leaf node, if [Node::is_leaf] returns true.
43	pub fn internal_idx(&self) -> usize {
44		self.idx.checked_sub(self.nb_tree_leaves)
45			.expect("called internal_idx on leaf node") as usize
46	}
47
48	pub fn parent(&self) -> Option<usize> {
49		self.parent.map(|p| p as usize)
50	}
51
52	pub fn children(&self) -> impl Iterator<Item = usize> {
53		self.children.clone().into_iter().filter_map(|c| c).map(|c| c as usize)
54	}
55
56	/// The level of the node in the tree, starting with 0 for a leaf
57	pub fn level(&self) -> usize {
58		self.level as usize
59	}
60
61	/// The internal level of the node in the tree
62	///
63	/// Panics if this node is a leaf node, if [Node::is_leaf] returns true.
64	///
65	/// Returns 0 for a node  that has leaves as children
66	pub fn internal_level(&self) -> usize {
67		self.level.checked_sub(1).expect("called internal_level on leaf node") as usize
68	}
69
70	/// An iterator over all leaf indices under this node.
71	#[allow(clippy::arithmetic_side_effects)]
72	pub fn leaves(&self) -> impl Iterator<Item = usize> + Clone {
73		let (first, last) = self.leaves;
74		let nb = self.nb_tree_leaves;
75		(first..)
76			.take(nb as usize)
77			.map(move |e| e % nb)
78			.take_while(move |e| first == last || *e != last)
79			.map(|e| e as usize)
80	}
81
82	pub fn is_leaf(&self) -> bool {
83		self.children.iter().all(|o| o.is_none())
84	}
85
86	pub fn is_root(&self) -> bool {
87		self.parent.is_none()
88	}
89}
90
91//TODO(stevenroose) consider eliminating this type in favor of straight in-line iterators
92// for all nodes and for branches
93/// A radix-4 tree.
94#[derive(Debug, Clone)]
95pub struct Tree {
96	/// The nodes in the tree, starting with all the leaves
97	/// and then building up towards the root.
98	nodes: Vec<Node>,
99	nb_leaves: usize,
100}
101
102impl Tree {
103	/// Calculate the total number of nodes a tree would have
104	/// for the given number of leaves.
105	// Tree-size accumulation: bounded by RADIX-base log of nb_leaves.
106	#[allow(clippy::arithmetic_side_effects)]
107	pub fn nb_nodes_for_leaves(nb_leaves: usize) -> usize {
108		let mut ret = nb_leaves;
109		let mut left = nb_leaves;
110		while left > 1 {
111			let radix = cmp::min(left, RADIX);
112			left -= radix;
113			left += 1;
114			ret += 1;
115		}
116		ret
117	}
118
119	// Tree construction: cursor/nb_children/level bounded by RADIX-base log of nb_leaves.
120	#[allow(clippy::arithmetic_side_effects)]
121	pub fn new(
122		nb_leaves: usize,
123	) -> Tree {
124		assert_ne!(nb_leaves, 0, "trees can't be empty");
125
126		let mut nodes = Vec::with_capacity(Tree::nb_nodes_for_leaves(nb_leaves));
127
128		// First we add all the leaves to the tree.
129		nodes.extend((0..nb_leaves).map(|i| Node::new_leaf(i, nb_leaves)));
130
131		let mut cursor = 0;
132		// As long as there is more than 1 element on the leftover stack,
133		// we have to add more nodes.
134		while cursor < nodes.len() - 1 {
135			let mut children = [None; RADIX];
136			let mut nb_children = 0;
137			let mut max_child_level = 0;
138			while cursor < nodes.len() && nb_children < RADIX {
139				children[nb_children] = Some(u32::try_from(cursor).expect("node index fits in u32"));
140
141				let new_idx = nodes.len(); // idx of next node
142				let child = &mut nodes[cursor];
143				child.parent = Some(u32::try_from(new_idx).expect("node index fits in u32"));
144
145				// adjust level and leaf indices
146				if child.level > max_child_level {
147					max_child_level = child.level;
148				}
149
150				cursor += 1;
151				nb_children += 1;
152			}
153			nodes.push(Node {
154				idx: u32::try_from(nodes.len()).expect("node index fits in u32"),
155				leaves: (
156					nodes[children.first().unwrap().unwrap() as usize].leaves.0,
157					nodes[children.iter().filter_map(|c| *c).last().unwrap() as usize].leaves.1,
158				),
159				children,
160				level: max_child_level + 1,
161				parent: None,
162				nb_tree_leaves: u32::try_from(nb_leaves).expect("leaf count fits in u32"),
163			});
164		}
165
166		Tree { nodes, nb_leaves }
167	}
168
169	pub fn nb_leaves(&self) -> usize {
170		self.nb_leaves
171	}
172
173	pub fn nb_nodes(&self) -> usize {
174		self.nodes.len()
175	}
176
177	/// The number of internal nodes
178	pub fn nb_internal_nodes(&self) -> usize {
179		self.nodes.len().checked_sub(self.nb_leaves)
180			.expect("tree can't have less nodes than leaves")
181	}
182
183	pub fn node_at(&self, node_idx: usize) -> &Node {
184		self.nodes.get(node_idx).expect("node_idx out of bounds")
185	}
186
187	pub fn root(&self) -> &Node {
188		self.nodes.last().expect("no empty trees")
189	}
190
191	/// Iterate over all nodes, starting with the leaves, towards the root.
192	pub fn iter(&self) -> std::slice::Iter<'_, Node> {
193		self.nodes.iter()
194	}
195
196	/// Iterate over all internal nodes, starting with the ones
197	/// right beyond the leaves, towards the root.
198	pub fn iter_internal(&self) -> std::slice::Iter<'_, Node> {
199		self.nodes[self.nb_leaves..].iter()
200	}
201
202	/// Iterate over all nodes, starting with the leaves, towards the root.
203	pub fn into_iter(self) -> std::vec::IntoIter<Node> {
204		self.nodes.into_iter()
205	}
206
207	/// Iterate nodes over a branch starting at the leaf
208	/// with index `leaf_idx` ending in the root.
209	pub fn iter_branch(&self, leaf_idx: usize) -> BranchIter<'_> {
210		assert!(leaf_idx < self.nodes.len());
211		BranchIter {
212			tree: &self,
213			cursor: Some(leaf_idx),
214		}
215	}
216
217	/// Iterate over ancestors of a node with child indices.
218	///
219	/// Starting from `node_idx`, walks up towards the root. The starting node
220	/// is excluded from iteration. Each returned tuple `(ancestor_idx, child_idx)`
221	/// indicates that `child_idx` is the child position that leads back down
222	/// towards `node_idx`.
223	///
224	/// # Example
225	///
226	/// For a node 12 with children `[4, 5, 6, 7]`:
227	/// ```text
228	/// iter_branch_with_output(6) yields (12, 2), ..., (root_idx, ...)
229	/// ```
230	/// Node 6 is at child index 2 (0-indexed) of node 12.
231	pub fn iter_branch_with_output(&self, node_idx: usize) -> BranchWithOutputIter<'_> {
232		assert!(node_idx < self.nodes.len());
233		BranchWithOutputIter {
234			tree: self,
235			prev_idx: node_idx,
236			cursor: self.nodes[node_idx].parent(),
237		}
238	}
239
240	pub fn parent_idx_of(&self, idx: usize) -> Option<usize> {
241		self.nodes.get(idx).and_then(|n| n.parent.map(|c| c as usize))
242	}
243
244	/// Returns index of the the parent of the node with given `idx`,
245	/// and the index of the node among its siblings.
246	pub fn parent_idx_of_with_sibling_idx(&self, idx: usize) -> Option<(usize, usize)> {
247		self.nodes.get(idx).and_then(|n| n.parent).map(|parent_idx| {
248			let child_idx = self.nodes[parent_idx as usize].children.iter()
249				.position(|c| *c == Some(u32::try_from(idx).expect("node index fits in u32")))
250				.expect("broken tree");
251			(self.nodes[parent_idx as usize].idx as usize, child_idx as usize)
252		})
253	}
254
255}
256
257/// Iterates a tree branch.
258#[derive(Clone)]
259pub struct BranchIter<'a> {
260	tree: &'a Tree,
261	cursor: Option<usize>,
262}
263
264impl<'a> Iterator for BranchIter<'a> {
265	type Item = &'a Node;
266	fn next(&mut self) -> Option<Self::Item> {
267		if let Some(cursor) = self.cursor {
268			let ret = &self.tree.nodes[cursor];
269			self.cursor = ret.parent();
270			Some(ret)
271		} else {
272			None
273		}
274	}
275}
276
277/// Iterates ancestors of a node, returning (node_idx, child_idx) tuples.
278#[derive(Clone)]
279pub struct BranchWithOutputIter<'a> {
280	tree: &'a Tree,
281	prev_idx: usize,
282	cursor: Option<usize>,
283}
284
285impl<'a> Iterator for BranchWithOutputIter<'a> {
286	type Item = (usize, usize);
287	fn next(&mut self) -> Option<Self::Item> {
288		let cursor = self.cursor?;
289		let node = &self.tree.nodes[cursor];
290		let child_idx = node.children()
291			.position(|c| c == self.prev_idx)
292			.expect("broken tree");
293		self.prev_idx = cursor;
294		self.cursor = node.parent();
295		Some((cursor, child_idx))
296	}
297}
298
299#[cfg(test)]
300mod test {
301	use std::collections::HashSet;
302
303use super::*;
304
305	#[test]
306	fn test_simple_tree() {
307		for n in 1..100 {
308			let tree = Tree::new(n);
309
310			assert!(tree.nodes.iter().rev().skip(1).all(|n| n.parent.is_some()));
311			assert!(tree.nodes.iter().enumerate().skip(tree.nb_leaves).all(|(i, n)| {
312				n.children.iter().filter_map(|v| *v)
313					.all(|c| tree.nodes[c as usize].parent == Some(i as u32))
314			}));
315			assert!(tree.nodes.iter().enumerate().rev().skip(1).all(|(i, n)| {
316				let parent_idx = n.parent.unwrap() as usize;
317				tree.nodes[parent_idx].children.iter().find(|c| **c == Some(i as u32)).is_some()
318			}));
319			assert_eq!(Tree::nb_nodes_for_leaves(n), tree.nb_nodes(), "leaves: {}", n);
320		}
321	}
322
323	#[test]
324	fn test_leaves_range() {
325		for n in 1..42 {
326			let tree = Tree::new(n);
327
328			for node in &tree.nodes[0..tree.nb_leaves()] {
329				assert_eq!(node.leaves().collect::<Vec<_>>(), vec![node.idx()]);
330			}
331			for node in tree.iter() {
332				if !node.is_leaf() {
333					assert_eq!(
334						node.leaves().count(),
335						node.children().map(|c| tree.nodes[c].leaves().count()).sum::<usize>(),
336						"idx: {}", node.idx(),
337					);
338				}
339				assert!(node.leaves().all(|l| l < tree.nb_leaves()));
340				assert_eq!(
341					node.leaves().count(),
342					node.leaves().collect::<HashSet<_>>().len(),
343				);
344			}
345			println!("n={n} ok");
346		}
347	}
348
349	#[test]
350	fn test_iter_branch_with_output() {
351		for n in 1..100 {
352			let tree = Tree::new(n);
353
354			for start_idx in 0..tree.nb_nodes() {
355				let results: Vec<_> = tree.iter_branch_with_output(start_idx).collect();
356
357				// 1. Verify the iterator excludes the starting node
358				assert!(results.iter().all(|(idx, _)| *idx != start_idx));
359
360				// 2. Verify each returned node is an ancestor of the previous
361				let mut expected_parent = tree.nodes[start_idx].parent();
362				for (ancestor_idx, _) in &results {
363					assert_eq!(Some(*ancestor_idx), expected_parent);
364					expected_parent = tree.nodes[*ancestor_idx].parent();
365				}
366
367				// 3. Verify child_idx actually points back down the branch
368				let mut prev = start_idx;
369				for (ancestor_idx, child_idx) in &results {
370					let child = tree.nodes[*ancestor_idx].children().nth(*child_idx).unwrap();
371					assert_eq!(child, prev);
372					prev = *ancestor_idx;
373				}
374
375				// 4. Verify the last node is the root (has no parent)
376				if let Some((last_idx, _)) = results.last() {
377					assert!(tree.nodes[*last_idx].is_root());
378				}
379
380				// 5. Verify consistency with iter_branch (same path, minus starting node)
381				let branch_len = tree.iter_branch(start_idx).skip(1).count();
382				assert_eq!(results.len(), branch_len);
383			}
384		}
385	}
386}