@@ -137,3 +137,209 @@ def test_boost_example(self):
137137 self .assertDictEqual (result , {0 : 1 , 1 : 7 , 2 : 7 , 3 : 4 , 4 : 5 , 5 : 7 , 6 : 4 , 7 : 7 })
138138
139139 self .assertDictEqual (nx .immediate_dominators (nx_graph .reverse (copy = False ), 7 ), result )
140+
141+
142+ class TestDominanceFrontiers (unittest .TestCase ):
143+ """
144+ Test `rustworkx.dominance_frontiers`.
145+
146+ Test cases adapted from `networkx`:
147+ https://github.com/networkx/networkx/blob/9c5ca54b7e5310a21568bb2e0104f8c87bf74ff7/networkx/algorithms/tests/test_dominance.py
148+ (Copyright 2004-2024 NetworkX Developers, 3-clause BSD License)
149+ """
150+
151+ def test_empty (self ):
152+ """
153+ Edge case: empty graph.
154+ """
155+ graph = rx .PyDiGraph ()
156+
157+ with self .assertRaises (rx .NullGraph ):
158+ rx .dominance_frontiers (graph , 0 )
159+
160+ def test_start_node_not_in_graph (self ):
161+ """
162+ Edge case: start_node is not in the graph.
163+ """
164+ graph = rx .PyDiGraph ()
165+ graph .add_node (0 )
166+
167+ self .assertEqual (list (graph .node_indices ()), [0 ])
168+
169+ with self .assertRaises (rx .InvalidNode ):
170+ rx .dominance_frontiers (graph , 1 )
171+
172+ def test_singleton (self ):
173+ """
174+ Edge cases: single node, optionally cyclic.
175+ """
176+ graph = rx .PyDiGraph ()
177+ graph .add_node (0 )
178+ self .assertDictEqual (rx .dominance_frontiers (graph , 0 ), {0 : set ()})
179+
180+ graph .add_edge (0 , 0 , None )
181+ self .assertDictEqual (rx .dominance_frontiers (graph , 0 ), {0 : set ()})
182+
183+ def test_irreducible1 (self ):
184+ """
185+ Graph taken from figure 2 of "A simple, fast dominance algorithm." (2006).
186+ https://hdl.handle.net/1911/96345
187+ """
188+ edges = [(1 , 2 ), (2 , 1 ), (3 , 2 ), (4 , 1 ), (5 , 3 ), (5 , 4 )]
189+ graph = rx .PyDiGraph ()
190+ graph .add_node (0 )
191+ graph .extend_from_edge_list (edges )
192+
193+ result = rx .dominance_frontiers (graph , 5 )
194+ self .assertDictEqual (result , {1 : {2 }, 2 : {1 }, 3 : {2 }, 4 : {1 }, 5 : set ()})
195+
196+ nx_graph = nx .DiGraph ()
197+ nx_graph .add_edges_from (graph .edge_list ())
198+ self .assertDictEqual (nx .dominance_frontiers (nx_graph , 5 ), result )
199+
200+ def test_irreducible2 (self ):
201+ """
202+ Graph taken from figure 4 of "A simple, fast dominance algorithm." (2006).
203+ https://hdl.handle.net/1911/96345
204+ """
205+ edges = [(1 , 2 ), (2 , 1 ), (2 , 3 ), (3 , 2 ), (4 , 2 ), (4 , 3 ), (5 , 1 ), (6 , 4 ), (6 , 5 )]
206+ graph = rx .PyDiGraph ()
207+ graph .add_node (0 )
208+ graph .extend_from_edge_list (edges )
209+
210+ result = rx .dominance_frontiers (graph , 6 )
211+
212+ self .assertDictEqual (
213+ result ,
214+ {
215+ 1 : {2 },
216+ 2 : {1 , 3 },
217+ 3 : {2 },
218+ 4 : {2 , 3 },
219+ 5 : {1 },
220+ 6 : set (),
221+ },
222+ )
223+
224+ nx_graph = nx .DiGraph ()
225+ nx_graph .add_edges_from (graph .edge_list ())
226+ self .assertDictEqual (nx .dominance_frontiers (nx_graph , 6 ), result )
227+
228+ def test_domrel_png (self ):
229+ """
230+ Graph taken from https://commons.wikipedia.org/wiki/File:Domrel.png
231+ """
232+ edges = [(1 , 2 ), (2 , 3 ), (2 , 4 ), (2 , 6 ), (3 , 5 ), (4 , 5 ), (5 , 2 )]
233+ graph = rx .PyDiGraph ()
234+ graph .add_node (0 )
235+ graph .extend_from_edge_list (edges )
236+
237+ result = rx .dominance_frontiers (graph , 1 )
238+
239+ self .assertDictEqual (
240+ result ,
241+ {
242+ 1 : set (),
243+ 2 : {2 },
244+ 3 : {5 },
245+ 4 : {5 },
246+ 5 : {2 },
247+ 6 : set (),
248+ },
249+ )
250+
251+ nx_graph = nx .DiGraph ()
252+ nx_graph .add_edges_from (graph .edge_list ())
253+ self .assertDictEqual (nx .dominance_frontiers (nx_graph , 1 ), result )
254+
255+ # Test postdominance.
256+ graph .reverse ()
257+ result = rx .dominance_frontiers (graph , 6 )
258+ self .assertDictEqual (
259+ result ,
260+ {
261+ 1 : set (),
262+ 2 : {2 },
263+ 3 : {2 },
264+ 4 : {2 },
265+ 5 : {2 },
266+ 6 : set (),
267+ },
268+ )
269+
270+ self .assertDictEqual (nx .dominance_frontiers (nx_graph .reverse (copy = False ), 6 ), result )
271+
272+ def test_boost_example (self ):
273+ """
274+ Graph taken from Figure 1 of
275+ http://www.boost.org/doc/libs/1_56_0/libs/graph/doc/lengauer_tarjan_dominator.htm
276+ """
277+ edges = [(0 , 1 ), (1 , 2 ), (1 , 3 ), (2 , 7 ), (3 , 4 ), (4 , 5 ), (4 , 6 ), (5 , 7 ), (6 , 4 )]
278+ graph = rx .PyDiGraph ()
279+ graph .extend_from_edge_list (edges )
280+
281+ nx_graph = nx .DiGraph ()
282+ nx_graph .add_edges_from (graph .edge_list ())
283+
284+ result = rx .dominance_frontiers (graph , 0 )
285+ self .assertDictEqual (
286+ result ,
287+ {
288+ 0 : set (),
289+ 1 : set (),
290+ 2 : {7 },
291+ 3 : {7 },
292+ 4 : {4 , 7 },
293+ 5 : {7 },
294+ 6 : {4 },
295+ 7 : set (),
296+ },
297+ )
298+
299+ self .assertDictEqual (nx .dominance_frontiers (nx_graph , 0 ), result )
300+
301+ # Test postdominance
302+ graph .reverse ()
303+ result = rx .dominance_frontiers (graph , 7 )
304+ self .assertDictEqual (
305+ result ,
306+ {
307+ 0 : set (),
308+ 1 : set (),
309+ 2 : {1 },
310+ 3 : {1 },
311+ 4 : {1 , 4 },
312+ 5 : {1 },
313+ 6 : {4 },
314+ 7 : set (),
315+ },
316+ )
317+
318+ self .assertDictEqual (nx .dominance_frontiers (nx_graph .reverse (copy = False ), 7 ), result )
319+
320+ def test_missing_immediate_doms (self ):
321+ """
322+ Test that the `dominance_frontiers` function doesn't regress on
323+ https://github.com/networkx/networkx/issues/2070
324+ """
325+ edges = [(0 , 1 ), (1 , 2 ), (2 , 3 ), (3 , 4 ), (5 , 3 )]
326+ graph = rx .PyDiGraph ()
327+ graph .extend_from_edge_list (edges )
328+
329+ idom = rx .immediate_dominators (graph , 0 )
330+ self .assertNotIn (5 , idom )
331+
332+ # In networkx#2070, the call would fail because node 5
333+ # has no immediate dominators
334+ result = rx .dominance_frontiers (graph , 0 )
335+ self .assertDictEqual (
336+ result ,
337+ {
338+ 0 : set (),
339+ 1 : set (),
340+ 2 : set (),
341+ 3 : set (),
342+ 4 : set (),
343+ 5 : {3 },
344+ },
345+ )
0 commit comments