• 検索結果がありません。

部分グラフ 与えられたグラフの一部分からなるグラフ 与えられたグラフ 経路 ( パス ) や全域木などは部分グラフ 部分グラフの例 部分グラフ列挙 与えられた条件を満たす部分グラフをすべて求める 例 : から までの 同じ頂点を通らない経路は? - 経路 (- パス ) 全域木 5 6 部分グラフ列

N/A
N/A
Protected

Academic year: 2021

シェア "部分グラフ 与えられたグラフの一部分からなるグラフ 与えられたグラフ 経路 ( パス ) や全域木などは部分グラフ 部分グラフの例 部分グラフ列挙 与えられた条件を満たす部分グラフをすべて求める 例 : から までの 同じ頂点を通らない経路は? - 経路 (- パス ) 全域木 5 6 部分グラフ列"

Copied!
18
0
0

読み込み中.... (全文を見る)

全文

(1)

graphillion - 莫大な数の部分

グラフを扱う Python ライブラリ

奈良先端科学技術大学院大学

川原 純

謝辞 本スライドで使用している図の一部と全適用事例は発売予定の書籍 「超高速グラフ列挙アルゴリズム」(仮題) のドラフト版から引用しています。図の引用は「ZDD書籍から引用」と明示しています。 graphillion ライブラリの作者 井上 武 さん,岩下 洋哲 さん 書籍の著者 湊 真一 先生,斎藤 寿樹 先生,安田 宜仁さん,井上 武 さん, 羽室 行信 先生,前川 浩基 さん,丸橋 弘明 さん,堀山 貴史 先生,その他の著者の皆様, JST ERATO 湊離散構造処理系プロジェクトメンバーの皆様に感謝いたします。

今日の内容

graphillion ライブラリの紹介

graphillion ライブラリでできること

graphillion の内部データ構造

• ZDD

graphillion が使用しているアルゴリズム

• フロンティア法

適用事例紹介 (1), (2), (3)

2

graphillion とは

部分グラフ列挙ツール

グラフに関する様々な最適化問題を解く

http://graphillion.org

NTT研究所 井上 武 氏 作 3

graphillion とは

部分グラフ列挙ツール

グラフに関する様々な最適化問題を解く

グラフ 路線図 知り合い関係

グラフとは

「もの」と、「もの」のつながりを 抽象化して表したもの 頂点 辺 地図(の隣接関係)

http://graphillion.org

NTT研究所 井上 武 氏 作 4

(2)

部分グラフ

与えられたグラフの一部分からなるグラフ

経路(パス)や全域木などは部分グラフ

s t

s-t 経路(s-t パス)

全域木

与えられたグラフ 部分グラフの例 5

部分グラフ列挙

与えられた条件を満たす部分グラフを

すべて

求める

例:

s から t までの、 同じ頂点を通らない経路は?

s

t

6

部分グラフ列挙

与えられた条件を満たす部分グラフを

すべて

求める

例:

s から t までの、 同じ頂点を通らない経路は? 全体グラフ (universe) 部分グラフ

s

t

7

部分グラフ列挙

与えられた条件を満たす部分グラフを

すべて

求める

例:

s

t

全体グラフ (universe)

列挙して何が嬉しいのか?

後述

8

(3)

graphillion を使ってみよう(1)

インストール

(Mac, Linux)

python インタプリタを起動

ライブラリのインポート

$ easy_install graphillion

>>> from graphillion import GraphSet $ python

http://graphillion.org

または、 からダウンロード、ビルド 9

graphillion を使ってみよう(2)

グラフの表現

networkx ライブラリと同じ

全体グラフの設定

頂点: オブジェクト

(何でもよい) 2 3 4 5 6 7 8

辺: 頂点のタプル

(1, 2) や (2, 3) など

グラフ: 辺のリスト

[(1, 2), (1, 4), (2, 3), (2, 5), (3, 6), (4, 5), (4, 7), (5, 6), (5, 8), (6, 9), (7, 8), (8, 9)] >>> GraphSet.set_universe( [(1, 2), (1, 4), (2, 3), (2, 5), (3, 6), (4, 5), (4, 7),(5, 6), (5, 8), (6, 9), (7, 8), (8, 9)] ) 全体グラフ (universe)

s = 1

t = 9

本講演では1,2,3,... 10 >>> paths = GraphSet.paths(1, 9)

graphillion を使ってみよう(3)

s-t 経路を列挙する

paths 変数に、部分グラフの集合が格納される 引数に始点と終点 2 3 4 5 6 7 8 全体グラフ (universe)

s = 1

t = 9

11

graphillion でできること(1)

数のカウント

各部分グラフに対する処理

>>> for p in paths: ... print p 2 3 4 5 6 7 8 全体グラフ (universe)

s = 1

t = 9

>>> print paths.len() 12 12

(4)

>>> for p in paths: ... print p ... [(1, 2), (2, 3), (3, 6), (4, 5), (4, 7), (5, 6), (7, 8), (8, 9)] [(1, 2), (2, 3), (3, 6), (5, 6), (5, 8), (8, 9)] [(1, 2), (2, 3), (3, 6), (6, 9)] [(1, 2), (2, 5), (4, 5), (4, 7), (7, 8), (8, 9)] [(1, 2), (2, 5), (5, 6), (6, 9)] [(1, 2), (2, 5), (5, 8), (8, 9)] [(1, 4), (2, 3), (2, 5), (3, 6), (4, 5), (6, 9)] [(1, 4), (2, 3), (2, 5), (3, 6), (4, 7), (5, 8), (6, 9), (7, 8)] [(1, 4), (4, 5), (5, 6), (6, 9)] [(1, 4), (4, 5), (5, 8), (8, 9)] [(1, 4), (4, 7), (5, 6), (5, 8), (6, 9), (7, 8)] [(1, 4), (4, 7), (7, 8), (8, 9)]

graphillion でできること(1)

数のカウント

各部分グラフに対する処理

>>> print paths.len() 12 2 3 4 5 6 7 8 全体グラフ (universe)

s = 1

t = 9

13

graphillion でできること(2)

経路の短い順に、各部分グラフを処理

>>> for p in paths.min_iter(): ... print p ... [(1, 4), (4, 7), (7, 8), (8, 9)] [(1, 4), (4, 5), (5, 8), (8, 9)] [(1, 4), (4, 5), (5, 6), (6, 9)] [(1, 2), (2, 5), (5, 8), (8, 9)] [(1, 2), (2, 5), (5, 6), (6, 9)] [(1, 2), (2, 3), (3, 6), (6, 9)] [(1, 4), (4, 7), (5, 6), (5, 8), (6, 9), (7, 8)] [(1, 4), (2, 3), (2, 5), (3, 6), (4, 5), (6, 9)] [(1, 2), (2, 5), (4, 5), (4, 7), (7, 8), (8, 9)] [(1, 2), (2, 3), (3, 6), (5, 6), (5, 8), (8, 9)] [(1, 4), (2, 3), (2, 5), (3, 6), (4, 7), (5, 8), (6, 9), (7, 8)] [(1, 2), (2, 3), (3, 6), (4, 5), (4, 7), (5, 6), (7, 8), (8, 9)] 2 3 4 5 6 7 8 全体グラフ (universe)

s = 1

t = 9

14

graphillion でできること(3)

(一様)ランダムに1つ抽出

頂点5を通る経路のみを抽出

>>> p = paths.choice() >>> print p [(1, 2), (2, 3), (3, 6), (4, 5), (4, 7), (5, 6), (7, 8), (8, 9)] >>> paths2 = paths.including(5) 2 3 4 5 6 7 8 全体グラフ (universe)

s = 1

t = 9

15

graphillion でできること(4)

さらに、頂点3を通らない

経路のみを抽出

>>> paths3 = paths2.excluding(3) 2 3 4 5 6 7 8 全体グラフ (universe)

s = 1

t = 9

16

(5)

graphillion でできること(5)

辺に重みをつけて、重みの和が

最大・最小の部分グラフを求める

>>> weights = {} >>> weights[(1, 2)] = 3.2 >>> weights[(1, 4)] = 1.7 # (略) >>> weights[(8, 9)] = 6.2 >>> >>> iter = paths3.max_iter(weights) >>> p1 = iter.next() >>> p2 = iter.next() 辺の重みは、辺をキー、重みをバリューとするディクショナリで与える 一番長い経路 二番目に長い経路 2 3 4 5 6 7 8 全体グラフ (universe)

s = 1

t = 9

3.2 1.7 6.2 ... 17

graphillion の威力(1)

JR(Japan Railway)の路線図

頂点数: 4534, 辺数: 4646 最北駅(稚内)~最南駅(西大山) の経路 計算時間: 258.16 秒 >>> GraphSet.set_universe(jrmap) >>> weights = read_weights() >>> >>> paths = GraphSet.paths(“1111553”, “1193021”) >>> paths.len() 1112870539692503649611518720 経路は圧縮して保持されている 使用メモリ: 12.4 GB データ取得: 駅データ.jp http://ekidata.jp

Intel Xeon E5-1620 3.60GHz

ZDD書籍から引用18

graphillion の威力(2)

JR(Japan Railway)の路線図

頂点数: 4534, 辺数: 4646 最北駅(稚内)~最南駅(西大山) の経路 >>> max_path = paths.max_iter(weights).next() >>> print len(max_path) 2650 >>> sum = 0.0

>>> for edge in max_path: ... sum += weights[edge] ... >>> print sum 10337.3 最長経路を求める 駅数 ― 1 総距離 最短経路も求まるが、ダイクストラ法などの既存アルゴリズムの方が速い ZDD書籍から引用 19

graphillion で扱える部分グラフの種類

経路

s-t 経路

ハミルトン経路(すべての頂点を通る)

サイクル(1周して戻る)

森、全域森

木、全域木

連結成分

マッチング

クリーク

(頂点同士がすべて結ばれている頂点集合)

その他、様々な制約を課した部分グラフ

20

(6)

今日の内容

graphillion ライブラリの紹介

graphillion ライブラリでできること

graphillion の内部データ構造

• ZDD

graphillion が使用しているアルゴリズム

• フロンティア法

適用事例紹介 (1), (2), (3)

21

graphillion で用いられるデータ構造

Zero-suppressed Binary Decision Diagram (ZDD)

集合族(集合の集合)をコンパクトに効率良く記憶

{e1, e2, e5}, {e1, e3, e4, e7}, {e1, e5, e8, e12}, {e3, e7, e9}, {e2, e6, e7, e8, e9, e10}, {e4}, {e1, e4, e6, e8}, {e1, e2, e5, e8}, {e1, e9, e10}, {e4, e5, e9}, {e1, e3, e4, e5, e9, e11}, {e6, e7}, {e1, e4, e5}, {e1, e5, e8, e10}, {e2, e5, e11}, {e5, e8, e9}, {e2, e3, e7, e8}, {e10, e11, e12}, … 特殊な形をしたグラフ

ZDD

ゼロサプレス型二分決定グラフ [S.Minato 93] 22

{

}

e

1

e

2

e

2

e

4

e

5

e

4

e

3

,

,

e

3

,

e

5

e

5

e

5

e

5

,

{

}

{

} {

}

{

} {

}

{

}

ZDD

集合族

0

1

1

0

e

1

e

2

e

3

e

4

e

5

e

3

e

3

ZDD の基本 要素は {e

1

, e

2

, e

3

, e

4

, e

5

} の5種類で固定 (事前に固定する必要あり) 23

{

}

e

2

e

2

e

4

e

5

e

4

e

3

,

,

e

3

,

e

5

e

5

e

5

e

5

,

{

} {

}

{

} {

}

{

}

ZDD

0

: 0 終端 (0-terminal)

1

: 1 終端 (1-terminal)

それぞれ

1つずつもつ

e

i

: ノード

e

1

e

5

いずれかのラベル

e

1

, e

2

,…, e

5

の順序

0

1

1

0

e

1

e

2

e

3

e

4

e

5

e

3

e

1

{

e

3

}

root ZDD の基本 24

(7)

{

}

e

2

e

2

e

4

e

5

e

4

e

3

,

,

e

3

,

e

5

e

5

e

5

e

5

,

{

} {

}

{

} {

}

{

}

ZDD

ノードは0枝と1枝を1つずつもつ

e

i

: ノード

e

1

e

5

いずれかのラベル

e

1

, e

2

,…, e

5

の順序

0

1

1

0

e

1

e

2

e

3

e

4

e

5

e

3

e

1

{

e

3

}

0

: 0 終端 (0-terminal)

1

: 1 終端 (1-terminal)

それぞれ

1つずつもつ

root ZDD の基本 25

0

1

1

0

e

1

e

2

e

3

e

4

e

5

e

3

{

}

e

2

e

2

e

4

e

5

e

4

e

3

,

,

e

3

,

e

5

e

5

e

5

e

5

,

{

} {

}

{

} {

}

{

}

ZDD

0 : 0-terminal 1 : 1-terminal

e

i : node with label

ノードは0枝と1枝を1つずつもつ

1つの集合が、

root から

までの1本のパスに対応

e

1

{

e

3

}

root

e

1 ~

e

5 1 ZDD の基本 26

0

1

1

0

e

1

e

2

e

3

e

4

e

5

e

3

{

}

e

2

e

2

e

4

e

5

e

4

e

3

,

,

e

3

,

e

5

e

5

e

5

e

5

,

{

} {

}

{

} {

}

{

}

ZDD

ノードは0枝と1枝を1つずつもつ

1つの集合が、

root から

までの1本のパスに対応

0 : 0-terminal 1 : 1-terminal

e

i : node with label

e

1 ~

e

5

e

1

{

e

3

}

root 1 ZDD の基本 27

0

1

1

0

e

1

e

2

e

3

e

4

e

5

e

3

{

}

e

2

e

2

e

4

e

5

e

4

e

3

,

,

e

3

,

e

5

e

5

e

5

e

5

,

{

} {

}

{

} {

}

{

}

ZDD

ノードは0枝と1枝を1つずつもつ

1つの集合が、

root から

1

までの1本のパスに対応

0 : 0-terminal 1 : 1-terminal

e

i : node with label

e

1

{

e

3

}

root

e

1 ~

e

5 ZDD の基本 28

(8)

e

1

e

1

= 0

e

2

e

2

= 0

e

4

e

2

e

2

= 1 e

2

= 0

e

2

= 1

e

1

= 1

e

5

e

3

e

3

e

3

e

3

0

1

1

1

1

1

他は 0

{

}

e

2

e

2

e

4

e

5

e

4

e

3

,

,

e

3

,

e

5

e

5

e

5

e

5

,

{

} {

},

{

} {

}

{

}

1

1

e

5

{

}

{

e

3

e

5

}

ZDD は2分木を圧縮したものとみなすことができる

ZDD

0

1

1

0

e

1

e

2

e

3

e

4

e

5

e

3

e

1

{

e

3

}

ZDD の基本 29

ノード共有ルール

1 0 ... ... 2つの「等価な」ノードは 共有される 1 0 ... ...

ゼロサプレスルール

1 0 ... ... 1-枝が0-Terminalを指す ノードは削除される 1 0 ... ... ei ZDD の基本 2種類のルールを 繰り返し適用して圧縮 30

ZDDの演算

ZDD を用いると、集合演算や、要素の検索等、様々な演算が

効率良く行える

和集合を求める(union)

{e1, e2, e5}, {e1, e3, e4, e7}

{e1, e4}, {e1, e3, e4, e7}

{e1, e2, e5}, {e1, e4} {e1, e3, e4, e7}

{e1, e2, e5}, {e1, e4} {e1, e3, e4, e7}

{e1, e4} {e1, e3, e4, e7}

要素の抽出 e4 を含む 集合を取り出す アルゴリズムは省略31

今日の内容

graphillion ライブラリの紹介

graphillion ライブラリでできること

graphillion の内部データ構造

• ZDD

graphillion が使用しているアルゴリズム

• フロンティア法

適用事例紹介 (1), (2), (3)

s-t 経路を例に説明

32

(9)

s

e

1

t

e

2

e

3

e

4

e

5

s

e

1

t

e

2

e

3

e

4

e

5

s

e

1

t

e

2

e

3

e

4

e

5

s

e

1

t

e

2

e

3

e

4

e

5

s

e

1

t

e

2

e

3

e

4

e

5

{e

1

, e

4

}

{e

2

, e

5

}

{e

1

, e

3

,e

5

}

{e

2

, e

3

,e

4

}

s-t

経路は辺の集合で表現できる

33

s

e

1

t

e

2

e

3

e

4

e

5

s-t

経路は辺の集合で表現できる

s

e

1

t

e

2

e

3

e

4

e

5

s

e

1

t

e

2

e

3

e

4

e

5

s

e

1

t

e

2

e

3

e

4

e

5

s

e

1

t

e

2

e

3

e

4

e

5

{e

1

, e

4

}

{e

2

, e

5

}

{e

1

, e

3

,e

5

}

{e

2

, e

3

,e

4

}

全ての s-t 経路を列挙して、

辺集合の集合

で表す

34

s

e

1

t

e

2

e

3

e

4

e

5

s-t

経路は辺の集合で表現できる

s

e

1

t

e

2

e

3

e

4

e

5

s

e

1

t

e

2

e

3

e

4

e

5

s

e

1

t

e

2

e

3

e

4

e

5

s

e

1

t

e

2

e

3

e

4

e

5

{e

1

, e

4

}

{e

2

, e

5

}

{e

1

, e

3

,e

5

}

{e

2

, e

3

,e

4

}

全ての s-t 経路を列挙して、

辺集合の集合

で表す

{{e

1

, e

4

},{e

2

, e

5

},{e

1

, e

3

,e

5

},{e

2

, e

3

,e

4

}}

全 s-t 経路の集合 =

35

s

e

1

t

e

2

e

3

e

4

e

5

s-t

経路は辺の集合で表現できる

s

e

1

t

e

2

e

3

e

4

e

5

s

e

1

t

e

2

e

3

e

4

e

5

s

e

1

t

e

2

e

3

e

4

e

5

s

e

1

t

e

2

e

3

e

4

e

5

{e

1

, e

4

}

{e

2

, e

5

}

{e

1

, e

3

,e

5

}

{e

2

, e

3

,e

4

}

全ての s-t 経路を列挙して、

辺集合の集合

で表す

{{e

1

, e

4

},{e

2

, e

5

},{e

1

, e

3

,e

5

},{e

2

, e

3

,e

4

}}

これをZDDで表現する

全 s-t 経路の集合 =

(10)

s

e

1

t

経路列挙(ZDD構築)アルゴリズム [Knuth 08]

1. 辺に順番を付ける

(例えば、s から幅優先)

e

2

e

3

e

4

e

5

辺 e

1

, e

2

,… の順に処理

2. ZDDを構築

e

1

e

1

= 0

e

2

e

2

= 0

e

4

e

2

e

2

= 1 e

2

= 0

e

2

= 1

e

1

= 1

e

5

各辺変数 e

i

に対し、

e

i

= 0 or 1 を決めていく

(もっと良い方法もあり)

e

3

e

3

e

3

e

3

0

1

s

e

1

t

e

2

e

3

e

4

e

5

e

i

= 1 である辺が s-t 経路になっているか?

s-t path

1

37

s

e

1

t

1. 辺に順番を付ける

(例えば、s から幅優先)

e

2

e

3

e

4

e

5

辺 e

1

, e

2

,… の順に処理

2. ZDDを構築

e

1

e

1

= 0

e

2

e

2

= 0

e

4

e

2

e

2

= 1 e

2

= 0

e

2

= 1

e

1

= 1

e

5

各辺変数 e

i

に対し、

e

i

= 0 or 1 を決めていく

(もっと良い方法もあり)

e

3

e

3

e

3

e

3

0

1

s

e

1

t

e

2

e

3

e

4

e

5

e

i

= 1 である辺が s-t 経路になっているか?

s-t経路でない

0

s

e

1

t

e

2

e

3

e

4

e

5

s-t path + 余分な辺

0

経路列挙(ZDD構築)アルゴリズム [Knuth 08]

38

s

e

1

t

1. 辺に順番を付ける

(例えば、s から幅優先)

e

2

e

3

e

4

e

5

辺 e

1

, e

2

,… の順に処理

2. ZDDを構築

e

1

e

1

= 0

e

2

e

2

= 0

e

4

e

2

e

2

= 1 e

2

= 0

e

2

= 1

e

1

= 1

e

5

各辺変数 e

i

に対し、

e

i

= 0 or 1 を決めていく

(もっと良い方法もあり)

e

3

e

3

e

3

e

3

0

1

1

1

1

他は0

1

経路列挙(ZDD構築)アルゴリズム [Knuth 08]

39

経路列挙(ZDD構築)アルゴリズム [Knuth 08]

a

b

c

s

t

e

1

e

2

e

3

e

4

e

5

e

6

… 40

(11)

経路列挙(ZDD構築)アルゴリズム [Knuth 08]

a

b

c

s

t

e

1

e

2

e

3

e

4

e

5

e

6

… 41

f

d

s

a

b

c

d

h

f

g

s

t

a

b

c

d

h

f

g

s

t

f

d

s

経路列挙(ZDD構築)アルゴリズム [Knuth 08]

フロンティア 処理済み辺 未処理辺 部分経路の反対側の端点を記憶しておき、 フロンティア上ですべて一致するなら、 2つは同じ状態とみなす。 42

ZDDの形式で保存

ZDDが構築できれば、経路の全列挙は簡単

top から 1-終端までたどればよい

構築したZDDはコンパクトなので、そのまま保持可能

ZDD演算を行うことで、経路の条件付き検索が可能

{e1, e2, e5}, {e1, e4} {e1, e3, e4, e7}

{e1, e4} {e1,e3, e4, e7}

e4 を通る 経路のみを 取り出す 43 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 2 2 1 1 1 1 2 2 2 4 1 2 3 3 2 4 3 3 2 4 3 3 2 6 6 6 6 12

経路の数え上げ

s

t

e

1

e

2

e

3

e

4

e

5

e

6

e

11

e

10

e

7

e

9

e

8

e

12

重み付き和の最大値・最小値も 同様の方法で行える 44

(12)

一様ランダムサンプリング

a

0

1

b

c

c

b

c

d

0

d

1

{d}, {c}, {c, d},

{b}, {b, d}, {b, c, d},

{a}, {a, d}, {a, c, d},

{a, b}, {a, b, c}, {a, b, d},

{a, b, c, d}

1 2 3 3 4 6 7 13

a

b

b

6 7 13

確率

6 13 7 13

確率

45

一様ランダムサンプリング

a

0

1

b

c

c

b

c

d

0

d

1

{d}, {c}, {c, d},

{b}, {b, d}, {b, c, d},

{a}, {a, d}, {a, c, d},

{a, b}, {a, b, c}, {a, b, d},

{a, b, c, d}

1 2 3 3 4 6 7 13

b

c

c

3 3 6

確率

3 6

確率

3 6 46

一様ランダムサンプリング

a

0

1

b

c

c

b

c

d

0

d

1

{d}, {c}, {c, d},

{b}, {b, d}, {b, c, d},

{a}, {a, d}, {a, c, d},

{a, b}, {a, b, c}, {a, b, d},

{a, b, c, d}

1 2 3 3 4 6 7 13

{b, d}

47

graphillion で扱える部分グラフの種類

経路

s-t 経路

ハミルトン経路(すべての頂点を通る)

サイクル(1周して戻る)

森、全域森

木、全域木

連結成分

マッチング

クリーク

(頂点同士がすべて結ばれている頂点集合)

その他、様々な制約を課した部分グラフ

(再掲) フロンティア法は、Knuth のアルゴリズム(s-t 経路)を、 様々な部分グラフに適用できるように拡張したもの 48

(13)

適用事例1: パズルソルバー

ナンバーリンク

同じ数字同士を、線を交差させずに結ぶ

ZDD書籍から引用 R. Yoshinaka, T. Saitoh, J. Kawahara, K. Tsuruma, H. Iwashita, S. Minato.

Finding all solutions and instances of numberlink and slitherlink by ZDDs.

Algorithms, 5, 176–213, 2012. 49

適用事例1-1: ナンバーリンクソルバー 1/4

グラフの問題として定式化

s1-t1 経路 s2-t2 経路 ... sp-tp 経路 (複数終端対経路) を同時に求める問題 ZDD書籍から引用50

適用事例1-1: ナンバーリンクソルバー 2/4

graphillion には、直接、複数終端対

経路を求めるメソッドはない

条件をつけた部分グラフを求める

メソッドを使う

ZDD書籍から引用 51

適用事例1-1: ナンバーリンクソルバー 3/4

次数の条件

終端(si, ti)の次数は1

それ以外の次数は0 または 2

>>> universe = [...] >>> GraphSet.set_universe(universe) >>> point_pairs = [[2, 6], [1, 11], [3, 22]] >>> points = sum(point_pairs, []) >>>

>>> deg_cons = dict([(v, 1) for v in ... set(range(1, 37)) if v in points]) >>> deg_cons.update(dict([(v, (0, 2)) for v in ... set(range(1, 37)) if v not in points]))

[2, 6, 1, 11, 3, 22]

{1: 1, 2: 1, 3: 1, 4: (0, 2), 5: (0, 2), 6: 1,... ZDD書籍から引用

(14)

適用事例1-1: ナンバーリンクソルバー 4/4

>>> solutions = GraphSet.graphs( ... vertex_groups=point_pairs, ... degree_constraints=deg_cons, ... no_loop=True) >>> >>> print solutions.len() 1 [[2, 6], [1, 11], [3, 22]] {1: 1, 2: 1, 3: 1, 4: (0, 2), 5: (0, 2), 6: 1,... ZDD書籍から引用 得られた解 s1 s2 s3 t3 t1 t2 53

適用事例1-2: スリザーリンクソルバー 1/4

スリザーリンク

サイクルを1個作る 書かれている数字の 本数の辺を使う ZDD書籍から引用54

適用事例1-2: スリザーリンクソルバー 2/4

初めに、マスの数字は無視して、サイクルをすべ

て求める

>>> universe = [...] >>> GraphSet.set_universe(universe) >>> >>> cycles = GraphSet.cycles() 55

適用事例1-2: スリザーリンクソルバー 3/4

次に、ある1つのマスに着目

そのマスの制約を満たしている部分グラフのみを抽出

15 16 23 24 >>> e1 = (15, 16) >>> e2 = (15, 23) >>> e3 = (16, 24) >>> e4 = (23, 24)

>>> from itertools import combinations

>>> g_set = list(combinations([e1, e2, e3, e4], 2))

>>> in_gs = GraphSet(g_set) >>> cycles = cycles.including(in_gs) e1 e2 e3 e4 ZDD書籍から引用 56

(15)

適用事例1-2: スリザーリンクソルバー 4/4

次に、ある1つのマスに着目

そのマスの制約を満たしている部分グラフのみを抽出

15 16 23 24 >>> g_set2 = list(combinations([e1,

e2, e3, e4], 3))

>>> ex_gs = GraphSet(g_set2) >>> cycles = cycles.excluding(ex_gs) e1 e2 e3 e4 これをすべてのマスについて行う。 得られた部分グラフが解 ZDD書籍から引用 得られた解 2 0 0 2 2 0 0 2 57

配電網

すべての家は ちょうど1つの変電所に つながっている必要がある サイクルが生じてはいけない 変電所を根とする根付き全域森

T. Inoue et al., “Distribution Loss Minimization with Guaranteed Error Bound,” IEEE Transactions on Smart Grid, Vol. 5, Issue 1, 2014, pp. 102-111.

引用:http://www.jst.go.jp/pr/announce/20120223/index.html

適用事例2: 配電網のスイッチ構成 1/10

58

適用事例2: 配電網のスイッチ構成 2/10

根付き全域森を列挙する

>>> universe = [...] >>> GraphSet.set_universe(universe) >>> forests = GraphSet.forests(roots=[1, 9, 73, 81], is_spanning=True) >>> print forests.len() 54060425088 ... 59

適用事例2: 配電網のスイッチ構成 3/10

電気制約

1つの変電所が給電可能な最大家庭数に制限がある

制限数 5 制限数オーバー 60

(16)

>>> all_trees = GraphSet.trees() >>> too_large_trees = all_trees.larger(6)

適用事例2: 配電網のスイッチ構成 4/10

電気制約を満たす根付き全域森を求める

制限数 6 ... ... まずは、電気制約を満たさない大きな木を求める 61

適用事例2: 配電網のスイッチ構成 5/10

電気制約を満たす根付き全域森を求める

>>> safe_forests = forests.excluding(too_large_trees) 制限数 6 ... ... 根付き全域森の集合から、電気制約に違反する 木を含む根付き全域森を削除 62

適用事例2: 配電網のスイッチ構成 6/10

与えられた構成(根付き全域森)が、制約を満たす

かどうか調べる

>>> unsafe_forest = [...] >>> unsafe_forest in safe_forests False 63

適用事例2: 配電網のスイッチ構成 7/10

与えられた構成から、スイッチON/OFFをいくつか

変化させて、制約を満たす構成に変化させる

与えられた構成 safe_forests (制約を満たす) ... 2回 5回 4回 変化数最小の構成を求めるには? 64

(17)

適用事例2: 配電網のスイッチ構成 8/10

最適化問題として定式化

スイッチを変化させるごとにペナルティーが発生 ペナルティーを最小化する構成を求める graphillion では、採用した辺にしか重みをつけることはできない 与えられた構成 (元グラフ) +1 -1 -1 -1 +1 +1 +1 +1+1 +1 +1 +1 -1 -1 -1 -1 -1 -1 元グラフにない辺を採用すると ペナルティー +1 点 (採用しないと 0点) 元グラフにある辺を採用すると ペナルティー -1 点 (採用しないと 0点)65

適用事例2: 配電網のスイッチ構成 9/10

与えられた構成(根付き全域森)が、制約を満たす

かどうか調べる

>>> unsafe_forest = [...] >>> >>> weights = {}

>>> for switch in universe:

... weights[switch] = 1 if switch in unsafe_forest else -1 ...

>>> for f in safe_forests.min_iter(weights): ... print f

... on_switches = [e for e in f if e not in unsafe_forest] ... off_switches = [e for e in unsafe_forest if e not in f]

66

適用事例2: 配電網のスイッチ構成 10/10

blocking set (hitting set)

切断によって、構成(根付き全域森)が なくなるような辺の集合 >>> failures = safe_forests.blocking() >>> minimal_failures = failures.minimal() 極小のものだけを求めることができる 67

事例3: 避難所割り当て 1/2

グラフと避難所が与えられたとき、避難所ごとにグ

ラフを分割

68

(18)

事例3: 避難所割り当て 2/2

割当をすべて列挙する

>>> universe = [...] >>> GraphSet.set_universe(universe) >>> assignments = GraphSet.graphs([[1], [6], [10]]) >>> >>> maximal_assignments = assignments.maximal() 1 6 10 1, 6, 10 は同じ連結成分に 含まれてはいけない 同じ連結成分内で辺が張れる場合は 必ず張る 69

その他の適用事例

選挙区割りの列挙

多面体の展開図の列挙

住宅フロアプランの列挙

...

70

まとめ

graphillion の紹介

内部データ構造とアルゴリズム

• ZDD • フロンティア法

適用事例の紹介

パズルソルバー(ナンバーリンク、スリザーリンク)

配電網のスイッチ構成

避難所割り当て

71

参照

関連したドキュメント

実行時の安全を保証するための例外機構は一方で速度低下の原因となるため,部分冗長性除去(Par- tial Redundancy

前章 / 節からの流れで、計算可能な関数のもつ性質を抽象的に捉えることから始めよう。話を 単純にするために、以下では次のような型のプログラム を考える。 は部分関数 (

の dual としてトーラスに埋め込まれた Heawood グラフは.

今回、新たな制度ができることをきっかけに、ステークホルダー別に寄せられている声を分析

なお、保育所についてはもう一つの視点として、横軸を「園児一人あたりの芝生

• パフォーマンス向上コーディネーター( PICO )を発電所各部に 配置した。 PICO は、⽇々の不適合/改善に関するデータのスク

これら諸々の構造的制約というフィルターを通して析出された行為を分析対象とする点で︑構

 筆記試験は与えられた課題に対して、時間 内に回答 しなければなりません。時間内に答 え を出すことは働 くことと 同様です。 だから分からな い問題は後回しでもいいので