Algebraic DP: 動的計画法を書きやすく

5,081 views

Published on

PFI社内セミナー(2012/11/22)で動的計画法の新手法・代数的動的計画法について発表した際の発表資料です。発表の模様はこちら: http://www.ustream.tv/recorded/27196711

Published in: Technology
0 Comments
8 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
5,081
On SlideShare
0
From Embeds
0
Number of Embeds
45
Actions
Shares
0
Downloads
22
Comments
0
Likes
8
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Algebraic DP: 動的計画法を書きやすく

    1. 1. Algebraic DP:動的計画法を書きやすく 石井 大海
    2. 2. 自己紹介• 石井 大海 (id:mr_konn / @mr_konn)• 早稲田大学数学科三年 • 集合論やモデル理論、圏論、代数学に興味 • 函数型言語、定理証明系など形式手法にも興味• 2010 Summer Intern から PFI でバイト中 • Haskell で Twitter やWebのクローラを書いている
    3. 3. 今日のおはなし• 朗報:Haskell の話じゃありません! • が、Haskell を使います。• Algebraic Dynamic Programming (ADP) • 連続データに対する動的計画法の新しい 設計・実装法 • バイオインフォマティクスの分野から
    4. 4. Table of Contents• 動的計画法の復習 • 動的計画法とは? • 動的計画法の例• ADP の紹介 • 動的計画法の問題点 • ADP とは?──原理と例 • ADP の改良版• まとめ
    5. 5. 動的計画法の復習
    6. 6. 動的計画法とは?動的計画法(どうてきけいかくほう、英: DynamicProgramming, DP)は、コンピュータ科学の分野において、ある最適化問題を複数の部分問題に分割して解く際に、そこまでに求められている以上の最適解が求められないような部分問題を切り捨てながら解いていく手法である。分割統治法がトップダウン的な手法であるのに対し、動的計画法はボトムアップ的な手法といえる。 ── 動的計画法 - Wikipedia
    7. 7. 動的計画法とは?動的計画法(どうてきけいかくほう、英: DynamicProgramming, DP)は、コンピュータ科学の分野において、ある最適化問題を複数の部分問題に分割して解く際に、そこまでに求められている以上の最適解が求められないような部分問題を切り捨てながら解いていく手法である。分割統治法がトップダウン的な手法であるのに対し、動的計画法はボトムアップ的な手法といえる。 ── 動的計画法 - Wikipedia
    8. 8. 結局どういうこと?• 小さい範囲の最適解を組み合わせて解ける最適 化問題を• 小さい部分での結果をメモ化しながら解く方法 • 指数時間かかりそうなものがだいたい多項式 時間で解けるようになる• 部分問題と全体の漸化式で表わされ、アルゴリズ ムはメモ化行列への反復作業として記述される
    9. 9. 動的計画法の例• 編集距離• 最長一致部分列• 括弧の位置最適化• 最長増加部分列
    10. 10. 編集距離• 入力:二つの文字列• 出力:一方の文字列に文字を挿入・削除す ることで他方の文字列にするのに必要な最 短手数• 例:(darling, airline) • 4(darling→arling→airling→airlin→airline)
    11. 11. 編集距離の考え方• 入力:(a1a2...an, b1b2...bm) • d[i, j] = a1...ai と b1...bj の編集距離 • d[i+1, j+1] の候補: • ai+1 までを bj に編集して、bj+1を足す • ai までを bj+1 に編集して、ai+1 を削る • ai までを bj に編集して、ai+1を削ってbj+1を足す • これらの中で最も手数が少ないもの
    12. 12. 編集距離の漸化式• これをメモ化して、i, j を 1 から埋めて 再帰していく
    13. 13. 実装例(Ruby)def edit_distance(as, bs) n = as.length m = bs.length d = Hash.new {|h, k| h[k] = Hash.new(0)} for i in 0..n d[i][0] = i end for j in 0..m d[0][j] = j end for i in 1..n for j in 1..m delta = as[i] == bs[j] ? 0 : 2 d[i][j] = [d[i-1][j] + 1, d[i][j-1] + 1, d[i-1][j-1] + delta].min end end return d[n][m]end • 境界での初期化が必要になる
    14. 14. 問題• 挿入、削除に加えて置換を 1 score とカ ウントするように修正してみよ。• 実際に書き換える方法を示せ • 最小手が複数ある場合は列挙せよ一般に評価関数を書き換えたり出力を拡張するのは難しい
    15. 15. 最長一致部分列(LCS)• 入力:二つの文字列• 出力:一致する部分列の最大長 • 例:LCS(darling, airline) = 5 (“arlin”)• 漸化式:d[i, j] = a , b までの LCS の長さ i j • 境界値:d[0, j] = d[i, 0] = 0
    16. 16. 問題• 実際に一致部分列を挙げよ • 複数ある場合は全て列挙してみよ
    17. 17. 計算順序最適化• 入力:括弧のついていない数式 A• 出力:適切に括弧を付けて、答えを最大 / 最小化せよ • 例: 1 + 2 × 3 • 最大:(1+2) × 3 = 9 最小:1+(2×3)=7• 数式のパーズ・ill-formed な部分列は排除し なくてはいけない• 面倒なので、数字は一桁だけにする
    18. 18. 漸化式• a + b,a, b が最適値のとき。そこで ぞれ a × b が最適値を取るのは、それ• d[i, j] = (i +1)文字∼ j 文字までの最適解• 後はメモ化して書けばよいが、構文エ ラーなどの NULL の処理が入る• 上の添字で合っているかぶっちゃけ不安
    19. 19. 最長増加部分列(LIS)• 与えられた数列の中で最も長い増加部 分列の長さを求める。• 入力:{3, 1, 4, 2, 5}• 出力:3({3, 4, 5} と {1, 2, 5} が最長)
    20. 20. 最長増加部分列• d[i] = i 番目の要素が最後にくる増加列 の長さ• 候補:以下の内の長い方 • a のみから成る列 i • a 以前の a 未満の元の列に追加 i i
    21. 21. まとめ• DP = メモ化 + 部分最適化 • 部分最適解から全体最適解が得られる時 に使う • 指数空間の問題をほぼ多項式時間で解け る• 添字の処理が面倒(バグの温床)• デバッグ・検証が難しい• 細かな拡張性がわるい
    22. 22. ADP の紹介
    23. 23. 動的計画法の問題点• 行列に対する反復操作 • 意味がわかりづらい • 添字がバグの温床• 最適化・評価が渾然一体 • 変更がしづらい• 効率や正当性の検証がしづらい
    24. 24. ADP とは?• 発想:解の生成と評価フェーズを分離 • 最適化関数を再帰的に適用することで計 算量を減らす • コンパイラによる最適化等も活用• 対象となる入力は「データ列」 • 文字列に限らず、行列列、数列でもよい
    25. 25. 解生成と評価の分離• DP を 文法 と 代数 に分割 • うわっ難しそう……;; • 名前がゴツいだけ! • 列をパーズして解の候補を生成、最適化 しつつ評価、というのを形式的に書いた
    26. 26. ADP 作業の流れ1. データ列の要素を決める2. 扱う演算を決める3. 評価関数を考える4. 文法を書く
    27. 27. 例:編集距離• 文字の削除・挿入・置換の回数が最小に なるように文字列を書き換えたい• データ列の要素:文字• 扱う演算の決定 • 削除・挿入・置換を行った場所と、文字 列の終端がわかればよい
    28. 28. 評価代数の決定• 評価代数とは: • 前で決めた演算に対応する評価関数 • 解の候補から最適解を絞り込む最適化関数 h 標準的な「編集距離」 のスコア関数
    29. 29. 評価代数の例2 • 解の列挙や数え上げにも使える • 文法の定義の正当性を確認出来る!列挙用代数。Nil などはコンストラクタ 数え上げ用代数
    30. 30. 文法の定義(木)• 入力:(“darling”, “airline”) • 一本にしたいので “darling$enilria” のように纏める
    31. 31. 文法• 木構造のパーズに使う文法:木文法 • 能力的には CFG と同等 • 導出規則に操作名のラベルを付けただけ
    32. 32. 実際のコード:文法alignmentGrammar :: AlignmentAlg Char ans -> String -> String -> [ans]alignmentGrammar AlignmentAlg{..} inp1 inp2 = let inp = inp1 ++ $: reverse inp2 edit = tabulated $ -- 計算結果がメモ化可能であるということ nil <<< char $ -- 終端;区切りは $ ||| del <<< anychar -~~ edit -- 削除 ||| ins <<< edit ~~- anychar -- 挿入 ||| match <<< anychar -~~ edit ~~- anychar -- 置換 ... h -- 最適化函数がこれらの枝全てに適用可能 z = mk inp (_, n) = bounds z char = char z anychar = acharSep z $ tabulated = table n in axiom n a • ほぼ文法を ASCII に置き換えただけ • 評価関数・メモ化の有無を注釈できる
    33. 33. 最適化関数 h と文法• 解全体に h を適用すると指数時間 • パーズしながら h が適用出来れば枝が 刈れて、多項式時間で解ける!• 「h を適用可能」を文法に注釈
    34. 34. コード:評価代数-- | 編集距離の評価代数の型data AlignmentAlg alph ans = AlignmentAlg { nil :: alph -> ans -- ^ 終端 , del :: alph -> ans -> ans -- ^ 削除 , ins :: ans -> alph -> ans -- ^ 挿入 , match :: alph -> ans -> alph -> ans -- ^ 置換 , h :: [ans] -> [ans] -- ^ 最適化函数 }-- | 列挙用のデータ型data Edit = Nil | Del Char Edit | Ins Edit Char | Match Char Edit Char deriving (Eq, Ord, Show)-- | 列挙用評価代数enum :: AlignmentAlg Char Editenum = AlignmentAlg (const Nil) Del Ins Match id-- | 数え上げ用評価代数count :: AlignmentAlg Char Intcount = AlignmentAlg nil del ins match h where nil _ = 1; del _ s = s; ins s _ = s; match _ s _ = s h [] = [] h x = [sum x]
    35. 35. 編集距離の代数 -- | 編集距離計算用の評価代数 unit :: AlignmentAlg Char Int unit = AlignmentAlg nil del ins match h where nil _ = 0 -- 終端のスコアはゼロ del _ s = s + 1 -- 削除したら距離 + 1 ins s _ = s + 1 -- 挿入したら距離 + 1 match a s b | a == b = s -- 文字が一致したらそのまま | otherwise = s + 2 -- 一致しなければ + 2 h [] = [] h xs = [minimum xs] -- 編集距離最小のものを選ぶ• 列挙も評価も統一的に記述出来る!
    36. 36. 試してみる• 二つの代数の積 ⨂ を使うと、複数の条 件を組み合わせることが出来るghci> alignmentGrammar count "darling" "airline"[48639]ghci> alignmentGrammar unit "darling" "airline"[4]ghci> alignmentGrammar (unit ⨂ pretty) "darling" "airline"[(4,("da-rling-","-airlin-e")),(4,("da-rlin-g","-airline-")), (4,("da-rling","-airline"))]
    37. 37. 例:最長一致部分列• 実は、先程の文法を使って書ける • 文字が一致した時だけスコ アを +1 • 最大値を持つものが欲しい • 重複ケースが出るので、枝 刈りするには文法を改善
    38. 38. 例:計算順序最適化 • 今度は複数桁に対応してみる • 必要な演算は加算、乗算、数値、数値の拡張data Bill = Add Bill Char Bill -- ^ 加算 | Mul Bill Char Bill -- ^ 乗算 | Ext Bill Char -- ^ 数字の桁の続き "123" の 3 の部分 | Val Char -- ^ 数字 deriving (Show, Eq, Ord)data BillAlg alph ans = BillAlg { add :: ans -> alph -> ans -> ans , mul :: ans -> alph -> ans -> ans , ext :: ans -> alph -> ans , val :: alph -> ans , h :: [ans] -> [ans] }
    39. 39. 代数 -- | 数式を pretty print する代数 pretty :: BillAlg Char String pretty = BillAlg add mul ext val h where add x _ y = "(" ++ x ++ " + " ++ y ++ ")" mul x _ y = "(" ++ x ++ " * " ++ y ++ ")" val c = [c] ext i c = i ++ [c] h = id -- | 最小化代数 billMin :: BillAlg Char Int billMin = BillAlg add mul ext val h where add x _ y = x + y mul x _ y = x * y val c = digitToInt c ext i c = i * 10 + digitToInt c h [] = [] h xs = [minimum xs]• 列挙・数え上げ・最大化も同様
    40. 40. 文法 billGrammar :: BillAlg Char ans -> String -> [ans] billGrammar BillAlg{..} inp = axiom n bill where bill = tabulated $ -- 結果をメモ化する number ||| (add <<< bill ~~- char +) ~~~ bill -- 右側のパーズ結果が一定の文字数を越えないとき ~~- を使う -- 結合的でないので括弧がついている ||| (mul <<< bill ~~- char *) ~~~ bill ... h -- 数式それ自体には最適化函数を逐次適用 number = val <<< digit ||| ext <<< number ~~- digit -- 数値のパーズに h をつけてもしょうがない -- メモ化する意味も余りない• メモ化・最適化関数の適用を陽に指定できる強み• 文法を定義するのでパーズと解生成を一気にできる
    41. 41. 例:最長増加部分列• 解の生成で増加列を直に生成出来ればいいが…• 木文法は CFG とほぼ同等。「増加列」の概念 は木のラベル込みだと文脈依存になる(ハズ)• 全ての部分文字列を生成して、評価関数でフィ ルターするより他にない • ADP には向かない例(省略)
    42. 42. まとめ:ADP• データ列に対する DP の抽象化• 解の生成と評価・最適化を分離 • モジュラリティが高い • 似た問題をほぼ同じ枠組で解ける• 添字が出て来ない(バグ温床の解消)• 文法のデザインが一番難しい• CFG で表現出来ない物は余り向かない
    43. 43. 時間計算量?• 書き易さや検証可能性はよい。計算量は?• 仮定:最適化関数 h の返す値の数は有界(1 個とか n 個以下とか)• count 代数や最適化関数は一つなので良い• n-best 解も n で抑えられるのでよい• 列挙代数は爆発するので駄目• 文法から計算量の見積りが出来る
    44. 44. 計算量の見積り• weight(G) : 文法に現れる木の中でサイズが抑えられない非 終端記号(非有界ノードと呼ぶ)の数の最大値 - 1• このとき、時間計算量 O(n2+width(G)) となる• 計算量の見積りも簡単• 計算量を減らすには文法の非終端記号を分割して工夫する
    45. 45. 見積りの例• 編集距離:非有界ノードは edit のみ。 どの木にも一つずつしか出現しないの で width(G) = 0。計算量はO(n2)• 計算順序:非有界ノードは bill と number。bill は add や mul に二回登場。 width(G) = 1。計算量はO(n3)
    46. 46. 発展• ADP は生のチューンされた DP よりは速くな かったりする • Stream Fusion の技術と組み合わせて C のと 定数倍くらいの差まで迫れる• 複数入力を一つに纏める必要がある • MCFG(Multiple CFG)を使って複数入力に対 応したバージョンもある
    47. 47. MCFGの例:編集距離rewriteDel [c, a1, a2] = ([c, a1], [a2])rewriteIns [c, a1, a2] = ([a1], [c, a2])rewriteMatch [c1,c2,a1,a2] = ([c1, a1], [c2, a2])edit = tabulated2 $ nil <<< (EPS, EPS) >>>|| id2 ||| del <<< anychar ~~~|| edit >>>|| rewriteDel ||| ins <<< anychar ~~~|| edit >>>|| rewriteIns ||| match <<< anychar ~~~ anychar ~~~|| edit >>>|| rewriteMatch ... h• 複数入力をどう変形するかルールを書く• 細かい解説は省略。
    48. 48. 参考文献• “The Algebraic Dynamic Programming Homepage”, ADP project team, 2009• “adp-multi”, Maik Riechert, 2012• “A Discipline of Dynamic Programming over Sequence Data”, Robert Giegerich, Carsten Meyer and Peter Steffen, 2004• “Sneaking Around concatMap - Efficient Combinators for Dynamic Programming”, Christian Honer zu Siederdissen, 2012• “Algebraic Dynamic Programming”, R. Giegerich and C. Meyer, 2002• “プログラミングコンテストチャレンジブック”, 秋葉拓哉, 岩田 陽一 and 北側宜稔, 毎日コミュニケーションズ, 2010• “動的計画法 - Wikipedia”, Wikipedia, 2012
    49. 49. Any Questions?
    50. 50. 御清聴ありがとうございました

    ×