-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
all_node_cuts()
performance degrades much faster than predicted by Kanevsky's minimum cut algorithm
#7994
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I think this is a bug:
There's no vertex cut between neighboring nodes. |
Also, this seems weird:
|
There have been a number of corner case problems with the The PR #3039 represented a substantial change that corrected "multiple incorrect implementation in the original code " and also slowed down the code by quite a bit. The two cases you mention above (node_cuts for very small graphs) seem like corner cases, but could be indicative of mistakes in the larger implementation. They erode confidence in the rest of the code too. Looks like we need a deep dive into this algorithm and implementation. |
I'm not able to reproduce this issue. This test passes: def test_repro():
G = nx.Graph([(1, 2)])
assert nx.density(G) == 1
assert list(nx.all_node_cuts(G)) == []
# Address some corner cases first.
# For complete Graphs
if nx.density(G) == 1:
yield from ()
return What value do you get when you call |
I think the first comment above (with maybe bugs) runs OK on my machine -- as also reported by @amcandio
I think the result I do see the result in the following comment that a one node graph reports an empty set as a node cut. I'm not sure what a return value of an empty set would even mean -- I guess you might get that when the original graph is not connected... definitely strange... |
I put up a property-based test: def _random_connected_graph(n, prob, seed):
return nx.compose(
nx.random_labeled_tree(n, seed=seed),
nx.erdos_renyi_graph(n, prob, seed=seed),
)
@settings(print_blob=True)
@given(
graph_st(
_random_connected_graph,
n=st.integers(5, 10),
prob=st.floats(0, 1)
)
)
def test_random_connected_graph(G):
for flow_func in flow_funcs:
kwargs = {"flow_func": flow_func}
edge_cut = nx.minimum_edge_cut(G, **kwargs)
H = G.copy()
H.remove_edges_from(edge_cut)
assert not nx.is_connected(H)
node_cut = nx.minimum_node_cut(G, **kwargs)
H = G.copy()
H.remove_nodes_from(node_cut)
assert not nx.is_connected(H), f"Failed for {flow_func.__name__} with {G}" Hypothesis is able to find counter-examples. We seem to be strugling with complete graphs:
For this graph we detect |
NetworkX vs igraph. igraph implements Kanevsky's too.
Results dataframe w/ percent change calculated for
nx_t
andig_t
(* 100, b/c humans). Rate of growth is the interesting bit, b/c NetworkX is 100% Python, and igraph is C w/ a python binding. Raw data attached results.json.Clearly these implementations are following different growth curves. Kanevsky's algorithm should be growing at$\mathcal{O}(2^{k} n^3)$ . NetworkX's growth becomes geometric (or worse).
The cause seems to be for some graph sizes, the number of members of the
antichains(L)
set explodes---billions of members, in some case---but I have not yet figured out why that happens.Originally posted by @Cerebus in #7989 (comment)
The text was updated successfully, but these errors were encountered: