25
Purely Functional Data Structures 輪輪 輪 10 輪 “ Data-Structural Bootstrapping” 2006/07/21 輪輪輪 [email protected] p

Purely Functional Data Structures 輪講 第 10 章 “ Data-Structural Bootstrapping”

  • Upload
    carnig

  • View
    46

  • Download
    0

Embed Size (px)

DESCRIPTION

Purely Functional Data Structures 輪講 第 10 章 “ Data-Structural Bootstrapping”. 2006/07/21 いなば [email protected]. 今日の内容. Data-Structural Bootstrapping ある抽象データ構造を作るときに、実装の中で その抽象データ構造自身を利用すること Structural Decomposition 実装の中で自分自身を再帰的に使用するパターン ( やや微妙な ) 例: 普通の List - PowerPoint PPT Presentation

Citation preview

Page 1: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

Purely Functional Data Structures 輪講第 10 章

“ Data-Structural Bootstrapping”

2006/07/21 いなば[email protected]

Page 2: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

今日の内容 Data-Structural Bootstrapping

ある抽象データ構造を作るときに、実装の中でその抽象データ構造自身を利用すること

① Structural Decomposition 実装の中で自分自身を再帰的に使用するパターン

( やや微妙な ) 例: 普通の List

② Structural Abstraction 同じインターフェイスを持つ別の実装をラップして

機能を追加したり計算量を改善したりするパターン 例 : ExplicitMin Heap (Ch3):

③ Bootstrapping To Aggregate Types 型 t に関する実装を使って t list などに関する

効率的な実装を作るパターン

Page 3: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

① Structural Decomposition

実装の中で自分自身を再帰的に使用Uniform

Non-uniform

type ‘a list = Nil | Cons of ‘a * ‘a list

type ‘a seq = Nil | Cons of ‘a * (‘a*’a) seq

Page 4: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

注意事項 : Non-Uniform Recursion(Polymorphic Recursion) このようなデータ型は、 ML の型システム

ではあまりうまく扱えないtype ‘a seq = Nil | Cons of ‘a * (‘a*’a) seq

let rec length s = match s with Nil -> 0 | Cons(_,t) -> 1 + 2*(length t)

File "test.ml", line 7, characters 36-37:This expression has type ('a * 'a) seq but is here used with type 'a seq

Page 5: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

注意事項 : Non-Uniform Recursion(Polymorphic Recursion) 方法1 : Coercion

方法2 : Explicit Type Annotation (Haskell)

type ‘a EP = E of ‘a | P of ‘a EP * ‘a EPtype ‘a seq = Nil | Cons of EP ‘a * ‘a seq

len :: Seq a -> Intlen s = case s of Nil -> 0 Cons _ t -> 1 + 2*(len t)

Page 6: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

例1Binary Random-Access List Rivisited

さっきの

は実用上はあまり意味がない。(サイズ 2n-1 のリストしか表現できない)

→ Numerical Representation の考え方で→ “ BinRan.hs”

type ‘a seq = Nil | Cons of ‘a * (‘a*’a) seq

Page 7: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

例1Binary Random-Access List Rivisited

第9章の RList と何が違うのか?type ‘a tree = Leaf of ‘a | Node of ‘a tree * ‘a treetype ‘a digit = Zero | One of ‘a treetype ‘a rlist = (‘a digit) list本質的な違いはない

cons, head, tail, get, set は O(log n)

Non-Uniform Recursion によって 桁ごとの weight が倍々になっていることを型で保証 「次の桁」を得るのが簡単

Page 8: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

Exercise 10.2Zeroless 表現 前回の「 Zeroless 表現」も同様に non-u

niform recursion で実現できるcons, head, tail が amortized O(1)

type ‘a seq = Nil | One of ‘a * (‘a*’a) seq | Two of ‘a * ‘a * (‘a*’a) seq | Three of ‘a * ‘a * ‘a * (‘a*’a) seq

Page 9: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

例2Bootstrapped Queues 復習 : Banker’s Queue

type ‘a queue = int * ‘a list lazy_t * int * ‘a list lazy_tlet rotate (fl,f,rl,r) = (fl+rl, f @ (rev r), 0, [])

Banker’s Queue の問題点Append が Left-Associative に使われる

計算量的には問題ないが、実用面では少し遅い

(((f @ (rev r1)) @ (rev r2)) @ (rev r3)) @ ..

Page 10: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

例2Bootstrapped Queues どうするか?

実際に append はしないで、リストのリストとしてとっておく。

{ (rev r1), (rev r2), (rev r3), ... }

このリスト↑に適用したい演算は?先頭からの取り出し末尾への追加

(((f @ (rev r1)) @ (rev r2)) @ (rev r3)) @ ..

Queue !!

Page 11: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

例2Bootstrapped Queues 実装の概要

type ‘a queue = int * ‘a list lazy_t * (‘a list lazy_t) queue * int * ‘a list lazy_t

let rotate (fl,f,m,rl,r) = (fl+rl, f, snoc m (rev r), 0, [])

let tail (fl,_::[],m,rl,r) = (fl-1, head m, tail m, rl, r)

Page 12: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

例2Bootstrapped Queues 計算量

(rev r) の suspension が作られるタイミング・評価されるタイミングは Banker’s Queue と同じ

rev の分に関しては、 Amortized O(1)

snoc,tail は内部 Queue の snoc,tail を呼び出す 内部 Queue の長さは O(log n) よって nest の深さは Hyper-logarithm O(log* n)

snoc, tail は O(log* n) log* (265536) = 5 なので、実質的に定数

Page 13: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

② Structural Abstraction

同じインターフェイスを持つ別の実装をラップして機能を追加したり計算量を改善する

Queue をラップして効率的に append できるQueue

Heap をラップして効率的に merge できるHeap

Page 14: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

例3Catenable Queues head, tail, cons, snoc, append が Amortized

O(1) な Queuehead, tail, cons ができるので List とも呼べる

発想はさっきの Bootstrapped Queues と同じすでに既存の ‘ a queue (head, tail, snoc が amorti

zed O(1) なもの ) が実装済みと仮定

→ “catQ.ml”

type ‘a cat = E | C of ‘a * ‘a cat queue

Page 15: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

例3Catenable Queues 計算量

tail 以外は自明に O(1) tail も頑張って証明すると、償却 O(1)

直感的には、 tail は O(Queue のサイズ ) でQueue のサイズ = それまでに append した回数なので append で将来の tail の分の借金を払えばOK

Persistent に使っても償却 O(1) にしたい時はtype ‘a cat = E | C of ‘a * ‘a cat lazy_t queue

Page 16: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

例4Heaps with Efficient Merging Heaps with Efficient Merging

insert, merge, findMin : 最悪 O(1) deleteMin : 最悪 O(log n)

実装済みと仮定する Heap insert : 最悪 O(1) mergin, findMin, deleteMin : O(log n) たとえば

Scheduled Binomial Heap (7.3) Skew Binomial Heap (9.3.2)

Page 17: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

例4Heaps with Efficient Merging 発想はやはりさっきと同じ

→ “emheap.ml”

ただし、‘ a emheap 間の比較演算を、「最小要素が小さい方が小さい」と定義

type ‘a emheap = E | H of ‘a * ‘a emheap heap

Page 18: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

② Structural Abstraction まとめ (1) 元にするデータ構造

どこか1カ所に関する、効率的な要素追加関数どこか1カ所に関する、効率的な要素取得関数type ‘a Baseval add : ‘a -> ‘a Base -> ‘a Base val get : ‘a Base -> ‘a例

‘a Queue と snoc と head ‘a Heap と insert と findMin

Page 19: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

② Structural Abstraction まとめ (2) Bootstrap されたデータ構造

要素追加要素取得

type ‘a BootStrapped = E | B of ‘a * (‘a BootStrapped) Base

let add x b = join (Base.add x Base.empty) blet get (B(x,_)) = x

Page 20: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

② Structural Abstraction まとめ (3) Bootstrap されたデータ構造

二つの Bootstrapped 構造を「結合」 Queue の append 、 Heap の merge

let join (B(x1,bs)) b = B(x1, Base.add b bs)

Structural Abstraction によって、このような「結合」演算を効率化できる

Page 21: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

③ Bootstrapping To Aggregates

型 t に関する実装を使って t list などに関する効率的な実装を作る例 : t を key とする Map を使って、

t list を key とする Map を作るmodule type Map = sig type ‘a map; type key val empty : ‘a map val lookup: key -> ‘a map -> ‘a val bind : key->‘a->‘a map->‘a mapend

Page 22: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

例Trie 一般的な Map

key 上の順序比較を使ったバランス木による実装 O( log(Map のサイズ ) ) 回の比較で検索

リストの比較 要素毎の比較を辞書式順序に拡張したものとするこ

とが多い 最悪 O( リストの長さ ) の時間

リストを Key とする Map 最悪 O( Key の長さ * log(Map のサイズ ) ) の検索時

Page 23: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

例Trie 「リストを Key とする辞書式順による M

ap 」を 「要素を Key とする Map 」 から Bootstrap→ “trie.ml”module Trie(B : Map) : Map = struct type key = B.key list type ‘a map = Trie of ‘a option * (‘a map) B.map ...

Page 24: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

おはなしGeneralized Tries Trie の考え方は、

リストに限らず一般の product と sum による型に適用できるα MapFrom_β×γ = (α MapFrom_β) MapFrom_γ

α MapFrom_β + γ = (α MapFrom_β) × (α MapFrom_γ)

Page 25: Purely Functional Data Structures  輪講 第 10 章 “ Data-Structural Bootstrapping”

おはなしGeneralized Triestype ‘a tree = E | T of ‘a * ‘a tree * ‘a treemodule TrieOfTree(B:Map) : Map = struct type key = B.key tree type ‘a map = Some ‘a * ‘a map map B.map

let rec lookup t mp = match t, mp with | E, (None, _) -> raise Not_found | E, (Some v,_) -> v | T(e,a,b) (_,m) -> lookup b (lookup a (B.lookup e m))end