如何解决Networkx Kernighan-Lin多分区
我制作了一个图,并通过Kernighan-Lin划分算法将其分为2部分。在NetworkX软件包中,python仅对两个分区具有Kernighan-Lin算法,但对于多分区,我需要它。如何将其从两个分区更改为多分区?
我编写了一个示例图代码,还有Kernighan-Lin算法。
from collections import defaultdict
from itertools import islice
from operator import itemgetter
import networkx as nx
from networkx.utils import not_implemented_for,py_random_state
from networkx.algorithms.community.community_utils import is_partition
G = nx.Graph()
G.add_node('a')
G.add_node('b')
G.add_node('c')
G.add_node('d')
G.add_node('e')
G.add_node('f')
G.add_edge('a','b')
G.add_edge('c','b')
G.add_edge('d','e')
G.add_edge('e','f')
__all__ = ['kernighan_lin_bisection']
def _compute_delta(G,A,B,weight):
delta = defaultdict(float)
for u,v,d in G.edges(data=True):
w = d.get(weight,1)
if u in A:
if v in A:
delta[u] -= w
delta[v] -= w
elif v in B:
delta[u] += w
delta[v] += w
elif u in B:
if v in A:
delta[u] += w
delta[v] += w
elif v in B:
delta[u] -= w
delta[v] -= w
return delta
def _update_delta(delta,G,u,weight):
for _,nbr,d in G.edges(u,data=True):
w = d.get(weight,1)
if nbr in A:
delta[nbr] += 2 * w
if nbr in B:
delta[nbr] -= 2 * w
for _,d in G.edges(v,1)
if nbr in A:
delta[nbr] -= 2 * w
if nbr in B:
delta[nbr] += 2 * w
return delta
def _kernighan_lin_pass(G,weight):
multigraph = G.is_multigraph()
delta = _compute_delta(G,weight)
swapped = set()
gains = []
while len(swapped) < len(G):
gain = []
for u in A - swapped:
for v in B - swapped:
try:
if multigraph:
w = sum(d.get(weight,1) for d in G[u][v].values())
else:
w = G[u][v].get(weight,1)
except KeyError:
w = 0
gain.append((delta[u] + delta[v] - 2 * w,v))
if len(gain) == 0:
break
maxg,v = max(gain,key=itemgetter(0))
swapped |= {u,v}
gains.append((maxg,v))
delta = _update_delta(delta,A - swapped,B - swapped,weight)
return gains
@py_random_state(4)
@not_implemented_for('directed')
def kernighan_lin_bisection(G,partition=None,max_iter=10,weight='weight',seed=None):
if partition is None:
nodes = list(G)
seed.shuffle(nodes)
h = len(nodes) // 2
partition = (nodes[:h],nodes[h:])
try:
A,B = set(partition[0]),set(partition[1])
except:
raise ValueError('partition must be two sets')
if not is_partition(G,(A,B)):
raise nx.NetworkXError('partition invalid')
for i in range(max_iter):
gains = _kernighan_lin_pass(G,weight)
csum = list(nx.utils.accumulate(g for g,v in gains))
max_cgain = max(csum)
if max_cgain <= 0:
break
index = csum.index(max_cgain)
nodesets = islice(zip(*gains[:index + 1]),1,3)
anodes,bnodes = (set(s) for s in nodesets)
A |= bnodes
A -= anodes
B |= anodes
B -= bnodes
return A,B
def main() -> None:
kl = kernighan_lin_bisection(G,seed=None)
print(f'= {kl}')
if __name__ == '__main__':
main()
解决方法
您可以使用Metis算法来具有多个分区
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。