given a dict of pointing relations and a start node, this function
    will return a list of paths (each path is represented as a list of
    node IDs -- from the first node of the path to the last).

    Parameters
    ----------
    rel_dict : dict
        a dictionary mapping from an edge source node (node ID str)
        to a set of edge target nodes (node ID str)
    src_id : str

    Returns
    -------
    paths_starting_with_id : list of list of str
        each list constains a list of strings (i.e. a list of node IDs,
        which represent a chain of pointing relations)

def __walk_chain(rel_dict, src_id):
    """
    given a dict of pointing relations and a start node, this function
    will return a list of paths (each path is represented as a list of
    node IDs -- from the first node of the path to the last).

    Parameters
    ----------
    rel_dict : dict
        a dictionary mapping from an edge source node (node ID str)
        to a set of edge target nodes (node ID str)
    src_id : str

    Returns
    -------
    paths_starting_with_id : list of list of str
        each list constains a list of strings (i.e. a list of node IDs,
        which represent a chain of pointing relations)
    """
    paths_starting_with_id = []
    for target_id in rel_dict[src_id]:
        if target_id in rel_dict:
            for tail in __walk_chain(rel_dict, target_id):
                paths_starting_with_id.append([src_id] + tail)
        else:
            paths_starting_with_id.append([src_id, target_id])
    return paths_starting_with_id