diff template library
TRANSCRIPT
diff template libraryTatsuhiko Kubo
http://d.hatena.ne.jp/cubicdaiya
自己紹介
・名前 : 久保 達彦・ HatenaID:cubicdaiya・ twitter:@cubicdaiya・ HP:http://cccis.jp・職業 : プログラマ,時々サーバ管理者
diff template libraryとは
•拙作の diff ライブラリ (C++)
•略して dtl
•由来は C++ の STL(Standard Template Library
dtl-cpphttp://code.google.com/p/dtl-cpp/
dtl という名前は既に使われていたので、この名前に (_ _)
プロジェクトページ
今日の朝、最新版(1.08) をリリースしま
した。
dtl の特徴 (1)
•任意の型を持つ二つの要素列の差分が計算できる
•Unified Format が扱える
•C++ プログラムから diff3 が使える
•C++ プログラムから patch が使える
dtl の特徴 (2)
•修正 BSD ライセンス
•ヘッダファイルのみで構成
•他のライブラリには極力依存しない
•64bit 対応済
•生のポインタ使ってます
とりあえず使ってみよう
二つの文字列の差分を取る
二つの int 型配列の差分を取る
template によって要素と要素列という形で抽象化されるので、
いろんな場面で活用できる
・文字列 ( 文字の列 )・ int 型の配列 ( 数値の列 )・テキストファイル ( 文字列から成る行の列 )・ etc
三つの文字列をマージする
変更箇所が衝突した場合
patch
dtl の内部構造
そもそも Diff とは?
•Difference( 違い、差分 )
•複数のファイル間の差分を取るプログラム
Diff を取るというのは、
•Levenshtein Distance( 編集距離 )
•LCS(Long Common Subsequence)
•SES(Short Edit Script)
↑ の 3 つを求めることと同義
A から B への変換を実現するための要素の追加と削除の合計回数
2 つの要素列を A と B とするabcdef → acbedf C a D b C c D d A b C e A d C f
C: 共通 , D: 削除 , A: 追加
Levenstein Distance = A(n) + D(n) = 4
A(n) = 2, D(n) =2
Levenstein Distance
2 つの要素列を A と B とするabcdef → acbedf C a D b C c D d A b C e A d C f
C: 共通 , D: 削除 , A: 追加 LCS = (C a) + (C c) + (C e) + (C f) = acef
LCS
A と B の最長共通部分列
2 つの要素列を A と B とするabcdef → acbedf C a D b C c D d A b C e A d C f
C: 共通 , D: 削除 , A: 追加
SES
これ
A から B への変換を最小の編集回数で行うための手順
エディットグラフ
エディットグラフ
a
b
c
d
e
f
d a c f e a(0, 0)
(M, N)
x 軸
y 軸
•y 軸方向に +1 進む (SES の「追加」 )
•x 軸方向に +1 進む (SES の「削除」 )
• y 軸と x 軸の対角線上に進む (SES の「共通」 )
• 「共通」の場合のコストは 0 、それ以外は 1
Diff とは
a
b
c
d
e
f
d a c f e a(0, 0)
(M, N)
x 軸
y 軸
エディットグラフ上の点 (0, 0) から点 (M, N) (M=6, N=6) までの最短経路を求める問題
コスト = 編集距離
色んな Diff アルゴリズム
•動的計画法
•Myers のアルゴリズム
•Wu のアルゴリズム
•Gestalt Approach
差分の計算はかなり重い処理なので効率的なアルゴリズムが必要
dtl における差分の求め方
Wu のアルゴリズムを活用
•SES における削除回数 P に注目
•エディットグラフにおける座標 (M, N)までの最短経路を P=0 から 1 ずつ増やしていって探索する
•平均計算量は O(N+PD)
•最悪でも O(NP)
D = Δ + 2P
•二つの要素列の長さをそれぞれ M, N とする
•Δ = N - M (N >= M)
•D は編集距離
•P は SES における「削除」の合計数
Δ = D
a
b
c
a b c d e f
(3, 6)
a(0, 0)
Δ = 3
Δ ≠ D
a
b
c
d
q q a b e f(0, 0)
(4, 6)D=Δ の対角線からはみ出たらはみ出た分だけ戻ってこないといけない
P
Δ
P
D=Δ+2P により、探索範囲は以下のようになる
(0, 0)
(M, N)
P
Δ P
ここまでが探索範囲
探索の仕方
•fp(k, p) : P=p の時点で対角線k上における到達可能な最遠点
•snake(k ,y) : P=p の時点で任意の点(x, y) から到達可能な最遠点の y 座標を計算する関数
•k = y - x, p の初期値は 0 で 1 ずつ増やしていく
•fp(k, p)=N の時点での p が SES の削除回数 P
対角線 k = y - x
p(p, 0)
k = -p
pΔ
k= Δ
k= Δ+p
(0, 0)
(M, N)x
y
Wu のアルゴリズムの実装例http://github.com/cubicdaiya/onp
その他の機能の実装についてちょこっと紹介
diff3 の実装
dtl のマージ手順
1. 要素列 B と A の差分を取る (SES を SES_BA とする )2. 要素列 B と C の差分を取る (SES を SES_BC とする )3. SES_BA と SES_BC を先頭から比較していき、A と C の変更点が組み合わされた要素列 S を生成する
patch の実装
patch は SES を使えば簡単
擬似コードです
•google-diff-match-patch
•LibXDiff(Git で使われている )
その他の diff ライブラリ
参考文献
•S.W.Maner, G.Myers, W.Miller, "An O(NP) Sequence Comparison Algorithm"
最後に
もし C++ で diff したくなったり、必要になったら是非使ってみてください。
バグレポートやパッチも大歓迎↓
http://code.google.com/p/dtl-cpp
ご静聴ありがとうございました