20分でわかる Purely Functional Data Structures

Similar documents
Microsoft PowerPoint - 06.pptx

Functional Programming

PowerPoint プレゼンテーション

Microsoft PowerPoint - 6.pptx

PowerPoint プレゼンテーション

第8回 関数

Microsoft PowerPoint - kougi9.ppt

Microsoft Word - 1.抗がん剤治療を受けられるかたへ(最新版).doc

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

Microsoft PowerPoint - ProD0107.ppt

Taro-リストⅢ(公開版).jtd

PowerPoint Template

Taro-リストⅠ(公開版).jtd

Microsoft PowerPoint ppt

QXŁ\”ƒ

PowerPoint プレゼンテーション

Microsoft PowerPoint - 05.pptx

プログラミングI第10回

alg2015-3r3.ppt

Microsoft PowerPoint - chap10_OOP.ppt

2

memo

Microsoft PowerPoint - exp2-02_intro.ppt [互換モード]

contents

第2回

Microsoft PowerPoint Java基本技術PrintOut.ppt [互換モード]

PowerPoint プレゼンテーション

プログラミング基礎I(再)

Programming D 1/15

C プログラミング演習 1( 再 ) 2 講義では C プログラミングの基本を学び 演習では やや実践的なプログラミングを通して学ぶ

Microsoft PowerPoint - algo ppt [互換モード]

Microsoft PowerPoint - prog03.ppt

memo

Microsoft Word - no202.docx

デジタル表現論・第6回

org/ghc/ Windows Linux RPM 3.2 GHCi GHC gcc javac ghc GHCi(ghci) GHCi Prelude> GHCi :load file :l file :also file :a file :reload :r :type expr :t exp

GEC-Java

memo

始めに, 最下位共通先祖を求めるための関数 LcaDFS( int v ) の処理を記述する. この関数は値を返さない再帰的な void 関数で, 点 v を根とする木 T の部分木を深さ優先探索する. 整数の引数 v は, 木 T の点を示す点番号で, 配列 NodeSpace[ ] へのカーソル

論理と計算(2)

今回のプログラミングの課題 ( 前回の課題で取り上げた )data.txt の要素をソートして sorted.txt というファイルに書出す ソート (sort) とは : 数の場合 小さいものから大きなもの ( 昇順 ) もしくは 大きなものから小さなもの ( 降順 ) になるよう 並び替えること

レコードとオブジェクト

C のコード例 (Z80 と同機能 ) int main(void) { int i,sum=0; for (i=1; i<=10; i++) sum=sum + i; printf ("sum=%d n",sum); 2

PowerPoint Presentation

PowerPoint プレゼンテーション

PowerPoint プレゼンテーション

メソッドのまとめ

wireshark dissector with lua

科学的モデリング 2 回 継承 2 無断転載 & 無断配布を禁じます 第 2 回 : 科学的モデリング 継承 2 継承される特性( プロパティ ) 第 2 回の話題 継承は何を継承するのか? 今回のコラムの話題は 継承される特性 ( プロパティ ) についてです そもそもサブクラスはスーパークラスか

Microsoft Word - no206.docx

Java の ConcurrentHashMap における同期化 バッドケースとその対処法 2013 年 9 月湊隆行 1. はじめに表 1.1 に示すように Java の Collections Framework には 3 つの世代があります バージョン 1.0 から存在するレガシー API バ

Microsoft PowerPoint - Pro110111

ガイダンス

DA13

バイオプログラミング第 1 榊原康文 佐藤健吾 慶應義塾大学理工学部生命情報学科

Functional Programming

JavaプログラミングⅠ

PowerPoint プレゼンテーション

Microsoft PowerPoint - 09.pptx

スライド 1

Prog1_10th

.NETプログラマー早期育成ドリル ~VB編 付録 文法早見表~

ガイダンス

Functional Programming

ガイダンス

gengo1-11

情報処理Ⅰ演習

人工知能入門

ホームページ・ビルダー16

Microsoft PowerPoint - ca ppt [互換モード]

微分方程式 モデリングとシミュレーション

2

Functional Programming

GettingStarted.fm

4 ソフトウェア工学 Software Engineering 抽象データ型 ABSTRACT DATA TYPE データ抽象 (data abstraction) 目的 : データ構造を ( 実装に依存せずに ) 抽象的に定義 方法 : データにアクセス (read, write) する関数の仕様

PowerPoint プレゼンテーション

第3回 配列とリスト

プログラミング実習I

プログラミング入門1

次に示す数値の並びを昇順にソートするものとする このソートでは配列の末尾側から操作を行っていく まず 末尾の数値 9 と 8 に着目する 昇順にソートするので この値を交換すると以下の数値の並びになる 次に末尾側から 2 番目と 3 番目の 1

Microsoft Word - VBA基礎(6).docx

02: 変数と標準入出力

sinfI2005_VBA.doc

関数の動作 / printhw(); 7 printf(" n"); printhw(); printf("############ n"); 4 printhw(); 5 関数の作り方 ( 関数名 ) 戻り値 ( 後述 ) void である. 関数名 (

JEB Plugin 開発チュートリアル 第4回

第 3 回 Java 講座 今回の内容 今週の Java 講座はコレクション 拡張 for 文, ガベージコレクションについて扱う. 今週の Java 講座は一番内容が薄いも のになるだろう. コレクション コレクションとは大きさが決まっていない配列だと考えればよい. コレクションには List 先

グラフの探索 JAVA での実装

とても使いやすい Boost の serialization

文字列操作と正規表現

RX ファミリ用 C/C++ コンパイラ V.1.00 Release 02 ご使用上のお願い RX ファミリ用 C/C++ コンパイラの使用上の注意事項 4 件を連絡します #pragma option 使用時の 1 または 2 バイトの整数型の関数戻り値に関する注意事項 (RXC#012) 共用

Microsoft PowerPoint - lec10.ppt

2. データ構造ヒープに保存するデータは 番号付けられて保存される 従って リスト L として保存することとする 3. アルゴリズム 3.1. 要素の追加新しい要素の追加は リストの終端に置くことで開始する つまり 最下層の一番右 または新たに最下層を生成してその一番左となる この後 この要素を正し

PowerPoint プレゼンテーション

Quick Sort 計算機アルゴリズム特論 :2017 年度 只木進一

CプログラミングI

PowerPoint Presentation

memo

Microsoft PowerPoint - prog08.ppt

PowerPoint プレゼンテーション

Transcription:

20 分でわかる Purely Functional Data Structures k.inaba (http://www.kmonos.net/) Apr. 4, 2010

あらすじ 遅デいータ構造は イミュータブル

Immutable Object だけで作るデータ構造 この本の 内 容を 全速力で 布教する

お題 : キュー (Queue) FIFO (First-In First-Out) pushback(e) でデータeを入れる popfront() で取り出せる 入れた順に出てくる 以上

代入 Immutable Object でない 打倒すべき目標 破壊的キュー

手続き型でよくある interface Queue<E> { void pushback(e e); E popfront(); }

よくある実装 class HakaiQueue<E> implements Queue<E> { class Cell { E e; Cell next; } Cell fst, last; } void pushback(e e) {last=last.next=new Cell(e,null);} E popfront() {E e=fst.e; fst=fst.next; return e;} 1 2 3 4

破壊的キューの特徴 Mutable Object を使用 リスト末尾を指すポインタをもっておき末尾のセルを pushback 時に書換 1 2 3 4 Persistent でない 操作前の状態をとっておくには全コピーしかない pushback, popfront の最悪実行時間は O(1) HakaiQueue<E> q = 略 ; HakaiQueue<E> p = q; q.pushback(e); //p も変化!

Ephemeral ( 儚い ) 使い方での計算量 計算量 儚 A W ( 比較対象 ) 破壊的 2 リスト銀行家実時間 O(1) O(1) Amortized( 償却 ) 計算量 Worst-Case( 最悪 ) 計算量 詳しくはあとで 永 A W n/a n/a Persistent ( 永続的な ) 使い方での計算量

償却計算量! Immutable な実装 2 リストキュー

非破壊的キュー フィールドの書き換えを使わないキュー pushback, popfront は 操作後のキュー を別のオブジェクトを作って返す interface ImuQueue<E> { ImuQueue<E> pushback(e e); Pair<E, ImuQueue<E>> popfront(); }

非破壊キュー 単純にやると全コピー : 計算量 O(n) 1 2 3 4 コピー コピー コピー 1 2 3 4

2 リストキュー ちょっと工夫 キューの後ろの方は逆順で持つ pushback がリスト先頭への追加なので O(1) に! 1 2 3 5 4 data Queue a = Q [a] [a] -- ここからコードは Haskell です pushback (Q front rear) e = Q front (e:rear) popfront (Q [] r) = popfront (Q (reverse r) []) popfront (Q (e:f) r) = (e, Q f r)

2 リストキューの特徴 front 側と rear 側の 2 つのリストで表現 len(front) == 0 になったら rear を reverse Persistent である 最悪実行時間は reverse が発生する瞬間 O(n) でも 償却実行時間は O(1) 1 2 3 5 4 なので トータルの実行時間的に考えると計算時間は O(1) と思って問題ない!

償却計算量とは? pushback 1 [] [1] pushback 2 [] [2,1] pushback 3 [] [3,2,1] popfront [1,2,3] [] [2,3] [] popfront [3] [] pushback 4 [3] [4] popfront [] [4] popfront [4] [] [] [] 操作列全体でコストを平均化して見たときの計算量 reverse は たまにしか 起きない 時間 t かかる reverse が発生する前に 必ず t 回 pushback している

償却計算量とは? 時間 t かかる reverse が発生する前に 必ず t 回 pushback している 現実の計算量 pushback 1 popfront( 軽 ) 1 popfront ( 重 ) t+1 pushback 1 [] [1] 1 2 pushback 2 [] [2,1] 1 2 pushback 3 [] [3,2,1] 1 2 popfront [1,2,3] [] [2,3] [] 3+1 1 popfront [3] [] 1 1 pushback 4 [3] [4] 1 2 popfront [] [4] 1 1 popfront [4] [] [] [] 1+1 1 合計 12 12 分担をごまかした計算量 pushback 2 popfront( 軽 ) 1 popfront ( 重 ) 1 こう思えば全部 O(1) だしトータル計算量も変わらないので問題ない!

計算量 ( 比較対象 ) 破壊的 2 リスト銀行家実時間 儚 永 A O(1) O(1) W O(1) O(n) A n/a O(n) W n/a O(n)!?

キュー 2 リスト ブートストラップキュー 実時間キュー 銀行家キュー 銀行家キュー

2 リストキューは本当に Persistent と言えるのか??? Persistent なら 同じバージョンを 取っておいて何回も使えるはず let q = loadsomequeue () in (dohoge q) (dofuga q) (dopiyo q) (dohige q)

破滅的な例 reverse が起きる寸前のキューを何回も使う let q = needreversequeue () in (popfront q) (popfront q) (popfront q) (popfront q)

ごまかしきれてない reverse が起きる寸前のキューを何回も使う let q = pushfront (pushfront (pushfront (Queue [] []) 1) 2) 3 in (popfront q) (popfront q) (popfront q) (popfront q) 実際の計算時間は 1*3+4*4 = 19! 現実の計算量 pushback 1 popfront( 軽 ) 1 popfront ( 重 ) 1+t 計算時間は 2*3+4 = 10 です! 分担をごまかした計算量 pushback 2 popfront( 軽 ) 1 popfront ( 重 ) 1

どうしましょう Persistent な使い方 ( 同じ バージョンを何回も使い回 す ) をしても償却計算量を O(1) にするには?

さらなる工夫 len(front)==0 になったら reverse len(front)+1 == len(rear) になったら遅延評価で reverse f r 1 2 5 4 3 front の方が短くなったら早めの reverse data Queue a = Q [a] Int [a] Int pushback(q f fl r rl) e = chk (Q f fl (e:r) (rl+1)) popfront(q (e:f) fl r rl)= (e, chk (Q f (fl-1) r rl))

さらなる工夫 len(front)+1 == len(rear) になったら遅延評価で reverse data Queue a = Q [a] Int [a] Int pushback(q f fl r rl) e = chk (Q f fl (e:r) (rl+1)) popfront(q (e:f) fl r rl)= (e, chk (Q f (fl-1) r rl)) chk (Q f fl r rl) = if fl+1 == rl then (Q (f++reverse r) (fl+rl) [] 0) else (Q f fl r rl) Haskell なのでデフォルト遅延

特徴 front 側と rear 側の 2 つのリストで表現 len(front)+1 == len(rear) になったら遅延 reverse f r 1 2 5 4 3 Persistent である 最悪実行時間は reverse が発生するとき O(n) 償却実行時間は (persistent な使い方でも ) O(1)

計算量の見積もり方 積み立て金メソッド 時間 t かかる reverse の前に必ず t 回 pushback してる pushback のコストを 2 にして 先に reverse の負担の分を払っておけば OK から借金メソッドへ 早めの遅延評価 reverse しておけば 値が本当に必要になるまでに時間がある 本当に必要になる支払期限までに t 回の popfront で負担金を用意できれば問題ない

償却計算量とは? 長さ t の reverse 結果が必要となるまでに t 回は popfront するはず 現実の計算量 pushback 1 popfront( 軽 ) 1 popfront ( 重 ) x+1 分担をごまかした計算量 pushback 1 popfront 2 pushback 1 [] [1] []r[1] [] 1 1 pushback 2 []r[1] [2] 1 1 pushback 3 []r[1] [3,2] []r[1]r[3,2] [] 1 1 popfront r[1] 実行 r[3,2] [] 1+1 2 popfront r[3,2] 実行 [3] [] 2+1 2 pushback 4 [3] [4] 1 1 popfront [] [4] []r[4] [] 1 2 popfront r[4] 実行 [] [] 1+1 2 合計 12 12

少し大きい例 :pushback 1~15 [] [1] []r[1] [] []r[1] [2] []r[1] [3,2] []r[1]r[3,2] [] []r[1]r[3,2] [4] []r[1]r[3,2] [5,4] []r[1]r[3,2] [6,5,4] []r[1]r[3,2] [7,6,5,4] []r[1]r[3,2]r[7..4] [] []r[1]r[3,2]r[7..4] [15..8] []r[1]r[3,2]r[7..4]r[15..8] []

popfront [] [1] []r[1] [] []r[1] [3,2] []r[1]r[3,2] [] []r[1]r[3,2] [7,6,5,4] []r[1]r[3,2]r[7..4] [] []r[1]r[3,2]r[7..4] [15..8] []r[1]r[3,2]r[7..4]r[15..8] [] popfront: r[1] 実行 r[3,2]r[7..4]r[15..8] 1+1 popfront: r[3,2] 実行 [3]r[7..4]r[15..8] 1+1 popfront: r[7..4]r[15..8] 1+1 popfront: r[7..4] 実行 [5,6,7]r[15..8] 1+1 popfront: [6,7]r[15..8] 1+1 popfront: [7]r[15..8] 1+1 popfront: r[15..8] 1+1 popfront: r[15..8] 実行 [9..15] 1+1 借金返済間に合ってる

なぜ借金メソッド? 積立金は一度使うとなくなるけど rev に 3 億円使う let q = pushfront (pushfront (pushfront (Queue [] []) 1) 2) 3 in (popfront q) (popfront q) (popfront q) (popfront q) rev に 3 億円使う rev に 3 億円使う 3 億円貯金 rev に 3 億円使う

なぜ借金メソッド? 借金は 一度返せば大丈夫! 遅延評価でメモ化されてるから 15 億円借金 rev 実行返済 let q = []r[1]r[3,2]r[7..4][15..8] [] in (popfront q) (popfront q) (popfront q) (popfront q) メモ化されてるのでもう rev 不要 メモ化されてるのでもう rev 不要 メモ化されてるのでもう rev 不要

計算量 ( 比較対象 ) 破壊的 2 リスト銀行家実時間 儚 永 A O(1) O(1) O(1) W O(1) O(n) O(n) A n/a O(n) O(1) W n/a O(n) O(n)

注釈 銀行家キューという名前はなんですか 償却計算量の評価の方法として (Functional データ構造に限らず一般の話として ) 銀行家 (Banker) の方法 物理学者 (Phyisicist) の方法 の二つがあって その 銀行家の方法 で設計したキューという意味だそうです 本には両方の手法が紹介されています

悪計算量 定数 実時間キュー

償却計算量とはなんだったのか 分担をごまかした計算量 pushback 2 popfront( 軽 ) 1 popfront ( 重 ) 1 こう思えば全部 O(1) だしトータル計算量も変わらないので問題ない! 仮想的に 積立金 や 借金 を 考え仮想的に返済する

仮想世界を現実にする popfront で 仮想的にではなく 実際に 借金 を返す = popfront のたびに reverse 処理を 実際に ちょっとずつ実行 する

やりかた 1: 借金ポインターを追加 ( 遅延評価サンクを指しておく ) data Queue a = Q [a] Int [a] Int [a] pushback(q f fl r rl s) e = seq chk (Q f fl (e:r) (rl+1) s) popfront(q (e:f) fl r rl s) = (e, seq chk (Q f (fl-1) r rl s)) 2: chk 関数は reverse チェックのついでに無駄に遅延サンクをちょっとづつ実行 (chk 自体は遅延しないように eager 実行 )

やりかた 2.1: 借金ポインタに対してパターンマッチ = cons セル 1 個分だけ実行される chk (Q f fl r rl (_:s)) = (Q f fl r rl s) chk (Q f fl r rl []) = -- 実は fl+1 == rl のときだけこっちに来る let ff = rotate f r [] in (Q ff (fl+rl) [] 0 ff) 2.2:rotate xs ys zs は xs++rev ys++zs する関数 rotate [] (y:_) zs = y : zs rotate (x:xs) (y:ys) ff = x : rotate xs ys (y:zs) セル 1 個だけ実行 しやすい reverse

計算量 ( 比較対象 ) 破壊的 2 リスト銀行家実時間 儚 永 A O(1) O(1) O(1) O(1) W O(1) O(n) O(n) O(1) A n/a O(n) O(1) O(1) W n/a O(n) O(n) O(1)

ニューメリカル表現の 多相再帰 ブートストデラーッタプ構造 再帰 スローダウンが そのほかの話題

目次 ( 紹介した部分 ) 2~3 章 :: 簡単な関数型データ構造の紹介 2 リストキュー 赤黒木 二項ヒープ 4 章 :: 遅延評価とは 5 章 :: 償却計算量とは 6 章 :: 遅延評価を駆使して 永続性と償却計算量を両立 ( キュー, ヒープ, ) 7 章 :: リアルタイム化 ( キュー, ヒープ, ) 8~11 章 :: 関数型データ構造汎用技法集 n 進数表記に学ぶ ブートストラップ 再帰スローダウン

あとは みんな を読もう!

THANK YOU FOR LISTENING! スライド内の漫画はすべて増田こうすけ 増田こうすけ劇場ギャグマンガ日和 ( 巻の 5) からの引用です