あなたの質問には、いくつかの難しい計算問題が含まれています。
まず、いくつかの理論。グラフ G が平面の場合、G のすべてのサブグラフは平面です。G (エッジを持つ) からエッジを反転すると、指数関数的 (つまり、巨大で「悪い」) な平面サブグラフ (接続性を気にしない場合e
) が得られます。2^e-1
おそらく、「最大」の平面サブグラフを見つけたいと思うでしょう。
平面のように見える平面グラフを描画したい場合は、計算上困難です。つまり、エッジが交差しないグラフィカルな表現が存在することを知ることと、そのような表現を見つけることは別のことです。
実装へ。networkx には、グラフが平面かどうかをチェックする機能がないようです。グラフを操作する他のパッケージには、(たとえば、sageにはグラフ オブジェクトであるg.is_planar()
関数があります) があります。以下に、クラトフスキーの定理g
に基づいて、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()
edit2 の終了。
結果はこんな感じ。
画像上に 1 つの交差があることがわかります (しかし、グラフは平面です)。これは実際には良い結果です (問題が計算上難しいことを忘れないでください)。pygraphviz は、ヒューリスティック アルゴリズムを使用するGraphvizのラッパーです。この行A.layout(prog='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 グラフ オブジェクト) ができました。