1const SUPERBLOCK_WORDS: usize = 8;
46
47#[derive(Debug, Clone)]
52pub struct LoudsTree {
53 bits: Vec<u64>,
55 rank_superblocks: Vec<u64>,
57 bit_len: usize,
59 n: usize,
61}
62
63impl LoudsTree {
64 pub fn from_degrees(degrees: &[usize]) -> Self {
74 assert!(!degrees.is_empty(), "degree sequence must not be empty");
75
76 let n = degrees.len();
77 let total_children: usize = degrees.iter().sum();
80 assert_eq!(
81 total_children,
82 n - 1,
83 "degree sum ({total_children}) must equal n-1 ({}) for a tree with {n} nodes",
84 n - 1
85 );
86
87 let bit_len = 2 * n + 1;
88 let num_words = bit_len.div_ceil(64);
89 let mut bits = vec![0u64; num_words];
90
91 set_bit(&mut bits, 0);
93 let mut pos = 2; for &d in degrees {
97 for _ in 0..d {
98 set_bit(&mut bits, pos);
99 pos += 1;
100 }
101 pos += 1;
103 }
104
105 assert_eq!(
106 pos, bit_len,
107 "encoding used {pos} bits but expected {bit_len}"
108 );
109
110 let rank_superblocks = build_rank_superblocks(&bits);
111
112 Self {
113 bits,
114 rank_superblocks,
115 bit_len,
116 n,
117 }
118 }
119
120 pub fn from_children(children: &[&[usize]]) -> Self {
129 let degrees: Vec<usize> = children.iter().map(|c| c.len()).collect();
130 Self::from_degrees(°rees)
131 }
132
133 #[inline]
135 pub fn node_count(&self) -> usize {
136 self.n
137 }
138
139 #[inline]
141 pub fn is_empty(&self) -> bool {
142 self.n == 0
143 }
144
145 pub fn size_in_bytes(&self) -> usize {
147 self.bits.len() * 8 + self.rank_superblocks.len() * 8
148 }
149
150 pub fn degree(&self, v: usize) -> usize {
156 assert!(v < self.n, "node {v} out of bounds (n={})", self.n);
157 let end = self.select0(v + 1); let start = if v == 0 {
162 self.select0(0) + 1 } else {
164 self.select0(v) + 1 };
166 end - start
167 }
168
169 pub fn parent(&self, v: usize) -> Option<usize> {
175 assert!(v < self.n, "node {v} out of bounds (n={})", self.n);
176 if v == 0 {
177 return None;
178 }
179 let child_bit = self.select1(v);
183 Some(self.rank0(child_bit) - 1)
186 }
187
188 pub fn first_child(&self, v: usize) -> Option<usize> {
194 assert!(v < self.n, "node {v} out of bounds (n={})", self.n);
195
196 let block_start = self.select0(v) + 1;
199 if block_start >= self.bit_len || !get_bit(&self.bits, block_start) {
200 return None;
201 }
202
203 Some(self.rank1(block_start + 1) - 1)
207 }
208
209 pub fn next_sibling(&self, v: usize) -> Option<usize> {
215 assert!(v < self.n, "node {v} out of bounds (n={})", self.n);
216 if v == 0 {
217 return None; }
219
220 let v_bit = self.select1(v);
223 let next_bit = v_bit + 1;
224 if next_bit >= self.bit_len || !get_bit(&self.bits, next_bit) {
225 return None;
226 }
227 Some(v + 1)
228 }
229
230 pub fn is_leaf(&self, v: usize) -> bool {
236 self.first_child(v).is_none()
237 }
238
239 pub fn depth(&self, v: usize) -> usize {
247 let mut d = 0;
248 let mut cur = v;
249 while let Some(p) = self.parent(cur) {
250 d += 1;
251 cur = p;
252 }
253 d
254 }
255
256 pub fn children(&self, v: usize) -> ChildIter<'_> {
262 assert!(v < self.n, "node {v} out of bounds (n={})", self.n);
263 let first = self.first_child(v);
264 ChildIter {
265 tree: self,
266 next: first,
267 }
268 }
269
270 pub fn subtree_size(&self, v: usize) -> usize {
278 assert!(v < self.n, "node {v} out of bounds (n={})", self.n);
279 let mut count = 0;
280 let mut queue = vec![v];
281 while let Some(node) = queue.pop() {
282 count += 1;
283 for child in self.children(node) {
284 queue.push(child);
285 }
286 }
287 count
288 }
289
290 fn rank1(&self, pos: usize) -> usize {
294 if pos == 0 {
295 return 0;
296 }
297 let word_idx = pos / 64;
298 let bit_idx = pos % 64;
299
300 let sb_idx = word_idx / SUPERBLOCK_WORDS;
301 let mut count = self.rank_superblocks[sb_idx] as usize;
302
303 let sb_start = sb_idx * SUPERBLOCK_WORDS;
304 for i in sb_start..word_idx.min(self.bits.len()) {
305 count += self.bits[i].count_ones() as usize;
306 }
307
308 if bit_idx > 0 && word_idx < self.bits.len() {
309 let mask = (1u64 << bit_idx) - 1;
310 count += (self.bits[word_idx] & mask).count_ones() as usize;
311 }
312
313 count
314 }
315
316 fn rank0(&self, pos: usize) -> usize {
318 pos - self.rank1(pos)
319 }
320
321 fn select1(&self, k: usize) -> usize {
323 let target = k as u64;
324 let mut lo = 0usize;
325 let mut hi = self.rank_superblocks.len() - 1;
326 while lo < hi {
327 let mid = lo + (hi - lo) / 2;
328 if self.rank_superblocks[mid + 1] <= target {
329 lo = mid + 1;
330 } else {
331 hi = mid;
332 }
333 }
334
335 let sb = lo;
336 let mut remaining = k - self.rank_superblocks[sb] as usize;
337 let word_start = sb * SUPERBLOCK_WORDS;
338
339 for w in word_start..self.bits.len() {
340 let ones = self.bits[w].count_ones() as usize;
341 if remaining < ones {
342 return w * 64 + select_in_word(self.bits[w], remaining);
343 }
344 remaining -= ones;
345 }
346
347 panic!("select1({k}): not enough 1-bits")
348 }
349
350 fn select0(&self, k: usize) -> usize {
352 let mut lo = 0usize;
353 let mut hi = self.rank_superblocks.len() - 1;
354 while lo < hi {
355 let mid = lo + (hi - lo) / 2;
356 let total_bits = (mid + 1) * SUPERBLOCK_WORDS * 64;
357 let ones = self.rank_superblocks[mid + 1] as usize;
358 let zeros = total_bits - ones;
359 if zeros <= k {
360 lo = mid + 1;
361 } else {
362 hi = mid;
363 }
364 }
365
366 let sb = lo;
367 let sb_total_bits = sb * SUPERBLOCK_WORDS * 64;
368 let sb_ones = self.rank_superblocks[sb] as usize;
369 let mut remaining = k - (sb_total_bits - sb_ones);
370 let word_start = sb * SUPERBLOCK_WORDS;
371
372 for w in word_start..self.bits.len() {
373 let zeros = self.bits[w].count_zeros() as usize;
374 if remaining < zeros {
375 return w * 64 + select0_in_word(self.bits[w], remaining);
376 }
377 remaining -= zeros;
378 }
379
380 panic!("select0({k}): not enough 0-bits")
381 }
382}
383
384pub struct ChildIter<'a> {
386 tree: &'a LoudsTree,
387 next: Option<usize>,
388}
389
390impl Iterator for ChildIter<'_> {
391 type Item = usize;
392
393 fn next(&mut self) -> Option<usize> {
394 let v = self.next?;
395 self.next = self.tree.next_sibling(v);
396 Some(v)
397 }
398}
399
400fn set_bit(bits: &mut [u64], pos: usize) {
404 let word = pos / 64;
405 let bit = pos % 64;
406 bits[word] |= 1u64 << bit;
407}
408
409fn get_bit(bits: &[u64], pos: usize) -> bool {
411 let word = pos / 64;
412 let bit = pos % 64;
413 (bits[word] >> bit) & 1 == 1
414}
415
416fn build_rank_superblocks(bits: &[u64]) -> Vec<u64> {
418 let num_superblocks = bits.len().div_ceil(SUPERBLOCK_WORDS);
419 let mut superblocks = Vec::with_capacity(num_superblocks + 1);
420 superblocks.push(0u64);
421 let mut cumulative = 0u64;
422 for chunk in bits.chunks(SUPERBLOCK_WORDS) {
423 for &word in chunk {
424 cumulative += word.count_ones() as u64;
425 }
426 superblocks.push(cumulative);
427 }
428 superblocks
429}
430
431fn select_in_word(word: u64, k: usize) -> usize {
433 let mut remaining = k;
434 let mut w = word;
435 for bit in 0..64 {
436 if w & 1 == 1 {
437 if remaining == 0 {
438 return bit;
439 }
440 remaining -= 1;
441 }
442 w >>= 1;
443 if w == 0 {
444 break;
445 }
446 }
447 unreachable!("select_in_word: not enough 1-bits")
448}
449
450fn select0_in_word(word: u64, k: usize) -> usize {
452 let mut remaining = k;
453 let inverted = !word;
454 let mut w = inverted;
455 for bit in 0..64 {
456 if w & 1 == 1 {
457 if remaining == 0 {
458 return bit;
459 }
460 remaining -= 1;
461 }
462 w >>= 1;
463 }
464 unreachable!("select0_in_word: not enough 0-bits")
465}
466
467#[cfg(test)]
468mod tests {
469 use super::*;
470
471 #[test]
474 fn single_node_tree() {
475 let tree = LoudsTree::from_degrees(&[0]);
476 assert_eq!(tree.node_count(), 1);
477 assert!(tree.is_leaf(0));
478 assert_eq!(tree.parent(0), None);
479 assert_eq!(tree.first_child(0), None);
480 assert_eq!(tree.depth(0), 0);
481 }
482
483 #[test]
484 fn linear_chain() {
485 let tree = LoudsTree::from_degrees(&[1, 1, 1, 0]);
487 assert_eq!(tree.node_count(), 4);
488
489 assert_eq!(tree.parent(0), None);
490 assert_eq!(tree.parent(1), Some(0));
491 assert_eq!(tree.parent(2), Some(1));
492 assert_eq!(tree.parent(3), Some(2));
493
494 assert_eq!(tree.first_child(0), Some(1));
495 assert_eq!(tree.first_child(1), Some(2));
496 assert_eq!(tree.first_child(2), Some(3));
497 assert!(tree.is_leaf(3));
498
499 assert_eq!(tree.depth(0), 0);
500 assert_eq!(tree.depth(1), 1);
501 assert_eq!(tree.depth(2), 2);
502 assert_eq!(tree.depth(3), 3);
503 }
504
505 #[test]
506 fn binary_tree() {
507 let tree = LoudsTree::from_degrees(&[2, 2, 0, 0, 0]);
513 assert_eq!(tree.node_count(), 5);
514
515 assert_eq!(tree.first_child(0), Some(1));
516 assert_eq!(tree.next_sibling(1), Some(2));
517 assert_eq!(tree.next_sibling(2), None);
518
519 assert_eq!(tree.first_child(1), Some(3));
520 assert_eq!(tree.next_sibling(3), Some(4));
521 assert!(tree.is_leaf(3));
522 assert!(tree.is_leaf(4));
523 assert!(tree.is_leaf(2));
524
525 assert_eq!(tree.parent(1), Some(0));
526 assert_eq!(tree.parent(2), Some(0));
527 assert_eq!(tree.parent(3), Some(1));
528 assert_eq!(tree.parent(4), Some(1));
529 }
530
531 #[test]
532 fn wide_tree() {
533 let tree = LoudsTree::from_degrees(&[4, 0, 0, 0, 0]);
537 assert_eq!(tree.node_count(), 5);
538
539 assert_eq!(tree.first_child(0), Some(1));
540 assert_eq!(tree.next_sibling(1), Some(2));
541 assert_eq!(tree.next_sibling(2), Some(3));
542 assert_eq!(tree.next_sibling(3), Some(4));
543 assert_eq!(tree.next_sibling(4), None);
544
545 for i in 1..5 {
546 assert!(tree.is_leaf(i));
547 assert_eq!(tree.parent(i), Some(0));
548 assert_eq!(tree.depth(i), 1);
549 }
550 }
551
552 #[test]
553 fn three_level_tree() {
554 let tree = LoudsTree::from_degrees(&[2, 1, 2, 0, 0, 0]);
560 assert_eq!(tree.node_count(), 6);
561
562 assert_eq!(tree.first_child(0), Some(1));
563 assert_eq!(tree.next_sibling(1), Some(2));
564 assert_eq!(tree.first_child(1), Some(3));
565 assert_eq!(tree.first_child(2), Some(4));
566 assert_eq!(tree.next_sibling(4), Some(5));
567
568 assert_eq!(tree.parent(3), Some(1));
569 assert_eq!(tree.parent(4), Some(2));
570 assert_eq!(tree.parent(5), Some(2));
571
572 assert_eq!(tree.depth(4), 2);
573 assert_eq!(tree.depth(5), 2);
574 }
575
576 #[test]
579 fn degree_matches_input() {
580 let degrees = [2, 1, 2, 0, 0, 0];
581 let tree = LoudsTree::from_degrees(°rees);
582 for (i, &d) in degrees.iter().enumerate() {
583 assert_eq!(tree.degree(i), d, "degree mismatch at node {i}");
584 }
585 }
586
587 #[test]
590 fn children_iter() {
591 let tree = LoudsTree::from_degrees(&[3, 0, 1, 0, 0]);
592 let root_children: Vec<_> = tree.children(0).collect();
593 assert_eq!(root_children, vec![1, 2, 3]);
594
595 let node2_children: Vec<_> = tree.children(2).collect();
596 assert_eq!(node2_children, vec![4]);
597
598 let leaf_children: Vec<_> = tree.children(1).collect();
599 assert!(leaf_children.is_empty());
600 }
601
602 #[test]
605 fn subtree_size_root() {
606 let tree = LoudsTree::from_degrees(&[2, 2, 0, 0, 0]);
607 assert_eq!(tree.subtree_size(0), 5);
608 }
609
610 #[test]
611 fn subtree_size_leaf() {
612 let tree = LoudsTree::from_degrees(&[2, 2, 0, 0, 0]);
613 assert_eq!(tree.subtree_size(3), 1);
614 }
615
616 #[test]
617 fn subtree_size_internal() {
618 let tree = LoudsTree::from_degrees(&[2, 2, 0, 0, 0]);
619 assert_eq!(tree.subtree_size(1), 3);
621 }
622
623 #[test]
626 fn from_children_matches_degrees() {
627 let children: &[&[usize]] = &[&[1, 2], &[3, 4], &[], &[], &[]];
628 let tree = LoudsTree::from_children(children);
629 assert_eq!(tree.node_count(), 5);
630 assert_eq!(tree.first_child(0), Some(1));
631 assert_eq!(tree.first_child(1), Some(3));
632 }
633
634 #[test]
637 fn memory_much_less_than_pointers() {
638 let n = 1000;
639 let total = 2 * n - 1;
642 let mut degrees = vec![0usize; total];
643 for d in degrees.iter_mut().take(n - 1) {
644 *d = 2;
645 }
646 let tree = LoudsTree::from_degrees(°rees);
647
648 let louds_bytes = tree.size_in_bytes();
649 let pointer_bytes = total * 3 * 8; assert!(
651 louds_bytes < pointer_bytes / 10,
652 "LOUDS ({louds_bytes}B) should be < 10% of pointer tree ({pointer_bytes}B)"
653 );
654 }
655
656 #[test]
657 fn memory_scaling() {
658 for &n in &[100, 1000, 10_000] {
659 let total = 2 * n - 1;
660 let mut degrees = vec![0usize; total];
661 for d in degrees.iter_mut().take(n - 1) {
662 *d = 2;
663 }
664 let tree = LoudsTree::from_degrees(°rees);
665 let bits_per_node = (tree.size_in_bytes() * 8) as f64 / total as f64;
666 assert!(
668 bits_per_node < 4.0,
669 "n={n}: {bits_per_node:.1} bits/node exceeds 4.0"
670 );
671 }
672 }
673
674 #[test]
677 fn root_no_siblings() {
678 let tree = LoudsTree::from_degrees(&[2, 0, 0]);
679 assert_eq!(tree.next_sibling(0), None);
680 }
681
682 #[test]
683 #[should_panic(expected = "degree sum")]
684 fn invalid_degree_sum_panics() {
685 LoudsTree::from_degrees(&[3, 0, 0]); }
687
688 #[test]
689 #[should_panic(expected = "must not be empty")]
690 fn empty_degrees_panics() {
691 LoudsTree::from_degrees(&[]);
692 }
693
694 #[test]
697 fn parent_child_roundtrip() {
698 let tree = LoudsTree::from_degrees(&[3, 2, 0, 1, 0, 0, 0]);
700 for v in 1..tree.node_count() {
701 let p = tree.parent(v).unwrap();
702 let children: Vec<_> = tree.children(p).collect();
704 assert!(
705 children.contains(&v),
706 "node {v}'s parent is {p} but {v} not in parent's children: {children:?}"
707 );
708 }
709 }
710
711 #[test]
712 fn all_nodes_reachable_from_root() {
713 let tree = LoudsTree::from_degrees(&[3, 2, 0, 1, 0, 0, 0]);
714 let mut visited = vec![false; tree.node_count()];
715 let mut stack = vec![0usize];
716 while let Some(v) = stack.pop() {
717 visited[v] = true;
718 for child in tree.children(v) {
719 stack.push(child);
720 }
721 }
722 assert!(visited.iter().all(|&v| v), "not all nodes reachable");
723 }
724
725 #[cfg(test)]
728 mod proptests {
729 use super::*;
730 use proptest::prelude::*;
731
732 fn arb_degree_sequence(max_nodes: usize) -> impl Strategy<Value = Vec<usize>> {
737 (2..=max_nodes).prop_flat_map(|n| {
738 prop::collection::vec(0..=4usize, n).prop_map(move |raw| {
739 let mut degrees = vec![0usize; n];
740 let mut total_children: usize = 0;
741 let target = n - 1;
742
743 for i in 0..n {
744 let remaining = target - total_children;
745 if remaining == 0 {
746 break;
747 }
748 let min_needed = (i + 1).saturating_sub(total_children);
752 let max_allowed = remaining.min(raw[i].max(min_needed));
753 let d = max_allowed.max(min_needed);
754 degrees[i] = d;
755 total_children += d;
756 }
757
758 let deficit = target.saturating_sub(total_children);
761 if deficit > 0 {
762 degrees[0] += deficit;
763 }
764
765 degrees
766 })
767 })
768 }
769
770 proptest! {
771 #[test]
772 fn navigation_consistent(degrees in arb_degree_sequence(50)) {
773 let tree = LoudsTree::from_degrees(°rees);
774 let n = tree.node_count();
775 prop_assert_eq!(n, degrees.len());
776
777 for v in 1..n {
779 let p = tree.parent(v);
780 prop_assert!(p.is_some(), "node {v} has no parent");
781 prop_assert!(p.unwrap() < v, "parent {} >= child {v}", p.unwrap());
782 }
783
784 for v in 0..n {
786 for child in tree.children(v) {
787 prop_assert_eq!(tree.parent(child), Some(v));
788 }
789 }
790
791 for (v, &expected_deg) in degrees.iter().enumerate().take(n) {
793 let child_count = tree.children(v).count();
794 prop_assert_eq!(tree.degree(v), child_count);
795 prop_assert_eq!(tree.degree(v), expected_deg);
796 }
797 }
798
799 #[test]
800 fn subtree_sizes_sum(degrees in arb_degree_sequence(30)) {
801 let tree = LoudsTree::from_degrees(°rees);
802 prop_assert_eq!(tree.subtree_size(0), tree.node_count());
804 }
805
806 #[test]
807 fn depth_matches_parent_chain(degrees in arb_degree_sequence(50)) {
808 let tree = LoudsTree::from_degrees(°rees);
809 for v in 0..tree.node_count() {
810 let d = tree.depth(v);
811 if v == 0 {
812 prop_assert_eq!(d, 0);
813 } else {
814 let parent_depth = tree.depth(tree.parent(v).unwrap());
815 prop_assert_eq!(d, parent_depth + 1);
816 }
817 }
818 }
819
820 #[test]
821 fn memory_sublinear(n in 50..500usize) {
822 let total = 2 * n - 1;
823 let mut degrees = vec![0usize; total];
824 for d in degrees.iter_mut().take(n - 1) {
825 *d = 2;
826 }
827 let tree = LoudsTree::from_degrees(°rees);
828 let bits_per_node = (tree.size_in_bytes() * 8) as f64 / total as f64;
829 prop_assert!(bits_per_node < 5.0,
831 "n={n}: {bits_per_node:.1} bits/node exceeds 5.0");
832 }
833 }
834 }
835}