11"""Unit tests for the :mod:`networkx.algorithms.approximation.kcutsets` module."""
22
33import itertools
4+
45import pytest
6+
57import networkx as nx
6- from networkx .algorithms .approximation import minimum_multiway_cut , minimum_k_cut
7- from networkx import minimum_cut_value
8+ from networkx .algorithms import approximation as approx
89
910
1011class TestMinMultiwayCut :
@@ -18,14 +19,14 @@ def test_null_graph(self):
1819 with pytest .raises (
1920 nx .NetworkXError , match = "Expected non-empty NetworkX graph!"
2021 ):
21- minimum_multiway_cut (G , G .nodes ())
22+ approx . minimum_multiway_cut (G , G .nodes ())
2223
2324 def test_undirected_non_connected (self ):
2425 """Test an undirected disconnected graph."""
2526 G = nx .path_graph (10 )
2627 G .remove_edge (3 , 4 )
2728 with pytest .raises (nx .NetworkXError , match = "Graph not connected." ):
28- minimum_multiway_cut (G , G .nodes ())
29+ approx . minimum_multiway_cut (G , G .nodes ())
2930
3031 def test_invalid_terminals (self ):
3132 """Test empty terminals."""
@@ -34,12 +35,12 @@ def test_invalid_terminals(self):
3435 with pytest .raises (
3536 nx .NetworkXError , match = "At least two terminals should be provided."
3637 ):
37- minimum_multiway_cut (G , [])
38+ approx . minimum_multiway_cut (G , [])
3839
3940 def test_path_graph_unweighted (self ):
4041 """Test min multiway cut for a path graph."""
4142 G = nx .path_graph (2 )
42- cut_value , cutset = minimum_multiway_cut (G , [0 , 1 ])
43+ cut_value , cutset = approx . minimum_multiway_cut (G , [0 , 1 ])
4344 assert cut_value == 1
4445 G .remove_edges_from (cutset )
4546 assert len (list (nx .connected_components (G ))) == 2
@@ -50,18 +51,50 @@ def test_path_graph_weighted(self):
5051 G .add_weighted_edges_from (
5152 [(0 , 1 , 10 ), (1 , 2 , 10 ), (2 , 3 , 5 )], weight = "capacity"
5253 )
53- cut_value , cutset = minimum_multiway_cut (G , [0 , 3 ], weight = "capacity" )
54+ cut_value , cutset = approx . minimum_multiway_cut (G , [0 , 3 ], weight = "capacity" )
5455 assert cut_value == 5
5556
5657 def test_complete_graph (self ):
5758 """Test min multiway cut for a complete graph."""
5859 G = nx .complete_graph (5 )
59- cut_value , cutset = minimum_multiway_cut (G , G .nodes ())
60+ cut_value , cutset = approx . minimum_multiway_cut (G , G .nodes ())
6061 assert cut_value == 10
6162 # remove the edges
6263 G .remove_edges_from (cutset )
6364 assert set (G .edges ()) == set ()
6465
66+ def test_single_terminal (self ):
67+ """Test that a single terminal raises an error."""
68+ G = nx .path_graph (5 )
69+ with pytest .raises (
70+ nx .NetworkXError , match = "At least two terminals should be provided."
71+ ):
72+ approx .minimum_multiway_cut (G , [0 ])
73+
74+ def test_terminals_not_in_graph (self ):
75+ """Test terminals that are not in the graph are ignored."""
76+ G = nx .path_graph (5 )
77+ # terminals 100 and 200 don't exist, only 0 and 4 are valid
78+ cut_value , cutset = approx .minimum_multiway_cut (G , [0 , 4 , 100 , 200 ])
79+ assert cut_value == 1
80+ G .remove_edges_from (cutset )
81+ components = list (nx .connected_components (G ))
82+ assert len (components ) == 2
83+
84+ def test_directed_graph_raises (self ):
85+ """Test that directed graphs raise NetworkXNotImplemented."""
86+ G = nx .DiGraph ()
87+ G .add_edges_from ([(0 , 1 ), (1 , 2 ), (2 , 3 )])
88+ with pytest .raises (nx .NetworkXNotImplemented ):
89+ approx .minimum_multiway_cut (G , [0 , 3 ])
90+
91+ def test_multigraph_raises (self ):
92+ """Test that multigraphs raise NetworkXNotImplemented."""
93+ G = nx .MultiGraph ()
94+ G .add_edges_from ([(0 , 1 ), (1 , 2 ), (2 , 3 )])
95+ with pytest .raises (nx .NetworkXNotImplemented ):
96+ approx .minimum_multiway_cut (G , [0 , 3 ])
97+
6598 @pytest .mark .parametrize (
6699 "graph_class" ,
67100 [
@@ -82,8 +115,8 @@ def test_compare_min_cut(self, graph_class, s, t):
82115 """
83116 G = graph_class ()
84117 nx .set_edge_attributes (G , values = 10 , name = "weight" )
85- cut_value , cutset = minimum_multiway_cut (G , {s , t }, weight = "weight" )
86- assert cut_value == minimum_cut_value (G , s , t , capacity = "weight" )
118+ cut_value , cutset = approx . minimum_multiway_cut (G , {s , t }, weight = "weight" )
119+ assert cut_value == nx . minimum_cut_value (G , s , t , capacity = "weight" )
87120
88121
89122class TestMinkCut :
@@ -97,28 +130,49 @@ def test_null_graph(self):
97130 with pytest .raises (
98131 nx .NetworkXError , match = "Expected non-empty NetworkX graph!"
99132 ):
100- minimum_k_cut (G , 3 )
133+ approx . minimum_k_cut (G , 3 )
101134
102135 def test_undirected_non_connected (self ):
103136 """Test an undirected disconnected graph."""
104137 G = nx .path_graph (10 )
105138 G .remove_edge (3 , 4 )
106139 with pytest .raises (nx .NetworkXError , match = "Graph not connected." ):
107- minimum_k_cut (G , 3 )
140+ approx . minimum_k_cut (G , 3 )
108141
109142 def test_invalid_k (self ):
110- """Test empty terminals ."""
143+ """Test invalid k values ."""
111144 G = nx .path_graph (10 )
112145 with pytest .raises (nx .NetworkXError , match = "k should be within 1 and 10" ):
113- minimum_k_cut (G , 0 )
146+ approx . minimum_k_cut (G , 0 )
114147 with pytest .raises (nx .NetworkXError , match = "k should be within 1 and 10" ):
115- minimum_k_cut (G , 11 )
148+ approx .minimum_k_cut (G , 11 )
149+
150+ def test_directed_graph_raises (self ):
151+ """Test that directed graphs raise NetworkXNotImplemented."""
152+ G = nx .DiGraph ()
153+ G .add_edges_from ([(0 , 1 ), (1 , 2 ), (2 , 3 )])
154+ with pytest .raises (nx .NetworkXNotImplemented ):
155+ approx .minimum_k_cut (G , 2 )
156+
157+ def test_multigraph_raises (self ):
158+ """Test that multigraphs raise NetworkXNotImplemented."""
159+ G = nx .MultiGraph ()
160+ G .add_edges_from ([(0 , 1 ), (1 , 2 ), (2 , 3 )])
161+ with pytest .raises (nx .NetworkXNotImplemented ):
162+ approx .minimum_k_cut (G , 2 )
163+
164+ def test_k_equals_one (self ):
165+ """Test k=1 returns empty cutset with zero cut value."""
166+ G = nx .complete_graph (5 )
167+ cut_value , cutset = approx .minimum_k_cut (G , 1 )
168+ assert cut_value == 0
169+ assert len (cutset ) == 0
116170
117171 @pytest .mark .parametrize ("k,expected" , [(1 , 0 ), (2 , 1 ), (3 , 2 ), (4 , 3 ), (5 , 4 )])
118172 def test_path_graph (self , k , expected ):
119173 """Test various k for a path graph of 5 nodes."""
120174 G = nx .path_graph (n = 5 )
121- cut_value , cutset = minimum_k_cut (G , k , weight = "capacity" )
175+ cut_value , cutset = approx . minimum_k_cut (G , k , weight = "capacity" )
122176 assert cut_value == expected
123177 G .remove_edges_from (cutset )
124178 assert len (list (nx .connected_components (G ))) == k
@@ -127,7 +181,7 @@ def test_path_graph(self, k, expected):
127181 def test_complete_graph (self , k , expected ):
128182 """Test various k for a complete graph of 5 nodes."""
129183 G = nx .complete_graph (5 )
130- cut_value , cutset = minimum_k_cut (G , k )
184+ cut_value , cutset = approx . minimum_k_cut (G , k )
131185 assert cut_value == expected
132186 G .remove_edges_from (cutset )
133187 assert len (list (nx .connected_components (G ))) >= k
@@ -147,15 +201,15 @@ def test_complete_graph(self, k, expected):
147201 def test_connected_components (self , graph_class , k ):
148202 """Test multiple graph types and k."""
149203 G = graph_class ()
150- cut_value , cutset = minimum_k_cut (G , k )
204+ cut_value , cutset = approx . minimum_k_cut (G , k )
151205 G .remove_edges_from (cutset )
152206 assert len (list (nx .connected_components (G ))) >= k
153207
154208 def test_complete_graph_weighted (self ):
155209 """Test min k-cut for a weighted complete graph."""
156210 G = nx .complete_graph (5 )
157211 nx .set_edge_attributes (G , values = 10 , name = "weight" )
158- cut_value , cutset = minimum_k_cut (G , 5 , weight = "weight" )
212+ cut_value , cutset = approx . minimum_k_cut (G , 5 , weight = "weight" )
159213 assert cut_value == 100
160214 # remove the edges
161215 G .remove_edges_from (cutset )
@@ -167,7 +221,7 @@ def test_path_graph_weighted(self):
167221 G .add_weighted_edges_from (
168222 [(0 , 1 , 10 ), (1 , 2 , 10 ), (2 , 3 , 5 )], weight = "capacity"
169223 )
170- cut_value , cutset = minimum_k_cut (G , 3 , weight = "capacity" )
224+ cut_value , cutset = approx . minimum_k_cut (G , 3 , weight = "capacity" )
171225 assert cut_value == 15
172226 G .remove_edges_from (cutset )
173227 assert len (list (nx .connected_components (G ))) == 3
0 commit comments