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 11:04 編集
2019/06/26 06:04