[英]Networkx: Find all minimal cuts consisting of only nodes from one set in a bipartite graph
In the networkx python package, is there a way to find all node cuts of minimal size consisting of only nodes from one set in a bipartite graph? 在networkx python包中,有没有办法找到最小尺寸的所有节点剪切,只包含二分图中一组的节点? For example, if the two sides of a bipartite graph are A and B, how might I go about finding all minimal node cuts consisting of nodes entirely from set B? 例如,如果二分图的两边是A和B,我怎样才能找到完全来自集合B的节点组成的所有最小节点切割? The following code I have works but it's extremely slow: 以下代码我的工作,但它非常慢:
def get_one_sided_cuts(G, A, B):
#get all cuts that consist of nodes exclusively from B which disconnect
#nodes from A
one_sided_cuts = []
seen = []
l = list(combinations(A, 2))
for x in l:
s = x[0]
t = x[1]
cut = connectivity.minimum_st_node_cut(G, s, t)
if set(cut).issubset(B) and (cut not in seen):
one_sided_cuts.append(cut)
seen.append(cut)
#find minimum cut size
cur_min = float("inf")
for i in one_sided_cuts:
if len(i) < cur_min:
cur_min = len(i)
one_sided_cuts = [x for x in one_sided_cuts if len(x) == cur_min]
return one_sided_cuts
Note that this actually only checks if there is a minimal cut which, if removed, would disconnect two nodes in A only. 请注意,这实际上只检查是否存在最小切割,如果移除,将仅断开A中的两个节点。 If your solution does this (instead of finding a cut that will separate any two nodes) that's fine too. 如果您的解决方案执行此操作(而不是找到将任意两个节点分开的剪切),那也没关系。 Any ideas on how to do this more efficiently? 关于如何更有效地做到这一点的任何想法?
As stated in the comment, there are a couple of interpretations of “all node cuts of minimal size consisting of only nodes from one set in a bipartite graph”. 正如评论中所述,对“最小尺寸的所有节点切割仅包含来自二部图中的一个集合的节点”有几种解释。 It either means 它或者意味着
From your code example you are interested in 2. According to the docs, there is a way to speed up this calculation, and from profile results it helps a bit. 从您感兴趣的代码示例2.根据文档,有一种方法可以加快计算速度,并从配置文件结果中获得一些帮助。 There are auxiliary structures built, per graph, to determine the minimum node cuts. 每个图形都有辅助结构,用于确定最小节点切割。 Each node is replaced by 2 nodes, additional directed edges are added, etc. according to the Algorithm 9 in http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf We can reuse these structures instead of reconstructing them inside a tight loop: 根据http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf中的算法9,每个节点被2个节点替换,添加额外的有向边等。我们可以重用这些结构而不是重建他们在一个紧密的循环中:
Improvement for Case 2: 案例2的改进:
from networkx.algorithms.connectivity import (
build_auxiliary_node_connectivity)
from networkx.algorithms.flow import build_residual_network
from networkx.algorithms.flow import edmonds_karp
def getone_sided_cuts_Case2(G, A, B):
# build auxiliary networks
H = build_auxiliary_node_connectivity(G)
R = build_residual_network(H, 'capacity')
# get all cutes that consist of nodes exclusively from B which disconnet
# nodes from A
one_sided_cuts = []
seen = []
l = list(combinations(A,2))
for x in l:
s = x[0]
t = x[1]
cut = minimum_st_node_cut(G, s, t, auxiliary=H, residual=R)
if set(cut).issubset(B):
if cut not in seen:
one_sided_cuts.append(cut)
seen.append(cut)
# Find minimum cut size
cur_min = float('inf')
for i in one_sided_cuts:
if len(i) < cur_min:
curr_min = len(i)
one_sided_cuts = [x for x in one_sided_cuts if len(x) == cur_min]
return one_sided_cuts
For profiling purposes, you might use the following, or one of the built-in bipartite graph generators in Networkx: 对于分析目的,您可以使用以下或Networkx中的内置二分图生成器之一:
def create_bipartite_graph(size_m, size_n, num_edges):
G = nx.Graph()
edge_list_0 = list(range(size_m))
edge_list_1 = list(range(size_m,size_m+size_n))
all_edges = []
G.add_nodes_from(edge_list_0, bipartite=0)
G.add_nodes_from(edge_list_1, bipartite=1)
all_edges = list(product(edge_list_0, edge_list_1))
num_all_edges = len(all_edges)
edges = [all_edges[i] for i in random.sample(range(num_all_edges), num_edges)]
G.add_edges_from(edges)
return G, edge_list_0, edge_list_1
Using %timeit
, the second version runs about 5-10% faster. 使用%timeit
,第二个版本运行速度提高约5-10%。
For Case 1, the logic is a little more involved. 对于案例1,逻辑更复杂一些。 We need to consider minimal cuts from nodes only inside B. This requires a change to minimum_st_node_cut
in the following way. 我们需要考虑仅在B内部节点的最小切割。这需要以下列方式更改minimum_st_node_cut
。 Then replace all occurences of minimum_st_node_cut
to rest_minimum_st_node_cut
in your solution or the Case 2 solution I gave above, noting that the new function also requires specification of the sets A
, B
, necessarily: 然后在您的解决方案或上面给出的案例2解决方案rest_minimum_st_node_cut
minimum_st_node_cut
所有出现替换为rest_minimum_st_node_cut
,注意新函数还需要指定集合A
, B
,必要:
def rest_build_auxiliary_node_connectivity(G,A,B):
directed = G.is_directed()
H = nx.DiGraph()
for node in A:
H.add_node('%sA' % node, id=node)
H.add_node('%sB' % node, id=node)
H.add_edge('%sA' % node, '%sB' % node, capacity=1)
for node in B:
H.add_node('%sA' % node, id=node)
H.add_node('%sB' % node, id=node)
H.add_edge('%sA' % node, '%sB' % node, capacity=1)
edges = []
for (source, target) in G.edges():
edges.append(('%sB' % source, '%sA' % target))
if not directed:
edges.append(('%sB' % target, '%sA' % source))
H.add_edges_from(edges, capacity=1)
return H
def rest_minimum_st_node_cut(G, A, B, s, t, auxiliary=None, residual=None, flow_func=edmonds_karp):
if auxiliary is None:
H = rest_build_auxiliary_node_connectivity(G, A, B)
else:
H = auxiliary
if G.has_edge(s,t) or G.has_edge(t,s):
return []
kwargs = dict(flow_func=flow_func, residual=residual, auxiliary=H)
for node in [x for x in A if x not in [s,t]]:
edge = ('%sA' % node, '%sB' % node)
num_in_edges = len(H.in_edges(edge[0]))
H[edge[0]][edge[1]]['capacity'] = num_in_edges
edge_cut = minimum_st_edge_cut(H, '%sB' % s, '%sA' % t,**kwargs)
node_cut = set([n for n in [H.nodes[node]['id'] for edge in edge_cut for node in edge] if n not in A])
return node_cut - set([s,t])
We then have, for example: 然后我们有,例如:
In [1]: G = nx.Graph()
# A = [0,1,2,3], B = [4,5,6,7]
In [2]: G.add_edges_from([(0,4),(0,5),(1,6),(1,7),(4,1),(5,1),(6,3),(7,3)])
In [3]: minimum_st_node_cut(G, 0, 3)
{1}
In [4]: rest_minimum_st_node_cut(G,A,B,0,3)
{6, 7}
Finally note that the minimum_st_edge_cut()
function returns []
if two nodes are adjacent. 最后请注意,如果两个节点相邻,则minimum_st_edge_cut()
函数返回[]
。 Sometimes the convention is to return a set of n-1
nodes in this case, all nodes except the source or sink. 有时,惯例是在这种情况下返回一组n-1
节点,除源或接收器之外的所有节点。 Anyway, with the empty list convention, and since your original solution to Case 2 loops over node pairs in A
, you will likely get []
as a return value for most configurations, unless no nodes in A
are adjacent, say. 无论如何,使用空列表约定,并且由于您对Case 2的原始解决方案在A
节点对上循环,您可能会将[]
作为大多数配置的返回值,除非A
中的节点没有相邻,例如。
EDIT 编辑
The OP encountered a problem with bipartite graphs for which the sets A, B contained a mix of integers and str types. OP遇到了二分图的问题,其中集A,B包含整数和str类型的混合。 It looks to me like the build_auxiliary_node_connectivity
converts those str nodes to integers causing collisions. 在我看来, build_auxiliary_node_connectivity
将这些str节点转换为导致冲突的整数。 I rewrote things above, I think that takes care of it. 我重写了上面的内容,我认为这样可以解决它。 I don't see anything in the networkx
docs about this, so either use all integer nodes or use the rest_build_auxiliary_node_connectivity()
thing above. 我没有在networkx
文档中看到任何关于此的内容,因此要么使用所有整数节点,要么使用上面的rest_build_auxiliary_node_connectivity()
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.