From ccfa3b46028aa9678e62b25d7eb24efe667052b4 Mon Sep 17 00:00:00 2001 From: Aryan Roy Date: Sat, 8 Jun 2024 17:13:03 +0530 Subject: [PATCH 01/23] Added function skeleton Signed-off-by: Aryan Roy --- pywhy_graphs/algorithms/generic.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index 2c336df06..bff78bc07 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -823,3 +823,6 @@ def is_maximal(G, L: Optional[Set] = None, S: Optional[Set] = None): else: continue return True + +def possibly_directed_path(G, X: Optional[Set] = None, Y: Optional[Set] = None): + pass \ No newline at end of file From 97144bae28c19285d966debd4666d7f6e45ce8af Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 15:13:15 +0000 Subject: [PATCH 02/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pywhy_graphs/algorithms/generic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index d6c5a602d..8fb36718e 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -856,6 +856,6 @@ def all_vstructures(G: nx.DiGraph, as_edges: bool = False): vstructs.add((p1, node, p2)) # type: ignore return vstructs - + def possibly_directed_path(G, X: Optional[Set] = None, Y: Optional[Set] = None): pass From a5caac132ff65dcd11a541a9c0e4aa7dd8cbe126 Mon Sep 17 00:00:00 2001 From: Aryan Roy Date: Sat, 27 Jul 2024 17:29:12 +0530 Subject: [PATCH 03/23] Some more code Signed-off-by: Aryan Roy --- pywhy_graphs/algorithms/generic.py | 26 ++++++++++++++++++- pywhy_graphs/algorithms/tests/test_generic.py | 12 +++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index bff78bc07..ca41367a8 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -17,6 +17,7 @@ "valid_mag", "dag_to_mag", "is_maximal", + "possibly_directed_path" ] @@ -824,5 +825,28 @@ def is_maximal(G, L: Optional[Set] = None, S: Optional[Set] = None): continue return True +def get_X_neighbors(G, X : set): + + final_neighbors = set() + + for elem in X: + elem_possible_neighbors = set(G.neighbors(elem)) + to_remove = X.intersection(elem_possible_neighbors) + elem_neighbors = elem_possible_neighbors - to_remove + final_neighbors.update(elem_neighbors) + + return final_neighbors + + + def possibly_directed_path(G, X: Optional[Set] = None, Y: Optional[Set] = None): - pass \ No newline at end of file + + if isinstance(X, set): + x_neighbors = get_X_neighbors(G, X) + else: + x_neighbors = G.neighbors(X) + + + # path_list = recursively_find_pd_paths(G, x_neigbors, Y) + + return \ No newline at end of file diff --git a/pywhy_graphs/algorithms/tests/test_generic.py b/pywhy_graphs/algorithms/tests/test_generic.py index 8b7e6c375..854c1dcb4 100644 --- a/pywhy_graphs/algorithms/tests/test_generic.py +++ b/pywhy_graphs/algorithms/tests/test_generic.py @@ -468,3 +468,15 @@ def test_is_maximal(): S = {} L = {"Y"} assert not pywhy_graphs.is_maximal(admg, L, S) + +def test_possibly_directed(): + # X <- Y <-> Z <-> H; Z -> X + admg = ADMG() + admg.add_edge("Y", "X", admg.directed_edge_name) + admg.add_edge("Z", "X", admg.directed_edge_name) + admg.add_edge("Z", "Y", admg.bidirected_edge_name) + admg.add_edge("Z", "H", admg.bidirected_edge_name) + + S = "X" + L = {"Y","Z"} + assert not pywhy_graphs.possibly_directed_path(admg, L, S) From 415085ef1d76c325904badb9c068e51a92f5558b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 27 Jul 2024 12:02:00 +0000 Subject: [PATCH 04/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pywhy_graphs/algorithms/tests/test_generic.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pywhy_graphs/algorithms/tests/test_generic.py b/pywhy_graphs/algorithms/tests/test_generic.py index eed95342b..17edb3abf 100644 --- a/pywhy_graphs/algorithms/tests/test_generic.py +++ b/pywhy_graphs/algorithms/tests/test_generic.py @@ -471,7 +471,6 @@ def test_is_maximal(): assert not pywhy_graphs.is_maximal(admg, L, S) - def test_all_vstructures(): # Create a directed graph G = nx.DiGraph() @@ -508,5 +507,5 @@ def test_possibly_directed(): admg.add_edge("Z", "H", admg.bidirected_edge_name) S = "X" - L = {"Y","Z"} - assert not pywhy_graphs.possibly_directed_path(admg, L, S) \ No newline at end of file + L = {"Y", "Z"} + assert not pywhy_graphs.possibly_directed_path(admg, L, S) From bf09476993084a2658c60a89e34e3fe4727ee839 Mon Sep 17 00:00:00 2001 From: Aryan Roy Date: Sat, 27 Jul 2024 17:32:57 +0530 Subject: [PATCH 05/23] fixed issue Signed-off-by: Aryan Roy --- pywhy_graphs/algorithms/generic.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index 63c59e3a1..fdf50a94a 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -18,11 +18,8 @@ "valid_mag", "dag_to_mag", "is_maximal", -<<<<<<< HEAD - "possibly_directed_path" -======= "all_vstructures", ->>>>>>> 66e89d881425c95666389fc64cb459b7951b0f5f + "possibly_directed_path" ] From 06fe76f24b8cbd1233f8324bfabb65a5591dba62 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 27 Jul 2024 12:03:54 +0000 Subject: [PATCH 06/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pywhy_graphs/algorithms/generic.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index fdf50a94a..634927809 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -19,7 +19,7 @@ "dag_to_mag", "is_maximal", "all_vstructures", - "possibly_directed_path" + "possibly_directed_path", ] @@ -857,18 +857,18 @@ def all_vstructures(G: nx.DiGraph, as_edges: bool = False): vstructs.add((p1, node, p2)) # type: ignore return vstructs -def get_X_neighbors(G, X : set): + +def get_X_neighbors(G, X: set): final_neighbors = set() for elem in X: - elem_possible_neighbors = set(G.neighbors(elem)) - to_remove = X.intersection(elem_possible_neighbors) - elem_neighbors = elem_possible_neighbors - to_remove - final_neighbors.update(elem_neighbors) - - return final_neighbors + elem_possible_neighbors = set(G.neighbors(elem)) + to_remove = X.intersection(elem_possible_neighbors) + elem_neighbors = elem_possible_neighbors - to_remove + final_neighbors.update(elem_neighbors) + return final_neighbors def possibly_directed_path(G, X: Optional[Set] = None, Y: Optional[Set] = None): @@ -878,7 +878,6 @@ def possibly_directed_path(G, X: Optional[Set] = None, Y: Optional[Set] = None): else: x_neighbors = G.neighbors(X) - # path_list = recursively_find_pd_paths(G, x_neigbors, Y) - return \ No newline at end of file + return From e940486774e56093d98a495ec3c56fa8aeda6ff0 Mon Sep 17 00:00:00 2001 From: Aryan Roy Date: Wed, 7 Aug 2024 20:01:57 +0530 Subject: [PATCH 07/23] added more code Signed-off-by: Aryan Roy --- pywhy_graphs/algorithms/generic.py | 58 +++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index 634927809..52cb7f9e0 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -857,27 +857,77 @@ def all_vstructures(G: nx.DiGraph, as_edges: bool = False): vstructs.add((p1, node, p2)) # type: ignore return vstructs +def check_back_arrow(G: ADMG, X, Y: set): + + out = set() + + for elem in Y: + if not (G.has_edge(X,elem,G.bidirected_edge_name) or G.has_edge(elem,X,G.directed_edge_name)): + out.update(elem) + + return out def get_X_neighbors(G, X: set): final_neighbors = set() for elem in X: - elem_possible_neighbors = set(G.neighbors(elem)) + elem_neighbors = set(G.neighbors(elem)) + elem_possible_neighbors = check_back_arrow(G, elem, elem_neighbors) to_remove = X.intersection(elem_possible_neighbors) elem_neighbors = elem_possible_neighbors - to_remove final_neighbors.update(elem_neighbors) - return final_neighbors + out = [] + + for elem in final_neighbors: + temp = dict() + temp[0] = elem + out.append(temp) + + return out + +def recursively_find_pd_paths(G, X, paths, Y): + + counter = 0 + new_paths = [] + + for i in range(len(paths)): + cur_elem = paths[i][paths[i].keys()[-1]] + if cur_elem in Y: + counter += 1 + continue + nbr_temp = G.neighbors(X) + nbr_possible = check_back_arrow(nbr_temp) + + + endpoints = nbr_possible.intersection(Y) + if len(endpoints) > 0: + paths[i][len(paths[i])] = next(iter(endpoints)) + else: + pass + if len(nbr_possible) != 0: + new_paths.append(paths[i]) + + + def possibly_directed_path(G, X: Optional[Set] = None, Y: Optional[Set] = None): if isinstance(X, set): x_neighbors = get_X_neighbors(G, X) else: - x_neighbors = G.neighbors(X) + nbr_temp = G.neighbors(X) + nbr_possible = check_back_arrow(nbr_temp) + x_neighbors = [] + + for elem in nbr_possible: + temp = dict() + temp[0] = elem + x_neighbors.append(temp) - # path_list = recursively_find_pd_paths(G, x_neigbors, Y) + print(x_neighbors) + path_list = recursively_find_pd_paths(G, X, x_neighbors, Y) return From 31c606944715fda5a653701d54261e0fcb8feb98 Mon Sep 17 00:00:00 2001 From: Aryan Roy Date: Sat, 10 Aug 2024 15:07:40 +0530 Subject: [PATCH 08/23] completed the implementation Signed-off-by: Aryan Roy --- pywhy_graphs/algorithms/generic.py | 59 +++++---- pywhy_graphs/algorithms/tests/test_generic.py | 112 +++++++++++++++++- 2 files changed, 141 insertions(+), 30 deletions(-) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index 52cb7f9e0..fb3720c65 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -869,21 +869,22 @@ def check_back_arrow(G: ADMG, X, Y: set): def get_X_neighbors(G, X: set): - final_neighbors = set() + out = [] for elem in X: elem_neighbors = set(G.neighbors(elem)) elem_possible_neighbors = check_back_arrow(G, elem, elem_neighbors) to_remove = X.intersection(elem_possible_neighbors) elem_neighbors = elem_possible_neighbors - to_remove - final_neighbors.update(elem_neighbors) - - out = [] - for elem in final_neighbors: - temp = dict() - temp[0] = elem - out.append(temp) + if len(elem_neighbors) != 0: + temp = dict() + count = 0 + temp[count] = elem + for elem in elem_neighbors: + count += 1 + temp[count] = elem + out.append(temp) return out @@ -893,23 +894,33 @@ def recursively_find_pd_paths(G, X, paths, Y): new_paths = [] for i in range(len(paths)): - cur_elem = paths[i][paths[i].keys()[-1]] - if cur_elem in Y: - counter += 1 - continue - nbr_temp = G.neighbors(X) - nbr_possible = check_back_arrow(nbr_temp) + cur_elem = paths[i][list(paths[i].keys())[-1]] + nbr_temp = G.neighbors(cur_elem) + nbr_possible = check_back_arrow(G, cur_elem, nbr_temp) + if len(nbr_possible) == 0: + new_paths.append(paths[i].copy()) + + possible_end = nbr_possible.intersection(Y) - endpoints = nbr_possible.intersection(Y) - if len(endpoints) > 0: - paths[i][len(paths[i])] = next(iter(endpoints)) - else: - pass - if len(nbr_possible) != 0: - new_paths.append(paths[i]) + if len(possible_end) != 0: + for elem in possible_end: + temp_path = paths[i].copy() + temp_path[len(temp_path)] = elem + new_paths.append(temp_path) + + remaining_nodes = nbr_possible - possible_end + remaining_nodes = remaining_nodes - remaining_nodes.intersection(paths[i].values()) - remaining_nodes.intersection(X) + + temp_arr = [] + for elem in remaining_nodes: + temp_paths = paths[i].copy() + temp_paths[len(temp_paths)] = elem + temp_arr.append(temp_paths) + new_paths.extend(recursively_find_pd_paths(G, X, temp_arr, Y)) + return new_paths @@ -924,10 +935,10 @@ def possibly_directed_path(G, X: Optional[Set] = None, Y: Optional[Set] = None): for elem in nbr_possible: temp = dict() - temp[0] = elem + temp[0] = X + temp[1] = elem x_neighbors.append(temp) - print(x_neighbors) path_list = recursively_find_pd_paths(G, X, x_neighbors, Y) - return + return path_list diff --git a/pywhy_graphs/algorithms/tests/test_generic.py b/pywhy_graphs/algorithms/tests/test_generic.py index 17edb3abf..65f5a6603 100644 --- a/pywhy_graphs/algorithms/tests/test_generic.py +++ b/pywhy_graphs/algorithms/tests/test_generic.py @@ -500,12 +500,112 @@ def test_all_vstructures(): def test_possibly_directed(): # X <- Y <-> Z <-> H; Z -> X + admg = ADMG() admg.add_edge("Y", "X", admg.directed_edge_name) - admg.add_edge("Z", "X", admg.directed_edge_name) - admg.add_edge("Z", "Y", admg.bidirected_edge_name) - admg.add_edge("Z", "H", admg.bidirected_edge_name) + admg.add_edge("X", "Z", admg.directed_edge_name) + admg.add_edge("Z", "H", admg.directed_edge_name) + + Y = {"H"} + X = {"Y"} + + + correct = [{0: 'Y', 1: 'X', 2: 'Z', 3: 'H'}] + out = pywhy_graphs.possibly_directed_path(admg, X, Y) + assert correct[0] == out[0] + + admg = ADMG() + admg.add_edge("A", "X", admg.directed_edge_name) + admg.add_edge("Y", "X", admg.directed_edge_name) + admg.add_edge("X", "Z", admg.directed_edge_name) + admg.add_edge("Z", "H", admg.directed_edge_name) + + Y = {"H"} + X = {"Y", "A"} + + correct = [{0: 'A', 1: 'X', 2: 'Z', 3: 'H'}, {0: 'Y', 1: 'X', 2: 'Z', 3: 'H'}] + pywhy_graphs.possibly_directed_path(admg, X, Y) + assert correct[0] == out[0] + assert correct[1] == out[1] + + admg = ADMG() + admg.add_edge("X", "A", admg.directed_edge_name) + admg.add_edge("Y", "X", admg.directed_edge_name) + admg.add_edge("X", "Z", admg.directed_edge_name) + admg.add_edge("Z", "H", admg.directed_edge_name) + + Y = {"H"} + X = {"Y", "A"} + + correct = [{0: 'Y', 1: 'X', 2: 'Z', 3: 'H'}] + pywhy_graphs.possibly_directed_path(admg, X, Y) + assert correct[0] == out[0] + + + admg = ADMG() + admg.add_edge("X", "A", admg.directed_edge_name) + admg.add_edge("Y", "X", admg.directed_edge_name) + admg.add_edge("X", "Z", admg.directed_edge_name) + admg.add_edge("Z", "H", admg.directed_edge_name) + admg.add_edge("K", "Z", admg.directed_edge_name) + + Y = {"H", "K"} + X = {"Y", "A"} + + correct = [{0: 'Y', 1: 'X', 2: 'Z', 3: 'H'}] + pywhy_graphs.possibly_directed_path(admg, X, Y) + assert correct[0] == out[0] + + + admg = ADMG() + admg.add_edge("A", "X", admg.directed_edge_name) + admg.add_edge("Y", "X", admg.directed_edge_name) + admg.add_edge("X", "Z", admg.directed_edge_name) + admg.add_edge("Z", "H", admg.directed_edge_name) + admg.add_edge("Z", "K", admg.directed_edge_name) + + Y = {"H", "K"} + X = {"Y", "A"} + + correct = [{0: 'A', 1: 'X', 2: 'Z', 3: 'H'}, {0: 'A', 1: 'X', 2: 'Z', 3: 'K'}, {0: 'Y', 1: 'X', 2: 'Z', 3: 'H'}, {0: 'Y', 1: 'X', 2: 'Z', 3: 'K'}] + pywhy_graphs.possibly_directed_path(admg, X, Y) + assert correct[0] == out[0] + assert correct[1] == out[1] + assert correct[2] == out[2] + assert correct[3] == out[3] + + + admg = ADMG() + admg.add_edge("A", "G", admg.directed_edge_name) + admg.add_edge("G", "C", admg.directed_edge_name) + admg.add_edge("C", "H", admg.directed_edge_name) + admg.add_edge("Y", "X", admg.directed_edge_name) + admg.add_edge("X", "Z", admg.directed_edge_name) + admg.add_edge("Z", "K", admg.directed_edge_name) + + Y = {"H", "K"} + X = {"Y", "A"} + + correct = [{0: 'A', 1: 'G', 2: 'C', 3: 'H'}, {0: 'Y', 1: 'X', 2: 'Z', 3: 'K'}] + pywhy_graphs.possibly_directed_path(admg, X, Y) + assert correct[0] == out[0] + assert correct[1] == out[1] + + + admg = ADMG() + admg.add_edge("A", "G", admg.directed_edge_name) + admg.add_edge("G", "C", admg.directed_edge_name) + admg.add_edge("C", "H", admg.directed_edge_name) + admg.add_edge("Z", "C", admg.directed_edge_name) + admg.add_edge("Y", "X", admg.directed_edge_name) + admg.add_edge("X", "Z", admg.directed_edge_name) + admg.add_edge("Z", "K", admg.directed_edge_name) + + Y = {"H", "K"} + X = {"Y", "A"} - S = "X" - L = {"Y", "Z"} - assert not pywhy_graphs.possibly_directed_path(admg, L, S) + correct = [{0: 'A', 1: 'G', 2: 'C', 3: 'H'}, {0: 'Y', 1: 'X', 2: 'Z', 3: 'K'}, {0: 'Y', 1: 'X', 2: 'Z', 3: 'C', 4: 'H'}] + pywhy_graphs.possibly_directed_path(admg, X, Y) + assert correct[0] == out[0] + assert correct[1] == out[1] + assert correct[2] == out[2] \ No newline at end of file From fd5736c972a90ebbe7853fc72439149029069dac Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 10 Aug 2024 09:38:05 +0000 Subject: [PATCH 09/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pywhy_graphs/algorithms/generic.py | 24 +++++--- pywhy_graphs/algorithms/tests/test_generic.py | 56 ++++++++++--------- 2 files changed, 46 insertions(+), 34 deletions(-) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index fb3720c65..f0294ed95 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -857,16 +857,20 @@ def all_vstructures(G: nx.DiGraph, as_edges: bool = False): vstructs.add((p1, node, p2)) # type: ignore return vstructs + def check_back_arrow(G: ADMG, X, Y: set): - + out = set() for elem in Y: - if not (G.has_edge(X,elem,G.bidirected_edge_name) or G.has_edge(elem,X,G.directed_edge_name)): + if not ( + G.has_edge(X, elem, G.bidirected_edge_name) or G.has_edge(elem, X, G.directed_edge_name) + ): out.update(elem) return out + def get_X_neighbors(G, X: set): out = [] @@ -877,7 +881,7 @@ def get_X_neighbors(G, X: set): to_remove = X.intersection(elem_possible_neighbors) elem_neighbors = elem_possible_neighbors - to_remove - if len(elem_neighbors) != 0: + if len(elem_neighbors) != 0: temp = dict() count = 0 temp[count] = elem @@ -888,6 +892,7 @@ def get_X_neighbors(G, X: set): return out + def recursively_find_pd_paths(G, X, paths, Y): counter = 0 @@ -900,7 +905,7 @@ def recursively_find_pd_paths(G, X, paths, Y): if len(nbr_possible) == 0: new_paths.append(paths[i].copy()) - + possible_end = nbr_possible.intersection(Y) if len(possible_end) != 0: @@ -910,19 +915,22 @@ def recursively_find_pd_paths(G, X, paths, Y): new_paths.append(temp_path) remaining_nodes = nbr_possible - possible_end - remaining_nodes = remaining_nodes - remaining_nodes.intersection(paths[i].values()) - remaining_nodes.intersection(X) + remaining_nodes = ( + remaining_nodes + - remaining_nodes.intersection(paths[i].values()) + - remaining_nodes.intersection(X) + ) temp_arr = [] for elem in remaining_nodes: - temp_paths = paths[i].copy() - temp_paths[len(temp_paths)] = elem + temp_paths = paths[i].copy() + temp_paths[len(temp_paths)] = elem temp_arr.append(temp_paths) new_paths.extend(recursively_find_pd_paths(G, X, temp_arr, Y)) return new_paths - def possibly_directed_path(G, X: Optional[Set] = None, Y: Optional[Set] = None): diff --git a/pywhy_graphs/algorithms/tests/test_generic.py b/pywhy_graphs/algorithms/tests/test_generic.py index 65f5a6603..021ecf384 100644 --- a/pywhy_graphs/algorithms/tests/test_generic.py +++ b/pywhy_graphs/algorithms/tests/test_generic.py @@ -509,10 +509,9 @@ def test_possibly_directed(): Y = {"H"} X = {"Y"} - - correct = [{0: 'Y', 1: 'X', 2: 'Z', 3: 'H'}] + correct = [{0: "Y", 1: "X", 2: "Z", 3: "H"}] out = pywhy_graphs.possibly_directed_path(admg, X, Y) - assert correct[0] == out[0] + assert correct[0] == out[0] admg = ADMG() admg.add_edge("A", "X", admg.directed_edge_name) @@ -523,10 +522,10 @@ def test_possibly_directed(): Y = {"H"} X = {"Y", "A"} - correct = [{0: 'A', 1: 'X', 2: 'Z', 3: 'H'}, {0: 'Y', 1: 'X', 2: 'Z', 3: 'H'}] + correct = [{0: "A", 1: "X", 2: "Z", 3: "H"}, {0: "Y", 1: "X", 2: "Z", 3: "H"}] pywhy_graphs.possibly_directed_path(admg, X, Y) - assert correct[0] == out[0] - assert correct[1] == out[1] + assert correct[0] == out[0] + assert correct[1] == out[1] admg = ADMG() admg.add_edge("X", "A", admg.directed_edge_name) @@ -537,10 +536,9 @@ def test_possibly_directed(): Y = {"H"} X = {"Y", "A"} - correct = [{0: 'Y', 1: 'X', 2: 'Z', 3: 'H'}] + correct = [{0: "Y", 1: "X", 2: "Z", 3: "H"}] pywhy_graphs.possibly_directed_path(admg, X, Y) - assert correct[0] == out[0] - + assert correct[0] == out[0] admg = ADMG() admg.add_edge("X", "A", admg.directed_edge_name) @@ -552,10 +550,9 @@ def test_possibly_directed(): Y = {"H", "K"} X = {"Y", "A"} - correct = [{0: 'Y', 1: 'X', 2: 'Z', 3: 'H'}] + correct = [{0: "Y", 1: "X", 2: "Z", 3: "H"}] pywhy_graphs.possibly_directed_path(admg, X, Y) - assert correct[0] == out[0] - + assert correct[0] == out[0] admg = ADMG() admg.add_edge("A", "X", admg.directed_edge_name) @@ -567,13 +564,17 @@ def test_possibly_directed(): Y = {"H", "K"} X = {"Y", "A"} - correct = [{0: 'A', 1: 'X', 2: 'Z', 3: 'H'}, {0: 'A', 1: 'X', 2: 'Z', 3: 'K'}, {0: 'Y', 1: 'X', 2: 'Z', 3: 'H'}, {0: 'Y', 1: 'X', 2: 'Z', 3: 'K'}] + correct = [ + {0: "A", 1: "X", 2: "Z", 3: "H"}, + {0: "A", 1: "X", 2: "Z", 3: "K"}, + {0: "Y", 1: "X", 2: "Z", 3: "H"}, + {0: "Y", 1: "X", 2: "Z", 3: "K"}, + ] pywhy_graphs.possibly_directed_path(admg, X, Y) - assert correct[0] == out[0] - assert correct[1] == out[1] - assert correct[2] == out[2] - assert correct[3] == out[3] - + assert correct[0] == out[0] + assert correct[1] == out[1] + assert correct[2] == out[2] + assert correct[3] == out[3] admg = ADMG() admg.add_edge("A", "G", admg.directed_edge_name) @@ -586,11 +587,10 @@ def test_possibly_directed(): Y = {"H", "K"} X = {"Y", "A"} - correct = [{0: 'A', 1: 'G', 2: 'C', 3: 'H'}, {0: 'Y', 1: 'X', 2: 'Z', 3: 'K'}] + correct = [{0: "A", 1: "G", 2: "C", 3: "H"}, {0: "Y", 1: "X", 2: "Z", 3: "K"}] pywhy_graphs.possibly_directed_path(admg, X, Y) - assert correct[0] == out[0] - assert correct[1] == out[1] - + assert correct[0] == out[0] + assert correct[1] == out[1] admg = ADMG() admg.add_edge("A", "G", admg.directed_edge_name) @@ -604,8 +604,12 @@ def test_possibly_directed(): Y = {"H", "K"} X = {"Y", "A"} - correct = [{0: 'A', 1: 'G', 2: 'C', 3: 'H'}, {0: 'Y', 1: 'X', 2: 'Z', 3: 'K'}, {0: 'Y', 1: 'X', 2: 'Z', 3: 'C', 4: 'H'}] + correct = [ + {0: "A", 1: "G", 2: "C", 3: "H"}, + {0: "Y", 1: "X", 2: "Z", 3: "K"}, + {0: "Y", 1: "X", 2: "Z", 3: "C", 4: "H"}, + ] pywhy_graphs.possibly_directed_path(admg, X, Y) - assert correct[0] == out[0] - assert correct[1] == out[1] - assert correct[2] == out[2] \ No newline at end of file + assert correct[0] == out[0] + assert correct[1] == out[1] + assert correct[2] == out[2] From d235b2f0aa83e6b12cf902af497cac155105d078 Mon Sep 17 00:00:00 2001 From: Aryan Roy Date: Sat, 10 Aug 2024 15:55:30 +0530 Subject: [PATCH 10/23] Added more tests Signed-off-by: Aryan Roy --- pywhy_graphs/algorithms/generic.py | 19 ++-- pywhy_graphs/algorithms/tests/test_generic.py | 95 +++++++++++++++++-- 2 files changed, 99 insertions(+), 15 deletions(-) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index f0294ed95..9df5e3904 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -882,14 +882,11 @@ def get_X_neighbors(G, X: set): elem_neighbors = elem_possible_neighbors - to_remove if len(elem_neighbors) != 0: - temp = dict() - count = 0 - temp[count] = elem - for elem in elem_neighbors: - count += 1 - temp[count] = elem - out.append(temp) - + for nbh in elem_neighbors: + temp = dict() + temp[0] = elem + temp[1] = nbh + out.append(temp) return out @@ -900,6 +897,11 @@ def recursively_find_pd_paths(G, X, paths, Y): for i in range(len(paths)): cur_elem = paths[i][list(paths[i].keys())[-1]] + + if cur_elem in Y: + new_paths.append(paths[i]) + continue + nbr_temp = G.neighbors(cur_elem) nbr_possible = check_back_arrow(G, cur_elem, nbr_temp) @@ -947,6 +949,7 @@ def possibly_directed_path(G, X: Optional[Set] = None, Y: Optional[Set] = None): temp[1] = elem x_neighbors.append(temp) + path_list = recursively_find_pd_paths(G, X, x_neighbors, Y) return path_list diff --git a/pywhy_graphs/algorithms/tests/test_generic.py b/pywhy_graphs/algorithms/tests/test_generic.py index 021ecf384..56c7d22c2 100644 --- a/pywhy_graphs/algorithms/tests/test_generic.py +++ b/pywhy_graphs/algorithms/tests/test_generic.py @@ -2,7 +2,7 @@ import pytest import pywhy_graphs -from pywhy_graphs import ADMG +from pywhy_graphs import ADMG, PAG from pywhy_graphs.algorithms import all_vstructures @@ -523,7 +523,7 @@ def test_possibly_directed(): X = {"Y", "A"} correct = [{0: "A", 1: "X", 2: "Z", 3: "H"}, {0: "Y", 1: "X", 2: "Z", 3: "H"}] - pywhy_graphs.possibly_directed_path(admg, X, Y) + out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct[0] == out[0] assert correct[1] == out[1] @@ -537,7 +537,7 @@ def test_possibly_directed(): X = {"Y", "A"} correct = [{0: "Y", 1: "X", 2: "Z", 3: "H"}] - pywhy_graphs.possibly_directed_path(admg, X, Y) + out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct[0] == out[0] admg = ADMG() @@ -551,7 +551,7 @@ def test_possibly_directed(): X = {"Y", "A"} correct = [{0: "Y", 1: "X", 2: "Z", 3: "H"}] - pywhy_graphs.possibly_directed_path(admg, X, Y) + out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct[0] == out[0] admg = ADMG() @@ -570,7 +570,7 @@ def test_possibly_directed(): {0: "Y", 1: "X", 2: "Z", 3: "H"}, {0: "Y", 1: "X", 2: "Z", 3: "K"}, ] - pywhy_graphs.possibly_directed_path(admg, X, Y) + out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct[0] == out[0] assert correct[1] == out[1] assert correct[2] == out[2] @@ -588,7 +588,7 @@ def test_possibly_directed(): X = {"Y", "A"} correct = [{0: "A", 1: "G", 2: "C", 3: "H"}, {0: "Y", 1: "X", 2: "Z", 3: "K"}] - pywhy_graphs.possibly_directed_path(admg, X, Y) + out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct[0] == out[0] assert correct[1] == out[1] @@ -609,7 +609,88 @@ def test_possibly_directed(): {0: "Y", 1: "X", 2: "Z", 3: "K"}, {0: "Y", 1: "X", 2: "Z", 3: "C", 4: "H"}, ] - pywhy_graphs.possibly_directed_path(admg, X, Y) + out = pywhy_graphs.possibly_directed_path(admg, X, Y) + assert correct[0] == out[0] + assert correct[1] == out[1] + assert correct[2] == out[2] + + admg = ADMG() + admg.add_edge("A", "G", admg.directed_edge_name) + admg.add_edge("A", "H", admg.directed_edge_name) + admg.add_edge("K", "G", admg.directed_edge_name) + admg.add_edge("K", "H", admg.directed_edge_name) + + Y = {"G","H"} + X = {"A","K"} + + correct = [{0: 'K', 1: 'G'}, {0: 'K', 1: 'H'}, {0: 'A', 1: 'G'}, {0: 'A', 1: 'H'}] + out = pywhy_graphs.possibly_directed_path(admg, X, Y) + assert correct[0] == out[0] + assert correct[1] == out[1] + assert correct[2] == out[2] + assert correct[3] == out[3] + + admg = ADMG() + admg.add_edge("A", "G", admg.directed_edge_name) + admg.add_edge("G", "C", admg.directed_edge_name) + admg.add_edge("C", "H", admg.directed_edge_name) + admg.add_edge("Z", "C", admg.bidirected_edge_name) + admg.add_edge("Y", "X", admg.directed_edge_name) + admg.add_edge("X", "Z", admg.directed_edge_name) + admg.add_edge("Z", "K", admg.directed_edge_name) + + Y = {"H", "K"} + X = {"Y", "A"} + + correct = [ + {0: "A", 1: "G", 2: "C", 3: "H"}, + {0: "Y", 1: "X", 2: "Z", 3: "K"}, + ] + out = pywhy_graphs.possibly_directed_path(admg, X, Y) + assert correct[0] == out[0] + assert correct[1] == out[1] + + admg = ADMG() + admg.add_edge("A", "G", admg.directed_edge_name) + admg.add_edge("G", "C", admg.directed_edge_name) + admg.add_edge("C", "H", admg.directed_edge_name) + admg.add_edge("Z", "C", admg.bidirected_edge_name) + admg.add_edge("Y", "X", admg.directed_edge_name) + admg.add_edge("X", "Z", admg.directed_edge_name) + admg.add_edge("Z", "K", admg.directed_edge_name) + + Y = {"H", "K"} + X = {"Y", "A"} + + correct = [ + {0: "A", 1: "G", 2: "C", 3: "H"}, + {0: "Y", 1: "X", 2: "Z", 3: "K"}, + {0: "Y", 1: "X", 2: "Z", 3: "C", 4: "H"}, + {0: 'A', 1: 'G', 2: 'C', 3: 'Z', 4: 'K'}, + ] + out = pywhy_graphs.possibly_directed_path(admg, X, Y) + assert correct[0] == out[0] + assert correct[1] == out[1] + assert correct[2] == out[2] + + + admg = PAG() + admg.add_edge("A", "G", admg.directed_edge_name) + admg.add_edge("G", "C", admg.directed_edge_name) + admg.add_edge("C", "H", admg.directed_edge_name) + admg.add_edge("Z", "C", admg.circle_edge_name) + admg.add_edge("C", "Z", admg.circle_edge_name) + admg.add_edge("Y", "X", admg.directed_edge_name) + admg.add_edge("X", "Z", admg.directed_edge_name) + admg.add_edge("Z", "K", admg.directed_edge_name) + + Y = {"H", "K"} + X = {"Y", "A"} + + correct = [[{0: 'Y', 1: 'X', 2: 'Z', 3: 'K'}, {0: 'Y', 1: 'X', 2: 'Z', 3: 'C', 4: 'H'}, {0: 'A', 1: 'G', 2: 'C', 3: 'H'}, {0: 'A', 1: 'G', 2: 'C', 3: 'Z', 4: 'K'}]] + + out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct[0] == out[0] assert correct[1] == out[1] assert correct[2] == out[2] + assert correct[3] == out[3] \ No newline at end of file From 0acd084d68ac133400e39b546d5d4baa6efab79d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 10 Aug 2024 10:25:51 +0000 Subject: [PATCH 11/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pywhy_graphs/algorithms/generic.py | 1 - pywhy_graphs/algorithms/tests/test_generic.py | 20 ++++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index 9df5e3904..3737339a2 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -949,7 +949,6 @@ def possibly_directed_path(G, X: Optional[Set] = None, Y: Optional[Set] = None): temp[1] = elem x_neighbors.append(temp) - path_list = recursively_find_pd_paths(G, X, x_neighbors, Y) return path_list diff --git a/pywhy_graphs/algorithms/tests/test_generic.py b/pywhy_graphs/algorithms/tests/test_generic.py index 56c7d22c2..3ae6c0599 100644 --- a/pywhy_graphs/algorithms/tests/test_generic.py +++ b/pywhy_graphs/algorithms/tests/test_generic.py @@ -620,10 +620,10 @@ def test_possibly_directed(): admg.add_edge("K", "G", admg.directed_edge_name) admg.add_edge("K", "H", admg.directed_edge_name) - Y = {"G","H"} - X = {"A","K"} + Y = {"G", "H"} + X = {"A", "K"} - correct = [{0: 'K', 1: 'G'}, {0: 'K', 1: 'H'}, {0: 'A', 1: 'G'}, {0: 'A', 1: 'H'}] + correct = [{0: "K", 1: "G"}, {0: "K", 1: "H"}, {0: "A", 1: "G"}, {0: "A", 1: "H"}] out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct[0] == out[0] assert correct[1] == out[1] @@ -666,14 +666,13 @@ def test_possibly_directed(): {0: "A", 1: "G", 2: "C", 3: "H"}, {0: "Y", 1: "X", 2: "Z", 3: "K"}, {0: "Y", 1: "X", 2: "Z", 3: "C", 4: "H"}, - {0: 'A', 1: 'G', 2: 'C', 3: 'Z', 4: 'K'}, + {0: "A", 1: "G", 2: "C", 3: "Z", 4: "K"}, ] out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct[0] == out[0] assert correct[1] == out[1] assert correct[2] == out[2] - admg = PAG() admg.add_edge("A", "G", admg.directed_edge_name) admg.add_edge("G", "C", admg.directed_edge_name) @@ -687,10 +686,17 @@ def test_possibly_directed(): Y = {"H", "K"} X = {"Y", "A"} - correct = [[{0: 'Y', 1: 'X', 2: 'Z', 3: 'K'}, {0: 'Y', 1: 'X', 2: 'Z', 3: 'C', 4: 'H'}, {0: 'A', 1: 'G', 2: 'C', 3: 'H'}, {0: 'A', 1: 'G', 2: 'C', 3: 'Z', 4: 'K'}]] + correct = [ + [ + {0: "Y", 1: "X", 2: "Z", 3: "K"}, + {0: "Y", 1: "X", 2: "Z", 3: "C", 4: "H"}, + {0: "A", 1: "G", 2: "C", 3: "H"}, + {0: "A", 1: "G", 2: "C", 3: "Z", 4: "K"}, + ] + ] out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct[0] == out[0] assert correct[1] == out[1] assert correct[2] == out[2] - assert correct[3] == out[3] \ No newline at end of file + assert correct[3] == out[3] From f0ef2795b37fb11a72adc967c82f154e8e4506bf Mon Sep 17 00:00:00 2001 From: Aryan Roy Date: Thu, 15 Aug 2024 07:25:13 +0530 Subject: [PATCH 12/23] Switched to set Signed-off-by: Aryan Roy --- pywhy_graphs/algorithms/generic.py | 42 ++++----- pywhy_graphs/algorithms/tests/test_generic.py | 88 ++++++------------- 2 files changed, 46 insertions(+), 84 deletions(-) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index 3737339a2..d35cc5233 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -873,7 +873,7 @@ def check_back_arrow(G: ADMG, X, Y: set): def get_X_neighbors(G, X: set): - out = [] + out = set() for elem in X: elem_neighbors = set(G.neighbors(elem)) @@ -883,53 +883,52 @@ def get_X_neighbors(G, X: set): if len(elem_neighbors) != 0: for nbh in elem_neighbors: - temp = dict() - temp[0] = elem - temp[1] = nbh - out.append(temp) + temp = (elem,) + temp = temp + (nbh,) + out.add(temp) return out def recursively_find_pd_paths(G, X, paths, Y): counter = 0 - new_paths = [] + new_paths = set() - for i in range(len(paths)): - cur_elem = paths[i][list(paths[i].keys())[-1]] + for elem in paths: + cur_elem = elem[-1] if cur_elem in Y: - new_paths.append(paths[i]) + new_paths.add(elem) continue nbr_temp = G.neighbors(cur_elem) nbr_possible = check_back_arrow(G, cur_elem, nbr_temp) if len(nbr_possible) == 0: - new_paths.append(paths[i].copy()) + new_paths = new_paths + (elem,) possible_end = nbr_possible.intersection(Y) if len(possible_end) != 0: - for elem in possible_end: - temp_path = paths[i].copy() - temp_path[len(temp_path)] = elem - new_paths.append(temp_path) + for nbr in possible_end: + temp_path = elem + temp_path = temp_path + (nbr,) + new_paths.add(temp_path) remaining_nodes = nbr_possible - possible_end remaining_nodes = ( remaining_nodes - - remaining_nodes.intersection(paths[i].values()) + - remaining_nodes.intersection(set(elem)) - remaining_nodes.intersection(X) ) - temp_arr = [] - for elem in remaining_nodes: - temp_paths = paths[i].copy() - temp_paths[len(temp_paths)] = elem - temp_arr.append(temp_paths) + temp_set = set() + for nbr in remaining_nodes: + temp_paths = elem + temp_paths = temp_paths + (nbr,) + temp_set.add(temp_paths) - new_paths.extend(recursively_find_pd_paths(G, X, temp_arr, Y)) + new_paths.update(recursively_find_pd_paths(G, X, temp_set, Y)) return new_paths @@ -950,5 +949,6 @@ def possibly_directed_path(G, X: Optional[Set] = None, Y: Optional[Set] = None): x_neighbors.append(temp) path_list = recursively_find_pd_paths(G, X, x_neighbors, Y) + print(path_list) return path_list diff --git a/pywhy_graphs/algorithms/tests/test_generic.py b/pywhy_graphs/algorithms/tests/test_generic.py index 3ae6c0599..42c2c7fa0 100644 --- a/pywhy_graphs/algorithms/tests/test_generic.py +++ b/pywhy_graphs/algorithms/tests/test_generic.py @@ -509,9 +509,9 @@ def test_possibly_directed(): Y = {"H"} X = {"Y"} - correct = [{0: "Y", 1: "X", 2: "Z", 3: "H"}] + correct = {('Y', 'X', 'Z', 'H')} out = pywhy_graphs.possibly_directed_path(admg, X, Y) - assert correct[0] == out[0] + assert correct == out admg = ADMG() admg.add_edge("A", "X", admg.directed_edge_name) @@ -522,10 +522,9 @@ def test_possibly_directed(): Y = {"H"} X = {"Y", "A"} - correct = [{0: "A", 1: "X", 2: "Z", 3: "H"}, {0: "Y", 1: "X", 2: "Z", 3: "H"}] + correct = {('Y', 'X', 'Z', 'H'), ('A', 'X', 'Z', 'H')} out = pywhy_graphs.possibly_directed_path(admg, X, Y) - assert correct[0] == out[0] - assert correct[1] == out[1] + assert correct == out admg = ADMG() admg.add_edge("X", "A", admg.directed_edge_name) @@ -536,9 +535,9 @@ def test_possibly_directed(): Y = {"H"} X = {"Y", "A"} - correct = [{0: "Y", 1: "X", 2: "Z", 3: "H"}] + correct = {('Y', 'X', 'Z', 'H')} out = pywhy_graphs.possibly_directed_path(admg, X, Y) - assert correct[0] == out[0] + assert correct == out admg = ADMG() admg.add_edge("X", "A", admg.directed_edge_name) @@ -550,9 +549,9 @@ def test_possibly_directed(): Y = {"H", "K"} X = {"Y", "A"} - correct = [{0: "Y", 1: "X", 2: "Z", 3: "H"}] + correct = {('Y', 'X', 'Z', 'H')} out = pywhy_graphs.possibly_directed_path(admg, X, Y) - assert correct[0] == out[0] + assert correct == out admg = ADMG() admg.add_edge("A", "X", admg.directed_edge_name) @@ -564,17 +563,9 @@ def test_possibly_directed(): Y = {"H", "K"} X = {"Y", "A"} - correct = [ - {0: "A", 1: "X", 2: "Z", 3: "H"}, - {0: "A", 1: "X", 2: "Z", 3: "K"}, - {0: "Y", 1: "X", 2: "Z", 3: "H"}, - {0: "Y", 1: "X", 2: "Z", 3: "K"}, - ] + correct = {('Y', 'X', 'Z', 'K'), ('A', 'X', 'Z', 'K'), ('Y', 'X', 'Z', 'H'), ('A', 'X', 'Z', 'H')} out = pywhy_graphs.possibly_directed_path(admg, X, Y) - assert correct[0] == out[0] - assert correct[1] == out[1] - assert correct[2] == out[2] - assert correct[3] == out[3] + assert correct == out admg = ADMG() admg.add_edge("A", "G", admg.directed_edge_name) @@ -587,10 +578,9 @@ def test_possibly_directed(): Y = {"H", "K"} X = {"Y", "A"} - correct = [{0: "A", 1: "G", 2: "C", 3: "H"}, {0: "Y", 1: "X", 2: "Z", 3: "K"}] + correct = {('Y', 'X', 'Z', 'K'), ('A', 'G', 'C', 'H')} out = pywhy_graphs.possibly_directed_path(admg, X, Y) - assert correct[0] == out[0] - assert correct[1] == out[1] + assert correct == out admg = ADMG() admg.add_edge("A", "G", admg.directed_edge_name) @@ -604,15 +594,9 @@ def test_possibly_directed(): Y = {"H", "K"} X = {"Y", "A"} - correct = [ - {0: "A", 1: "G", 2: "C", 3: "H"}, - {0: "Y", 1: "X", 2: "Z", 3: "K"}, - {0: "Y", 1: "X", 2: "Z", 3: "C", 4: "H"}, - ] + correct = {('Y', 'X', 'Z', 'K'), ('Y', 'X', 'Z', 'C', 'H'), ('A', 'G', 'C', 'H')} out = pywhy_graphs.possibly_directed_path(admg, X, Y) - assert correct[0] == out[0] - assert correct[1] == out[1] - assert correct[2] == out[2] + assert correct == out admg = ADMG() admg.add_edge("A", "G", admg.directed_edge_name) @@ -623,12 +607,9 @@ def test_possibly_directed(): Y = {"G", "H"} X = {"A", "K"} - correct = [{0: "K", 1: "G"}, {0: "K", 1: "H"}, {0: "A", 1: "G"}, {0: "A", 1: "H"}] + correct = {('K', 'H'), ('K', 'G'), ('A', 'G'), ('A', 'H')} out = pywhy_graphs.possibly_directed_path(admg, X, Y) - assert correct[0] == out[0] - assert correct[1] == out[1] - assert correct[2] == out[2] - assert correct[3] == out[3] + assert correct == out admg = ADMG() admg.add_edge("A", "G", admg.directed_edge_name) @@ -642,13 +623,12 @@ def test_possibly_directed(): Y = {"H", "K"} X = {"Y", "A"} - correct = [ - {0: "A", 1: "G", 2: "C", 3: "H"}, - {0: "Y", 1: "X", 2: "Z", 3: "K"}, - ] + correct = { + ("A","G","C","H"), + ("Y","X","Z","K"), + } out = pywhy_graphs.possibly_directed_path(admg, X, Y) - assert correct[0] == out[0] - assert correct[1] == out[1] + assert correct == out admg = ADMG() admg.add_edge("A", "G", admg.directed_edge_name) @@ -662,16 +642,9 @@ def test_possibly_directed(): Y = {"H", "K"} X = {"Y", "A"} - correct = [ - {0: "A", 1: "G", 2: "C", 3: "H"}, - {0: "Y", 1: "X", 2: "Z", 3: "K"}, - {0: "Y", 1: "X", 2: "Z", 3: "C", 4: "H"}, - {0: "A", 1: "G", 2: "C", 3: "Z", 4: "K"}, - ] + correct = {('Y', 'X', 'Z', 'K'), ('A', 'G', 'C', 'H')} out = pywhy_graphs.possibly_directed_path(admg, X, Y) - assert correct[0] == out[0] - assert correct[1] == out[1] - assert correct[2] == out[2] + assert correct == out admg = PAG() admg.add_edge("A", "G", admg.directed_edge_name) @@ -686,17 +659,6 @@ def test_possibly_directed(): Y = {"H", "K"} X = {"Y", "A"} - correct = [ - [ - {0: "Y", 1: "X", 2: "Z", 3: "K"}, - {0: "Y", 1: "X", 2: "Z", 3: "C", 4: "H"}, - {0: "A", 1: "G", 2: "C", 3: "H"}, - {0: "A", 1: "G", 2: "C", 3: "Z", 4: "K"}, - ] - ] - + correct = {('Y', 'X', 'Z', 'K'), ('Y', 'X', 'Z', 'C', 'H'), ('A', 'G', 'C', 'H'), ('A', 'G', 'C', 'Z', 'K')} out = pywhy_graphs.possibly_directed_path(admg, X, Y) - assert correct[0] == out[0] - assert correct[1] == out[1] - assert correct[2] == out[2] - assert correct[3] == out[3] + assert correct == out From 7296014260ac843179fbf6711ed89fb83559dbcd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 15 Aug 2024 01:55:32 +0000 Subject: [PATCH 13/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pywhy_graphs/algorithms/tests/test_generic.py | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/pywhy_graphs/algorithms/tests/test_generic.py b/pywhy_graphs/algorithms/tests/test_generic.py index 42c2c7fa0..ca91e7b1c 100644 --- a/pywhy_graphs/algorithms/tests/test_generic.py +++ b/pywhy_graphs/algorithms/tests/test_generic.py @@ -509,7 +509,7 @@ def test_possibly_directed(): Y = {"H"} X = {"Y"} - correct = {('Y', 'X', 'Z', 'H')} + correct = {("Y", "X", "Z", "H")} out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct == out @@ -522,7 +522,7 @@ def test_possibly_directed(): Y = {"H"} X = {"Y", "A"} - correct = {('Y', 'X', 'Z', 'H'), ('A', 'X', 'Z', 'H')} + correct = {("Y", "X", "Z", "H"), ("A", "X", "Z", "H")} out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct == out @@ -535,7 +535,7 @@ def test_possibly_directed(): Y = {"H"} X = {"Y", "A"} - correct = {('Y', 'X', 'Z', 'H')} + correct = {("Y", "X", "Z", "H")} out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct == out @@ -549,7 +549,7 @@ def test_possibly_directed(): Y = {"H", "K"} X = {"Y", "A"} - correct = {('Y', 'X', 'Z', 'H')} + correct = {("Y", "X", "Z", "H")} out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct == out @@ -563,7 +563,12 @@ def test_possibly_directed(): Y = {"H", "K"} X = {"Y", "A"} - correct = {('Y', 'X', 'Z', 'K'), ('A', 'X', 'Z', 'K'), ('Y', 'X', 'Z', 'H'), ('A', 'X', 'Z', 'H')} + correct = { + ("Y", "X", "Z", "K"), + ("A", "X", "Z", "K"), + ("Y", "X", "Z", "H"), + ("A", "X", "Z", "H"), + } out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct == out @@ -578,7 +583,7 @@ def test_possibly_directed(): Y = {"H", "K"} X = {"Y", "A"} - correct = {('Y', 'X', 'Z', 'K'), ('A', 'G', 'C', 'H')} + correct = {("Y", "X", "Z", "K"), ("A", "G", "C", "H")} out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct == out @@ -594,7 +599,7 @@ def test_possibly_directed(): Y = {"H", "K"} X = {"Y", "A"} - correct = {('Y', 'X', 'Z', 'K'), ('Y', 'X', 'Z', 'C', 'H'), ('A', 'G', 'C', 'H')} + correct = {("Y", "X", "Z", "K"), ("Y", "X", "Z", "C", "H"), ("A", "G", "C", "H")} out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct == out @@ -607,7 +612,7 @@ def test_possibly_directed(): Y = {"G", "H"} X = {"A", "K"} - correct = {('K', 'H'), ('K', 'G'), ('A', 'G'), ('A', 'H')} + correct = {("K", "H"), ("K", "G"), ("A", "G"), ("A", "H")} out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct == out @@ -624,8 +629,8 @@ def test_possibly_directed(): X = {"Y", "A"} correct = { - ("A","G","C","H"), - ("Y","X","Z","K"), + ("A", "G", "C", "H"), + ("Y", "X", "Z", "K"), } out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct == out @@ -642,7 +647,7 @@ def test_possibly_directed(): Y = {"H", "K"} X = {"Y", "A"} - correct = {('Y', 'X', 'Z', 'K'), ('A', 'G', 'C', 'H')} + correct = {("Y", "X", "Z", "K"), ("A", "G", "C", "H")} out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct == out @@ -659,6 +664,11 @@ def test_possibly_directed(): Y = {"H", "K"} X = {"Y", "A"} - correct = {('Y', 'X', 'Z', 'K'), ('Y', 'X', 'Z', 'C', 'H'), ('A', 'G', 'C', 'H'), ('A', 'G', 'C', 'Z', 'K')} + correct = { + ("Y", "X", "Z", "K"), + ("Y", "X", "Z", "C", "H"), + ("A", "G", "C", "H"), + ("A", "G", "C", "Z", "K"), + } out = pywhy_graphs.possibly_directed_path(admg, X, Y) assert correct == out From 7f01c98335a38d2b62980fd4058207698308ee9b Mon Sep 17 00:00:00 2001 From: Aryan Roy Date: Thu, 15 Aug 2024 07:30:07 +0530 Subject: [PATCH 14/23] Made some functions private Signed-off-by: Aryan Roy --- pywhy_graphs/algorithms/generic.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index d35cc5233..60771bdf3 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -858,7 +858,7 @@ def all_vstructures(G: nx.DiGraph, as_edges: bool = False): return vstructs -def check_back_arrow(G: ADMG, X, Y: set): +def _check_back_arrow(G: ADMG, X, Y: set): out = set() @@ -871,13 +871,13 @@ def check_back_arrow(G: ADMG, X, Y: set): return out -def get_X_neighbors(G, X: set): +def _get_X_neighbors(G, X: set): out = set() for elem in X: elem_neighbors = set(G.neighbors(elem)) - elem_possible_neighbors = check_back_arrow(G, elem, elem_neighbors) + elem_possible_neighbors = _check_back_arrow(G, elem, elem_neighbors) to_remove = X.intersection(elem_possible_neighbors) elem_neighbors = elem_possible_neighbors - to_remove @@ -889,7 +889,7 @@ def get_X_neighbors(G, X: set): return out -def recursively_find_pd_paths(G, X, paths, Y): +def _recursively_find_pd_paths(G, X, paths, Y): counter = 0 new_paths = set() @@ -902,7 +902,7 @@ def recursively_find_pd_paths(G, X, paths, Y): continue nbr_temp = G.neighbors(cur_elem) - nbr_possible = check_back_arrow(G, cur_elem, nbr_temp) + nbr_possible = _check_back_arrow(G, cur_elem, nbr_temp) if len(nbr_possible) == 0: new_paths = new_paths + (elem,) @@ -928,7 +928,7 @@ def recursively_find_pd_paths(G, X, paths, Y): temp_paths = temp_paths + (nbr,) temp_set.add(temp_paths) - new_paths.update(recursively_find_pd_paths(G, X, temp_set, Y)) + new_paths.update(_recursively_find_pd_paths(G, X, temp_set, Y)) return new_paths @@ -936,10 +936,10 @@ def recursively_find_pd_paths(G, X, paths, Y): def possibly_directed_path(G, X: Optional[Set] = None, Y: Optional[Set] = None): if isinstance(X, set): - x_neighbors = get_X_neighbors(G, X) + x_neighbors = _get_X_neighbors(G, X) else: nbr_temp = G.neighbors(X) - nbr_possible = check_back_arrow(nbr_temp) + nbr_possible = _check_back_arrow(nbr_temp) x_neighbors = [] for elem in nbr_possible: @@ -948,7 +948,7 @@ def possibly_directed_path(G, X: Optional[Set] = None, Y: Optional[Set] = None): temp[1] = elem x_neighbors.append(temp) - path_list = recursively_find_pd_paths(G, X, x_neighbors, Y) + path_list = _recursively_find_pd_paths(G, X, x_neighbors, Y) print(path_list) return path_list From 6ad4765ebad0bbce977b53e5275a3a2330fe883b Mon Sep 17 00:00:00 2001 From: Aryan Roy Date: Thu, 15 Aug 2024 07:39:06 +0530 Subject: [PATCH 15/23] Added docstring Signed-off-by: Aryan Roy --- pywhy_graphs/algorithms/generic.py | 64 ++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index 60771bdf3..1808948a8 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -859,7 +859,23 @@ def all_vstructures(G: nx.DiGraph, as_edges: bool = False): def _check_back_arrow(G: ADMG, X, Y: set): + """Retrieve all the neigbors of X that do not have + an arrow pointing back to it. + Parameters + ---------- + G : DiGraph + A directed graph. + X : Node + Y : Set + A set of neigbors of X. + + Returns + ------- + out : set + A set of all the neighbors of X that do not have an arrow pointing + back to it. + """ out = set() for elem in Y: @@ -872,6 +888,20 @@ def _check_back_arrow(G: ADMG, X, Y: set): def _get_X_neighbors(G, X: set): + """Retrieve all the neigbors of X when X has more than one element. + + Parameters + ---------- + G : DiGraph + A directed graph. + X : Set + + Returns + ------- + out : set + A set of all the neighbors of X. + """ + out = set() @@ -890,6 +920,24 @@ def _get_X_neighbors(G, X: set): def _recursively_find_pd_paths(G, X, paths, Y): + """Recursively finds all the possibly directed paths for a given + graph. + + Parameters + ---------- + G : DiGraph + A directed graph. + X : Set + Source. + Y : Set + Destination + + Returns + ------- + out : set + A set of all the possibly directed paths. + """ + counter = 0 new_paths = set() @@ -934,6 +982,22 @@ def _recursively_find_pd_paths(G, X, paths, Y): def possibly_directed_path(G, X: Optional[Set] = None, Y: Optional[Set] = None): + """Find all the possibly directed paths in a graph. + + Parameters + ---------- + G : DiGraph + A directed graph. + X : Set + Source. + Y : Set + Destination + + Returns + ------- + out : set + A set of all the possibly directed paths. + """ if isinstance(X, set): x_neighbors = _get_X_neighbors(G, X) From b15843b231df2c80c2b695acda2f2e044c38db2e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 15 Aug 2024 02:10:01 +0000 Subject: [PATCH 16/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pywhy_graphs/algorithms/generic.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index 1808948a8..42089eed1 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -873,7 +873,7 @@ def _check_back_arrow(G: ADMG, X, Y: set): Returns ------- out : set - A set of all the neighbors of X that do not have an arrow pointing + A set of all the neighbors of X that do not have an arrow pointing back to it. """ out = set() @@ -902,7 +902,6 @@ def _get_X_neighbors(G, X: set): A set of all the neighbors of X. """ - out = set() for elem in X: @@ -938,7 +937,6 @@ def _recursively_find_pd_paths(G, X, paths, Y): A set of all the possibly directed paths. """ - counter = 0 new_paths = set() From ae6ae4e0bd756cb78da62302e91ae5204c4b8547 Mon Sep 17 00:00:00 2001 From: Aryan Roy Date: Thu, 15 Aug 2024 07:49:32 +0530 Subject: [PATCH 17/23] added changelog Signed-off-by: Aryan Roy --- doc/whats_new/v0.2.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/whats_new/v0.2.rst b/doc/whats_new/v0.2.rst index aebb2d19e..92fe1043d 100644 --- a/doc/whats_new/v0.2.rst +++ b/doc/whats_new/v0.2.rst @@ -33,6 +33,7 @@ Changelog - |Feature| Implement functions for converting between a DAG and PDAG and CPDAG for generating consistent extensions of a CPDAG for example. These functions are :func:`pywhy_graphs.algorithms.pdag_to_cpdag`, :func:`pywhy_graphs.algorithms.pdag_to_dag` and :func:`pywhy_graphs.algorithms.dag_to_cpdag`, by `Adam Li`_ (:pr:`102`) - |API| Remove poetry based setup, by `Adam Li`_ (:pr:`110`) - |Feature| Implement and test function to validate PAG, by `Aryan Roy`_ (:pr:`100`) +- |Feature| Implement and test function to find all the proper possibly directed paths, by `Aryan Roy`_ (:pr:`112`) Code and Documentation Contributors ----------------------------------- From 6ebbc4a426eaa161fcb7816b11ac4b891c985896 Mon Sep 17 00:00:00 2001 From: Aryan Roy Date: Fri, 16 Aug 2024 11:43:49 +0530 Subject: [PATCH 18/23] changed docstring Signed-off-by: Aryan Roy --- pywhy_graphs/algorithms/generic.py | 6 ++--- pywhy_graphs/algorithms/tests/test_generic.py | 24 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index 42089eed1..86716e141 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -19,7 +19,7 @@ "dag_to_mag", "is_maximal", "all_vstructures", - "possibly_directed_path", + "proper_possibly_directed_path", ] @@ -979,7 +979,7 @@ def _recursively_find_pd_paths(G, X, paths, Y): return new_paths -def possibly_directed_path(G, X: Optional[Set] = None, Y: Optional[Set] = None): +def proper_possibly_directed_path(G, X: Optional[Set] = None, Y: Optional[Set] = None): """Find all the possibly directed paths in a graph. Parameters @@ -994,7 +994,7 @@ def possibly_directed_path(G, X: Optional[Set] = None, Y: Optional[Set] = None): Returns ------- out : set - A set of all the possibly directed paths. + A set of all the proper possibly directed paths. """ if isinstance(X, set): diff --git a/pywhy_graphs/algorithms/tests/test_generic.py b/pywhy_graphs/algorithms/tests/test_generic.py index ca91e7b1c..fc08adfc0 100644 --- a/pywhy_graphs/algorithms/tests/test_generic.py +++ b/pywhy_graphs/algorithms/tests/test_generic.py @@ -498,7 +498,7 @@ def test_all_vstructures(): assert len(v_structs_tuples) == 0 -def test_possibly_directed(): +def test_proper_possibly_directed(): # X <- Y <-> Z <-> H; Z -> X admg = ADMG() @@ -510,7 +510,7 @@ def test_possibly_directed(): X = {"Y"} correct = {("Y", "X", "Z", "H")} - out = pywhy_graphs.possibly_directed_path(admg, X, Y) + out = pywhy_graphs.proper_possibly_directed_path(admg, X, Y) assert correct == out admg = ADMG() @@ -523,7 +523,7 @@ def test_possibly_directed(): X = {"Y", "A"} correct = {("Y", "X", "Z", "H"), ("A", "X", "Z", "H")} - out = pywhy_graphs.possibly_directed_path(admg, X, Y) + out = pywhy_graphs.proper_possibly_directed_path(admg, X, Y) assert correct == out admg = ADMG() @@ -536,7 +536,7 @@ def test_possibly_directed(): X = {"Y", "A"} correct = {("Y", "X", "Z", "H")} - out = pywhy_graphs.possibly_directed_path(admg, X, Y) + out = pywhy_graphs.proper_possibly_directed_path(admg, X, Y) assert correct == out admg = ADMG() @@ -550,7 +550,7 @@ def test_possibly_directed(): X = {"Y", "A"} correct = {("Y", "X", "Z", "H")} - out = pywhy_graphs.possibly_directed_path(admg, X, Y) + out = pywhy_graphs.proper_possibly_directed_path(admg, X, Y) assert correct == out admg = ADMG() @@ -569,7 +569,7 @@ def test_possibly_directed(): ("Y", "X", "Z", "H"), ("A", "X", "Z", "H"), } - out = pywhy_graphs.possibly_directed_path(admg, X, Y) + out = pywhy_graphs.proper_possibly_directed_path(admg, X, Y) assert correct == out admg = ADMG() @@ -584,7 +584,7 @@ def test_possibly_directed(): X = {"Y", "A"} correct = {("Y", "X", "Z", "K"), ("A", "G", "C", "H")} - out = pywhy_graphs.possibly_directed_path(admg, X, Y) + out = pywhy_graphs.proper_possibly_directed_path(admg, X, Y) assert correct == out admg = ADMG() @@ -600,7 +600,7 @@ def test_possibly_directed(): X = {"Y", "A"} correct = {("Y", "X", "Z", "K"), ("Y", "X", "Z", "C", "H"), ("A", "G", "C", "H")} - out = pywhy_graphs.possibly_directed_path(admg, X, Y) + out = pywhy_graphs.proper_possibly_directed_path(admg, X, Y) assert correct == out admg = ADMG() @@ -613,7 +613,7 @@ def test_possibly_directed(): X = {"A", "K"} correct = {("K", "H"), ("K", "G"), ("A", "G"), ("A", "H")} - out = pywhy_graphs.possibly_directed_path(admg, X, Y) + out = pywhy_graphs.proper_possibly_directed_path(admg, X, Y) assert correct == out admg = ADMG() @@ -632,7 +632,7 @@ def test_possibly_directed(): ("A", "G", "C", "H"), ("Y", "X", "Z", "K"), } - out = pywhy_graphs.possibly_directed_path(admg, X, Y) + out = pywhy_graphs.proper_possibly_directed_path(admg, X, Y) assert correct == out admg = ADMG() @@ -648,7 +648,7 @@ def test_possibly_directed(): X = {"Y", "A"} correct = {("Y", "X", "Z", "K"), ("A", "G", "C", "H")} - out = pywhy_graphs.possibly_directed_path(admg, X, Y) + out = pywhy_graphs.proper_possibly_directed_path(admg, X, Y) assert correct == out admg = PAG() @@ -670,5 +670,5 @@ def test_possibly_directed(): ("A", "G", "C", "H"), ("A", "G", "C", "Z", "K"), } - out = pywhy_graphs.possibly_directed_path(admg, X, Y) + out = pywhy_graphs.proper_possibly_directed_path(admg, X, Y) assert correct == out From 7bc6f75627fae801ae730a7b5bcf2e600c3e06f0 Mon Sep 17 00:00:00 2001 From: Aryan Roy <50577809+aryan26roy@users.noreply.github.com> Date: Tue, 20 Aug 2024 20:23:57 +0530 Subject: [PATCH 19/23] Update pywhy_graphs/algorithms/generic.py Co-authored-by: Adam Li Signed-off-by: Aryan Roy <50577809+aryan26roy@users.noreply.github.com> --- pywhy_graphs/algorithms/generic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index 86716e141..6222a1292 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -887,7 +887,7 @@ def _check_back_arrow(G: ADMG, X, Y: set): return out -def _get_X_neighbors(G, X: set): +def _get_neighbors_of_set(G, X: set): """Retrieve all the neigbors of X when X has more than one element. Parameters From 1828221db88cd45ed46d82aaaf5a900007acc1f0 Mon Sep 17 00:00:00 2001 From: Aryan Roy Date: Fri, 23 Aug 2024 20:44:57 +0530 Subject: [PATCH 20/23] incorporated review suggestions Signed-off-by: Aryan Roy --- pywhy_graphs/algorithms/generic.py | 30 +++++++++++++++++-- pywhy_graphs/algorithms/tests/test_generic.py | 23 +++++++------- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index 6222a1292..9a13fee2b 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -979,8 +979,10 @@ def _recursively_find_pd_paths(G, X, paths, Y): return new_paths -def proper_possibly_directed_path(G, X: Optional[Set] = None, Y: Optional[Set] = None): - """Find all the possibly directed paths in a graph. +def proper_possibly_directed_path(G, X: Optional[Set], Y: Optional[Set]): + """Find all the proper possibly directed paths in a graph. A proper possibly directed + path from X to Y is a set of edges with just the first node in X and none of the edges + with an arrow pointing back to X. Parameters ---------- @@ -995,10 +997,32 @@ def proper_possibly_directed_path(G, X: Optional[Set] = None, Y: Optional[Set] = ------- out : set A set of all the proper possibly directed paths. + + Examples + -------- + The function generates a set of tuples containing all the valid + proper possibly directed paths from X to Y. + + >>> import pywhy_graphs + >>> from pywhy_graphs import PAG + >>> pag = PAG() + >>> pag.add_edge("A", "G", pag.directed_edge_name) + >>> pag.add_edge("G", "C", pag.directed_edge_name) + >>> pag.add_edge("C", "H", pag.directed_edge_name) + >>> pag.add_edge("Z", "C", pag.circle_edge_name) + >>> pag.add_edge("C", "Z", pag.circle_edge_name) + >>> pag.add_edge("Y", "X", pag.directed_edge_name) + >>> pag.add_edge("X", "Z", pag.directed_edge_name) + >>> pag.add_edge("Z", "K", pag.directed_edge_name) + >>> Y = {"H", "K"} + >>> X = {"Y", "A"} + >>> pywhy_graphs.proper_possibly_directed_path(pag, X, Y) + {('A', 'G', 'C', 'H'), ('Y', 'X', 'Z', 'C', 'H'), ('Y', 'X', 'Z', 'K'), ('A', 'G', 'C', 'Z', 'K')} + """ if isinstance(X, set): - x_neighbors = _get_X_neighbors(G, X) + x_neighbors = _get_neighbors_of_set(G, X) else: nbr_temp = G.neighbors(X) nbr_possible = _check_back_arrow(nbr_temp) diff --git a/pywhy_graphs/algorithms/tests/test_generic.py b/pywhy_graphs/algorithms/tests/test_generic.py index fc08adfc0..e3c7b2876 100644 --- a/pywhy_graphs/algorithms/tests/test_generic.py +++ b/pywhy_graphs/algorithms/tests/test_generic.py @@ -651,15 +651,18 @@ def test_proper_possibly_directed(): out = pywhy_graphs.proper_possibly_directed_path(admg, X, Y) assert correct == out - admg = PAG() - admg.add_edge("A", "G", admg.directed_edge_name) - admg.add_edge("G", "C", admg.directed_edge_name) - admg.add_edge("C", "H", admg.directed_edge_name) - admg.add_edge("Z", "C", admg.circle_edge_name) - admg.add_edge("C", "Z", admg.circle_edge_name) - admg.add_edge("Y", "X", admg.directed_edge_name) - admg.add_edge("X", "Z", admg.directed_edge_name) - admg.add_edge("Z", "K", admg.directed_edge_name) + +def test_ppdp_PAG(): + + pag = PAG() + pag.add_edge("A", "G", pag.directed_edge_name) + pag.add_edge("G", "C", pag.directed_edge_name) + pag.add_edge("C", "H", pag.directed_edge_name) + pag.add_edge("Z", "C", pag.circle_edge_name) + pag.add_edge("C", "Z", pag.circle_edge_name) + pag.add_edge("Y", "X", pag.directed_edge_name) + pag.add_edge("X", "Z", pag.directed_edge_name) + pag.add_edge("Z", "K", pag.directed_edge_name) Y = {"H", "K"} X = {"Y", "A"} @@ -670,5 +673,5 @@ def test_proper_possibly_directed(): ("A", "G", "C", "H"), ("A", "G", "C", "Z", "K"), } - out = pywhy_graphs.proper_possibly_directed_path(admg, X, Y) + out = pywhy_graphs.proper_possibly_directed_path(pag, X, Y) assert correct == out From 7a259313442c68ea5321dc983bed99f26a353fa0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 23 Aug 2024 15:15:14 +0000 Subject: [PATCH 21/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pywhy_graphs/algorithms/generic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index 9a13fee2b..07e836ac2 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -1018,7 +1018,7 @@ def proper_possibly_directed_path(G, X: Optional[Set], Y: Optional[Set]): >>> X = {"Y", "A"} >>> pywhy_graphs.proper_possibly_directed_path(pag, X, Y) {('A', 'G', 'C', 'H'), ('Y', 'X', 'Z', 'C', 'H'), ('Y', 'X', 'Z', 'K'), ('A', 'G', 'C', 'Z', 'K')} - + """ if isinstance(X, set): From 76ca2f734bb85c72a20e465026c059ea86837580 Mon Sep 17 00:00:00 2001 From: Aryan Roy Date: Fri, 23 Aug 2024 20:46:38 +0530 Subject: [PATCH 22/23] improved docstring Signed-off-by: Aryan Roy --- pywhy_graphs/algorithms/generic.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index 9a13fee2b..78eadb805 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -890,6 +890,8 @@ def _check_back_arrow(G: ADMG, X, Y: set): def _get_neighbors_of_set(G, X: set): """Retrieve all the neigbors of X when X has more than one element. + Note that if X is not a set, graph.neighbors(X) is sufficient. + Parameters ---------- G : DiGraph @@ -1018,7 +1020,7 @@ def proper_possibly_directed_path(G, X: Optional[Set], Y: Optional[Set]): >>> X = {"Y", "A"} >>> pywhy_graphs.proper_possibly_directed_path(pag, X, Y) {('A', 'G', 'C', 'H'), ('Y', 'X', 'Z', 'C', 'H'), ('Y', 'X', 'Z', 'K'), ('A', 'G', 'C', 'Z', 'K')} - + """ if isinstance(X, set): From 440c8bb47b12dcc90973f0094f83411906e1e2a1 Mon Sep 17 00:00:00 2001 From: Aryan Roy Date: Fri, 23 Aug 2024 21:18:48 +0530 Subject: [PATCH 23/23] cleanup Signed-off-by: Aryan Roy --- pywhy_graphs/algorithms/generic.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pywhy_graphs/algorithms/generic.py b/pywhy_graphs/algorithms/generic.py index 78eadb805..5166c057c 100644 --- a/pywhy_graphs/algorithms/generic.py +++ b/pywhy_graphs/algorithms/generic.py @@ -930,6 +930,8 @@ def _recursively_find_pd_paths(G, X, paths, Y): A directed graph. X : Set Source. + paths : Set + Set of initial paths from X. Y : Set Destination @@ -1037,6 +1039,5 @@ def proper_possibly_directed_path(G, X: Optional[Set], Y: Optional[Set]): x_neighbors.append(temp) path_list = _recursively_find_pd_paths(G, X, x_neighbors, Y) - print(path_list) return path_list