簡易DPLLアルゴリズムによるSAT Solver
そろそろ関数型言語もやっとかないとね、ということでF#でプログラミングしてみる。
参考文献
- プログラミングF#
- 実践F# 関数型プログラミング入門
SAT Solver
- ちょっと前に「P=NP証明か?」とか話題になったね。
- DPLLアルゴリズム
- DPLLアルゴリズム - Wikipedia
- 真偽値の確定する論理変数を考慮しつつバックトラック法でしらみ潰しに真偽値の割り当てを探索する
F#で実装
- 1リテラル規則のみを使用
- だからまぁ早くはない
- 論理変数は整数で表現
- 否定(not)は単項マイナスで表現
- だからリテラルはintで表せる
- 節(clause)はint list、論理式はint list list でそれぞれ表現
/// リテラルvに真を割り当てる let assign (F : int list list) (v:int) = F |> List.filter (List.forall ((<>) v)) |> List.map (List.filter ((<>) -v)) /// 1リテラル規則を適用 let rec apply_unit_rule (F: int list list) = match F |> List.tryFind (fun cl -> cl.Length = 1) with | Some v -> apply_unit_rule (assign F v.Head) | None -> F /// DPLL(1リテラル規則のみ) let rec DPLL (F : int list list) = match apply_unit_rule F with | [] -> true | newF when List.exists List.isEmpty newF -> false | newF -> let v = newF.Head.Head DPLL (assign newF v) || DPLL (assign newF -v) // 充足可能な時 let SatFormula = [ [ -1; 2 ]; [ 1; -2 ] ] printfn "%A, %A" "SatFormula" (DPLL SatFormula) // 充足不能な時 let UnsatFormula = [ [ 1; 2 ]; [ 1; -2 ]; [ -1; 2 ]; [ -1; -2 ] ] printfn "%A, %A" "UnsatFormula" (DPLL UnsatFormula)
↓実行結果
"SatFormula", true "UnsatFormula", false
こんなに短く書けるF#超楽しい。
SATに関してその他もろもろ
- だいたい毎年SAT Solverの性能を競うコンペが開かれる SAT Competitions
- 入力形式はDIMACS
- SATLIB - Benchmark Problemsとかにベンチマーク用のファイルがいっぱいある
- 入力形式はDIMACS