comparison env/lib/python3.9/site-packages/networkx/algorithms/approximation/tests/test_treewidth.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 networkx as nx
2 from networkx.algorithms.approximation import treewidth_min_degree
3 from networkx.algorithms.approximation import treewidth_min_fill_in
4 from networkx.algorithms.approximation.treewidth import min_fill_in_heuristic
5 from networkx.algorithms.approximation.treewidth import MinDegreeHeuristic
6 import itertools
7
8
9 def is_tree_decomp(graph, decomp):
10 """Check if the given tree decomposition is valid."""
11 for x in graph.nodes():
12 appear_once = False
13 for bag in decomp.nodes():
14 if x in bag:
15 appear_once = True
16 break
17 assert appear_once
18
19 # Check if each connected pair of nodes are at least once together in a bag
20 for (x, y) in graph.edges():
21 appear_together = False
22 for bag in decomp.nodes():
23 if x in bag and y in bag:
24 appear_together = True
25 break
26 assert appear_together
27
28 # Check if the nodes associated with vertex v form a connected subset of T
29 for v in graph.nodes():
30 subset = []
31 for bag in decomp.nodes():
32 if v in bag:
33 subset.append(bag)
34 sub_graph = decomp.subgraph(subset)
35 assert nx.is_connected(sub_graph)
36
37
38 class TestTreewidthMinDegree:
39 """Unit tests for the min_degree function"""
40
41 @classmethod
42 def setup_class(cls):
43 """Setup for different kinds of trees"""
44 cls.complete = nx.Graph()
45 cls.complete.add_edge(1, 2)
46 cls.complete.add_edge(2, 3)
47 cls.complete.add_edge(1, 3)
48
49 cls.small_tree = nx.Graph()
50 cls.small_tree.add_edge(1, 3)
51 cls.small_tree.add_edge(4, 3)
52 cls.small_tree.add_edge(2, 3)
53 cls.small_tree.add_edge(3, 5)
54 cls.small_tree.add_edge(5, 6)
55 cls.small_tree.add_edge(5, 7)
56 cls.small_tree.add_edge(6, 7)
57
58 cls.deterministic_graph = nx.Graph()
59 cls.deterministic_graph.add_edge(0, 1) # deg(0) = 1
60
61 cls.deterministic_graph.add_edge(1, 2) # deg(1) = 2
62
63 cls.deterministic_graph.add_edge(2, 3)
64 cls.deterministic_graph.add_edge(2, 4) # deg(2) = 3
65
66 cls.deterministic_graph.add_edge(3, 4)
67 cls.deterministic_graph.add_edge(3, 5)
68 cls.deterministic_graph.add_edge(3, 6) # deg(3) = 4
69
70 cls.deterministic_graph.add_edge(4, 5)
71 cls.deterministic_graph.add_edge(4, 6)
72 cls.deterministic_graph.add_edge(4, 7) # deg(4) = 5
73
74 cls.deterministic_graph.add_edge(5, 6)
75 cls.deterministic_graph.add_edge(5, 7)
76 cls.deterministic_graph.add_edge(5, 8)
77 cls.deterministic_graph.add_edge(5, 9) # deg(5) = 6
78
79 cls.deterministic_graph.add_edge(6, 7)
80 cls.deterministic_graph.add_edge(6, 8)
81 cls.deterministic_graph.add_edge(6, 9) # deg(6) = 6
82
83 cls.deterministic_graph.add_edge(7, 8)
84 cls.deterministic_graph.add_edge(7, 9) # deg(7) = 5
85
86 cls.deterministic_graph.add_edge(8, 9) # deg(8) = 4
87
88 def test_petersen_graph(self):
89 """Test Petersen graph tree decomposition result"""
90 G = nx.petersen_graph()
91 _, decomp = treewidth_min_degree(G)
92 is_tree_decomp(G, decomp)
93
94 def test_small_tree_treewidth(self):
95 """Test small tree
96
97 Test if the computed treewidth of the known self.small_tree is 2.
98 As we know which value we can expect from our heuristic, values other
99 than two are regressions
100 """
101 G = self.small_tree
102 # the order of removal should be [1,2,4]3[5,6,7]
103 # (with [] denoting any order of the containing nodes)
104 # resulting in treewidth 2 for the heuristic
105 treewidth, _ = treewidth_min_fill_in(G)
106 assert treewidth == 2
107
108 def test_heuristic_abort(self):
109 """Test heuristic abort condition for fully connected graph"""
110 graph = {}
111 for u in self.complete:
112 graph[u] = set()
113 for v in self.complete[u]:
114 if u != v: # ignore self-loop
115 graph[u].add(v)
116
117 deg_heuristic = MinDegreeHeuristic(graph)
118 node = deg_heuristic.best_node(graph)
119 if node is None:
120 pass
121 else:
122 assert False
123
124 def test_empty_graph(self):
125 """Test empty graph"""
126 G = nx.Graph()
127 _, _ = treewidth_min_degree(G)
128
129 def test_two_component_graph(self):
130 """Test empty graph"""
131 G = nx.Graph()
132 G.add_node(1)
133 G.add_node(2)
134 treewidth, _ = treewidth_min_degree(G)
135 assert treewidth == 0
136
137 def test_heuristic_first_steps(self):
138 """Test first steps of min_degree heuristic"""
139 graph = {
140 n: set(self.deterministic_graph[n]) - {n} for n in self.deterministic_graph
141 }
142 deg_heuristic = MinDegreeHeuristic(graph)
143 elim_node = deg_heuristic.best_node(graph)
144 print(f"Graph {graph}:")
145 steps = []
146
147 while elim_node is not None:
148 print(f"Removing {elim_node}:")
149 steps.append(elim_node)
150 nbrs = graph[elim_node]
151
152 for u, v in itertools.permutations(nbrs, 2):
153 if v not in graph[u]:
154 graph[u].add(v)
155
156 for u in graph:
157 if elim_node in graph[u]:
158 graph[u].remove(elim_node)
159
160 del graph[elim_node]
161 print(f"Graph {graph}:")
162 elim_node = deg_heuristic.best_node(graph)
163
164 # check only the first 5 elements for equality
165 assert steps[:5] == [0, 1, 2, 3, 4]
166
167
168 class TestTreewidthMinFillIn:
169 """Unit tests for the treewidth_min_fill_in function."""
170
171 @classmethod
172 def setup_class(cls):
173 """Setup for different kinds of trees"""
174 cls.complete = nx.Graph()
175 cls.complete.add_edge(1, 2)
176 cls.complete.add_edge(2, 3)
177 cls.complete.add_edge(1, 3)
178
179 cls.small_tree = nx.Graph()
180 cls.small_tree.add_edge(1, 2)
181 cls.small_tree.add_edge(2, 3)
182 cls.small_tree.add_edge(3, 4)
183 cls.small_tree.add_edge(1, 4)
184 cls.small_tree.add_edge(2, 4)
185 cls.small_tree.add_edge(4, 5)
186 cls.small_tree.add_edge(5, 6)
187 cls.small_tree.add_edge(5, 7)
188 cls.small_tree.add_edge(6, 7)
189
190 cls.deterministic_graph = nx.Graph()
191 cls.deterministic_graph.add_edge(1, 2)
192 cls.deterministic_graph.add_edge(1, 3)
193 cls.deterministic_graph.add_edge(3, 4)
194 cls.deterministic_graph.add_edge(2, 4)
195 cls.deterministic_graph.add_edge(3, 5)
196 cls.deterministic_graph.add_edge(4, 5)
197 cls.deterministic_graph.add_edge(3, 6)
198 cls.deterministic_graph.add_edge(5, 6)
199
200 def test_petersen_graph(self):
201 """Test Petersen graph tree decomposition result"""
202 G = nx.petersen_graph()
203 _, decomp = treewidth_min_fill_in(G)
204 is_tree_decomp(G, decomp)
205
206 def test_small_tree_treewidth(self):
207 """Test if the computed treewidth of the known self.small_tree is 2"""
208 G = self.small_tree
209 # the order of removal should be [1,2,4]3[5,6,7]
210 # (with [] denoting any order of the containing nodes)
211 # resulting in treewidth 2 for the heuristic
212 treewidth, _ = treewidth_min_fill_in(G)
213 assert treewidth == 2
214
215 def test_heuristic_abort(self):
216 """Test if min_fill_in returns None for fully connected graph"""
217 graph = {}
218 for u in self.complete:
219 graph[u] = set()
220 for v in self.complete[u]:
221 if u != v: # ignore self-loop
222 graph[u].add(v)
223 next_node = min_fill_in_heuristic(graph)
224 if next_node is None:
225 pass
226 else:
227 assert False
228
229 def test_empty_graph(self):
230 """Test empty graph"""
231 G = nx.Graph()
232 _, _ = treewidth_min_fill_in(G)
233
234 def test_two_component_graph(self):
235 """Test empty graph"""
236 G = nx.Graph()
237 G.add_node(1)
238 G.add_node(2)
239 treewidth, _ = treewidth_min_fill_in(G)
240 assert treewidth == 0
241
242 def test_heuristic_first_steps(self):
243 """Test first steps of min_fill_in heuristic"""
244 graph = {
245 n: set(self.deterministic_graph[n]) - {n} for n in self.deterministic_graph
246 }
247 print(f"Graph {graph}:")
248 elim_node = min_fill_in_heuristic(graph)
249 steps = []
250
251 while elim_node is not None:
252 print(f"Removing {elim_node}:")
253 steps.append(elim_node)
254 nbrs = graph[elim_node]
255
256 for u, v in itertools.permutations(nbrs, 2):
257 if v not in graph[u]:
258 graph[u].add(v)
259
260 for u in graph:
261 if elim_node in graph[u]:
262 graph[u].remove(elim_node)
263
264 del graph[elim_node]
265 print(f"Graph {graph}:")
266 elim_node = min_fill_in_heuristic(graph)
267
268 # check only the first 2 elements for equality
269 assert steps[:2] == [6, 5]