diff --git a/src/pybel_tools/selection/metapaths.py b/src/pybel_tools/selection/metapaths.py index 7a176787..12c53edf 100644 --- a/src/pybel_tools/selection/metapaths.py +++ b/src/pybel_tools/selection/metapaths.py @@ -10,6 +10,8 @@ """ +from functools import lru_cache + from pybel.constants import FUNCTION __all__ = [ @@ -31,6 +33,7 @@ def convert_path_to_metapath(graph, nodes): ] +@lru_cache(maxsize=None) def get_walks_exhaustive(graph, node, length): """Gets all walks under a given length starting at a given node @@ -38,33 +41,73 @@ def get_walks_exhaustive(graph, node, length): :param node: Starting node :param int length: The length of walks to get :return: A list of paths + :rtype: list[tuple] """ if 0 == length: return (node,), - return [ + return tuple( (node, key) + path for neighbor in graph.edge[node] for path in get_walks_exhaustive(graph, neighbor, length - 1) if node not in path - for key, data in graph.edge[node][neighbor].items() - ] + for key in graph.edge[node][neighbor] + ) -def match_simple_metapath(graph, node, metapath): +def match_simple_metapath(graph, node, simple_metapath): """Matches a simple metapath starting at the given node - :param graph: A BEL graph - :param node: A BEL node - :param metapath: A list of BEL Functions + :param pybel.BELGraph graph: A BEL graph + :param tuple node: A BEL node + :param list[str] simple_metapath: A list of BEL Functions :return: An iterable over paths from the node matching the metapath + :rtype: iter[tuple] """ - if 0 == len(metapath): + if 0 == len(simple_metapath): yield node, else: for neighbor in graph.edge[node]: - if graph.node[neighbor][FUNCTION] == metapath[0]: - for path in match_simple_metapath(graph, neighbor, metapath[1:]): + if graph.node[neighbor][FUNCTION] == simple_metapath[0]: + for path in match_simple_metapath(graph, neighbor, simple_metapath[1:]): if node not in path: yield (node,) + path + + +def convert_simple_walk(graph, simple_walk): + """Converts a walk into a sequence of BEL functions + + :param pybel.BELGraph graph: A BEL graph + :param iter[tuple] simple_walk: An iterable of BEL nodes + :return: A list of BEL functions of the walk + :rtype: list[str] + """ + return [ + graph.node[node][FUNCTION] + for node in simple_walk + ] + + +def match_complex_metapath(graph, node, complex_metapath): + """Matches a complex metapath starting at the given node + + :param pybel.BELGraph graph: A BEL graph + :param tuple node: A BEL node + :param list[str] complex_metapath: An iterable of alternating BEL nodes and relations + :return: An iterable over paths from the node matching the metapath + :rtype: iter[tuple] + """ + raise NotImplemented + + +def convert_complex_walk(graph, complex_walk): + """Converts a walk into an alternative sequence of BEL functions and BEL relations, starting and ending + with a BEL function + + :param pybel.BELGraph graph: A BEL graph + :param iter[tuple] complex_walk: An iterable of alternating BEL nodes and relations + :return: An alternating list of BEL functions and relations of the walk + :rtype: list[str] + """ + raise NotImplemented