class_docstr: Represents hierarchical relationships between nodes (time series).
  
  Nodes are indexed by their position in the tree, in breadth-first search (BFS) order.
  Matrix attributes such as ``bottom_up_transform`` are applied from the
  left against tree values, represented as a `numpy.array` 2D array with
  the values of each node as a row.
  
  Attributes
  ----------
  levels : `list` [`list` [`int]] or None
      Specifies the number of children of each parent (internal) node in the tree.
      The number of inner lists is the height of the tree. The ith inner list provides the number
      of children of each node at depth i.
      For example::
  
          # root node with 3 children
          levels = [[3]]
  
          # root node with 3 children, who have 2, 3, 3 children respectively
          levels = [[3], [2, 3, 3]]
          # These children are ordered from "left" to "right", so that the one with
          # 2 children is the first in the 2nd level.
          # This will be used as our running example.
          #           0                # level 0
          #   1       2        3       # level 1
          #  4 5    6 7 8    9 10 11   # level 2
  
      All leaf nodes must have the same depth. Thus, the first sublist must have one
      integer, the length of a sublist must equal the sum of the previous sublist,
      and all integers in ``levels`` must be positive.
  
  num_children_per_parent : `list` [`int`]
      Flattened version of ``levels``.
      The number of children for each parent (internal) node.
      [3, 2, 3, 3] in our example.
  num_internal_nodes : `int`
      The number of internal (parent) nodes (i.e. with children).
      4 in our example.
  num_leaf_nodes : `int`
      The number of leaf nodes (i.e. without children).
      8 in our example.
  num_nodes : `int`
      The total number of nodes.
      12 in our example.
  nodes_per_level : `list` [`int`]
      The number of nodes at each level of the tree.
      [1, 3, 8] in our example.
  starting_index_per_level : `list` [`int`]
      The index of the first node in each level.
      [0, 1, 4] in our example.
  starting_child_index_per_parent : `list` [`int`]
      For each parent node, the index of its first child.
      [1, 4, 6, 9]  in our example.
  sum_matrix : `numpy.array`, shape (``self.num_nodes``, ``self.num_leaf_nodes``)
      Sum matrix used to compute values of all nodes from the leaf nodes. When
      applied to a matrix with the values for leaf nodes, returns values for every
      node by bubbling up leaf node values to the internal nodes. A node's value is
      equal to the sum of its corresponding leaf nodes' values.
  
      ``Y_{all} = sum_matrix @ Y_{leaf}``
      In our example::
  
          # 4   5   6   7   8   9   10  11  (leaf nodes)
          [[1., 1., 1., 1., 1., 1., 1., 1.], # 0
           [1., 1., 0., 0., 0., 0., 0., 0.], # 1
           [0., 0., 1., 1., 1., 0., 0., 0.], # 2
           [0., 0., 0., 0., 0., 1., 1., 1.], # 3
           [1., 0., 0., 0., 0., 0., 0., 0.], # 4
           [0., 1., 0., 0., 0., 0., 0., 0.], # 5
           [0., 0., 1., 0., 0., 0., 0., 0.], # 6
           [0., 0., 0., 1., 0., 0., 0., 0.], # 7
           [0., 0., 0., 0., 1., 0., 0., 0.], # 8
           [0., 0., 0., 0., 0., 1., 0., 0.], # 9
           [0., 0., 0., 0., 0., 0., 1., 0.], # 10
           [0., 0., 0., 0., 0., 0., 0., 1.]] # 11 (all nodes)
  
  leaf_projection_matrix : `numpy.array`, shape (``self.num_leaf_nodes``, ``self.num_nodes``)
      Projection matrix to get leaf nodes. When applied to a matrix with the values for
      all nodes, the projection matrix selects only the rows corresponding to leaf nodes.
  
      ``Y_{leaf} = leaf_projection_matrix @ Y_{actual}``
      In our example::
  
          # 0   1   2   3   4   5   6   7   8   9   10  11  (all nodes)
          [[0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],  # 4
           [0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],  # 5
           [0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],  # 6
           [0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],  # 7
           [0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],  # 8
           [0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],  # 9
           [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],  # 10
           [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1.]]  # 11 (leaf nodes)
  
  bottom_up_transform: `numpy.array`, shape (``self.num_nodes,`` ``self.num_nodes``)
      Bottom-up transformation matrix. When applied to a matrix with the values for
      all nodes, returns values for every node by bubbling up leaf node values to the
      internal nodes. The original values of internal nodes are ignored.
  
      ``Y_{bu} = bottom_up_transform @ Y_{actual}``
      Note that ``bottom_up_transform = sum_matrix @ leaf_projection_matrix``.
      In our example::
  
          # 0   1   2   3   4   5   6   7   8   9   10  11  (all nodes)
          [[0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1.], # 0
           [0., 0., 0., 0., 1., 1., 0., 0., 0., 0., 0., 0.], # 1
           [0., 0., 0., 0., 0., 0., 1., 1., 1., 0., 0., 0.], # 2
           [0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1.], # 3
           [0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0.], # 4
           [0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0.], # 5
           [0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.], # 6
           [0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.], # 7
           [0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0.], # 8
           [0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0.], # 9
           [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0.], # 10
           [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1.]] # 11 (all nodes)
  
  constraint_matrix : `numpy.array`, shape (``self.num_internal_nodes``, ``self.num_nodes``)
      Constraint matrix representing hierarchical additive constraints, where a parent's value
      is equal the sum of its leaf nodes' values.
      ``constraint_matrix @ Y_{all} = 0`` if ``Y_{all}`` satisfies the constraints.
      In our example::
  
          #  0    1    2    3    4    5    6    7    8    9    10   11  (all nodes)
          [[-1.,  0.,  0.,  0.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],  # 0
           [ 0., -1.,  0.,  0.,  1.,  1.,  0.,  0.,  0.,  0.,  0.,  0.],  # 1
           [ 0.,  0., -1.,  0.,  0.,  0.,  1.,  1.,  1.,  0.,  0.,  0.],  # 2
           [ 0.,  0.,  0., -1.,  0.,  0.,  0.,  0.,  0.,  1.,  1.,  1.]]  # 3 (internal nodes)
  
  Methods
  -------
  get_level_of_node : callable
      Returns a node's level in the tree
  get_child_nodes : callable
      Returns the indices of a node's children in the tree
  __set_sum_matrix : callable
      Constructs the summing matrix to compute values of all nodes from the leaf nodes.
  __set_leaf_projection_matrix : callable
      Constructs leaf projection matrix to retain only values of leaf nodes.
  __set_constraint_matrix : callable
      Constructs constraint matrix that requires each parent's
      value to be the sum of its leaf node's values.
docstr: Constructs constraint matrix that requires each parent nodes's
  value to be the sum of its leaf nodes' values.
  
  Returns
  -------
  constraint_matrix : `numpy.array`, shape (``self.num_internal_nodes``, ``self.num_nodes``)
      Constraint matrix representing hierarchical additive constraints,
      where a parent's value equals the sum of its leaf nodes' values.
code: def __set_constraint_matrix(self):
      """Constructs constraint matrix that requires each parent nodes's
      value to be the sum of its leaf nodes' values.
  
      Returns
      -------
      constraint_matrix : `numpy.array`, shape (``self.num_internal_nodes``, ``self.num_nodes``)
          Constraint matrix representing hierarchical additive constraints,
          where a parent's value equals the sum of its leaf nodes' values.
      """
      assert (
          hasattr(self, "bottom_up_transform")
          and self.bottom_up_transform is not None
      )
      arr = self.bottom_up_transform - np.eye(
          self.bottom_up_transform.shape[0]
      )
      return arr[: self.num_internal_nodes,]
  
file_path: greykite/greykite/algo/reconcile/hierarchical_relationship.py
imports: import numpy
  from greykite.common.python_utils import flatten_list
label_desc: Use image node_id 6 for calling the HierarchicalRelationship obj's underlying member method code with example usage: obj.__set_constraint_matrix() and returns: arr