comparison env/lib/python3.9/site-packages/networkx/algorithms/tests/test_lowest_common_ancestors.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 import pytest
2 from itertools import chain, combinations, product
3
4 import networkx as nx
5
6 tree_all_pairs_lca = nx.tree_all_pairs_lowest_common_ancestor
7 all_pairs_lca = nx.all_pairs_lowest_common_ancestor
8
9
10 def get_pair(dictionary, n1, n2):
11 if (n1, n2) in dictionary:
12 return dictionary[n1, n2]
13 else:
14 return dictionary[n2, n1]
15
16
17 class TestTreeLCA:
18 @classmethod
19 def setup_class(cls):
20 cls.DG = nx.DiGraph()
21 edges = [(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), (2, 6)]
22 cls.DG.add_edges_from(edges)
23 cls.ans = dict(tree_all_pairs_lca(cls.DG, 0))
24 gold = {(n, n): n for n in cls.DG}
25 gold.update({(0, i): 0 for i in range(1, 7)})
26 gold.update(
27 {
28 (1, 2): 0,
29 (1, 3): 1,
30 (1, 4): 1,
31 (1, 5): 0,
32 (1, 6): 0,
33 (2, 3): 0,
34 (2, 4): 0,
35 (2, 5): 2,
36 (2, 6): 2,
37 (3, 4): 1,
38 (3, 5): 0,
39 (3, 6): 0,
40 (4, 5): 0,
41 (4, 6): 0,
42 (5, 6): 2,
43 }
44 )
45
46 cls.gold = gold
47
48 @staticmethod
49 def assert_has_same_pairs(d1, d2):
50 for (a, b) in ((min(pair), max(pair)) for pair in chain(d1, d2)):
51 assert get_pair(d1, a, b) == get_pair(d2, a, b)
52
53 def test_tree_all_pairs_lowest_common_ancestor1(self):
54 """Specifying the root is optional."""
55 assert dict(tree_all_pairs_lca(self.DG)) == self.ans
56
57 def test_tree_all_pairs_lowest_common_ancestor2(self):
58 """Specifying only some pairs gives only those pairs."""
59 test_pairs = [(0, 1), (0, 1), (1, 0)]
60 ans = dict(tree_all_pairs_lca(self.DG, 0, test_pairs))
61 assert (0, 1) in ans and (1, 0) in ans
62 assert len(ans) == 2
63
64 def test_tree_all_pairs_lowest_common_ancestor3(self):
65 """Specifying no pairs same as specifying all."""
66 all_pairs = chain(combinations(self.DG, 2), ((node, node) for node in self.DG))
67
68 ans = dict(tree_all_pairs_lca(self.DG, 0, all_pairs))
69 self.assert_has_same_pairs(ans, self.ans)
70
71 def test_tree_all_pairs_lowest_common_ancestor4(self):
72 """Gives the right answer."""
73 ans = dict(tree_all_pairs_lca(self.DG))
74 self.assert_has_same_pairs(self.gold, ans)
75
76 def test_tree_all_pairs_lowest_common_ancestor5(self):
77 """Handles invalid input correctly."""
78 empty_digraph = tree_all_pairs_lca(nx.DiGraph())
79 pytest.raises(nx.NetworkXPointlessConcept, list, empty_digraph)
80
81 bad_pairs_digraph = tree_all_pairs_lca(self.DG, pairs=[(-1, -2)])
82 pytest.raises(nx.NodeNotFound, list, bad_pairs_digraph)
83
84 def test_tree_all_pairs_lowest_common_ancestor6(self):
85 """Works on subtrees."""
86 ans = dict(tree_all_pairs_lca(self.DG, 1))
87 gold = {
88 pair: lca
89 for (pair, lca) in self.gold.items()
90 if all(n in (1, 3, 4) for n in pair)
91 }
92 self.assert_has_same_pairs(gold, ans)
93
94 def test_tree_all_pairs_lowest_common_ancestor7(self):
95 """Works on disconnected nodes."""
96 G = nx.DiGraph()
97 G.add_node(1)
98 assert {(1, 1): 1} == dict(tree_all_pairs_lca(G))
99
100 G.add_node(0)
101 assert {(1, 1): 1} == dict(tree_all_pairs_lca(G, 1))
102 assert {(0, 0): 0} == dict(tree_all_pairs_lca(G, 0))
103
104 pytest.raises(nx.NetworkXError, list, tree_all_pairs_lca(G))
105
106 def test_tree_all_pairs_lowest_common_ancestor8(self):
107 """Raises right errors if not a tree."""
108 # Cycle
109 G = nx.DiGraph([(1, 2), (2, 1)])
110 pytest.raises(nx.NetworkXError, list, tree_all_pairs_lca(G))
111 # DAG
112 G = nx.DiGraph([(0, 2), (1, 2)])
113 pytest.raises(nx.NetworkXError, list, tree_all_pairs_lca(G))
114
115 def test_tree_all_pairs_lowest_common_ancestor9(self):
116 """Test that pairs works correctly as a generator."""
117 pairs = iter([(0, 1), (0, 1), (1, 0)])
118 some_pairs = dict(tree_all_pairs_lca(self.DG, 0, pairs))
119 assert (0, 1) in some_pairs and (1, 0) in some_pairs
120 assert len(some_pairs) == 2
121
122 def test_tree_all_pairs_lowest_common_ancestor10(self):
123 """Test that pairs not in the graph raises error."""
124 lca = tree_all_pairs_lca(self.DG, 0, [(-1, -1)])
125 pytest.raises(nx.NodeNotFound, list, lca)
126
127 def test_tree_all_pairs_lowest_common_ancestor11(self):
128 """Test that None as a node in the graph raises an error."""
129 G = nx.DiGraph([(None, 3)])
130 pytest.raises(nx.NetworkXError, list, tree_all_pairs_lca(G))
131 pytest.raises(
132 nx.NodeNotFound, list, tree_all_pairs_lca(self.DG, pairs=G.edges())
133 )
134
135 def test_tree_all_pairs_lowest_common_ancestor12(self):
136 """Test that tree routine bails on DAGs."""
137 G = nx.DiGraph([(3, 4), (5, 4)])
138 pytest.raises(nx.NetworkXError, list, tree_all_pairs_lca(G))
139
140 def test_not_implemented_for(self):
141 NNI = nx.NetworkXNotImplemented
142 G = nx.Graph([(0, 1)])
143 pytest.raises(NNI, tree_all_pairs_lca, G)
144 pytest.raises(NNI, all_pairs_lca, G)
145 pytest.raises(NNI, nx.lowest_common_ancestor, G, 0, 1)
146 G = nx.MultiGraph([(0, 1)])
147 pytest.raises(NNI, tree_all_pairs_lca, G)
148 pytest.raises(NNI, all_pairs_lca, G)
149 pytest.raises(NNI, nx.lowest_common_ancestor, G, 0, 1)
150 G = nx.MultiDiGraph([(0, 1)])
151 pytest.raises(NNI, tree_all_pairs_lca, G)
152 pytest.raises(NNI, all_pairs_lca, G)
153 pytest.raises(NNI, nx.lowest_common_ancestor, G, 0, 1)
154
155 def test_tree_all_pairs_lowest_common_ancestor13(self):
156 """Test that it works on non-empty trees with no LCAs."""
157 G = nx.DiGraph()
158 G.add_node(3)
159 ans = list(tree_all_pairs_lca(G))
160 assert ans == [((3, 3), 3)]
161
162
163 class TestDAGLCA:
164 @classmethod
165 def setup_class(cls):
166 cls.DG = nx.DiGraph()
167 nx.add_path(cls.DG, (0, 1, 2, 3))
168 nx.add_path(cls.DG, (0, 4, 3))
169 nx.add_path(cls.DG, (0, 5, 6, 8, 3))
170 nx.add_path(cls.DG, (5, 7, 8))
171 cls.DG.add_edge(6, 2)
172 cls.DG.add_edge(7, 2)
173
174 cls.root_distance = nx.shortest_path_length(cls.DG, source=0)
175
176 cls.gold = {
177 (1, 1): 1,
178 (1, 2): 1,
179 (1, 3): 1,
180 (1, 4): 0,
181 (1, 5): 0,
182 (1, 6): 0,
183 (1, 7): 0,
184 (1, 8): 0,
185 (2, 2): 2,
186 (2, 3): 2,
187 (2, 4): 0,
188 (2, 5): 5,
189 (2, 6): 6,
190 (2, 7): 7,
191 (2, 8): 7,
192 (3, 3): 8,
193 (3, 4): 4,
194 (3, 5): 5,
195 (3, 6): 6,
196 (3, 7): 7,
197 (3, 8): 8,
198 (4, 4): 4,
199 (4, 5): 0,
200 (4, 6): 0,
201 (4, 7): 0,
202 (4, 8): 0,
203 (5, 5): 5,
204 (5, 6): 5,
205 (5, 7): 5,
206 (5, 8): 5,
207 (6, 6): 6,
208 (6, 7): 5,
209 (6, 8): 6,
210 (7, 7): 7,
211 (7, 8): 7,
212 (8, 8): 8,
213 }
214 cls.gold.update(((0, n), 0) for n in cls.DG)
215
216 def assert_lca_dicts_same(self, d1, d2, G=None):
217 """Checks if d1 and d2 contain the same pairs and
218 have a node at the same distance from root for each.
219 If G is None use self.DG."""
220 if G is None:
221 G = self.DG
222 root_distance = self.root_distance
223 else:
224 roots = [n for n, deg in G.in_degree if deg == 0]
225 assert len(roots) == 1
226 root_distance = nx.shortest_path_length(G, source=roots[0])
227
228 for a, b in ((min(pair), max(pair)) for pair in chain(d1, d2)):
229 assert (
230 root_distance[get_pair(d1, a, b)] == root_distance[get_pair(d2, a, b)]
231 )
232
233 def test_all_pairs_lowest_common_ancestor1(self):
234 """Produces the correct results."""
235 self.assert_lca_dicts_same(dict(all_pairs_lca(self.DG)), self.gold)
236
237 def test_all_pairs_lowest_common_ancestor2(self):
238 """Produces the correct results when all pairs given."""
239 all_pairs = list(product(self.DG.nodes(), self.DG.nodes()))
240 ans = all_pairs_lca(self.DG, pairs=all_pairs)
241 self.assert_lca_dicts_same(dict(ans), self.gold)
242
243 def test_all_pairs_lowest_common_ancestor3(self):
244 """Produces the correct results when all pairs given as a generator."""
245 all_pairs = product(self.DG.nodes(), self.DG.nodes())
246 ans = all_pairs_lca(self.DG, pairs=all_pairs)
247 self.assert_lca_dicts_same(dict(ans), self.gold)
248
249 def test_all_pairs_lowest_common_ancestor4(self):
250 """Graph with two roots."""
251 G = self.DG.copy()
252 G.add_edge(9, 10)
253 G.add_edge(9, 4)
254 gold = self.gold.copy()
255 gold[9, 9] = 9
256 gold[9, 10] = 9
257 gold[9, 4] = 9
258 gold[9, 3] = 9
259 gold[10, 4] = 9
260 gold[10, 3] = 9
261 gold[10, 10] = 10
262
263 testing = dict(all_pairs_lca(G))
264
265 G.add_edge(-1, 9)
266 G.add_edge(-1, 0)
267 self.assert_lca_dicts_same(testing, gold, G)
268
269 def test_all_pairs_lowest_common_ancestor5(self):
270 """Test that pairs not in the graph raises error."""
271 pytest.raises(nx.NodeNotFound, all_pairs_lca, self.DG, [(-1, -1)])
272
273 def test_all_pairs_lowest_common_ancestor6(self):
274 """Test that pairs with no LCA specified emits nothing."""
275 G = self.DG.copy()
276 G.add_node(-1)
277 gen = all_pairs_lca(G, [(-1, -1), (-1, 0)])
278 assert dict(gen) == {(-1, -1): -1}
279
280 def test_all_pairs_lowest_common_ancestor7(self):
281 """Test that LCA on null graph bails."""
282 pytest.raises(nx.NetworkXPointlessConcept, all_pairs_lca, nx.DiGraph())
283
284 def test_all_pairs_lowest_common_ancestor8(self):
285 """Test that LCA on non-dags bails."""
286 pytest.raises(nx.NetworkXError, all_pairs_lca, nx.DiGraph([(3, 4), (4, 3)]))
287
288 def test_all_pairs_lowest_common_ancestor9(self):
289 """Test that it works on non-empty graphs with no LCAs."""
290 G = nx.DiGraph()
291 G.add_node(3)
292 ans = list(all_pairs_lca(G))
293 assert ans == [((3, 3), 3)]
294
295 def test_all_pairs_lowest_common_ancestor10(self):
296 """Test that it bails on None as a node."""
297 G = nx.DiGraph([(None, 3)])
298 pytest.raises(nx.NetworkXError, all_pairs_lca, G)
299 pytest.raises(nx.NodeNotFound, all_pairs_lca, self.DG, pairs=G.edges())
300
301 def test_lowest_common_ancestor1(self):
302 """Test that the one-pair function works on default."""
303 G = nx.DiGraph([(0, 1), (2, 1)])
304 sentinel = object()
305 assert nx.lowest_common_ancestor(G, 0, 2, default=sentinel) is sentinel
306
307 def test_lowest_common_ancestor2(self):
308 """Test that the one-pair function works on identity."""
309 G = nx.DiGraph()
310 G.add_node(3)
311 assert nx.lowest_common_ancestor(G, 3, 3) == 3