diem_types/proof/position/mod.rs
1// Copyright (c) The Diem Core Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4// Copyright 2021 Conflux Foundation. All rights reserved.
5// Conflux is free software and distributed under GNU General Public License.
6// See http://www.gnu.org/licenses/
7
8//! This module provides an abstraction for positioning a node in a binary tree,
9//! A `Position` uniquely identifies the location of a node
10//!
11//! In this implementation, `Position` is represented by the in-order-traversal
12//! sequence number of the node. The process of locating a node and jumping
13//! between nodes is done through in-order position calculation, which can be
14//! done with bit manipulation.
15//!
16//! For example
17//! ```text
18//! 3
19//! / \
20//! / \
21//! 1 5 <-[Node index, a.k.a, Position]
22//! / \ / \
23//! 0 2 4 6
24//!
25//! 0 1 2 3 <[Leaf index]
26//! ```
27//! Note1: The in-order-traversal counts from 0
28//! Note2: The level of tree counts from leaf level, start from 0
29//! Note3: The leaf index starting from left-most leaf, starts from 0
30
31use crate::proof::definition::{
32 LeafCount, MAX_ACCUMULATOR_LEAVES, MAX_ACCUMULATOR_PROOF_DEPTH,
33};
34use anyhow::{ensure, Result};
35use mirai_annotations::*;
36use std::fmt;
37
38#[cfg(test)]
39mod position_test;
40
41#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
42pub struct Position(u64);
43// invariant Position.0 < u64::max_value() - 1
44
45#[derive(Debug, Eq, PartialEq)]
46pub enum NodeDirection {
47 Left,
48 Right,
49}
50
51impl Position {
52 /// What level is this node in the tree, 0 if the node is a leaf,
53 /// 1 if the level is one above a leaf, etc.
54 pub fn level(self) -> u32 { (!self.0).trailing_zeros() }
55
56 fn is_leaf(self) -> bool { self.0 & 1 == 0 }
57
58 /// What position is the node within the level? i.e. how many nodes
59 /// are to the left of this node at the same level
60 #[cfg(test)]
61 fn pos_counting_from_left(self) -> u64 { self.0 >> (self.level() + 1) }
62
63 /// pos count start from 0 on each level
64 pub fn from_level_and_pos(level: u32, pos: u64) -> Self {
65 precondition!(level < 64);
66 assume!(1u64 << level > 0); // bitwise and integer operations don't mix.
67 let level_one_bits = (1u64 << level) - 1;
68 let shifted_pos = if level == 63 { 0 } else { pos << (level + 1) };
69 Position(shifted_pos | level_one_bits)
70 }
71
72 pub fn from_inorder_index(index: u64) -> Self { Position(index) }
73
74 pub fn to_inorder_index(self) -> u64 { self.0 }
75
76 pub fn from_postorder_index(index: u64) -> Result<Self> {
77 ensure!(
78 index < !0u64,
79 "node index {} is invalid (equal to 2^64 - 1)",
80 index
81 );
82 Ok(Position(postorder_to_inorder(index)))
83 }
84
85 pub fn to_postorder_index(self) -> u64 {
86 inorder_to_postorder(self.to_inorder_index())
87 }
88
89 /// What is the parent of this node?
90 pub fn parent(self) -> Self {
91 assume!(self.0 < u64::max_value() - 1); // invariant
92 Self(
93 (self.0 | isolate_rightmost_zero_bit(self.0))
94 & !(isolate_rightmost_zero_bit(self.0) << 1),
95 )
96 }
97
98 /// What is the left node of this node? Will overflow if the node is a leaf
99 pub fn left_child(self) -> Self {
100 checked_precondition!(!self.is_leaf());
101 Self::child(self, NodeDirection::Left)
102 }
103
104 /// What is the right node of this node? Will overflow if the node is a leaf
105 pub fn right_child(self) -> Self {
106 checked_precondition!(!self.is_leaf());
107 Self::child(self, NodeDirection::Right)
108 }
109
110 fn child(self, dir: NodeDirection) -> Self {
111 checked_precondition!(!self.is_leaf());
112 assume!(self.0 < u64::max_value() - 1); // invariant
113
114 let direction_bit = match dir {
115 NodeDirection::Left => 0,
116 NodeDirection::Right => isolate_rightmost_zero_bit(self.0),
117 };
118 Self(
119 (self.0 | direction_bit)
120 & !(isolate_rightmost_zero_bit(self.0) >> 1),
121 )
122 }
123
124 /// Whether this position is a left child of its parent. The observation is
125 /// that, after stripping out all right-most 1 bits, a left child will
126 /// have a bit pattern of xxx00(11..), while a right child will be
127 /// represented by xxx10(11..)
128 pub fn is_left_child(self) -> bool {
129 assume!(self.0 < u64::max_value() - 1); // invariant
130 self.0 & (isolate_rightmost_zero_bit(self.0) << 1) == 0
131 }
132
133 pub fn is_right_child(self) -> bool { !self.is_left_child() }
134
135 // Opposite of get_left_node_count_from_position.
136 pub fn from_leaf_index(leaf_index: u64) -> Self {
137 Self::from_level_and_pos(0, leaf_index)
138 }
139
140 /// This method takes in a node position and return its sibling position
141 ///
142 /// The observation is that, after stripping out the right-most common bits,
143 /// two sibling nodes flip the next right-most bits with each other.
144 /// To find out the right-most common bits, first remove all the right-most
145 /// ones because they are corresponding to level's indicator. Then
146 /// remove next zero right after.
147 pub fn sibling(self) -> Self {
148 assume!(self.0 < u64::max_value() - 1); // invariant
149 Self(self.0 ^ (isolate_rightmost_zero_bit(self.0) << 1))
150 }
151
152 // Given a leaf index, calculate the position of a minimum root which
153 // contains this leaf
154 /// This method calculates the index of the smallest root which contains
155 /// this leaf. Observe that, the root position is composed by a "height"
156 /// number of ones
157 ///
158 /// For example
159 /// ```text
160 /// 0010010(node)
161 /// 0011111(smearing)
162 /// -------
163 /// 0001111(root)
164 /// ```
165 pub fn root_from_leaf_index(leaf_index: u64) -> Self {
166 let leaf = Self::from_leaf_index(leaf_index);
167 Self(smear_ones_for_u64(leaf.0) >> 1)
168 }
169
170 pub fn root_from_leaf_count(leaf_count: LeafCount) -> Self {
171 assert!(leaf_count > 0);
172 Self::root_from_leaf_index((leaf_count - 1) as u64)
173 }
174
175 pub fn root_level_from_leaf_count(leaf_count: LeafCount) -> u32 {
176 assert!(leaf_count > 0);
177 let index = (leaf_count - 1) as u64;
178 MAX_ACCUMULATOR_PROOF_DEPTH as u32 + 1 - index.leading_zeros()
179 }
180
181 /// Given a node, find its right most child in its subtree.
182 /// Right most child is a Position, could be itself, at level 0
183 pub fn right_most_child(self) -> Self {
184 let level = self.level();
185 Self(self.0 + (1_u64 << level) - 1)
186 }
187
188 /// Given a node, find its left most child in its subtree
189 /// Left most child is a node, could be itself, at level 0
190 pub fn left_most_child(self) -> Self {
191 // Turn off its right most x bits. while x=level of node
192 let level = self.level();
193 Self(turn_off_right_most_n_bits(self.0, level))
194 }
195}
196
197// Some helper functions to perform general bit manipulation
198
199/// Smearing all the bits starting from MSB with ones
200fn smear_ones_for_u64(v: u64) -> u64 {
201 let mut n = v;
202 n |= n >> 1;
203 n |= n >> 2;
204 n |= n >> 4;
205 n |= n >> 8;
206 n |= n >> 16;
207 n |= n >> 32;
208 n
209}
210
211/// Turn off n right most bits
212///
213/// For example
214/// ```text
215/// 00010010101
216/// -----------
217/// 00010010100 n=1
218/// 00010010000 n=3
219/// ```
220fn turn_off_right_most_n_bits(v: u64, n: u32) -> u64 {
221 debug_checked_precondition!(n < 64);
222 (v >> n) << n
223}
224
225/// Finds the rightmost 0-bit, turns off all bits, and sets this bit to 1 in
226/// the result. For example:
227///
228/// ```text
229/// 01110111 (x)
230/// --------
231/// 10001000 (~x)
232/// & 01111000 (x+1)
233/// --------
234/// 00001000
235/// ```
236/// http://www.catonmat.net/blog/low-level-bit-hacks-you-absolutely-must-know/
237fn isolate_rightmost_zero_bit(v: u64) -> u64 { !v & v.overflowing_add(1).0 }
238
239// The following part of the position implementation is logically separate and
240// depends on our notion of freezable. It should probably move to another
241// module.
242impl Position {
243 // Given index of right most leaf, calculate if a position is the root
244 // of a perfect subtree that does not contain any placeholder nodes.
245 //
246 // First find its right most child
247 // the right most child of any node will be at leaf level, which will be a
248 // either placeholder node or leaf node. if right most child is a leaf
249 // node, then it is freezable. if right most child is larger than
250 // max_leaf_node, it is a placeholder node, and not freezable.
251 pub fn is_freezable(self, leaf_index: u64) -> bool {
252 let leaf = Self::from_leaf_index(leaf_index);
253 let right_most_child = self.right_most_child();
254 right_most_child.0 <= leaf.0
255 }
256
257 // Given index of right most leaf, calculate if a position should contain
258 // a placeholder node at this moment
259 // A node is a placeholder if both two conditions below are true:
260 // 1, the node's in order traversal seq > max_leaf_node's, and
261 // 2, the node does not have left child or right child.
262 pub fn is_placeholder(self, leaf_index: u64) -> bool {
263 let leaf = Self::from_leaf_index(leaf_index);
264 if self.0 <= leaf.0 {
265 return false;
266 }
267 if self.left_most_child().0 <= leaf.0 {
268 return false;
269 }
270 true
271 }
272
273 /// Creates an `AncestorIterator` using this position.
274 pub fn iter_ancestor(self) -> AncestorIterator {
275 AncestorIterator { position: self }
276 }
277
278 /// Creates an `AncestorSiblingIterator` using this position.
279 pub fn iter_ancestor_sibling(self) -> AncestorSiblingIterator {
280 AncestorSiblingIterator { position: self }
281 }
282}
283
284impl fmt::Display for Position {
285 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
286 write!(f, "Pos({})", self.to_inorder_index())
287 }
288}
289
290/// `AncestorSiblingIterator` generates current sibling position and moves
291/// itself to its parent position for each iteration.
292#[derive(Debug)]
293pub struct AncestorSiblingIterator {
294 position: Position,
295}
296
297impl Iterator for AncestorSiblingIterator {
298 type Item = Position;
299
300 fn next(&mut self) -> Option<Position> {
301 let current_sibling_position = self.position.sibling();
302 self.position = self.position.parent();
303 Some(current_sibling_position)
304 }
305}
306
307/// `AncestorIterator` generates current position and moves itself to its parent
308/// position for each iteration.
309#[derive(Debug)]
310pub struct AncestorIterator {
311 position: Position,
312}
313
314impl Iterator for AncestorIterator {
315 type Item = Position;
316
317 fn next(&mut self) -> Option<Position> {
318 let current_position = self.position;
319 self.position = self.position.parent();
320 Some(current_position)
321 }
322}
323
324/// Traverse leaves from left to right in groups that forms full subtrees,
325/// yielding root positions of such subtrees.
326/// Note that each 1-bit in num_leaves corresponds to a full subtree.
327/// For example, in the below tree of 5=0b101 leaves, the two 1-bits corresponds
328/// to Fzn2 and L4 accordingly.
329///
330/// ```text
331/// Non-fzn
332/// / \
333/// / \
334/// / \
335/// Fzn2 Non-fzn
336/// / \ / \
337/// / \ / \
338/// Fzn1 Fzn3 Non-fzn [Placeholder]
339/// / \ / \ / \
340/// L0 L1 L2 L3 L4 [Placeholder]
341/// ```
342pub struct FrozenSubTreeIterator {
343 bitmap: u64,
344 seen_leaves: u64,
345 // invariant seen_leaves < u64::max_value() - bitmap
346}
347
348impl FrozenSubTreeIterator {
349 pub fn new(num_leaves: LeafCount) -> Self {
350 Self {
351 bitmap: num_leaves,
352 seen_leaves: 0,
353 }
354 }
355}
356
357impl Iterator for FrozenSubTreeIterator {
358 type Item = Position;
359
360 fn next(&mut self) -> Option<Position> {
361 assume!(self.seen_leaves < u64::max_value() - self.bitmap); // invariant
362
363 if self.bitmap == 0 {
364 return None;
365 }
366
367 // Find the remaining biggest full subtree.
368 // The MSB of the bitmap represents it. For example for a tree of
369 // 0b1010=10 leaves, the biggest and leftmost full subtree has
370 // 0b1000=8 leaves, which can be got by smearing all bits after
371 // MSB with 1-bits (got 0b1111), right shift once (got 0b0111) and add 1
372 // (got 0b1000=8). At the same time, we also observe that the
373 // in-order numbering of a full subtree root is (num_leaves - 1)
374 // greater than that of the leftmost leaf, and also (num_leaves
375 // - 1) less than that of the rightmost leaf.
376 let root_offset = smear_ones_for_u64(self.bitmap) >> 1;
377 assume!(root_offset < self.bitmap); // relate bit logic to integer logic
378 let num_leaves = root_offset + 1;
379 let leftmost_leaf = Position::from_leaf_index(self.seen_leaves);
380 let root = Position::from_inorder_index(
381 leftmost_leaf.to_inorder_index() + root_offset,
382 );
383
384 // Mark it consumed.
385 self.bitmap &= !num_leaves;
386 self.seen_leaves += num_leaves;
387
388 Some(root)
389 }
390}
391
392/// Given an accumulator of size `current_num_leaves`,
393/// `FrozenSubtreeSiblingIterator` yields the positions of required subtrees if
394/// we want to append these subtrees to the existing accumulator to generate a
395/// bigger one of size `new_num_leaves`.
396pub struct FrozenSubtreeSiblingIterator {
397 current_num_leaves: LeafCount,
398 remaining_new_leaves: LeafCount,
399}
400
401impl FrozenSubtreeSiblingIterator {
402 /// Constructs a new `FrozenSubtreeSiblingIterator` given the size of
403 /// current accumulator and the size of the bigger accumulator.
404 pub fn new(
405 current_num_leaves: LeafCount, new_num_leaves: LeafCount,
406 ) -> Self {
407 assert!(
408 new_num_leaves <= MAX_ACCUMULATOR_LEAVES,
409 "An accumulator can have at most 2^{} leaves. Provided num_leaves: {}.",
410 MAX_ACCUMULATOR_PROOF_DEPTH,
411 new_num_leaves,
412 );
413 assert!(
414 current_num_leaves <= new_num_leaves,
415 "Number of leaves needs to be increasing: current_num_leaves: {}, new_num_leaves: {}",
416 current_num_leaves,
417 new_num_leaves
418 );
419
420 Self {
421 current_num_leaves,
422 remaining_new_leaves: new_num_leaves - current_num_leaves,
423 }
424 }
425
426 /// Helper function to return the next set of leaves that form a complete
427 /// subtree. For example, if there are 5 leaves (..0101), 2 ^ (63 - 61
428 /// leading zeros) = 4 leaves should be taken next.
429 fn next_new_leaf_batch(&self) -> LeafCount {
430 let zeros = self.remaining_new_leaves.leading_zeros();
431 1 << (MAX_ACCUMULATOR_PROOF_DEPTH - zeros as usize)
432 }
433}
434
435impl Iterator for FrozenSubtreeSiblingIterator {
436 type Item = Position;
437
438 fn next(&mut self) -> Option<Self::Item> {
439 if self.remaining_new_leaves == 0 {
440 return None;
441 }
442
443 // Now we compute the size of the next subtree. If there is a rightmost
444 // frozen subtree, we may combine it with a subtree of the same
445 // size, or append a smaller one on the right. In
446 // case self.current_num_leaves is zero and there is no rightmost frozen
447 // subtree, the largest possible one is appended.
448 let next_subtree_leaves = if self.current_num_leaves > 0 {
449 let rightmost_frozen_subtree_leaves =
450 1 << self.current_num_leaves.trailing_zeros();
451 if self.remaining_new_leaves >= rightmost_frozen_subtree_leaves {
452 rightmost_frozen_subtree_leaves
453 } else {
454 self.next_new_leaf_batch()
455 }
456 } else {
457 self.next_new_leaf_batch()
458 };
459
460 // Now that the size of the next subtree is known, we compute the
461 // leftmost and rightmost leaves in this subtree. The root of
462 // the subtree is then the middle of these two leaves.
463 let first_leaf_index = self.current_num_leaves;
464 let last_leaf_index = first_leaf_index + next_subtree_leaves - 1;
465 self.current_num_leaves += next_subtree_leaves;
466 self.remaining_new_leaves -= next_subtree_leaves;
467
468 Some(Position::from_inorder_index(
469 (first_leaf_index + last_leaf_index) as u64,
470 ))
471 }
472}
473
474fn children_of_node(node: u64) -> u64 {
475 (isolate_rightmost_zero_bit(node) << 1) - 2
476}
477
478/// In a post-order tree traversal, how many nodes are traversed before `node`
479/// not including nodes that are children of `node`.
480fn nodes_to_left_of(node: u64) -> u64 {
481 // If node = 0b0100111, ones_up_to_level = 0b111
482 let ones_up_to_level = isolate_rightmost_zero_bit(node) - 1;
483 // Unset all the 1s due to the level
484 let unset_level_zeros = node ^ ones_up_to_level;
485
486 // What remains is a 1 bit set every time a node navigated right
487 // For example, consider node=5=0b101. unset_level_zeros=0b100.
488 // the 1 bit in unset_level_zeros at position 2 represents the
489 // fact that 5 is the right child at the level 1. At this level
490 // there are 2^2 - 1 children on the left hand side.
491 //
492 // So what we do is subtract the count of one bits from unset_level_zeros
493 // to account for the fact that if the node is the right child at level
494 // n that there are 2^n - 1 children.
495 unset_level_zeros - u64::from(unset_level_zeros.count_ones())
496}
497
498/// Given `node`, an index in an in-order traversal of a perfect binary tree,
499/// what order would the node be visited in post-order traversal?
500/// For example, consider this tree of in-order nodes.
501///
502/// ```text
503/// 3
504/// / \
505/// / \
506/// 1 5
507/// / \ / \
508/// 0 2 4 6
509/// ```
510///
511/// The post-order ordering of the nodes is:
512/// ```text
513/// 6
514/// / \
515/// / \
516/// 2 5
517/// / \ / \
518/// 0 1 3 4
519/// ```
520///
521/// post_order_index(1) == 2
522/// post_order_index(4) == 3
523pub fn inorder_to_postorder(node: u64) -> u64 {
524 let children = children_of_node(node);
525 let left_nodes = nodes_to_left_of(node);
526
527 children + left_nodes
528}
529
530pub fn postorder_to_inorder(mut node: u64) -> u64 {
531 // The number of nodes in a full binary tree with height `n` is `2^n - 1`.
532 let mut full_binary_size = !0u64;
533 let mut bitmap = 0u64;
534 for i in (0..64).rev() {
535 if node >= full_binary_size {
536 node -= full_binary_size;
537 bitmap |= 1 << i;
538 }
539 full_binary_size >>= 1;
540 }
541 let level = node as u32;
542 let pos = bitmap >> level;
543 Position::from_level_and_pos(level, pos).to_inorder_index()
544}