ZDDを用いたパスの列挙と索引生成
○ 川原 純 斎藤 寿樹 湊 真一 吉仲 亮
(JST ERATO 研究員) (JST ERATO 研究員) (JST ERATO 研究員)
(北海道大学・JST ERATO総括)
他、関わっている人 井上 武(ERATO)、岩下 洋哲(ERATO)、鈴木 拡(北海道大学)、 鶴間 浩二(ERATO)
(50音順)
パスの列挙
• 入力:グラフG=(V, E),2頂点 s, t
• 出力:s からt への全てのパス
3×3のグリッドグラフ
s
t
応用
• 地理情報処理
• ネットワークや論理回路の信頼性評価
• ソフトウェアのフローチャートを網羅する
テストケース作成
• Fisher’s Exact Test (統計の分野)
(故障検査)
他にもたくさん
既存研究と関連研究
• 既存研究
– バックトラックを用いたアルゴリズム • 一つあたり O(|V| + |E|) 時間 [Read and Tarjan, 75]
• 関連研究
– パスの数え上げ • #P完全問題
• Baxのアルゴリズム[Bax, 94]
• BDDを用いたパスのカウンティング[Sekine and Imai, 97]
(以下、Read の アルゴリズムと呼ぶ)
これまでの研究の流れ(1)
• 2010年10月
– The Art of Computer Programming 4-1 を読む輪講で
ZDD を用いたパスの列挙アルゴリズムが紹介される • 次の週、川原がC#で実装
• 2010年11月
– ZDD の代数演算のみで列挙するシンプルな
手法を考える(遅い) • ERATO合宿で発表
• 2011年1月
– 改良手法を考える 2月に冬のLAシンポジウムで発表 3月にアルゴリズム研究会
これまでの研究の流れ(2)
• 2010年10月 輪講で紹介
• 2010年11月 ZDDの代数演算のみの手法
• 2011年1月 ↑の改良
• 2011年3月 パス列挙技法をパズルに応用
– ゲーム・パズル研究集会で発表
• 2011年4月 ネットワークの信頼性評価への応用を検討
– 既存手法で Knuth の Alg. に似た手法が見つかる
発表の内容
• Knuth のアルゴリズム Simpath の紹介
• ZDDの代数演算のみを用いた手法(Mate-ZDD)の紹介
• 両者の中間の手法(Hybrid)の紹介
• 実験
• ネットワーク信頼性評価への応用
s e1
t
Knuth によるアルゴリズム Simpath
1. 枝に順番を付ける (例えば、s から幅優先)
e2
e3
e4
e5
枝 e1, e2,… の順に処理
2. 2分木を構築
e1 e1 = 0
e2 e2 = 0
e4
e2 e2 = 1 e2 = 0 e2 = 1
e1 = 1
e5
各枝変数 ei に対し、 ei = 0 or 1 を決めていく
(もっと良い方法もあり)
e3 e3 e3 e3 0 1
s e1 t
e2
e3
e4
e5
ei = 1 である枝が s-t パスになっているか?
s-t パスになっている 1
s e1
t
Knuth によるアルゴリズム Simpath
1. 枝に順番を付ける (例えば、s から幅優先)
e2
e3
e4
e5
枝 e1, e2,… の順に処理
2. 2分木を構築
e1 e1 = 0
e2 e2 = 0
e4
e2 e2 = 1 e2 = 0 e2 = 1
e1 = 1
e5
各枝変数 ei に対し、 ei = 0 or 1 を決めていく
(もっと良い方法もあり)
e3 e3 e3 e3 0 1
s e1 t
e2
e3
e4
e5
ei = 1 である枝が s-t パスになっているか?
s-t パスに なっていない 0
s e1 t
e2
e3
e4
e5
s-t パス + 余分な枝 0
s e1
t
Knuth によるアルゴリズム Simpath
1. 枝に順番を付ける (例えば、s から幅優先)
e2
e3
e4
e5
枝 e1, e2,… の順に処理
2. 2分木を構築
e1 e1 = 0
e2 e2 = 0
e4
e2 e2 = 1 e2 = 0 e2 = 1
e1 = 1
e5
各枝変数 ei に対し、 ei = 0 or 1 を決めていく
(もっと良い方法もあり)
e3 e3 e3 e3 0 1
1 1 他は0 1 1
が1つのパスに対応 1
2分木は全パスを保持している
Knuth によるアルゴリズム Simpath
s e1
t
e2
e3
e4
e5
木の枝刈り
e1 e1 = 0
e2 e2 = 0
e2
e1 = 1
0
e1 = 0 かつ e2 = 0 なら s-t パスができることはない
Knuth によるアルゴリズム Simpath
s e1
t
e2
e3
e4
e5
木の枝刈り
e1 e1 = 0
e2 e2 = 0
e2 e2 = 1 e2 = 0
e1 = 1
0
e1 = 0 かつ e2 = 0 なら s-t パスができることはない
e3 0 1
e4 0 1
e1 = 1 かつ e3 = 1 かつ e4 = 1 なら s-t パスができることはない
0
(分岐が生じる)
1
… …
…
… 木の枝刈りを行っても 場合の数は指数爆発
Knuth によるアルゴリズム Simpath
e8
e9 0
0 e10
0 e11
0 1
s e1 t
e2
e4
e3 e10
e5
e6 e7
e9
e8
e11 e8 s t
e11
e9
e10
e8 s t
e11
e9
e10
e8
e9 0
0 e10
0 e11
0 1
e8
s t
e11
e9
e10
以下の2つからは同じ木が生成される
Knuth によるアルゴリズム Simpath
e8
e9 0
0 e10
0 e11
0 1
s e1 t
e2
e4
e3 e10
e5
e6 e7
e9
e8
e11
e8
e9 0
0 e10
0 e11
0 1
e7
…
… …
…
e7
…
…
…
e8
s t
e11
e9
e10
Knuth によるアルゴリズム Simpath
e8
e9 0
0 e10
e11
0 1
s e1 t
e2
e4
e3 e10
e5
e6 e7
e9
e8
e11
e8
e9 0
0 e10
0 e11
0 1
e7
…
… …
…
e7
…
…
…
同じ形をもつ子は共有したい
…
e8
s t
e11
e9
e10
Knuth によるアルゴリズム Simpath
s e1 t
e2
e4
e3 e10
e5
e6 e7
e9
e8
e11
e7
…
… …
…
e7
…
…
…
e8 s t
e11
e9
e10
e8 s t
e11
e9
e10
e8
7 6
e8 s t
e11
e9
e10
5
6 は s とつながっている 5 は 7 とつながっている
e7 = 0 e7 = 1
e8
7 6
5
7 6
5
共有する
e7 e7
Knuth によるアルゴリズム Simpath
7 6
s t 5
接続情報の記憶法
1 2
3
4 8
9
mate 配列
頂点がパスの端
1 2 3 4 5 6 7 8 9 i
mate[i]
逆端の番号
自身の番号 頂点がいずれの パスにも含まれない
頂点がパスの途中 0
6 0 0 0 7 1 5 8 9
Knuth によるアルゴリズム Simpath
7
s t
6
5
接続情報の記憶法
1 2
3
4 8
9
mate 配列
頂点がパスの端
1 2 3 4 5 6 7 8 9
6 0 0 0 7 1 5 8 9
i
mate[i]
逆端の番号
自身の番号 頂点がいずれの パスにも含まれない
頂点がパスの途中 0
どの頂点の接続情報を覚えればよいか?
ei 枝 i を処理するとき、 枝 i に接続している頂点を「訪れた」と表現する
F := {訪れたことのある頂点} {二度と訪れない頂点}
F を frontier という。 frontier 頂点の接続情報を覚える
frontier
この部分のみ記憶
e8 e8
Knuth によるアルゴリズム Simpath
s e1 t
e2
e4
e3 e10
e5
e6 e7
e9
e8
e11
e7
…
… …
…
e7
…
…
…
e8 s t
e11
e9
e10
e8 s t
e11
e9
e10
7 6
e8 s t
e11
e9
e10
5
e7 = 0 e7 = 1
7 6
5
7 6
5 e7 e7
5 6 7 i
mate[i] 7 1 5
5 6 7 i
mate[i] 7 1 5
frontier の部分の mate が同じなら共有する
Knuth によるアルゴリズム Simpath
s e1 t
e2
e4
e3 e10
e5
e6 e7
e9
e8
e11
e1
…
1
1
e2 e2
1 2
1 2
1 2
2 1
0 e3
1 2 3
3 2 1
1
2
3
4
5
6
7
e3 0
1 2 3
2 1 3
e4
1 2 3 4
4 0 3 1 一般に
ex
ex+1
c
d
a
b ex
a b c d
c d a b
mate の更新
a b c d
0 0 d c
最大4か所書きかえれば更新できる
忘れてよい
Knuth によるアルゴリズム Simpath
Simpath では、(既約とは限らない)ZDD を構築している
→ 既約化アルゴリズムによって、 節点サイズに比例する時間で既約化できる
したがって、パスの列挙だけでなく、 ・ 列挙した結果を圧縮して保持 ・ 列挙したパスの索引生成 ・ 列挙した結果から条件を満たすパスを得る もできたことになる
e7
e8 0
0 e9
0 e10
0 1
e6
…
… e6
… e7
e8 0
0 e9
0 e10
0 1
e1 e1 = 0
e2 e2 = 0 e2 = 1
0 …
節点の削除 節点の共有
s
t
4
5
6
e1
e3
e4
1
2 3
7
8
各頂点のペア (i, j) ごとに変数 mi, j を用意する
m14 = 1, m56 = 1, m77 = 1,…
m11 = 0, m12 = 0,…
i, j が1本のパスの両端なら mi, j = 1
そうでないなら mi, j = 0
e6
ZDD の代数演算のみを用いて、ZDD を構築できないか?
Mate-ZDD 法(提案手法)
s
t
4
5
6
e1
e3
e4
1
2 3
7
8
i, j が1本のパスの両端なら mi, j = 1
選ばれた枝+mate を集合として表す
{e1, e3, e4, m14, m56, m33,…}
e6
Mate-ZDD 法(提案手法)
Mate-ZDD 法(提案手法)
s
t
4
5
6
e1
e3
e4
1
2 3
7
8
e6 まで処理済み、次は e7
{e1, e3, e4, m14, m56, m33,…}
e6
e7 = 0 なら mate は変化なし
e7 = 1 なら m14 → m17
{e1, e3, e4, e7, m17, m56, m33,…}
e7 s
t
4
5
6
e1
e3
e4
1
2 3
7
8 e6
e7
e7 = 1
e6 の処理が終わった時点での全状態を集めたものを考える
s
t
4
5
6
e1
e3
e4
1
2 3
7
8 e6
{e1, e3, e4, m14, m56, m33,…}
s
t
4
5
6
e1
e3
e4
1
2 3
7
8 e6
{e1, e3, m14, m25, m33,…}
これらの全状態に対して、先ほどの操作を行いたい
s
t
4
5
6
e1
e3
e4
1
2 3
7
8 e6
{e2, e3, m15, m44,…}
…
…
Mate-ZDD 法(提案手法)
集合の集合(集合族)は ZDD で効率よく保持できる
{{a, b, c, d}, {a, c}, {b, c}, {b, d}}
a 0 1
b
c
d
1
0 は省略
c
1
b
c
1 d
1
ZDD と集合族
a を含む集合だけを取り出し、a を消去する
ZDD と集合族
{{a, b, c, d}, {a, c}, {b, c}, {b, d}} {{b, c, d}, {c}}
a 0 1
b
c
d
1
c
1
b
c
d
1
トップの要素なら簡単にできる
b
c
d
1
c
1
集合族への操作例:
a を含まない集合だけ 取り出すなら、LO 枝側を もってこればよい
1
ZDD と集合族
c を含む集合だけを取り出し、c を消去する
{{a, b, c, d}, {a, c}, {b, c}, {b, d}} {{a, b, d}, {a}, {b}}
a 0 1
b
c
d
1
c
1
b
c
1 d
1
トップでなければ、その変数の深さまで潜って、 枝の付け替えを行う
a 0 1
b
c
d
1
c
1
b
c
1 d
1
集合族への操作例:
ZDD と集合族
c を含む集合だけを取り出し、c を消去する
{{a, b, c, d}, {a, c}, {b, c}, {b, d}} {{a, b, d}, {a}, {b}}
a 0 1
b
c
d
1
c
1
b
c
d
1
トップでなければ、その変数の深さまで潜って、 枝の付け替えを行う
a 0 1
b
c c
b
c
d
1
1
集合族への操作例:
c を含まない集合だけ 取り出すなら、LO 枝の 方に付け替えればよい
d
1
1 1 0 0
ZDD と集合族
e を各要素に追加する
{{a, b, c, d}, {a, c}, {b, c}, {b, d}}
集合族への操作例:
{{a, b, c, d, e}, {a, c, e}, {b, c, e}, {b, d, e}}
a 0 1
b
c
d
1
c
1
b
c
1 d
1
a
b
c
d
1
c
1
b
c
1 d
1
e
トップに加える場合
ZDD と集合族
e を各要素に追加する
{{a, b, c, d}, {a, c}, {b, c}, {b, d}}
集合族への操作例:
{{a, b, c, d, e}, {a, c, e}, {b, c, e}, {b, d, e}}
a 0 1
b
c
d
1
c
1
b
c
d
1
a
b
c
d
1
c
1
b
c
1 d
1
e
間に加える場合
e e
e
1
ZDD と集合族
{{a, b, c, d}, {a, c}, {b, c}, {b, d}}
集合族を積と和で表現すると見やすい
abcd + ac + bc + bd
e を各要素に追加する (abcd + ac + bc + bd) × e = abcde + ace + bce + bde
a を含む集合だけを取り出し、 a を消去する
(abcd + ac + bc + bd) = a(bcd + c) + bc + bd
なので、
a を含まない集合だけを取り出し、 a を消去する
(abcd + ac + bc + bd) / a = bcd + c
(abcd + ac + bc + bd) % a = bc + bd (多項式の除算、剰余算)
Mate-ZDD 法(提案手法)
e6 の処理が終わった時点での全状態を集めたものを考える
s
t
4
5
6
e1
e3
e4
1
2 3
7
8 e6
f = e1e3e4m14m56m33 +
s
t
4
5
6
e1
e3
e4
1
2 3
7
8 e6
e1e3m14m25m33 +
これらの全状態に対して、先ほどの操作を行いたい
s
t
4
5
6
e1
e3
e4
1
2 3
7
8 e6
e2e3m15m44 +
…
…
集合族を ZDD で表したものを f とする
Mate-ZDD 法(提案手法)
e6 の処理が終わった時点での全状態を集めたものを考える
これらの全状態に対して、先ほどの操作を行いたい
f = f + f / m14 × e7 × m17
e7 を追加 m17 を追加
m14 を含むものを取り出し、 m14 を削除
m14 → m17 の付け替え演算
f = e1e3e4m14m56m33 + e1e3m14m25m33 + e2e3m15m44 + …
初期値 f = m11 × m22 × m33 × ...
f = f + f × e / mik / mjl × mkl
frontier の中の各頂点 k,l について
頂点 p を二度と訪れないならば 各 k = p について f = f % mpk (頂点 p の次数が1の項は削除)
f = f / mpp + f % mpp (mpp 変数の除去)
最後に f = f / mst
各枝 e = {i, j} について
frontier を計算
Mate-ZDD 法(提案手法)
アルゴリズム
e
i k
j l
p k
e
i k
j l
変数は ZDD のトップに追加する方が計算が早いので、 Mate-ZDD 法では、先に処理した枝変数を ZDD の下にするのがよい
m11
m 変数は頻繁に操作されるので、e 変数の上に するのがよい
m22
…
e1 処理 m11
m12
…
m11
e1 e1
e2 処理
m11
m12
…
m11
e1 e1
e2 e2
(ボトムアップ的) (Simpath はトップダウン的)
Mate-ZDD 法の変数順
Mate-ZDD 法の変数順
…
e1 e2
… e 変数
m 変数
{e1, e3, e4, m14, m56, m33}
m56
m33
m14
e4
e3
e1
1
上段で m 変数の集合、すなわち mate を表している。 ある mate 値をもつ e 変数の集合がぶら下がっている
…
…
e1 e2
… e 変数
m 変数
フロンティアの2乗の個数の m 変数が存在し、 それらを更新しなければならない
フロンティアの2乗の段数
Mate-ZDD 法の変数順
…
e1 e2
… e 変数
{e1, e3, e4, m14, m56, m33}
e4
e3
e1
1
mate の管理に、m 変数ではなく、 (Simpath で使われている)配列を用いる
4 0 3 1 6 5 7 8 9 10 11 12
速度は Simpath と Mate-ZDD 法の中間くらいになる(と期待される)
Hybrid 法
Hybrid 法のメリット
…
e1 e2
… e 変数
{e1, e3, e4, m14, m56, m33}
e4
e3
e1
1
枝に制約条件を加えて、列挙を行うことが容易になる。
4 0 3 1 6 5 7 8 9 10 11 12
例えば、e3 と e4 の少なくとも一方の枝を使うという条件なら
F = F / e3 × e3 + F / e4 × e4
の演算を e4 の処理時に全体に施せばよい。
mate 配列に所属する e 変数がなくなれば、mate 配列を削除できる
0
頂点数 CyPath Simpath Mate-ZDD Hybrid Mate-ZDD法の
ZDDノード数 パスの数
日本地図 47 > 1000 0.02 <0.01 <0.01 951 1.4 × 1010
2重化 94 > 1000 40.64 248.72 340.77 18,971,787 5.0 × 1044
(単位:秒)
CyPath: Read ‘75 のalg. Simpath: Knuth のalg. Mate-ZDD: 提案手法 Hybrid: 提案手法
14797272518 本
5039760385115189594214594926092397238616064 本 (= 503正9760澗3851溝1518穣9594杼2145垓9492京6092兆3972億3861万6064)
実験結果 日本地図グラフ
北海道から鹿児島までの全パス
日本地図グラフの頂点を 2倍に増やしたグラフ
L 頂点数 CyPath Simpath Mate-ZDD Hybrid Mate-ZDD法の
ZDDノード数 パスの数
8 64 > 1000 0.17 0.28 0.11 3.1 × 104 7.8 × 1011
9 81 > 1000 0.48 1.58 0.32 1.1 × 105 3.2 × 1015
10 100 > 1000 1.40 5.69 1.75 3.7 × 105 4.1 × 1019
11 121 > 1000 3.50 24.49 8.37 1.2 × 106 1.5 × 1024
12 144 > 1000 10.29 92.96 30.77 4.2 × 106 1.8 × 1029
L × L グリッド
・・・
・・・
・・・
・ ・ ・
・ ・ ・
・ ・ ・
L
L
(単位:秒)
実験結果
s
t
CyPath: Read ‘75 のalg. Simpath: Knuth のalg. Mate-ZDD: 提案手法 Hybrid: 提案手法
n CyPath Simpath Mate-ZDD Mate-ZDD法の
ZDDノード数 パスの数
10 < 0.01 < 0.01 < 0.01 4.7 × 102 5.8 × 102
15 0.42 < 0.01 0.16 1.6 × 104 1.1 × 105
16 49.61 1.30 23.28 1.1 × 105 5.3 × 107
17 > 1000 2.42 70.10 2.3 × 106 8.1 × 107
18 > 1000 6.48 213.94 8.1 × 106 7.1 × 108
n 頂点ランダムグラフ、枝の生成確率 0.5
(単位:秒)
実験結果 CyPath: Read ‘75 のalg. Simpath: Knuth のalg. Mate-ZDD: 提案手法 Hybrid: 提案手法
マルチパスの列挙
s1
t2
s2
t1
s1 - t1 パス
s2 - t2 パス の組を全列挙 交差しない
ms1t1 と ms2t2 と ms3t3 を含む集合を 残せばよい s3
t3 s3 - t3 パス
条件付きパス(サイクル)の列挙
1 e1
e2
e3
e4 f = f + f / e4 % e3 % e2 % e1) * e4 + (f % e4 / e3 % e2 % e1) * e3 + (f % e4 % e3 / e2 % e1) * e2 + (f % e4 % e3 % e2 / e1) * e1
条件付きパス(サイクル)の列挙
連結部分グラフの列挙
s
e1
t
e2 e3
e4 e10
e5 e6
e7
e8 e9
s と t が連結になるような 部分グラフを列挙 → ネットワーク信頼性評価への応用
s
t
4
5
6
e1
e3
e4
1
2 3
7
8 e6
e7 4 は 1 と同じ連結成分 5 は 6 と同じ連結成分
まとめ
• s-t-パスを列挙するアルゴリズム
– Simpath (Knuth)
– Mate-ZDD (提案手法)
– Hybrid 法 (提案手法)
• 今後の課題
– 計算時間の解析
– 頂点の順序付け
– 様々な条件下での列挙