質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

1642閲覧

networkxを用いたランダム有向グラフの生成

hoshi1996

総合スコア53

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2019/06/25 05:46

編集2019/06/25 07:25

あるエッジリストをもとにランダムな有向グラフを生成したいです。

python

1import networkx as nx 2 3G = nx.read_edgelist(path, create_using=nx.DiGraph())#自己ループも多重辺も存在しない。

ここで生成するランダム有向グラフの条件として
・Gのノード数と一致する
・GのノードのIn、Outの次数を保存している
・自己ループは存在して良いが多重辺は存在してはならない。よってGのエッジの数を保存している。

python

1A = nx.directed_configuration_model(in_degree_sequence, 2 out_degree_sequence=, create_using=nx.DiGraph())

上のコードを用い、ランダムグラフを生成しました。
この関数は普通、MultiDiGraphを返します。そのためDiGraphと指定しました。
しかし、この関数は、指定したグラフを生成するわけではなく、MultiDiGraphを生成した後にそれをDiGraphに直しているようです。
そのためノード数は一致しますが次数とエッジ数がGとは異なるランダム有向グラフを生成してしまいました。

また

python

1B = nx.directed_havel_hakimi_graph(in_deg_sequence, out_deg_sequence)

この関数を使ったら条件を全て満たすことができますが、辺に偏りが生まれてしまうため
別の方法を用いて生成したいです。

どのような方法で条件を満たすランダム有向グラフが生成できますか。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

自分も隣接行列の列ごと行ごとの和を考えていたんですが
グラフの隣接行列が100万×100万のとても大きいものを考えていたため頓挫してしまいました。
ここまで親切に回答して下さりありがとうございます

投稿2019/06/25 08:42

hoshi1996

総合スコア53

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiitoi

2019/06/25 11:04 編集

もしかしたらできる方法はあるかもしれません。 回答に書いた通り、線形計画問題に帰着できるので、その解空間からランダムにサンプルする手法を探すという方向性なら可能性がありそうです。 「random sample linear programming」などのキーワードで調べたらいくつか情報が出てきましたが、中身は見てないので使えるかどうかはわかりません。。。 networkx はグラフ理論で出てくるアルゴリズム等はだいたい実装されていますから、そこにないということは、需要があまりないのか、計算量的に現実的な時間で実行するのが無理なのかということになりますね。
hoshi1996

2019/06/26 06:04

多重辺は全体の0.1%にも満たないため大きな影響を与えないと考えました。 そのため以前のランダムグラフで検討することにしました。 とても親切な回答ありがとうございました。
guest

0

ベストアンサー

networkx の生成系の関数を探してみましたが、そのような関数はなさそうです。

少し考えてみましたが、やろうとしていることは無理なのではないでしょうか。

題意を整理すると、「ある有向グラフ G が与えられたとき、入次数、出次数が G と等しいランダムな有向グラフを作成したい」ということになります。

有向グラフ G の隣接行列を A としたとき、A の (i, j) 成分が1であれば、有向辺 (i, j) が存在することを意味するので、G の列ごとの和が入次数、行ごとの和が出次数になります。

よって、先程の問題は「行ごとの和、列ごとの和が指定した値となるような同じ大きさで値が0 or 1 の行列」をランダムに生成するということになります。

python

1import networkx as nx 2 3D = nx.gnm_random_graph(10, 20, seed=42, directed=True) 4in_degree = [deg for node, deg in D.in_degree()] 5out_degree = [deg for node, deg in D.out_degree()] 6print(in_degree) # [3, 2, 1, 3, 1, 1, 2, 0, 3, 4] 7print(out_degree) # [2, 5, 2, 2, 2, 3, 2, 1, 1, 0] 8 9# 隣接行列を取得する。A[i, j] = 1 ならば、有向辺 (i, j) が存在することを意味する。 10A = nx.to_numpy_array(D) 11print(A) 12# [[0. 1. 0. 0. 0. 0. 0. 0. 1. 0.] 13# [1. 0. 0. 0. 0. 1. 1. 0. 1. 1.] 14# [0. 0. 0. 1. 0. 0. 1. 0. 0. 0.] 15# [0. 0. 1. 0. 0. 0. 0. 0. 1. 0.] 16# [1. 0. 0. 1. 0. 0. 0. 0. 0. 0.] 17# [0. 1. 0. 0. 1. 0. 0. 0. 0. 1.] 18# [1. 0. 0. 1. 0. 0. 0. 0. 0. 0.] 19# [0. 0. 0. 0. 0. 0. 0. 0. 0. 1.] 20# [0. 0. 0. 0. 0. 0. 0. 0. 0. 1.] 21# [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]] 22print(A.sum(axis=0)) # [3. 2. 1. 3. 1. 1. 2. 0. 3. 4.] 23print(A.sum(axis=1)) # [2. 5. 2. 2. 2. 3. 2. 1. 1. 0.]

ノード数が10の有向グラフの場合、隣接行列は (10, 10) なので、2^100 通り考えられ、そのうち、「行ごとの和、列ごとの和が指定した値となる行列」がいくつかあることになります。
ランダムに生成といった場合、まず「2^100 通りから条件を満たす行列を列挙し、ランダムにその中から1つ選ぶ」ということになるので、現実的には難しいのではないでしょうか。

以下、「行ごとの和、列ごとの和が指定した値となる」という条件で整数計画問題で解いた例
条件を満たす1つの解はでてきますが、全部の解を列挙するといったことはできません。

python

1import networkx as nx 2from pulp import * 3 4D = nx.gnm_random_graph(10, 20, seed=42, directed=True) 5in_degree = [deg for node, deg in D.in_degree()] 6out_degree = [deg for node, deg in D.out_degree()] 7 8# モデルを作成する。 9model = LpProblem( 10 name="generate digraph with specific sequence of indege and out degree.", 11 sense=LpMaximize, 12) 13 14# # 変数を作成する。 15X = np.array([[LpVariable(f"{i}{j}", cat=LpBinary) for j in D.nodes] for i in D.nodes]) 16 17# 制約を設定する。 18 19# (1) 入次数が一致している必要がある。 20for j, deg in zip(range(len(D.nodes)), in_degree): 21 model += lpSum(X[:, j]) == deg 22 23# (2) 出次数が一致している必要がある。 24for i, deg in zip(range(len(D.nodes)), out_degree): 25 model += lpSum(X[i]) == deg 26 27# モデルを表示する。 28# print(model) 29 30# 解く。 31ret = model.solve() 32print("status", LpStatus[ret]) # status Optimal 33 34# 解けた場合は結果を表示する。 35if ret == 1: 36 A2 = np.vectorize(lambda x: x.value())(X) 37 print(A2) 38# [[1. 0. 0. 0. 1. 0. 0. 0. 0. 0.] 39# [1. 1. 0. 1. 0. 0. 0. 0. 1. 1.] 40# [0. 1. 0. 1. 0. 0. 0. 0. 0. 0.] 41# [1. 0. 0. 0. 0. 0. 0. 0. 0. 1.] 42# [0. 0. 0. 0. 0. 0. 1. 0. 1. 0.] 43# [0. 0. 0. 1. 0. 0. 1. 0. 1. 0.] 44# [0. 0. 1. 0. 0. 0. 0. 0. 0. 1.] 45# [0. 0. 0. 0. 0. 1. 0. 0. 0. 0.] 46# [0. 0. 0. 0. 0. 0. 0. 0. 0. 1.] 47# [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]] 48 # 入次数、出次数が一致するかどうか 49 print(np.array_equal(in_degree, A.sum(axis=0))) # True 50 print(np.array_equal(out_degree, A.sum(axis=1))) # True

投稿2019/06/25 07:41

tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問