code: def collapse_vertically(tree, columns):
      
  
      def _same_states(node1, node2, columns):
          for column in columns:
              if getattr(node1, column, set()) != getattr(node2, column, set()):
                  return False
          return True
  
      num_collapsed = 0
      for n in tree.traverse('postorder'):
          if n.is_leaf():
              continue
  
          children = list(n.children)
          for child in children:
              # merge the child into this node if their states are the same
              if _same_states(n, child, columns):
                  getattr(n, TIPS_INSIDE).extend(getattr(child, TIPS_INSIDE))
                  getattr(n, INTERNAL_NODES_INSIDE).extend(getattr(child, INTERNAL_NODES_INSIDE))
  
                  n.remove_child(child)
                  grandchildren = list(child.children)
                  for grandchild in grandchildren:
                      n.add_child(grandchild)
                  num_collapsed += 1
      if num_collapsed:
          logging.getLogger('pastml').debug('Collapsed vertically {} internal nodes without state change.'
                                            .format(num_collapsed))
docs: Collapses a child node into its parent if they are in the same state.
      :param columns: a list of characters
      :param tree: ete3.Tree
      :return: void, modifies the input tree