docs: def visit(H, source_node):
      """Executes the 'Visit' algorithm described in the paper:
      Giorgio Gallo, Giustino Longo, Stefano Pallottino, Sang Nguyen,
      Directed hypergraphs and applications, Discrete Applied Mathematics,
      Volume 42, Issues 2-3, 27 April 1993, Pages 177-201, ISSN 0166-218X,
      http://dx.doi.org/10.1016/0166-218X(93)90045-P.
      (http://www.sciencedirect.com/science/article/pii/0166218X9390045P)
  
      The Visit algorithm begins from a source node and traverses a hyperedge
      after any node in the hyperedge's tail has been reached.
  
      :param H: the hypergraph to perform the 'Visit' algorithm on.
      :param source_node: the initial node to begin traversal from.
      :returns: set -- nodes that were visited in this traversal.
                dict -- mapping from each node to the ID of the hyperedge that
                preceeded it in this traversal; will map a node to None
                if that node wasn't visited or if that node is the source
                node.
                dict -- mapping from each hyperedge ID to the node that preceeded
                it in this traversal.
      :raises: TypeError -- Algorithm only applicable to directed hypergraphs
  
      """
      if not isinstance(H, DirectedHypergraph):
          raise TypeError("Algorithm only applicable to directed hypergraphs")
  
      node_set = H.get_node_set()
      # Pv keeps track of the ID of the hyperedge that directely
      # preceeded each node in the traversal
      Pv = {node: None for node in node_set}
  
      hyperedge_id_set = H.get_hyperedge_id_set()
      # Pe keeps track of the node that directedly preceeded
      # each hyperedge in the traversal
      Pe = {hyperedge_id: None for hyperedge_id in hyperedge_id_set}
  
      # Explicitly tracks the set of visited nodes
      visited_nodes = set([source_node])
  
      Q = Queue()
      Q.put(source_node)
  
      while not Q.empty():
          current_node = Q.get()
          # At current_node, we can traverse each hyperedge in its forward star
          for hyperedge_id in H.get_forward_star(current_node):
              if Pe[hyperedge_id] is not None:
                  continue
              Pe[hyperedge_id] = current_node
              # Traversing a hyperedge in current_node's forward star yields
              # the set of head nodes of the hyperedge; visit each head node
              for head_node in H.get_hyperedge_head(hyperedge_id):
                  if head_node in visited_nodes:
                      continue
                  Pv[head_node] = hyperedge_id
                  Q.put(head_node)
                  visited_nodes.add(head_node)
  
      return visited_nodes, Pv, Pe