Mercurial > hg > Papers > 2020 > ryokka-master
view paper/hoare.tex @ 12:bf3288c36d7e
update abstract_eng
author | ryokka |
---|---|
date | Mon, 10 Feb 2020 17:26:24 +0900 |
parents | 831316a767e8 |
children | e8655e0264b8 |
line wrap: on
line source
\chapter{Hoare Logic} \label{c:hoare} Floyd-Hoare Logic \cite{10.1145/363235.363259}(以下 Hoare Logic) とは C.A.R Hoare、 R.W Floyd が考案したプログラムの検証の手法である。 Hoare Logic では事前条件が成り立つとき、何らかの計算(以下コマンド)を実行した後に 事後条件が成り立つことを検証する。 事前条件を P 、 何らかの計算を C 、 事後条件を Q としたとき、 \[\{P\}\ C \ \{Q\}\] といった形で表される。 Hoare Logic ではプログラムの部分的な正当性を検証することができ、 事後条件のあとに別の コマンド をつなげてプログラムを構築することで、 シンプルな計算に対する検証することができる。 本章は Agda で実装された Hoare Logic について解説し、 実際に Hoare Logic を用いた検証を行う。 \section{Hoare Logic} 現在 Agda 上での Hoare Logic は初期の Agda\cite{agda-alpa} で実装されたものとそれを現在の Agda に対応させたもの \cite{agda2-hoare}が存在している。 ここでは現在 Agda に対応した Hoare Logic を使用する。 例として \coderef{c-while} のようなプログラムを記述した。 これは変数 \verb/n/ と \verb/i/ を持ち、\verb/n/が 0 より大きいとき、\verb/i/を増やし \verb/n/を減らす、 疑似プログラムである。 このプログラムでの状態は、初めの $n = 10$、 $i = 0$ を代入する条件、 while loop 中に成り立っている条件を $n + i = 10$、 while loop が終了したとき成り立っている条件を $i = 10$ としている。 同様のプログラムを Hoare Logic 上で同様のプログラムを作成し、検証を行う。 \begin{lstlisting}[caption=while Loop Program,label=c-while] n = 10; i = 0; while (n > 0) { i++; n--; } \end{lstlisting} \coderef{agda-hoare} は Agda 上での Hoare Logic の構築子である。 \verb/Env/ は \coderef{c-while}の \verb/n/、 \verb/i/ といった変数をレコード型でまとめたもので、\verb/n/と\verb/i/それぞれが型として Agda 上での自然数の型である $\mathbb{N}$ を持つ。 \verb/PrimComm/ は Primitive Command で、 \verb/n/、\verb/i/ といった変数に 代入するときに使用される関数である。 \verb/Cond/ は Hoare Logic の 条件で、 \verb/Env/ を受け取って \verb/Bool/ 値、\verb/true/ か \verb/false/ を返す関数となっている。 Agda のデータで定義されている \verb/Comm/ は Hoare Logic での コマンド を表す。 \verb/Skip/ は何も変更しない コマンド で、 \verb/Abort/ はプログラムを中断する コマンド である。 \verb/PComm/ は PrimComm を受けて コマンド を返す型で定義されており、 変数を代入するときに使われる。 \verb/Seq/ は Sequence で コマンド を2つ受けて コマンド を返す型で定義されている。 これは、ある コマンド から コマンド に移り、その結果を次の コマンド に渡す型になっている。 \verb/If/ は \verb/Cond/ と \verb/Comm/ を2つ受け取り、 \verb/Cond/ が \verb/true/ か \verb/false/ かで 実行する \verb/Comm/ を変える コマンド である。 \verb/While/ は \verb/Cond/ と \verb/Comm/ を受け取り、 \verb/Cond/ の中身が \verb/True/ である間、 \verb/Comm/ を繰り返す コマンド である。 \begin{lstlisting}[caption=Agda での Hoare Logic の構成,label=agda-hoare] PrimComm : Set PrimComm = Env → Env Cond : Set Cond = (Env → Bool) data Comm : Set where Skip : Comm Abort : Comm PComm : PrimComm -> Comm Seq : Comm -> Comm -> Comm If : Cond -> Comm -> Comm -> Comm While : Cond -> Comm -> Comm \end{lstlisting} Agda 上の Hoare Logic で使われるプログラムは \verb/Comm/ 型の関数となる。 プログラムはコマンド \verb/Comm/を \verb/Seq/ でつないでいき、最終的な状態にたどり着くと値を返して止まる。 \coderef{agda-hoare-prog}は \coderef{c-while}で書いた While Loop を Hoare Logic でのコマンドで記述したものである。ここでの $\$$は $()$の対応を合わせる Agda の糖衣構文で、行頭から行末までを $()$で囲っていることと同義である。 比較しやすいように \coderef{c-while} を \coderef{c-while2} に再掲した。 \begin{lstlisting}[caption= while Loop (再掲),label=c-while-2] n = 10; i = 0; while (n > 0) { i++; n--; } \end{lstlisting} \lstinputlisting[caption= \coderef{c-while2} と対応した Hoare Logic のプログラム ,label=agda-hoare-prog]{src/agda-hoare-prog.agda.replaced} %% \begin{lstlisting}[caption= Hoare Logic のプログラム ,label=agda-hoare-prog] %% ,mathescape=false %% program : Comm %% program = %% Seq ( PComm (λ env → record env {varn = 10})) %% $ Seq ( PComm (λ env → record env {vari = 0})) %% $ While (λ env → lt zero (varn env ) ) %% (Seq (PComm (λ env → record env {vari = ((vari env) + 1)} )) %% $ PComm (λ env → record env {varn = ((varn env) - 1)} )) %% \end{lstlisting} この Comm を Agda 上で実行するため、 \coderef{agda-hoare-interpret} の \verb/interpret/ 関数を作成した。 \lstinputlisting[caption=Agda での Hoare Logic interpreter ,label=agda-hoare-interpret]{src/agda-hoare-interpret.agda.replaced} \coderef{agda-hoare-interpret}は 初期状態の \verb/Env/ と 実行する コマンド の並びを受けとって、実行後の \verb/Env/ を返すものとなっている。 \verb/interpret/ 関数は停止性を考慮していないため、 \verb/{-# TERMINATING #-}/ タグを付けている。 \coderef{agda-hoare-run}のように \verb/interpret/ に \verb/vari = 0 , varn = 0/ の \verb/record/ を渡し、 実行する \verb/Comm/ を渡して 評価すると \verb/record { varn = 0 ; vari = 10 }/ のような \verb/Env/ が返ってくる。 \verb/interpret/ で実行される コマンド は \coderef{agda-hoare-prog} で記述した While Loop するコマンドである \begin{lstlisting}[caption=Agda での Hoare Logic の実行 ,label=agda-hoare-run] test : Env test = interpret ( record { vari = 0 ; varn = 0 } ) program -- record { varn = 0 ; vari = 10 } \end{lstlisting} \section{While Program の部分正当性} ここでは先程記述した \coderef{agda-hoare-prog} の部分正当性の検証を行う。 \coderef{hoare-rule} の \verb/HTProof/ は Agda 上での Hoare Logic でのコマンドに対応した性質を型としてまとめたものである。 \verb/HTProof/ では Pre-Condition とコマンド、Post-Condition を受け取って定義される Agda のデータである。 \coderef{agda-hoare} のコマンドで定義された \verb/Skip/、 \verb/Abort/、 \verb/PComm/、 \verb/Seq/、\verb/If/、\verb/While/、に対応した証明のための命題が存在している。 \verb/PrimRule/ は Pre-Condition と PrimComm、 Post-Condition、 \coderef{axiom-taut} の \verb/Axiom/ を引数として \verb/PComm/の入った \verb/HTProof/ を返す。 \verb/SkipRule/ は Condition を受け取ってそのままの Condition を返す HTProof を返す。 \verb/AbortRule/ は Pre-Contition を受け取って、\verb/Abort/ を実行する HTProof を返す。 \verb/WeakeningRule/ は通常の Condition から制約を緩める際にに使用される。 \ref{axiom-taut} の \verb/Tautology/ を使って Condition が同じであることを \verb/SeqRule/ は3つの Condition と 2つの コマンド を受け取り、これらのプログラムの逐次的な実行を保証する。 \verb/IfRule/ は分岐に用いられ、3つの Condition と 2つの コマンド を受け取り、判定の Condition が成り立っているかいないかで実行する コマンド を変えるルールである。 この時、どちらかの コマンド が実行されることを保証している。 \verb/WhileRule/ はループに用いられ、1つの コマンド と2つの Condition を受け取り、事前条件が成り立っている間、 コマンド を繰り返すことを保証している。 \lstinputlisting[caption=Axiom と Tautology,label=axiom-taut]{src/axiom-taut.agda.replaced} \coderef{hoare-rule}を使って \coderef{c-while}の WhileProgram の仕様を構成する。 \lstinputlisting[caption=Agda での Hoare Locig の構成,label=hoare-rule]{src/agda-hoare-rule.agda.replaced} 全体の仕様は Code \ref{agda-hoare-while}の \verb/proof1/ の様になる。 \verb/proof1/ では型で initCond、 Code \ref{agda-hoare-prog}のprogram、 termCond を記述しており、 \verb/initCond/ から \verb/program/ を実行し \verb/termCond/ に行き着く Hoare Logic の証明になる。 それぞれの Condition は Rule の後に記述されている \verb/{}/ に囲まれた部分で、 \verb/initCond/のみ無条件で \verb/true/ を返す Condition になっている。 それぞれの Rule の中にそこで証明する必要のある補題が \verb/lemma/ で埋められている。 \verb/lemma1/ から \verb/lemma5/ の証明は概要のみを示し、全体は付録に載せる。 これらの lemma は HTProof の Rule に沿って必要なものを記述されており、 \verb/lemma1/ では PreCondition と PostCondition が存在するときの代入の保証、 \verb/lemma2/ では While Loop に入る前の Condition からループ不変条件への変換の証明、 \verb/lemma3/ では While Loop 内での PComm の代入の証明、 \verb/lemma4/ では While Loop を抜けたときの Condition の整合性、 \verb/lemma5/ では While Loop を抜けた後のループ不変条件からCondition への変換と termCond への移行の整合性を保証している。 \lstinputlisting[caption=Agda 上での WhileLoop の検証,label=agda-hoare-while]{src/agda-hoare-while.agda.replaced} %% \begin{lstlisting}[caption=Agda 上での WhileLoop の検証,label=agda-hoare-while] %% proof1 : HTProof initCond program termCond %% proof1 = %% SeqRule {λ e → true} ( PrimRule empty-case ) %% $ SeqRule {λ e → Equal (varn e) 10} ( PrimRule lemma1 ) %% $ WeakeningRule {λ e → (Equal (varn e) 10) ∧ (Equal (vari e) 0)} lemma2 ( %% WhileRule {_} {λ e → Equal ((varn e) + (vari e)) 10} %% $ SeqRule (PrimRule {λ e → whileInv e ∧ lt zero (varn e) } lemma3 ) %% $ PrimRule {whileInv'} {_} {whileInv} lemma4 ) lemma5 %% \end{lstlisting} proof1 は\coderef{agda-hoare-prog}の program と似た形をとっている。 Hoare Logic では Comannd に対応する証明規則があるため、仕様はプログラムに対応している。 \section{Hoare Logic での健全性} \coderef{agda-hoare-while} では Agda での Hoare Logic を用いた仕様の構成を行った。 この仕様で実際に正しく動作するかどうか(健全性)を検証する必要がある。 \coderef{agda-hoare-satisfies} は Hoare Logic 上での部分正当性を確かめるための関数である。 \verb/SemComm/ では Comm を受け取って成り立つ関係を返す。 \verb/Satisfies/ では Pre Condition と コマンド、 Post Condition を受け取って、 Pre Condition から Post Condition を正しく導けるという仕様を返す。 \lstinputlisting[caption= State Sequence の部分正当性,label=agda-hoare-satisfies]{src/agda-hoare-satisfies.agda.replaced} %% \begin{lstlisting}[caption= State Sequence の部分正当性,label=agda-hoare-satisfies] %% SemComm : Comm -> Rel State (Level.zero) %% SemComm Skip = RelOpState.deltaGlob %% SemComm Abort = RelOpState.emptyRel %% SemComm (PComm pc) = PrimSemComm pc %% SemComm (Seq c1 c2) = RelOpState.comp (SemComm c1) (SemComm c2) %% SemComm (If b c1 c2) %% = RelOpState.union %% (RelOpState.comp (RelOpState.delta (SemCond b)) %% (SemComm c1)) %% (RelOpState.comp (RelOpState.delta (NotP (SemCond b))) %% (SemComm c2)) %% SemComm (While b c) %% = RelOpState.unionInf %% (λ (n : $mathbb{N}$) -> %% RelOpState.comp (RelOpState.repeat %% n %% (RelOpState.comp %% (RelOpState.delta (SemCond b)) %% (SemComm c))) %% (RelOpState.delta (NotP (SemCond b)))) %% Satisfies : Cond -> Comm -> Cond -> Set %% Satisfies bPre cm bPost %% = (s1 : State) -> (s2 : State) -> %% SemCond bPre s1 -> SemComm cm s1 s2 -> SemCond bPost s2 %% \end{lstlisting} これらの仕様を検証することでそれぞれの コマンド に対する部分正当性を示す。 \coderef{agda-hoare-soundness} の \verb/Soundness/ では \verb/HTProof/ を受け取り、 \verb/Satisfies/ に合った証明を返す。 \verb/Soundness/ では \verb/HTProof/ に記述されている Rule でパターンマッチを行い、対応する証明を適応している。 \verb/Soundness/ のコードは量が多いため部分的に省略し、全文は付録に載せることにする。 \lstinputlisting[caption=Agda での Hoare Logic の健全性,label=agda-hoare-soundness]{src/agda-hoare-soundness.agda.replaced} \coderef{agda-hoare-prim-soundness} は \verb/HTProof/ で記述された仕様を、実際に満たすことが可能であることを \verb/Satisfies/ が返す。 証明部分では \verb/HTProof/ で構成された使用を受け取り、 \verb/Soundness/ が対応した証明を返すようになっている。 \begin{lstlisting}[caption=HTProof の Soundness への適用,label=agda-hoare-prim-soundness] PrimSoundness : {bPre : Cond} -> {cm : Comm} -> {bPost : Cond} -> HTProof bPre cm bPost -> Satisfies bPre cm bPost PrimSoundness {bPre} {cm} {bPost} ht = Soundness ht \end{lstlisting} \coderef{agda-hoare-prim-proof} では \coderef{agda-hoare-prog} の \verb/program/ の Hoare Logic での命題である。 この証明では初期状態\verb/initCond/と実行するコマンド群\verb/program/を受け取り終了状態として \verb/termCond/ が \verb/true/ であることを示す。 \begin{lstlisting}[caption=while program の健全性,label=agda-hoare-prim-proof] proofOfProgram : (c10 : $mathbb{N}$) → (input output : Env ) → initCond input ≡ true → (SemComm (program c10) input output) → termCond {c10} output ≡ true proofOfProgram c10 input output ic sem = PrimSoundness (proof1 c10) input output ic sem \end{lstlisting} この証明は実際に構築した仕様である \verb/proof1/ を \verb/\verb/PrimSoundness/ に入力として渡すことで満たすことができる。 ここまで記述することで Agda 上の Hoare Logic を用いた \verb/while program/ を検証することができた。