def path( self, node_a: str, node_b: str ) -> typing.Tuple[typing.Tuple[typing.Tuple[Node], ...], typing.Tuple[ typing.Dict[str, typing.Any], ...]]: connected, src_edges = self.connected(node_a, node_b) if not connected: return tuple(), tuple() # Iterate through the possible paths; can be 1 or more. paths = [] paths_meta = [] for src_edge in src_edges: log.debug("Finding path between {} and {} with source edge {}" "".format(node_a, node_b, src_edge)) with self.g.transaction(write=False) as txn: # Find the last edge we're looking for. query = 'e(type="{}")->@n(value="{}")'.format( src_edge.edge_type, node_b) log.debug("Using query {}".format(query)) tgt_edges = tuple(txn.query(query)) log.debug("Got tgt_edges {}".format(tgt_edges)) # Unravel tgt_edges = tuple(LGGraph._parse_edge(e[0]) for e in tgt_edges) log.debug("tgt_edges after unraveling {}".format(tgt_edges)) # There should be at least one connection, but can be more # if there are repeats. if len(tgt_edges) == 0: raise GraphException(g=self) log.debug("Checking source edge {} for {} target edges".format( src_edge, len(tgt_edges))) for tgt_edge in tgt_edges: log.debug("Checking for target edge {}".format(tgt_edge)) if src_edge.edge_value > tgt_edge.edge_value: log.debug("Skipping target edge {}".format(tgt_edge) + " with value {} because".format(src_edge) + "source edge has greater incr tag") continue path_nodes = self._find_path(src_edge, tgt_edge, txn) if path_nodes == -1: continue if len(path_nodes) < 2: raise GraphException(g=self) log.debug("Found path of length {}".format( len(path_nodes))) log.debug("Got path {}".format(path_nodes)) # Append paths.append(path_nodes) if src_edge.labels is not None: paths_meta.append({ 'edge_type': src_edge.edge_type, **src_edge.labels }) else: paths_meta.append({'edge_type': src_edge.edge_type}) return tuple(paths), tuple(paths_meta)
def test_dgraph_edges_multiple_reverse(dg: Dgraph): _setup_connected_multiple(dg) edges = dg.find_edges_reverse("CDE") try: assert len(edges) == 2 except: raise GraphException(dg)
def test_lemongraph_not_connected(prebuilt_graph: Graph): connected, starting_edges = prebuilt_graph.connected( 'GCTGGATACGT', 'CGTCCGGACGT') if connected: raise GraphException(prebuilt_graph) else: assert True assert len(starting_edges) == 0
def test_lemongraph_connected_distant(prebuilt_graph: Graph): connected, starting_edges = prebuilt_graph.connected( 'ATACGACGCCA', 'CGTCCGGACGT') if not connected: raise GraphException(prebuilt_graph) else: assert True assert len(starting_edges) == 1 log.debug("Found starting_edges as {}".format(starting_edges[0]))
def test_graph_connected_no_node(g: Graph): _setup_connected_no_node(g) connected, starting_edges = g.connected('ABC', 'BCD') if connected: raise GraphException(g) else: assert True assert len(starting_edges) == 0
def test_graph_connected(g: Graph): _setup_connected(g) connected, starting_edges = g.connected('ABC', 'BCD') if not connected: raise GraphException(g) else: assert True assert len(starting_edges) == 1 log.debug("Found starting_edges as {}".format(starting_edges[0]))
def test_graph_connected_shortcut(g: Graph): _setup_connected_shortcut(g) connected, starting_edges = g.connected('ABC', 'CDE') if not connected: raise GraphException(g) else: assert True assert len(starting_edges) == 2 log.debug("Found starting_edges as:") for e in starting_edges: log.debug(e)
def test_graph_connected_path(g: Graph): _setup_connected(g) paths, _ = g.path("ABC", "BCD") # There should be 1 path in paths assert len(paths) == 1 path = paths[0] if path[0].value != "ABC" or path[1].value != "BCD": raise GraphException(g=g) else: assert True joined = concat_values(path) assert joined == "ABCD"
def test_graph_basics_edges_dgraph(dg: Dgraph): g = dg expected = ["ABC", "BCE", "CEF"] expected = [Node(value=v) for v in expected] g.add_edge(Edge(src=expected[0].value, tgt=expected[1].value)) g.add_edge(Edge(src=expected[1].value, tgt=expected[2].value)) try: # In Dgraph we can retrieve the actual kmer value assert {(e.src, e.tgt) for e in g.edges} == { (expected[0].value, expected[1].value), (expected[1].value, expected[2].value)} except: raise GraphException(g)
def test_graph_connected_repeats_full_path(g: Graph): n1 = Node(value="ABC") n2 = Node(value="BCD") n3 = Node(value="CDE") g.upsert_node(n1) g.upsert_node(n2) g.upsert_node(n3) e1 = Edge(src="ABC", tgt="BCD", edge_value=0) g.add_edge(e1) e2 = Edge(src="BCD", tgt="CDE", edge_value=1) g.add_edge(e2) e3 = Edge(src="CDE", tgt="ABC", edge_value=2) g.add_edge(e3) e4 = Edge(src="ABC", tgt="BCD", edge_value=3) g.add_edge(e4) e5 = Edge(src="BCD", tgt="CDE", edge_value=4) g.add_edge(e5) g.save() try: paths, _ = g.path('ABC', 'CDE') except: raise GraphException(g) assert len(paths) == 3 c = 0 for path in paths: assert path[0].value == "ABC" assert path[-1].value == "CDE" if len(path) == 3: assert path[1].value == "BCD" # There are 2 copies of this c += 1 elif len(path) == 6: assert path[1].value == "BCD" assert path[2].value == "CDE" assert path[3].value == "ABC" assert path[4].value == "BCD" assert path[5].value == "CDE" assert c == 2
def test_graph_basics_edges_lemongraph(lgr: LGGraph): g = lgr expected = ["ABC", "BCE", "CEF"] expected = [Node(value=v) for v in expected] nodes_with_ids = [] for node in expected: # Returned the node with db_id set, these are required to check edges n = g.upsert_node(node) nodes_with_ids.append(n) g.add_edge(Edge(src=expected[0].value, tgt=expected[1].value)) g.add_edge(Edge(src=expected[1].value, tgt=expected[2].value)) try: # In lemongraph these are stored as numerical IDs assert {(e.src, e.tgt) for e in g.edges} == { (nodes_with_ids[0].db_id, nodes_with_ids[1].db_id), (nodes_with_ids[1].db_id, nodes_with_ids[2].db_id)} except: raise GraphException(g)