Class TreeIndex<N extends AbstractNode>

java.lang.Object
io.crums.util.mrkl.index.TreeIndex<N>

public class TreeIndex<N extends AbstractNode> extends Object
A breadth-first view of the structure of a Merkle tree. In this view each node is represented by 2 coordinates (level, index). Levels are counted up from the leaf nodes, with the leaves at level zero; index is just an index into nodes at that level. Instances are immutable and safe under concurrent access.

Terminology

Most expositions use the term "promoted" to describe how the last odd node at a level is stitched up the higher node levels to root. (Note in our zero-based index, the index of this last odd node is in fact even; the count is odd.) Here, we use the term carry to represent this special type of joining of two lower level nodes to form a higher level parent. Except for the edge case involving such carries, a node's children are always at adjacent indices at the level just below; for carries, however, a node's children may be from different levels (with the left child always at the same or higher level than the right child).

  • Carry. The parent node formed from 2 child nodes at different levels, or a parent node formed if one or more of its descendants have been so formed. There can only be one such node at any level, and then it may only be the node at the last index at that level. Another way to think of a carry is an existing node whose value would necessarily change if another (single) leaf node had been added.
  • Joins Carry. A child node of a carry. The child node itself may or may not be a carry.

Note, the root node is itself usually a carry. The only times it's not is when the number of leaves is an exact power of 2 in which case there are no carries in the tree. Conversely, if a node is a carry, then every ancestor of it (including the root node), every is another carry.

See Also:
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static interface 
    A node factory for a TreeIndex.
  • Constructor Summary

    Constructors
    Constructor
    Description
    TreeIndex(int count, TreeIndex.NodeFactory<N> factory)
    Creates a type-specific instance with the given factory.
  • Method Summary

    Modifier and Type
    Method
    Description
    final int
    Returns the number leaf nodes (data items) in the tree.
    final int
    count(int level)
    Returns the number of nodes at the given level.
    final int
    countSansCarry(int level)
    Returns the numbern of nodes at the given level excluding the carry (if it has one).
    final boolean
    Determines whether an instance is structurally equivalent to another.
    final List<N>
    Returns the frontier nodes.
    final N
    getLeftChild(int level, int index)
    Returns the left child of the internal node at the given coordinates.
    final N
    Returns the left child of the given parent node.
    final N
    getNode(int serialIndex)
    Returns the node at the given serial index.
    final N
    getNode(int level, int index)
    Returns the node at the given coordinates.
    final N
    getParent(int level, int index)
    Returns the parent of the node at the given coordinates.
    final N
    Returns the given node's parent.
    final N
    getRightChild(int level, int index)
    Returns the right child of the internal node at the given coordinates.
    final N
    Returns the right child of the given parent node.
    final N
    getSibling(int level, int index)
    Returns the sibling of the node at the given coordinates.
    final N
    Returns the given node's sibling.
    final boolean
    hasCarry(int level)
    Determines whether the last node is a carry.
    final int
    The instance's hash code is just the number of its leaves.
    final int
    Returns the height of the root of the tree relative to its base (the leaves).
    final boolean
    isCarry(int level, int index)
    Determines whether node at the given coordinates is a carry.
    final boolean
    isLeft(int level, int index)
    Determines if the node at the given coordinates is the left child of its parent node.
    final boolean
    isRight(int level, int index)
    Determines if the node at the given coordinates is the right child of its parent node.
    final boolean
    Determines whether the given node is this tree's root node.
    final int
    maxIndex(int level)
    Returns the maximum allowed index at the given level.
    final boolean
    maxIndexJoinsCarry(int level)
    Determines whether there are an odd number of nodes at this level (after accounting for the carries).
    static TreeIndex<?>
    newGeneric(int count)
    Creates and returns a purely structural tree index (the tree sans data, only node coordinates).
    static int
    rootHeightForCount(int count)
    Returns the height of the Merkle tree root node with count-many leaf elements.
    final int
    serialIndex(int level, int index)
    Returns the serial index of the node at the given cooridinate.
     
    final int
    Returns the total number of carries (otherwise known as promoted nodes).
    final int
    Returns the total number of nodes in the tree.
    final int
    Returns the total number of nodes in the tree excluding the carries.

    Methods inherited from class java.lang.Object

    clone, finalize, getClass, notify, notifyAll, wait, wait, wait
  • Constructor Details

    • TreeIndex

      public TreeIndex(int count, TreeIndex.NodeFactory<N> factory)
      Creates a type-specific instance with the given factory.
      Parameters:
      count - the number of items (leaf nodes) in the tree (≥ 2)
      factory - the node factory controls the return type <N>
      See Also:
  • Method Details

    • newGeneric

      public static TreeIndex<?> newGeneric(int count)
      Creates and returns a purely structural tree index (the tree sans data, only node coordinates). It has a miniscule memory footprint, no matter how large the tree.
      Parameters:
      count - the number items (leaves) in the tree (≥ 2)
      Returns:
      new TreeIndex<>(count, AbstractNode.FACTORY)
    • count

      public final int count()
      Returns the number leaf nodes (data items) in the tree. An instance's count uniquely determines its structure.
    • totalCount

      public final int totalCount()
      Returns the total number of nodes in the tree.
      Returns:
      2 * count() - 1
    • totalCarries

      public final int totalCarries()
      Returns the total number of carries (otherwise known as promoted nodes).
    • totalCountSansCarries

      public final int totalCountSansCarries()
      Returns the total number of nodes in the tree excluding the carries.
      Returns:
      the difference of totalCount() and totalCarries()
    • serialIndex

      public final int serialIndex(int level, int index) throws IndexOutOfBoundsException
      Returns the serial index of the node at the given cooridinate. A node's serial index is the node's index in a breadth-first traversal of the tree, starting with the tree's root node indexed at zero.
      Parameters:
      level - ≥ 0 and ≤ height()
      index - ≥ 0 and < count(level)
      Throws:
      IndexOutOfBoundsException
      See Also:
    • height

      public final int height()
      Returns the height of the root of the tree relative to its base (the leaves). In this terminology, the leaves are at level zero, and the root is at the level with maximum height.
      See Also:
    • count

      public final int count(int level) throws IndexOutOfBoundsException
      Returns the number of nodes at the given level.
      Parameters:
      level - ≥ 0 and ≤ height()
      Throws:
      IndexOutOfBoundsException
    • countSansCarry

      public final int countSansCarry(int level)
      Returns the numbern of nodes at the given level excluding the carry (if it has one).
    • maxIndex

      public final int maxIndex(int level) throws IndexOutOfBoundsException
      Returns the maximum allowed index at the given level.
      Returns:
      count(level) - 1
      Throws:
      IndexOutOfBoundsException
    • maxIndexJoinsCarry

      public final boolean maxIndexJoinsCarry(int level) throws IndexOutOfBoundsException
      Determines whether there are an odd number of nodes at this level (after accounting for the carries). If so, then the last node at this level joins the next unpaired node at a higher level to form a parent node one level above that next unpaired node.
      Parameters:
      level - ≥ 0 and ≤ height()
      Returns:
      true iff there are an odd number of nodes at this level
      Throws:
      IndexOutOfBoundsException
    • hasCarry

      public final boolean hasCarry(int level) throws IndexOutOfBoundsException
      Determines whether the last node is a carry. There is at most one carry in each level.
      Parameters:
      level - ≥ 0 and ≤ height()
      Throws:
      IndexOutOfBoundsException
    • isCarry

      public final boolean isCarry(int level, int index)
      Determines whether node at the given coordinates is a carry.
      Parameters:
      level - ≥ 0 and ≤ height()
      index - ≥ 0 and < count(level)
      See Also:
    • isRoot

      public final boolean isRoot(AbstractNode node)
      Determines whether the given node is this tree's root node.
      Returns:
      node.level() == height()
      See Also:
    • getNode

      public final N getNode(int level, int index) throws IndexOutOfBoundsException
      Returns the node at the given coordinates.
      Parameters:
      level - ≥ 0 and ≤ height()
      index - ≥ 0 and < count(level)
      Throws:
      IndexOutOfBoundsException
      See Also:
    • getNode

      public final N getNode(int serialIndex) throws IndexOutOfBoundsException
      Returns the node at the given serial index.
      Parameters:
      serialIndex - ≥ 0 and < totalCount()
      Throws:
      IndexOutOfBoundsException
      See Also:
    • getParent

      public final N getParent(AbstractNode node) throws IndexOutOfBoundsException
      Returns the given node's parent. Convenience method.
      Throws:
      IndexOutOfBoundsException
      See Also:
    • getParent

      public final N getParent(int level, int index) throws IndexOutOfBoundsException
      Returns the parent of the node at the given coordinates.
      Parameters:
      level - ≥ 0 and < height()
      index - ≥ 0 and < count(level)
      Throws:
      IndexOutOfBoundsException
      See Also:
    • getLeftChild

      public final N getLeftChild(AbstractNode parent) throws IndexOutOfBoundsException
      Returns the left child of the given parent node.
      Parameters:
      parent - an internal (non-leaf) node
      Throws:
      IndexOutOfBoundsException
    • getLeftChild

      public final N getLeftChild(int level, int index) throws IndexOutOfBoundsException
      Returns the left child of the internal node at the given coordinates.
      Parameters:
      level - ≥ 0 and ≤ height()
      index - ≥ 1 and < count(level)
      Throws:
      IndexOutOfBoundsException
      See Also:
    • getRightChild

      public final N getRightChild(AbstractNode parent) throws IndexOutOfBoundsException
      Returns the right child of the given parent node.
      Parameters:
      parent - an internal (non-leaf) node
      Throws:
      IndexOutOfBoundsException
    • getRightChild

      public final N getRightChild(int level, int index) throws IndexOutOfBoundsException
      Returns the right child of the internal node at the given coordinates.
      Parameters:
      level - ≥ 0 and ≤ height()
      index - ≥ 1 and < count(level)
      Throws:
      IndexOutOfBoundsException
      See Also:
    • getSibling

      public final N getSibling(AbstractNode node) throws IndexOutOfBoundsException
      Returns the given node's sibling. Convenience method.
      Throws:
      IndexOutOfBoundsException
      See Also:
    • getSibling

      public final N getSibling(int level, int index) throws IndexOutOfBoundsException
      Returns the sibling of the node at the given coordinates. Two nodes are siblings iff they have the same parent node in the tree.
      Parameters:
      level - 0 ≤ level < height()
      index - 0 ≤ index < count(level)
      Throws:
      IndexOutOfBoundsException
    • isRight

      public final boolean isRight(int level, int index) throws IndexOutOfBoundsException
      Determines if the node at the given coordinates is the right child of its parent node. The root level is defined to be left (tho, in principle, it should be undefined).
      Parameters:
      level - between zero and height() (inclusive)
      index - the zero-based node index at the given level
      Throws:
      IndexOutOfBoundsException
      See Also:
    • isLeft

      public final boolean isLeft(int level, int index) throws IndexOutOfBoundsException
      Determines if the node at the given coordinates is the left child of its parent node. The root level is defined to be left (tho, in principle, it should be undefined).
      Parameters:
      level - between zero and height() (inclusive)
      index - the zero-based node index at the given level
      Throws:
      IndexOutOfBoundsException
      See Also:
    • getFrontier

      public final List<N> getFrontier()
      Returns the frontier nodes. If you grow this tree (that is if you append more leaves) then part of new tree will contain exactly the same nodes. Unused meta at this time.
    • equals

      public final boolean equals(Object o)
      Determines whether an instance is structurally equivalent to another. I.e. it doesn't care about individual node values. As we know, only 1 parameter determines a tree's structure: the leaf count.
      Overrides:
      equals in class Object
    • hashCode

      public final int hashCode()

      The instance's hash code is just the number of its leaves.

      Overrides:
      hashCode in class Object
      See Also:
    • toString

      public String toString()
      Overrides:
      toString in class Object
      Returns:
      "TreeIndex(" + count() + ")"
    • rootHeightForCount

      public static int rootHeightForCount(int count) throws IllegalArgumentException
      Returns the height of the Merkle tree root node with count-many leaf elements. (The height of the leaves is zero.)
      Parameters:
      count - ≥ 2
      Returns:
      ceil(log2(count)
      Throws:
      IllegalArgumentException