Document

列挙学校:第4コマ
「複雑な構造の簡潔な列挙法と実装法」
宇野 毅明 (国立情報学研究所
&総合研究大学院大学)
2008年2月28・29日 列挙学校
簡単に自己紹介
名前: 宇野 毅明
年齢・職種: 37歳、准教授
研究分野: アルゴリズム理論
- コンピュータプログラムの設計手法の理論
- 速いコンピュータを作ったり、プログラミングの腕を競うの
ではなく、「設計方法の違いによる性能の向上」を目指す
最近の研究: ゲノム情報学やデータマイニングで出てくる巨大な
データベースの基礎的(とはいっても非常に時間のかかる)な解析
を超高速で行うアルゴリズムの開発
趣味(日課?): 子供と遊ぶこと
1.列挙のつかみどころ
1.1 列挙の難しさ
列挙の難しさ
・ 列挙アルゴリズムを設計するときには、いくつかの難しさがある
- 重複を回避する難しさ (逆探索  岡本さん)
- 全てを見つける難しさ (探索経路構築)
- 同型なものを同一視する難しさ (標準形  中野さん)
- 計算を速くする難しさ (計算アルゴリズム)
…
どう難しいのか、少しおさらいしてみましょう
重複を回避する難しさ
・ 探索はできるので、全て見つけることはできるとする
・ しかし、どうやって同じものを2度出さないようにするか、あるい
は同じ探索を繰り返さないようにするかは、それほど自明でない
・ 簡単に回避するなら、解を全部メモリに保存すればよい
 解が多くなるとメモリ効率が悪い
 動的にメモリを確保して解を保存するルーチンと、解を効率
よく検索するルーチンが必要(ハッシュがあればいい)
・ 今の解を出力するか、あるいは探索を続けるか、
過去の履歴を見ずに、解自体から計算でわかればよい
これを一般化すると、逆探索的なアイディアになる
回避する必要がないと
・ 解が多くなるとメモリ効率が悪い
・ 動的にメモリを確保して解を保存するルーチンと、解を効率よく
検索するルーチンが必要
・ これらが気にならないときは?
 解はそんなに多くない。あるいは、メモリがたくさんある
 ハッシュ or 2分木がある
・ 力ずくで組んだほうがすっきり簡単  工学的に有利
・ 時間計算量の意味でも問題はない  理論的にもOK
これを一般化すると、逆探索的なアイディアになる
同型なものの取り扱い
・ グラフなどの直線的でない構造を持つ構造は、2つのものが同
じかどうかを判定することからして難しい
・ 解決策は、比較しやすい構造(標準型)に変換すること
 同じものは同じものに変換されること
 サイズが巨大にならないこと
・ 順序木のビット列化  無順序木の順序木化  直並列グラフ
やコグラフの無順序木化
・ 標準型を列挙するアルゴリズムを作る = もとの構造の列挙ア
ルゴリズムを作る
同型判定が難しいと
・ 同型判定が難しかったらどうしましょうか?
 グラフ、系列データ、行列・・・
・ それでも、だいたいは指数時間かければ同型性の判定はできる
・ グラフマイニングのように、列挙するものがごく小さい(せいぜい
30枝)くらいであれば、根性入れて計算すればいい
 指数時間かからないことも多い
 そもそも、列挙部分でなく、埋込み判定がボトルネック
・ 計算量的には、数反復で指数時間、残りは多項式時間、
というアルゴリズムが設計できれば、全体としては多項式時間
 まだ、こういうタイプのアルゴリズムは存在しない
探索自体が難しい
・ クリークやパスは、列挙が簡単
- クリークは1つずつ付け足すと簡単に全てが得られる
- パスは再帰的な場合分けができ、空の問題のチェックが簡単
・ しかし、こううまくいくものばかりではない。
- 極大な××、極小な○○
- あの条件とこの条件とこの条件と...
 互いに隣接していない、場合分けも難しい
・ 探索が難しい問題は、大きく2つに分けられる
- 1つ見つけるのは簡単。しかし列挙は… (極大クリークなど)
- 1つ見つけるのすら難しい (SATの充足可能解など)
1つ見つけるのも難しい
・ 難しい問題(NP完全)の解は、1つは見つけることすら難しい
(最大クリーク、充足可能解、ハミルトンサイクル・・・)
・ その上、全部見つけるとなると、これはもう絶望的
 各反復がNP完全になるので
 理論的な結果はあきらめたほうが賢明
・ しかし、同型性と同じように、
-「多くの場合易しい」 充足可能解など
-「解はそんなに多くない」 極大、極小性がある
-「解の範囲が限られている」 大きさがある程度限られてる
のであれば、力ずくでも何とかなる
1つは見つけられる
・ 1つは見つけられる場合:
1つの解から他の解を作る方法を考える
- うまく作れれば、解から解へと探索できる
-全体がつながれば、列挙可能
・ しかし、「作る作業」が指数時間かかる、指数個の解が見つかる、
という状況だと、時間効率は悪い
・・・
他の解への移動方法
・ 極大解だったら
- いくつか取り除いて小さくし、違うものを加えて大きくする
 任意の解から任意の解へ移動できる
-しかし、隣り合う解の数が指数個あるので、
全て見に行くには、指数時間必要
・ 隣が少なくなるように、移動を制限する
- キーとなる要素を加えて、不要なものを除く
 除き方が指数通りあると、うまくいかない
・ 極大の場合、場合分け+枝刈りが比較的うまく動く
 極大解の上には何もない & 解の存在確認が簡単
計算の高速化
・ 高速化は、通常のアルゴリズムに対するテクニックが有効
・ 各反復の計算の高速化
- 2分木、ハッシュなどのデータ構造、
- 隣接行列  接続行列による疎性の利用
- よけいな処理を省いて、高速化  計算オーダー減少
- キャッシュ、コードの最適化
・ 列挙の場合、解を少しずつ変更する操作が多いので、
データを動的に管理する方法が有効
 各頂点の次数、重み和、頻出度など
・ 指数的に広がる再帰構造を使った高速化が特に有効
1.2 これからの列挙アルゴリズム
列挙アルゴリズムの設計
・ 列挙アルゴリズムの設計の場面は、主に3つ
- 新しいアルゴリズムの設計、計算量の改善 (理論)
- 実データに対する効率的な計算方法 (工学)
- 実用ツールの作成、特定データの解析 (実用)
・ 互いに、互いの価値観はいまひとつ意味がない
- 実データ一個解けても、計算量の改善にはならない
- 複雑な問題のアルゴリズムは、実用では使えない
- 特定問題のツールは、モデルの意味でつまらない
・ しかし、互いの要素がないと、面白くないことも事実
- 実用のない理論  おもちゃの研究
- 理論のない応用  単なるプログラミング
設計のセンス
・ いい研究・活動には、互いの分野を理解することが重要
・ しかし、知識の収集では分野のだけでは理解にならない
- 価値観、問題意識、目的、流儀、センス…
・ 以後の話では、価値観、センスのところに目を凝らして、
話を聞いてください。
実用面: データ中心の科学
・ 近年、IT技術の発達で、大規模なデータが半自動的に収集で
きるようになった
(POS、web、文書、顧客データ、財務、利用者、人事…)
既存のデータを使って何かを得たい
データの選別
モデル化
データ処理
いわば、データを出発点とした問題解決の科学
(人工知能、データマイニング、自然言語処理、セマンティックweb…
近年の情報学でもメジャーな研究スタイル)
データ中心科学の特徴
・ データが整形されていない
目的がはっきりしない、あるいは異なる目的のために集められたデータを用い
るため、必要なものがすぐ取り出せるとは限らない。また、ノイズや不正確な情
報も含まれうる。
・ 目的関数があいまい
データが情報の塊のようなものなので、そこから得られるものはやはり情報で
あることが多い(知識、特徴分析といったもの)。それら情報の価値は数理的な
尺度では計りにくい。また、従来の最適化とは異なる尺度を用いることが多い。
(グラフクラス、シークエンス、情報量、隣接性、類似度、頻出度・・・)
・ データが巨大で、構造を持つ
半自動で集められたデータであるので、データは通常、巨大である。しかし各
項目が持つ属性は少なく、疎である。
・ データ処理は列挙的な要因を持つものが多い
複雑な目的関数を評価するため解候補を列挙する、列挙で得た解を分析し
て全体像を得る、ランキングして、相対評価を行う、など
データ処理の変化
▪ 不ぞろいなデータから有用な情報を得るには複雑で豊かなモデ
ルを解く必要がある
▪ そのためには、解く問題を複雑にする必要がある
▪ 比較・統計量  全対比較・組合せ的な統計量
▪ キーワード検索  パターンマイニング
▪ 完全一致  類似検索
データベース
▪ 最適化  列挙
・ このように処理が変化すると、既存のアルゴリズムを用いて行っ
た場合に、非常に時間がかかることがある
例) 全対比較を通常の検索を用いて行うと、レコード数だけのクエ
リを必要とする
複雑かつ大量の計算を効率良く行う手法の開発が重要
データ処理に求められるもの
[多様性] 個別の案件に対してモデルが変化
 問題設定の変化に対して柔軟であること
- [基礎問題] 解く問題が基礎的であること
- [単純な構造] アルゴリズムのアイディアが単純であり、
汎用性の高いレベルで構築されていること
[速度] 大規模データに対しても高速に動作すること
 コードの改良より、良いアルゴリズムの開発
- [疎成] データの疎性、スケールフリー性を利用して
- [計算構造] 計算構造の改良により、無駄な探索を省く
- [スケールメリット] 多数の操作を一度に行うことで高速化
[正確性] なんらかの意味で正確な計算を行うこと
- [列挙] 全ての解をもらさず重複無く発見
- [精度保障] 誤差の範囲を保障する
アルゴリズム理論の利点
・ 大規模な計算には、アルゴリズム理論に基づいた技術が有効
 アルゴリズム理論による高速化は、問題の大きさに対する計算
時間の増加を抑える
 計算の結果は変化しない
100項目
100万項目
2-3倍
10000倍
データが巨大になるほど、アルゴリズム改良の加速率は上がる
列挙アルゴリズムの理論面
・ 基礎的な構造に関しては、ほぼ解かれていると考えてよい
 パス、木、部分グラフ、連結成分、クリーク、系列・・・
・ 同型性判定が容易なクラスも、けっこう解けている
 シークエンス、ネックレス、木、極大平面グラフ・・・
・ しかし、応用的な要素がちょっとでも入ると、とたんに解かれて
いるものが少なくなる
- 正例に含まれ、負例に含まれないパターンの列挙
- 計算量の削減、実用上の計算時間削減法
・ 少々複雑な構造を持つものも同様
- コーダルやインターバルなどのグラフクラス
- あいまい性を許容した列挙
- 複数の条件を扱う列挙 (クラス+重み+制約)
これからの理論
・ 基本アルゴリズムの完成度は高い
・ まったく新しいアルゴリズムの出現は、考えづらい
 ある意味で、アプローチが固定的 (探索しなければならない
のは共通)
・ 探索路決定、重複回避、標準型の設定など、次のレベルは大き
な未解決分野
 極大解列挙、幾何学パターンマイニング、仮説列挙・・・
・ 厳密解法、ランダムサンプリング、数え上げなどへの応用も、重
要な研究分野
 列挙技術が、研究の芯になる可能性が高い
 通常のアルゴリズムへの、列挙アルゴリズム技術の応用
これからの実用
・ 解列挙は、解の完全性という新しい状況を生む
・ ランキングや比較を行うことで、それぞれの解の質を厳密に評
価できる
 小さい問題で完全な評価を行えば、手法の質が測れる
・ 解候補の列挙 + 候補の絞込み、という方法は、
モデルの変化や 制約の変化に対して頑強
 いいツールを作っておけば、いろいろな場面で使いまわしで
きる
 お試し解析が簡単にできる
・ 高速解法を使うと、今まで手に負えなかった巨大データ解析で
きる
2.高速化の技術
2.1 頻出集合の列挙 (LCM)
頻出集合発見用のプログラム
・ 頻出集合発見は、データマイニングと呼ばれる最近興ったデータ
解析の中でも基礎的な問題なので、プログラムが多く作られている
・ 入力データ、出力する解、どちらも大きいことが多いので、計算
速度は非常に重要
・ しかも、アルゴリズムの設計しだい
で、パフォーマンスが大きく変わる
・ 国際プログラミングコンテスト
でも、こんな感じ。ばらつき大きい
(時間軸は対数)
どういう高速化技法あるの
か、見てみよう
トランザクションデータベース
トランザクションデータベース:
各トランザクション T がアイテム集合 E の部分集合
になっているようなデータベース、つまり、∀T ∈D, T ⊆ E
1,2,5,6,7,9
集合 P に対して:
2,3,4,5
P の出現: P を含むD のトランザクション
D = 1,2,7,8,9
P の出現集合 Occ(K): P の出現の集合
1,7,9
P の頻出度 frq( P): P の出現集合の大きさ
2,7,9
2
{1,2}の出現集合
= { {1,2,5,6,7,9},
{1,2,7,8,9} }
{2,7,9}の出現集合
= { {1,2,5,6,7,9},
{1,2,7,8,9},
{2,7,9} }
頻出集合
・ 頻出集合: D の定数σ個以上のトランザクションに含まれる集合
(頻出度がσ以上の集合)( σを最小サポートとよぶ)
例) データベース D の3つ以上のトランザクションに含まれる集合
1,2,5,6,7,9
2,3,4,5
D = 1,2,7,8,9
1,7,9
2,7,9
2
3つ以上に含まれるもの
{1} {2} {7} {9}
{1,7} {1,9}
{2,7} {2,9} {7,9}
{1,7,9} {2,7,9}
頻出集合列挙は、与えられたトランザクションデータベース
と最小サポートσに対して、頻出集合を全て見つける問題
バックトラック法
・ 頻出集合は単調性を満たす(部分集合は必ず頻出)
 バックトラック法が有効
Backtrack (P)
1 Output P
2 For each e > P の末尾( P の最大のアイテム)
If P +e が頻出集合 call Backtrack (P+e)
-再帰呼び出し回数は頻出集合数
O(|D|)
-1呼び出し(反復と言う)の時間は
(n-P の末尾)×(頻出度計算時間)
1,2,3,4
1,2,3 1,2,4 1,3,4 2,3,4
1,2 1,3 1,4 2,3 2,4 3,4
1
解1つあたり O(n|D|)、とても長い
3
2
φ
4
解1つ当たり、を速くする
・解1つあたりの計算時間はそれなりに(多項式時間で)抑えら
れたが、まだまだ大きい
・ 各 P+e について、その頻出度を計算
-単純にするなら、全ての項目(トランザクション)について、
P+e を含むかどうか調べる
 最悪、データベースの大きさに比例、
平均ではだいたい、項目数、
1,2,5,6,7,9
頻出度×Pの大きさ、の大きいほう
- 2分木のようなデータ構造を作って、含むものだけ 2,3,4,5
1,2,7,8,9
抜き出す、あるいは勘定する、というのは、難しい
1,7,9
2,7,9
ここにアルゴリズムが必要
2
幅優先探索の利用
D0={φ}, k := 1
while Dk-1 が空でない
for each Dk-1 のメンバー P
for each e
if P+e が頻出集合 then Dk に P+e を挿入
・ P+e の頻出度を計算する前に
P+e に含まれる部分集合が
全てDkにあるか調べる
1,2,3,4
1,2,3 1,2,4
1,2
1,3
1,3,4
1,4
2,3,4
2,3
2,4
3,4
2
3
4
・ ないものがあるなら、頻出でない
1
φ
メモリを使う点、検索に時間がかかる点がネック
含むものしか含まない
・ アイテム集合 P の出現集合を T とする
・ P+e の出現は P を含む(= P の出現)
 P+e を含むトランザクションを見つけるとき
には、 T のトランザクションしか見なくてよい
・ T のトランザクションで e を含むものを集めると
P+e の出現集合が得られる
・ 出現集合を更新すれば、
データ全体を見なくて良い
 計算時間はだいぶ短くなる
共通部分をとる
・ T のトランザクションで e を含むものを集めると P+e の出現
集合が得られる
 P+e の出現集合は、 Pの出現集合と e の出現集合の共
通部分 (両方に含まれるものを集めたもの)
・ 共通部分をとるには、両者をソートしておき、同時に先頭から
スキャンする
{1,3,7,8,9}
{1,2,4,7,9}
= {1,7,9}
計算時間は、スキャンしたアイテムの数  両者の大きさの和
ビット演算を使った共通部分の高速計算
・ 各アイテムの出現をビットの形で保持する
(現在の部分集合も同じように)
{1,3,7,8,9}
{1,2,4,7,9}


[101000111]
[110100101]
[100000101]
 共通部分の計算が、AND 演算でできる
(いっぺんに32個(最近は64個) 計算できる)
メモリの節約にもなる
しかし、後述するデータベース縮約と相性が悪い
振り分けによる高速化
・ 各アイテムに空のバケツを用意する
・ P の各出現 T に対して、以下を行う
- T に含まれるアイテム e に対して、 e のバケツにT を入れる
 この操作が終わった後は、各アイテムe
のバケツの中身は P+e の出現集合になる
A: 1,2,5,6,7,9
for each P の各出現 T
B: 2,3,4,5
for each T に含まれる e, e > Pの末尾
C: 1,2,7,8,9
eのバケツに T を挿入
D: 1,7,9
E: 2,7,9
F: 2
1: A,C,D
2: A,B,C,E,F
3: B
4: B
5: A,B
6: A
7: A,C,D,E
8: C
9: A,C,D,E
振り分けの計算時間
for each P の各出現 T
for each T に含まれる e, e > Pの末尾
eのバケツに T を挿入
・ 計算時間は,
P の各出現の (Pの末尾) より大きなアイテムの数の総和
・ 各アイテムに対する再帰呼び出しの
準備をいっぺんにすることで、
効率化している
A: 1,2,5,6,7
B: 2,3,4,5
C: 1,2,7,8,9
D: 1,7,9
E: 2,7,9
F: 2
Occurrence Deliver
・ Compute the denotations of P ∪{i} for all i’s at once,
A 1 A2
1,2,5,6,7,9
2,3,4,5
D= 1,2,7,8,9
1,7,9
2,7,9
P = {1,7}
2
Check the frequency for all
items to be added in linear
time of the database size
A5 A6 7
A9
B
2 3 4 5
C 1 C2
7 C8 C9
D 1
7
D9
7
9
E
2
F
2
Generating the recursive calls in reverse
direction, we can re-use the memory
1再帰呼び出しの計算時間のイメージ
・ 普通に頻出度の計算をすると
各 P+e に対してデータを
一回スキャンする
(n-t)個
・ 共通部分による計算は
効果はこれだけではない
Occ(P) と Occ({e})
のをスキャンする
 Occ(P) を n-t 回スキャンし、
+
データベースの t より大きな
t
アイテムをスキャンする
・ 振り分けは Occ(P) に含まれるトランザ
クションの t のをスキャンする t より
大きなアイテムをスキャンする
t
(n-t)個
末広がり性
・ 再帰呼び出しを繰り返すと、 Pの頻出度は小さくなる
 振り分けの計算時間も短くなる
・ バックトラックは、各反復で複数の再帰呼び出しをする
 計算木は、下に行くほど大きくなる
 計算時間を支配するのは一番下の数レベル
計算時間長
・・・
計算時間短
ほぼ全ての反復が短時間で終了  全体も速くなる
最小サポートが大きい場合も
・ σが大きいと、下のレベルでも多くの出現を見ることになる
 末広がり性による高速化はいまひとつ
・ データベースの縮約により、下のレベルの高速化をはかる
(1) 前回追加したアイテムより小さいアイテムは消す
(2) 現在の出現集合からできるデータベースの中で、頻出になって
いないアイテムは消去する
(再帰呼び出しの中で加えられることが無いから)
(3) まったく同一のトランザクションは、1つにまとめる
1
・ 実データだと、下のほうのレベルでは
だいたい大きさが定数になる
σが小さいときと速度の大きな差はない
1
3
2
2
6
4
7
4
3
2
5
4
3
1
4
4
4
5
6
7
6
7
6
7
キャッシュとの相性
・ 速いプログラムを作るとき、キャッシュのヒット率が良く問題になる
- ループを開く
- メモリの配置を変える
for i=1 to n { x[i]=0; }
 for i=1 to n step 3 { x[i]=0; x[i+1]=0; x[i+2]=0; }
●
●
●
●
●
●
▲
▲
▲
●●●
●▲
●
▲
●
▲
再帰的に問題が小さくなり、ある反復より先ではキャッシュに入る
 末広がり性より、ほぼ全ての部分でキャッシュに入っている
木構造を用いた圧縮 (trie, prefix tree)
・ 各トランザクションを文字列とみなすと、2分木の形で格納でき、メ
モリを節約できる
 振り分けと併用できる。スキャンの時間も、それだけ短くなる
*
A: 1,2,5,6,7,9
B: 2,3,4,5
C: 1,2,7,8,9
D: 1,7,9
E: 2,3,7,9
F: 2,7,9
1
2
1
2
5
6
7
7
8
9
7
9
3
4
5
7
9
7
9
D
F
B
E
9
C
A
参考文献など
・ 頻出集合およびその応用 (’90~) 星の数ほど
“frequent pattern”、”frequent itemset” で検索すると出てくる
・ 極大頻出集合およびその応用 (’90~) やはり多い
“maximal frequent itemset” などで検索すると出てくる
・ pasquerらのアルゴリズム (‘99) 飽和集合の導入
・ 宇野らのアルゴリズムLCM (‘04) 現在最速のアルゴリズム
・ 実装 LCM: (Linear time Closed itemset Miner) 宇野のHP
http:research.nii.ac.jp/~uno/
・ レポジトリ (実装、論文、比較実験の数々)
http://fimi.cs.helsinki.fi/
・ 中野・宇野・有村 (’03~ ) 順序木・無順序木の多項式時間頻出列挙
2.2 コンテストの結果
計算機実験: FIMI04
・ FIMI: Frequent Itemset Mining Implementations
- ICDM (International Conference on Data Mining) サテライト
ワークショップで、頻出/頻出飽和/極大頻出集合列挙のプ
ログラムコンテストを行った。2回目。3回目はなし
・第1回は15、第2回は8個の投稿があった
ルール:
- ファイルを読み、列挙してファイルに書くこと
- time コマンドで時間を計測(メモリも他のコマンドで計測)
- CPUを制御する命令(パイプラインなど)は使用禁止
計算機実験: FIMI04
・計算機環境:CPU、メモリ: Pentium4 3.2GHz、1GB RAM
OS、言語、コンパイラ: Linux 、C言語、gcc
・ データセット:
- 実データ: 疎、アイテム数大
- 機械学習用データ: 密、アイテム数小、規則的
- 人工データ: 疎、アイテム数大、ランダム
- 密な実データ: 超密、アイテム数小
LCM(宇野有村清見)、見事優勝
賞状と賞品
賞品は {ビール, 紙おむつ}
“Most Frequent Itemset” だそうです
実データ
(すかすか)
平均の大きさ5-10
BMS-POS
BMSWebView2
retail
実データ
(すかすか)
メモリ使用量
BMS-POS
BMSWebView2
retail
密(50%程度)で
構造があるデータ
pumsb
connect
chess
密で構造がある
データ、メモリ量
connect
pumsb
chess
密な実データ&
巨大データ
accidents
accidents メモリ
web-doc
他の頻出パターン
・ 末広がり性、含まれる項目の絞込み、データベースの縮約は他の
頻出パターン発見でも使える技術
- 文字列、シークエンス、系列データ
- 行列
- 幾何データ、図形、ベクトル
- グラフ、ツリー、パス、サイクル
パターン
{A,C,D}
XYZ
項目
{A,B,C,D,E}
AXccYddZf
2.3 全張木列挙の高速化
連結成分の列挙
・ 与えられたグラフの、頂点 r を含む頂点部分集合で、連結に
なっているものを列挙する問題
・ 現在の解に隣接する頂点を選び、
その頂点を含むものの列挙と、
含まないものの列挙に分割
 再帰的に列挙
効率的な計算
・ 現在解に隣接する頂点を動的に管理すれば、高速計算可能
・ 現在の解に隣接する頂点の集合と、
追加頂点に隣接する頂点の集合の
和集合を取ればいい
 各反復に O(候補数) 時間
効率的な計算
・ 各反復で2つ再帰呼び出しする  反復数 < 2×解数
v を使わない
O(1)
v を使う
O(d(r)+d(v))
使わない
使わない
・・・
使わない
使わない
・ 各反復が自分の右の子から
始まる左下パスの反復にO(1)
ずつ計算時間を配る
 各反復に O(1) 時間
 各解に O(1) 時間
全張木の列挙
・ 全張木とは、グラフの全ての頂点を含む木のこと
・ ある枝を選び、
その枝を含むものの列挙と、
含まないものの列挙に分割
 再帰的に列挙
再帰が深くなると
・ 再帰が深くなると、枝数・頂点数が減る
・ セルフループ、ブリッジも増える
・ セルフループは必ず使わない枝、ブリッジは必ず
使う枝なので、グラフから消せる
 グラフが小さくなる
 計算木の末端での計算時間が短くなる
再帰呼び出しのコピー
・ k 本の多重枝に関する分割  どれか一本を使う問題がk 個
・ k 本のサイクルもどき多重枝に関する分割  どれか一本を使
わない問題がk 個
 k 個の問題が短い時間で作れる
・ グラフが小さくなるときは、ブリッジ・セルフループがたくさん
でき、たくさんの子問題を作るように変更できる。後は演習
3. 探索の難しさ
3.1 場合分け的なアプローチ
充足可能解の列挙
・ 充足可能解とは、与えられた論理式を満たす真偽値の割当て
(x1∨x2∨¬x3) ∧ (¬x1∨x2∨x4)∧・・・∧(¬x5∨x4)
・ 充足可能解を見つける問題はNP完全
 列挙するのも、当然難しい
・ それでも列挙しようとしたら、どうするか?
 場合分けと枝刈り(分枝限定法)が一般的
分枝限定法
・ 1つ1つ、場合分けをするように変数の値を決めていく
・ それぞれの値について、再帰呼び出しを行う
・ 値を決めて行き、最後まで
決めたら解がひとつ見つかる
・ 途中で、分枝の先に解が
ないことが確認できたら、
探索を打ち切る
v1, v2
 この精度・速さが鍵
正確∩多項式なら、
多項式遅延
¬v1
v1
v1, ¬v2
¬v1, v2
¬v1, ¬v2
限定操作
・ 現在の分枝の先に解がない
 この先、どのように変数の値を決めても、充足できない
(x1∨x2∨¬x3) ∧ (¬x1∨x2∨x4)∧・・・∧(¬x5∨x4)
(x1∨x2∨¬x3) ∧ (¬x1∨x2∨偽)∧・・・∧(¬真∨偽)
・ 途中で解が見つかる
 途中で充足してしまった
・ 充足可能性の判定は通常たやすいので、速く動きそう
単調性を満たす族
・ 集合族は、集合の集合
・ 集合族 F の任意のメンバーの部分集合が F に含まれる
 F は(逆)単調性を満たす、という
- 頻出パターン、クリーク、森、非連結なグラフ・・・
・ 単調な集合族のメンバーの列挙は簡単だが、極大なメンバーの
列挙は難しい
 他のメンバーに真に含まれなければ極大
単調性を満たす族
・ 極大な要素の列挙は、比較的枝刈がしやすい
① いったんメンバーでなくなったら、枝刈できる
② 残り全部を追加してもメンバーなら、分枝の必要がない
・ ①を完璧にやっても、メンバーを全部探索してしまうと非効率
・ 1つ極大を見つけ、その要素を再帰の最後のレベルに寄せると、
「寄せた部分までを全て使わない」という再帰が不要になる
 ②にうまくはまる!
再帰の方向
解の大きさが30までなら、実用上はほぼ十分
単調性を満たす族
・ バックトラック的な書き方で、アルゴリズムを記述
(○○を使わない、を再帰でなくループで処理)
極大列挙(P:現在の解, I:決定していない要素)
P∪I に含まれる解の中で極大なもの S を見つける
if S が極大解 output S
for each e∈I\S
call 極大列挙(P∪e, I); I := I\{e}
再帰の方向
P
I
3.2 飽和集合の列挙
頻出集合の問題点
・ 面白い頻出集合を見つけようとすると、σを小さくする必要がある
 大量の頻出集合が出てくる
・ 情報を失わずに、頻出集合的な、数の少ないものを
見つけるようにモデルを変えたい
111…1
1. 極大頻出集合:
他の頻出集合に含まれない頻出集合
2. 飽和集合:
出現集合が等しいものの中で極大なもの
000…0
極大頻出集合と飽和集合の例
・ 頻出集合を出現集合で分類
1,2,5,6,7,9
2,3,4,5
D= 1,2,7,8,9
1,7,9
2,7,9
2
3つ以上に含まれるもの
{1}
{2}
{7}
{1,7}
{1,9}
{2,7}
{2,9}
{1,7,9}
{9}
{7,9}
{2,7,9}
頻出飽和集合
極大頻出集合
出現集合の共通部分が
飽和集合になる
極大頻出集合と飽和集合
極大頻出集合
・ 多項式時間で列挙できるかどうか、未解決
・ クリークと同じように枝刈りをすると、高速に列挙できる
・ 数が少ないがσによる解のぶれが大きい
飽和集合
・ 逆探索という探索手法で多項式時間列挙可能
・ 離散アルゴリズムと末広がり性を用いて、高速列挙可能
・ 出現の意味で情報の損失がない
・ ノイズが多いと出現集合が等しいものが少なくなり、
解の減少効率が悪くなる
両者とも、1つあたりほぼ定数時間、1秒間に1~10万個
2部グラフによる表現
・ アイテム、トランザクションを頂点とし、包含関係を枝とする
A: 1,2,5,6,7,9
B: 2,3,4,5
D= C: 1,2,7,8,9
D: 1,7,9
E: 2,7,9
F: 2
1 2 3 4 5 6 7 8 9
A
B
C
D
E
・ アイテム集合と、それらを含むトランザクションの集合
 2部グラフの2部クリーク
・ アイテム集合とその出現集合
 トランザクション側が極大な2部クリーク
・ 飽和集合とその出現集合  極大2部クリーク
F
隣接行列で見ると
・ アイテム、トランザクションを頂点とし、包含関係を枝とする
A: 1,2,5,6,7,9
B: 2,3,4,5
D= C: 1,2,7,8,9
D: 1,7,9
E: 2,7,9
F: 2
1 2 3 4 5 6 7 8 9
A 1 1
B
1 1 1
1
1 1 1 1
C 1 1
1 1 1
D 1
1
1
1
1
E
1
F
1
・ アイテム集合と、それらを含むトランザクションの集合
 全てのセルに1が入っている部分行列
飽和集合の列挙手法
・ 頻出集合列挙ベース
- 頻出集合列挙アルゴリズムをベースに、多少無駄な計算を
省く
- 飽和集合のよさが出ない。計算時間の改善も少ない
・ 保存 + 枝狩り
- 見つけた解を保存し、それを用いて無駄な分枝を刈る
- 計算速度はまあまあ
- 解保存のためにメモリを使用し、それがひとつのネック
・ 逆探索 + データベース縮約
- 計算効率が良い
- 解保存用のメモリが不要
(LCM)
飽和集合の隣接関係
・ 飽和集合から、添え字の大きい順に要素を抜いていく
・ どこかで出現集合が大きくなる
・ その出現集合の飽和集合を求める
・ こうして求めた飽和集合を、親とする (一意的に定まる)
・ 親の頻出度は必ず真に大きいので、親子関係は非巡回的
 親子関係は有向根付き木を導出する
逆探索
親子関係は有向根付き木を導出する
この木を深さ優先探索すれば全ての解を見つけられる
・ 探索には、子供を見つけるアルゴリズムがあれば十分
・ 子供が1つあたり多項式時間で見つかれば、全体も多項式時間
(親に要素を1つ加えて極大をとった飽和集合が子供になる)
非巡回的な親子関係と、子供を見つける多項式時間アル
ゴリズムがあれば、なんでも多項式時間列挙ができる
親子関係の例
・ データベースの全ての
飽和集合とその親子関係
φ
2
1,2,5,6,7,9
2,3,4,5
T = 1,2,7,8,9
1,7,9
2,7,9
2
7,9
1,7,9
2,5
1,2,7,9
2,3,4,5
出現集合が隣接
親子関係(ppc拡張)
1,2,7,8,9
1,2,5,6,7,9
2,7,9
子どもを求める
・ 子どもから親を作る際に抜いた、最後のアイテムを親に追加
すると、出現集合は子どもと等しくなる
 子どもは、アイテムを1つ追加して、出現集合の共通部分
をとると得られる
 とはいえ、そのようにして作ったもの全てが子どもになると
は限らない
 子どもである条件は、抜いたアイテムより前の部分に、新
しくアイテムが追加されないこと
(prefix preserving closure extension, prefix保存飽和拡張)
データベースの縮小
・ 頻出集合と同じように、データベースの縮小をしたい
・ 追加したアイテムの前半部分を捨てられない
 ppc 拡張の際に参照されるので
・ しかし、
-後半が同一なら、必ず同時に Occ に入る
-必要なのは前半(prefix)の共通部分だけ
なので、前半の共通部分をとり、保存すればよい
・ 多くのトランザクションが1つになれば、
自然に共通部分も小さくなる
1
1
2
2
5
6
4
7
4
3
2
4
4
3
1
θが小さいときと速度の大きな差はない
3
4
4
5
6
7
6
7
6
7
比較の手間
・K+e の出現の共通部分、素直に計算してもよいが、「共通部分
がKと等しいか」を調べるだけなので、必ずしも全て計算する必
要はない
 異なることがわかった時点で、計算をやめてよい
・ K+e の出現それぞれを小さい順にたどり、
K
全てに共通するものがあるか調べる
3 4 6 9 11
・ 全てに共通するものがあったら
K に入っているか調べる
・ 前回たどったところで止まって
おき、次回はそこからたどる
4 11
1 3 4 5 9 11
K+e の
出現集合
23 4 5 9 11
1 2 4 6 9 11
1 4 9 11
ビットマトリクス
・ スウィープポインタは、行列の形でデータを持ってないがゆえ
の工夫。隣接行列を持って入れば、もっと単純に速くできる
・が、隣接行列は、大きすぎて構築することすら不可能
・ 出現集合がある程度以下に小さくなったところで、
行列を構築しよう
 ビットで持てば、各列が1つの変数に入る!
ビットマトリクスの定数時間計算
・ 各アイテムに対応する列を1変数で持っていると、K+e の出現全
てにそのアイテムが含まれるかどうか、1ステップでチェックできる
・ K+e の出現のビットパターンと、アイテム i の列のビットパターン
の AND をとる
・アイテム i が K+e の出現全てに含まれるなら、共通部分はK+e
の出現ビットパターンと等しくなる
K の頂点
・・・
K<i ∩N(vi)
実データ
(すかすか)
平均の大きさ5-10
BMS-POS
BMSWebView2
retail
実データ
(すかすか)
メモリ使用量
BMS-POS
BMSWebView2
retail
密(50%程度)で
構造があるデータ
connect
pumsb
chess
密で構造がある
データ、メモリ量
connect
pumsb
chess
密な実データ&
巨大データ
accidents
accidents メモリ
web-doc
探索の難しさ: 極大クリークの列挙
クリーク列挙問題
グラフのクリーク: 部分グラフで、全ての頂点間に枝があるもの
・ 2部クリークの列挙は、グラフの変換でクリーク列挙に帰着可能
・ 最大クリークを求める問題はNP完全
・ 極大クリークは簡単に求められる
・ 最適化を中心に非常に多くの研究がある
・ 大規模かつ疎なグラフでの、クラスタリングなどの応用が多い
クリークの単調性
・ クリークの部分集合はクリーク
 単調性が成り立つ
 原点を出発して山を登り、
クリークでなくなったら、
戻って、他の方向に登る、
というバックトラック式の
列挙ができる
・ クリークであるかどうかのチェック
はO(n2) 時間、最高 n 方向に登る
 1つあたり O(n3) 時間
・ 巨大データでは長時間
111…1
クリーク
000…0
1,2,3,4
1,2,3 1,2,4
1,2
1,3
1
1,3,4
1,4
2,3,4
2,3
2,4
3,4
2
3
4
φ
追加できる候補を絞り込む
・ 追加できる頂点を効率よく見つけたい
追加できる  クリークの全ての頂点に隣接
あらかじめ、追加できる候補を調べておくと楽
・ さらに、新しい頂点を1つ追加したとき、
候補に残る頂点  新しい頂点に隣接
候補の集合の更新は、追加する頂点に
隣接する頂点と、候補の共通部分をとればいい
候補
隣接頂点
隣接頂点
クリーク一個あたり、頂点の次数の時間
末広がり性
・ バックトラックは、各反復で複数の再帰呼び出しをする
 計算木は、下に行くほど大きくなる
 計算時間を支配するのは一番下の数レベル
・ 追加した頂点より前の頂点は見なくていいので、更新の時間
は再帰が深くなるにつれ短くなる
次数大きい
頂点
・・・
ほぼ全ての反復が短時間で終了
(1秒間におよそ100万個)
次数小さい
頂点
クリークの個数
・ 実データには、比較的大きなクリークがよくある
・ 大きなクリークの任意の部分集合はやはりクリーク
なので、個数は大きくなる
・ 極大クリークのみを列挙しよう
クリーク
- 数が1/10~1/1000 に減る
- 任意のクリークは極大クリークに含ま
れるので、情報の損失がない
- 極大なほうが、中途半端なグループを含みにくく、
モデルとして的確
極大なクリークだけを上手に列挙できるか
探索の難しさと枝刈り
・ 極大クリークは山の頂上に対応
 単純な操作では行きあえない
・ そもそも、原点のそばに極大ク
リークがない
111…1
・ バックトラックが通じない
が、枝刈りをすると実に効率が良い
(上に登っても、以前見つけた
極大クリークに含まれるクリークしか
みつからないとき、枝刈りをする)
クリーク
000…0
ここでは、逆探索による多項式時間列挙を紹介
極大クリークの隣接関係
・ 極大クリーク K から、添え字の大きい順に頂点を抜いていく
・ どこかで「現在のクリークを含む辞書順最小の極大クリークK’」
が K でなくなる
(辞書順最小極大クリーク
=添え字の小さい順に頂点を加えてできる極大クリーク)
・ その K’を K の親 とする (一意的に定まる)
(prefix 保存飽和拡張とほとんど同じ。保存されないけど)
・ 親は子どもより必ず辞書順で小さいので、親子関係は非巡回的
 親子関係は有向根付き木を導出する
逆探索
親子関係は有向根付き木を導出する
この木を深さ優先探索すれば全ての解を見つけられる
・ 探索には、子供を見つけるアルゴリズムがあれば十分
・ 子供が1つあたり多項式時間で見つかれば、全体も多項式時間
非巡回的な親子関係と、子供を見つける多項式時間アル
ゴリズムがあれば、なんでも多項式時間列挙ができる
子どもの特徴づけ
・ K[i]: K に頂点 i を加え、i に隣接する頂点を取り除きできたク
リークを、含む辞書順最小のクリーク
・ K' が K の子供  K[i] = K' がいずれかの i について成り立つ
i
K[i] だけ調べればよい (高々|V|個)
・ i が K のどの頂点とも隣接しないなら、
K[i] の親は i を含む辞書順最小のクリーク
ここが多項式
性のポイント!
通常は、消すもの
が一通りでない
通常は K に隣接する i のみ調べればよい (高々(Δ+1)2個)
例題
・このグラフで実際の親子関係を見てみる
1, 2
3
1
3
7
5
4
1, 3, 5
6
2, 4, 6, 8
7
10
8
9
12
2
4
11
10
3, 5, 7, 9, 12
11
9, 11
11
6, 8, 10
11
8, 10, 11
4, 8, 11
12
10, 12
例題
・このグラフで実際の親子関係を見てみる
1, 2
3
1
3
7
5
4
1, 3, 5
6
2, 4, 6, 8
7
10
8
9
12
2
4
11
10
3, 5, 7, 9, 12
11
9, 11
11
6, 8, 10
11
8, 10, 11
4, 8, 11
12
10, 12
辞書順最小の極大クリークを求める
・ CAND(K):頂点集合 K の全ての頂点に隣接する頂点の集合
・ CAND(K) の中で最小添え字の頂点を
K に加える、という作業を、
CAND(K) が空になるまで続ける
・ CAND(K∪i) = CAND(K) ∩ (iに隣接する頂点)
なので、 i の次数の時間で更新可能
・ クリークの大きさは、最大次数 Δよりも高々1大きいだけなので、
繰り返し解数は、高々 Δ+1
O(Δ2) 時間で、「K を含む辞書順最小のクリーク」が求められる
親を計算する
・ K のいずれかの頂点に隣接する頂点全てについて、「 K のいく
つの頂点と隣接するか」を記録 (r(v)とする)
 r(v) = |K| ⇒ K に追加可能
・ K の最大添え字の頂点から順に消していき
r(v) を更新する ( O(Δ2) 時間)
 r(v) = |K| となるものができたら
K に追加可能な頂点が現れたということ
・ その時点で、 K を含む極大クリークを見つければよい
O(Δ2) 時間で、K の親が計算できる
子どもを見つける
通常は K に隣接する i のみ調べればよい (高々(Δ+1)2個)
O(Δ2) 時間で、K[i] の親が計算できる
・ 以上から、子どもを全て見つけるのにかかる時間はO(Δ4) であ
ることがわかる
・ アルゴリズムは、各反復で極大クリークを1つ見つける
極大クリークは1つあたり O(Δ4) 時間で列挙できる
子どもの特徴づけ
・ K<i: K に含まれる、添え字が i 未満の頂点の集合
・ C(K): K を含む辞書順最小のクリーク
・ N(v): v に隣接する頂点の集合(近傍)
・ K[i] が K の子ども 
① K<i ∩N(vi) = K[i]<i
② C(K<i ∩N(vi) ) = K
特に ② は、 が Kの親 L に対して、K = L[j]、j<i となることと、
② C(K<i ∩N(vi) )>i = K>i が成り立つことが必要十分
頂点 vi より前のみを見ればよい
高速計算の技法
・ 全ての集合は、配列で保持する(メモリもまとめて確保)
・ アクセスを良くするため、頂点の添え字順に並べておく
① K<i ∩N(vi): 普通に計算すれば、 O(|K<i|+| N(vi)<i| )
 振り分けを使って改良
・ K の各頂点 vj に対し、 N(vj)>j の各頂点のバケツにvjを挿入
・ 終了後、vi のバケツの中身は K<i ∩N(vi)
 計算時間は O(|K<i∩N(vi)<i| )
・ 再帰呼び出しを添え字の大きい順にすることで、バケツは再帰
呼び出し内で繰り返し使える
 初期設定でvi に大きさ N(vi) のバケツを確保すれば、
2度と確保しないでよい
計算時間
・ 疎なグラフであれば、極大クリークの数は通常非常に小さい
(頂点数の 10から100倍くらい)
ソーシャルネットワークデータ: 4万頂点 6万枝  3秒
辞書データ: 4万頂点 10万枝  50秒
webデータ: 500万頂点 5000万枝  1時間くらい?
…
現実的な疎データでは、だいたい全列挙可能と考えてよい
参考文献など
・ 築山らのアルゴリズム (‘78)
初の多項式時間アルゴリズム
・ 宇野らのアルゴリズム (‘03) 改良版。大きく疎なデータでも速い
・ 富田らのアルゴリズム (‘04) 枝刈りを用いた列挙。密でも速い
・ クリークの応用の文献は星の数ほど(Nature などにもある)
“クラスタリング” + “クリーク” などで検索
・ 実装 MACE: (MAximal Clique Enumerator)
http:research.nii.ac.jp/~uno/
宇野のHP
4.出力が多くない列挙問題
解の数が少なくても
・ 通常、列挙問題として考えられる問題は、
解が組合せ的で、最悪で指数個 存在する
・ そのような列挙問題で重要だったのは、解の数に対する計算時
間。1つ見つけるのに、平均どれくらいの時間がかかるか
・ この概念は、解の数がそれほど多くない問題でも重要
・ 出力が組合せ的でない例をいくつか見てみよう
4.1. 計算幾何学の列挙問題
計算幾何学
・ computational geometry のこと。(計算機科学ではない)
・ 幾何学的なデータをどのように扱い、問題をどのように解くかを
探求する分野
・ 幾何学的な構造を出力するときは、単なる数値を出すだけでは
ないことが多く、そうなると出力の大きさは O(1) ではない
・ 凸包構成問題と線分交差判定問題を紹介する
凸包
・ 平面上(一般には d 次元空間上)にある点集合を含む最小の凸
多角形(多面体)を見つける問題
・ 計算幾何学の3大基礎問題のような位置づけ
・ 出力の大きさは多角形の辺の数なので、最大 n
・ O(n log n) 時間で解ける。ソートが帰着できるので、これは最適
余談:一般次元だと
・ 3次元以上だと、面を出力する問題。面の数は O(nd/2) だそうで
す。
・ 幾何変換をすると、面で与えられた多面体の端点を出力す
る問題になる
(a1,…,ad)
=>
a1x1,…,adxd = c
行進法
・ y軸方向に一番下にある点を見つける。タイがあるときは、一番
右のものを選ぶ
・ そこからラップを包むように凸包の辺を見つける
・ 計算時間は、辺を見つける時間 × 辺の数
・ 出力の大きさに線形のアルゴリズム
次の辺を見つけるには
・ 現在の頂点から、各頂点へのベクトルを求める
・ 時計回り順で一番最後になるベクトルが、次の辺
・ 計算時間は O(n)。最適ではないが、出力数依存
・ 実際、ランダムな点配置では、辺の数は O(log n) 程度だそうだ
辺を1つずつ見つけるところが、出力数依存にきいている
線分交差判定問題
・ 平面上(一般には d 次元空間上)にある線分の集合に対して、
どの線分の組が交差するか調べる問題
・ 出力は辺の組なので、最大 n2。最悪、全部が交差する。
・ 2つの線分の交差判定は O(1) 時間でできる
・ 単純に全ての組を比較するアルゴリズムは、入力の大きさの
意味では最適なアルゴリズム
・ 出力数依存のアルゴリズムが作れるか?
スイープ法
・ 垂直な走査線を一番左から一番右へと移動し、途中にある交点
を1つずつ見つける
・ ① 線分の始まり ② 線分の終わり ③ 交点
をイベント点として、イベント点をたどってスキャンする
・ 次に来そうなイベント点を、x 座標をキーにしてヒープに突っ込
み、小さいものから順に取り出す
スイープ法
・ 走査線上で隣り合う線分のみ、交点があるかどうか調べる
 交わる2つの線分は、交点直前のイベント点で必ず隣接する
ので、これだけで全部見つけられる
・ 時間は (イベント点数)×(ヒープ操作時間) = O((n+K)log n)
 交点の数 K に対して線形時間
隣り合うものだけを見ることで、全部見ないですむ
他にも
- 文字列マッチング (部分文字列としてマッチするところを見つけ
る)
- 時系列データの中から、要素の平均が大きな区間を見つける
問題
- 平面上に与えられた頂点集合を含む、何らかの条件を満たす
極小な四角を見つける問題
4.2 類似項目の列挙
類似項目の発見
・ 工学的な基礎的な問題でも、解の少ない列挙問題はある
・ データベースの項目の中で、似た項目のペアを全て見つける
(項目のペア全てについて、
2項関係が成り立つかを調べる)
・ 類似している項目の検出は、
データベース解析の基礎的な手法
 基礎的なツールがあれば、使い方しだいで
いろいろなことができる
(大域的な類似性、データの局所的な関連の構造・・・)
類似項目発見の計算時間
・ 似たもののペアを全て見つけるさい、項目のペア全てについて、
単純に全対比較を行うと項目数の2乗の時間がかかる
 項目数が100万を越えるころか現実的には解けなくなる
100万×100万 ÷100万(演算per秒) = 100万秒
・ 類似検索を使う手もあるが、100万回のクエリを実行しなければ
ならない。類似検索は完全一致より大幅に時間がかかる
 1秒間にクエリが1000回できるとして、1000秒
問題が大きいので、平均的な意味でよいので、
計算オーダーの小さいアルゴリズムがほしい
応用1:リンクが似ているwebページ
・ リンク先、あるいはリンク元が、集合として似ているページは、
よく似ていると考えられる
 サッカーのページ、料理のページ、地域のページ
・ グループ化すれば、コミュニティー発見、著名なトピック、web
の構造の解析など、いろいろなことがやりやすくなる
・ さらに、例えば、「スパムサイト」の検出にも使えるかも
(レポート課題のコピーの検出、とか)
応用3:長い文章の比較
・ (文庫本のような)長い文章がいくつかあるときに、類似する部
分がどことどこにあるかを検出したい
 長い文章の比較はそれ自体が大変(時間がかかる)ので、
複数あると手が出ない
・ 長い文章を、短い文字列にスライスし、全体を比較する
 大域的に似た部分は、局所的に似ている
ところを多く含むと思われる
つまり、似ている短い文字列のペアを多く含む
・ 短い文字列の全対比較からアプローチできる
応用5: 特異的な部分を見つける
・ 似ているものがない項目は、データの中で特異的な部分と考え
られる
- 携帯電話・クレジットカードの不正使用
- 制御システムの故障・異常の発見
- 実験データから新しいものを発見
- マーカーの設計 (「宇野毅明のホームページは、”助教授,
宇野毅明の研究”で検索するとユニークに定まる)
・ 比較的大きなデータが複数あるような場合でも、特異な項目を
多く含むもの、他のどのデータとも、似ている部分が少ないもの
は、特異なデータだと考えられる
・ 「似ている項目の数」は、データがエラーを含む際の統計量とし
て使えるかも知れない
問題設定:短い文字列の比較
・ 具体的に見るため、扱うデータベースと問題を具体化する
問題: 各項目が同じ長さ l の短い文字列(50文字程度)である
データベースを入力したときに、文字列のペアで異なり数が d 文
字以下である組を全て見つけよ
(ハミング距離がd 以下)
・ 全ての項目が同じだと、およそ(項目数)2 個の出力がある
・ 現実には、やたらと似てるものがあるものを比較しても意味が
無い
 出力は少ないと仮定する
例題
・ ABC、ABD、ACC、EFG、FFG、AFG、GAB のペアでハミ
ング距離が1以下のものを求めよ
A
A
A
E
F
A
G
B
B
C
F
F
F
A
C
D
C
G
G
G
B
G
A
A
A
E
F
A
A
B
B
C
F
F
F
B
C
D
C
G
G
G
A
A
A
A
E
F
G
B
C
B
F
F
F
A
C
C
D
G
G
G
B
A
A
A
A
E
F
G
B
B
C
F
F
F
A
C
D
C
G
G
G
B
イメージ的には
・ 似ているもののペアを探す問題は、マトリクスのセルの中で必
要なものを全て見つける問題
・ 全対比較は、マトリクスのセルをすべて見ていることに対応
・ 分類によるアルゴリズムは、
分類を順々にしていると思えば、
木構造の探索を行っていることに対応
ゲノムの比較 (2)
ヒトX染色体とマウスX染色体の比較
・ 30文字で間違い2文
字以下のペアを列挙
・ 長さ3000、幅300
の領域に3つペア
があれば点を打つ
PCで 1時間で可能
X
・ ノイズをかなり
除去できている
マ
ウ
ス
染
色
体
ヒトX番染色体
4.3 包含関係の列挙
問題の定義
入力: 部分集合族(トランザクションデータベース) D = {T1,…,Tn}
( ただし、各 Ti はアイテム集合 E = {1,…,n} の部分集合)
+ 閾値 θ
出力: |Ti∩Tj| がθより大きいような、
全てのTi 、Tjのペア
例: 閾値 θ=2 のとき、
(A,B), (A,C), (A,D), (A,E)
(C,D), (C,E), (D,E)
D =
A: 1,2,5,6,7
B: 2,3,4,5
C: 1,2,7,8,9
D: 1,7,9
E: 2,7,9
F: 2
D が巨大かつ疎で(各Ti が平均的に小さい)、出力の数がそれ
ほど多くない( ||D|| の数倍)状況での高速化を考える
単純に全対比較すると
・ 単純に全対比較するアルゴリズムを考える
D =
for i=1 to |D|-1
for j=i to |D|
if |Ti∩Tj|≧ θ then output (Ti, Tj )
A: 1,2,5,6,7
B: 2,3,4,5
C: 1,2,7,8,9
D: 1,7,9
E: 2,7,9
F: 2
・ 共通部分の計算は、各 Ti をアイテム順でソートしておき、Ti 、Tj
をマージソートのように並行してスキャンすればよい。
時間はO(|Ti |+| Tj|)
・ 全体の計算時間は ∑i,j(|Ti |+| Tj|) = 2n ||D||
かなり時間がかかると見てよい
振り分けによる高速化
・各Ti に対し、|Ti∩Tj|がθ以上になるものを見つける問題を考える
・ 各アイテム e に対して、e を含む部分集合の集合を D(e) とする
・ Ti が含む各 e に対して、D(e) の各 T に対して、カウントを1つ増
やす、という作業をする
 全ての e∈Ti についてこの作業をすると、各 Tj のカウントは
|Ti∩Tj| になる
for each e∈Ti
for each Tj∈ D(e), j>i, do c(T)++
・ D(e) を添え字順にソートしておくと、j>i である
Tj∈ D(e) を見つけるのも簡単
D =
A: 1,2,5,6,7
B: 2,3,4,5
C: 1,2,7,8,9
D: 1,7,9
E: 2,7,9
F: 2
振り分けの計算時間
for each e∈Ti
for each Tj∈ D(e), j>i, do c(T)++
・ 計算時間は
∑j ∑e∈Ti |{ Tj∈D(e), i<j}| = ∑e |D(e)|2
 |D(e)| が平均的に小さければ、かなり速い
D =
A: 1,2,5,6,7
B: 2,3,4,5
C: 1,2,7,8,9
D: 1,7,9
E: 2,7,9
F: 2
1再帰呼び出しの計算時間のイメージ
・ 普通に頻出度の計算をすると
各 X+e に対してデータを
一回スキャンする
・ 共通部分による計算は
D(e) と D(e) のをスキャンする
 D(X) を n-t 回スキャンし、
データベースの t より大きな
アイテムをスキャンする
・ 振り分けは D(X) に含まれるトランザ
クションの t のをスキャンする t より
大きなアイテムをスキャンする
(n-t)個
+
t
t
(n-t)個
計算実験
・ webリンクのデータの一部を使用
- ノード数 550万、枝数1300万
- Pentium4 3.2GHz、メモリ2GB
・ リンク先 20個以上 288684個、20個以上共有する
ペア数が143683844個、計算時間、約8分
・ リンク元 20個以上が 138914個、20個以上共有する
ペア数が18846527個、計算時間、約3分
・ 方向を無視して、リンクが 100個以上あるものが 152131個、
100個以上共有するペア数が32451468個、計算時間、約7分
・方向を無視して、リンクが20個以上あるものが370377 個、
20個以上共有するペア数が152919813個、計算時間、約14分
簡単に追加できる条件
・ |A∩B| が、|A| のα倍以上 、(and/or) |B| のα倍以上
・ |A∩B| / |A∪B| ≧ α
・ |A∪B| -|A∩B| ≦ θ
など。
この手の、共通部分や和集合の大きさから計算できる評価値
であれば、簡単に評価できる
・ 計算時間は、ほぼ線形で増えていくと思われるので、多少
大きなデータでも大丈夫
まとめ
・ 列挙アルゴリズムの展望: 不整データと解候補列挙
・ 列挙アルゴリズムの難しさ: 解きたい問題に合わせた努力
・ 高速化の方法: 末広がり的な構造を使い、末端を高速化
- 頻出集合: データベース縮約
- 頻出集合: 頂点次数の管理
・ 難しい問題に対する手法:
- 分枝限定法: 探索順の変更による、枝刈りの効率化
- 極大クリーク: 探索順の変更による、枝刈りの効率化
面白い研究・ビジネスを目指してがんばってください
5. 演習問題
演習:初級1
① 数 a1,...,an を入力し、合計が b 以下となる組合せの中で極大な
ものを全て列挙する(多項式時間)アルゴリズムを設計せよ。(ヒン
ト:数をソートしておくといいことがある)
② 無向グラフとその頂点 s と t を入力し、s と t を結ぶパスを列挙
するアルゴリズムは、分割法で簡単に設計できる。
(sに接続する枝の、どれを選ぶか、で分枝する)
この問題を大規模なネットワークで解くときには、モデルとしてどの
ような点を気をつけるべきか。また、高速化を行うには、どのような
点を注意すればよいか。
③ グラフを入力し、その枝2連結である部分グラフで極小なものを
列挙するアルゴリズムを、講義の設計法に沿って設計せよ。多項
式性は問わない
演習:初級2
④ 2次元平面上に定義された各辺が軸に平行な長方形の集合が
与えられたとする。このとき、これら長方形の共通部分によって作
られる長方形を列挙したい。このような列挙問題に対して、解の数、
列挙法について論ぜよ。
⑤ 数列 a1,...,an に対して、その部分列 b1,...,bm で、bi>bi+1が任意
のiについて成り立つものを降順列とよぶ。(部分列は、列から一
部の数を順番を変えずに取り出したものである。)与えられた数列
a1,...,an の極大な降順列を列挙するアルゴリズムを設計せよ(ただ
し、数列内の任意の2つの数は異なるとする)
⑥ 状態の集合 V の上で定義されたマルコフ過程があるとする。
このとき、ある状態 S∈V から出発し、10回の遷移を行って得られ
る状態の列を全て列挙するアルゴリズムを設計せよ。また、その
高速化手法について論ぜよ。
演習:初級3
⑦ グラフとその頂点s を入力し、sから始まるハミルトンパスを全て
列挙するアルゴリズムを設計せよ。多項式性は問わない
演習:中級1
① 頂点が平面上の点の集合であり、各枝が点対を結ぶ線分であり、
かつどの2つの線分も内点を共有しない(真に交わらない)ようなグラ
フを平面埋め込みグラフという。極大な平面埋め込みグラフは、外面
を除くすべての面が3角形になることが知られている。与えられた2次
元上の点集合に対し、それを頂点集合とする極大な平面埋め込みグ
ラフの列挙問題を、部分グラフの列挙問題に帰着して解く方法を論
ぜよ。
② 無向グラフの s-t パス、サイクル、全張木の間に、列挙の帰着関
係を示せ。(どれを使うとどれが解ける、これよりこれが解が多い等)
③ 木 T が与えられたとき、T の葉を逐次的に取って T が空となる
まで取って、得られる頂点の列を T の葉除去列とよぶ。全ての葉除
去列を列挙するアルゴリズムを構築し、高速化の可能性を議論せよ。
また、計算量を算定せよ。
演習:上級1
① グラフ G=(V,E) と整数 k を入力し、G[U] の最大次数が k 以下と
なるような U を列挙する問題を解くアルゴリズムを構築し、高速化を
行うにはどのようなことを行えばよいか、論ぜよ。また、そのようなも
のの中で極大なものだけを列挙する多項式性アルゴリズムは存在
するか、論ぜよ。
② 全張木の列挙問題に対する講義中のアルゴリズムの計算時間を
算定せよ
③ 各項目が同一の頂点集合を持つグラフであるようなデータベース
があるとする。このとき、枝の差分が k 本以内であるような項目の組
を列挙するアルゴリズムを設計せよ