您的问题涉及几个困难的计算问题。
首先,一些理论。如果图 G 是平面的,则 G 的每个子图都是平面的。从 G 翻转边(有e
边),将给出2^e-1
平面子图(如果我们不关心连通性),这是指数的(即巨大的和“坏的”)。可能,您想找到“最大”平面子图。
如果您想绘制看起来也像平面的平面图在计算上是困难的,即知道存在边缘不交叉的图形表示是一回事,而找到这样的表示是另一回事。
要执行。似乎 networkx 没有检查图形是否为平面的功能。其他一些与图一起工作的包有(例如,sage有g.is_planar()
函数 whereg
是一个图对象)。下面,我根据Kuratowski 定理用 networkx 编写了一个“简单”(必须有更有效的方法)平面性检查。
import pygraphviz as pgv
import networkx as nx
import itertools as it
from networkx.algorithms import bipartite
def is_planar(G):
"""
function checks if graph G has K(5) or K(3,3) as minors,
returns True /False on planarity and nodes of "bad_minor"
"""
result=True
bad_minor=[]
n=len(G.nodes())
if n>5:
for subnodes in it.combinations(G.nodes(),6):
subG=G.subgraph(subnodes)
if bipartite.is_bipartite(G):# check if the graph G has a subgraph K(3,3)
X, Y = bipartite.sets(G)
if len(X)==3:
result=False
bad_minor=subnodes
if n>4 and result:
for subnodes in it.combinations(G.nodes(),5):
subG=G.subgraph(subnodes)
if len(subG.edges())==10:# check if the graph G has a subgraph K(5)
result=False
bad_minor=subnodes
return result,bad_minor
#create random planar graph with n nodes and p probability of growing
n=8
p=0.6
while True:
G=nx.gnp_random_graph(n,p)
if is_planar(G)[0]:
break
#visualize with pygraphviz
A=pgv.AGraph()
A.add_edges_from(G.edges())
A.layout(prog='dot')
A.draw('planar.png')
编辑2。如果你在使用 pygraphviz 时遇到麻烦,尝试使用 networkx 进行绘制,也许你会发现结果还可以。因此,不要使用“使用 pygraphviz 进行可视化”块尝试以下操作:
import matplotlib.pyplot as plt
nx.draw(G)
# comment the line above and uncomment one of the 3 lines below (try each of them):
#nx.draw_random(G)
#nx.draw_circular(G)
#nx.draw_spectral(G)
plt.show()
编辑2结束。
结果看起来像这样。
您会看到图片上有一个交叉点(但图形是平面的),这实际上是一个很好的结果(不要忘记这个问题在计算上很困难),pygraphviz 是使用启发式算法的Graphviz的包装器。在该行中A.layout(prog='dot')
,您可以尝试将 'dot' 替换为 'twopi'、'neato'、'circo' 等,看看是否能获得更好的可视化效果。
编辑. 让我们也考虑一下您关于平面子图的问题。让我们生成一个非平面图:
while True:
J=nx.gnp_random_graph(n,p)
if is_planar(J)[0]==False:
break
我认为找到平面子图的最有效方法是从“坏小调”(即 K(5) 或 K(3,3))中消除节点。这是我的实现:
def find_planar_subgraph(G):
if len(G)<3:
return G
else:
is_planar_boolean,bad_minor=is_planar(G)
if is_planar_boolean:
return G
else:
G.remove_node(bad_minor[0])
return find_planar_subgraph(G)
行动:
L=find_planar_subgraph(J)
is_planar(L)[0]
>> True
现在你有一个非平面图 G 的平面子图 L(一个 networkx 图对象)。