view user/ryokka/master-slide.md @ 18:46800d30a182

backup 2021-01-07
author autobackup
date Thu, 07 Jan 2021 00:10:03 +0900
parents b6c284fd5ae4
children
line wrap: on
line source

Continuation Based C の Hoare Logic を用いた仕様記述と検証
=====

琉球大学大学院 : 並列信頼研究室\
外間 政尊

---

## OS の検証技術としての Hoare Logic の問題点
- OS やアプリケーションの信頼性は重要な課題

- 信頼性を上げるために仕様の検証が必要

- 検証にはモデル検査や**定理証明**などが存在する

- また、仕様検証の手法として **Hoare Logic** がある
  -通常の関数でも実行する前に必要な引数があって何らかの出力がある
  - Hoare Logic ではコマンドを実行する上で引数が存在するなどの事前に成り立つ条件があり、コマンド実行後に異なる条件が成り立つ
- Hoare Logic では関数が最低限のコマンドで分割されており記述が困難(変数の代入、コマンド実行の遷移等)

---
## Hoare Logic をベースにした Gears 単位での検証
- 当研究室では 処理の単位を **CodeGear**、データの単位を **DataGear** としてプログラムを記述する手法を提案
- CodeGear は Input DataGear を受け取り、処理を行って Output DataGear に書き込む
- CodeGear は継続を用いて次の CodeGear に接続される
- 定理証明支援機の Agda 上で Gears 単位を用いた検証を行う
- 本研究では Gears 単位を用いた Hoare Logic ベースの検証手法を提案する

---

## Agda
 Agda は関数型言語
```AGAD
    name : type
    name = value
```
関数には型と定義を与える\
型は **:** で、 値は **=** で与える\
仮定なしに使えるのは Set のみ

構成要素としては以下の3種類
1. 関数
    - 型は(A : Set かつ B : Set のとき) A → B
    - 値は(x : A かつ y : B) λ x → y
1. record
1. data

---

## Agda の record とその例 ∧
導入は2つのものが同時に存在すること
```
   A   B    
------------ 
   A ∧ B    
```
除去は名前を区別する必要がある
```
   A ∧ B           A ∧ B 
 --------- pi1   --------- pi2       
     A               B
```
A ∧ B が成り立っていれば (pi1 A ∧ B) → A、 (pi2 A ∧ B) → B\
Agda ではこのような同時に存在する型を **record** で書く
```AGDA
   record _∧_ (A B : Set) : Set
     field
         pi1 : A
         pi2 : B
```
\_∧\_ は中間記法、変数が入る位置を _ で示せる\
実際の構築は x : A かつ y : B のとき
```AGDA
createAnd : (A : Set) → (B : Set) → A ∧ B
createAnd x y = record {pi1 = x ; pi2 = y}
```
のように記述する\
C 言語での構造体のようなもの

A や B に論理式が入ると2つのものが同時に成り立つ証明ができる

---

## Agda の data とその例 Sum
導入\
一つでも存在すること
```
        A               B
  ----------- p1   ---------- p2
     A ∨ B            A ∨ B  
```
除去\
A → C か B → C のとき C
```
               A      B
               :      :
      A ∨ B    C      C    
   ------------------------ 
           C                
```


A ∨ B が成り立っているとき A → A ∨ B、 B → A ∨ B\
どちらかが成り立つ型を **data** で書く\
```AGDA
    data _∨_ (A B : Set) : Set where
       p1 : A → A ∨ B
       p2 : B → A ∨ B
```
のように記述できる\
C 言語での union のようなもの\
p1、 p2 は case 文みたいな感じ

---

## Hoare Logic
Hoare Logic はプログラム検証の手法\
事前条件( P )が成り立つとき、コマンド( C )を実行すると事後条件( Q )が成り立つ

これは **{ P } C { Q }** の形で表され、Hoare Triple と呼ばれる


今回は以下のような while program を検証する

n = 10 となっているが検証では n は任意の自然数
```C
    n = 10;
    i = 0;

    while (n>0)
    {
      i++;
      n--;
    }
```

---

## Agda での Hoare Logic
Hoare Logic のプログラムは Command で構成される

Comm 型は data で記述されたコマンドのデータ構造

実際に実行するには解釈して動かす関数が必要

Commを使って while program を構築する

```AGDA
    data Comm : Set where
      Skip  : Comm
      Abort : Comm
      PComm : PrimComm → Comm
      Seq   : Comm → Comm → Comm
      If    : Cond → Comm → Comm → Comm
      While : Cond → Comm → Comm
```

---

## Hoare Logic での while program
検証する while program の擬似コード
```C
    n = 10;
    i = 0;

    while (n>0)
    {
      i++;
      n--;
    }
```
コマンドで構成した while program
```AGDA
    program : ℕ → Comm
    program c10 = 
        Seq ( PComm (λ env → record env {varn = c10}))
        $ 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)} ))
```

これは Hoare Logic のコマンドで以下のような構文木を記述している

```
        Seq
       /    \
   PComm     Seq
 (n=c10)     /  \
         PComm   While
         (i=0)      |
                  Cond
                  (0<n)
                    |
                   Seq
                  /   \
              PComm    PComm
              (i+1)     (n-1) 
```

---

## Hoare Logic での Command に対応する仕様
Command に対応する証明がある

**HTProof** は Hoare Triple Proof

**{P} Q {C}** が **Cond → Comm → Cond** に対応している

```agda
    data HTProof : Cond → Comm → Cond → Set where
```
すべての Command に対応する Proof を載せると長いので
必要なものだけ

\
PrimRule は 代入のときに成り立ってほしいルール

Axiom は Triple を受け取ってすべての Env は事前の Env が正しければ コマンドを実行した後のEnv も正しくなるという命題
```AGDA
      PrimRule : {bPre : Cond} → {pcm : PrimComm} → {bPost : Cond} →
                 (pr : Axiom bPre pcm bPost) →
                 HTProof bPre (PComm pcm) bPost
```
WekeningRule は 条件を緩める規則

While コマンドなどで条件が厳しいときに同時に成り立つ異なる条件へ変更必要がある

Tautology は2つの Cond 型 bPre、 bPre' を受け取り、 bPre が成り立つとき、 bPre'が成り立つという命題
```agda
      WeakeningRule : {bPre : Cond} → {bPre' : Cond} → {cm : Comm} →
                    {bPost' : Cond} → {bPost : Cond} →
                    Tautology bPre bPre' →
                    HTProof bPre' cm bPost' →
                    Tautology bPost' bPost →
                    HTProof bPre cm bPost
```
SeqRule は Seqcuence が正しい順番で行われることを保証

cm1、cm2 という2つのCommを受け取ってそれらがcm1、cm2の順で実行される

```
      SeqRule : {bPre : Cond} → {cm1 : Comm} → {bMid : Cond} →
                {cm2 : Comm} → {bPost : Cond} →
                HTProof bPre cm1 bMid →
                HTProof bMid cm2 bPost →
                HTProof bPre (Seq cm1 cm2) bPost
```
WhileRule は Comm 型の cm と Cond型の bInv、 bが存在するとき、
事前に
```
      WhileRule : {cm : Comm} → {bInv : Cond} → {b : Cond} →
                  HTProof (bInv and b) cm bInv →
                  HTProof bInv (While b cm) (bInv and neg b)
```
検証をするためにはこの HTProof で program と同様の仕様を構成する必要がある

## Hoare Logic での 仕様記述
HTProof で記述した仕様

HTProof が コマンドに対応しているのでほとんど同じ形で書けてる
```AGDA
    proof1 : (c10 : ℕ) → HTProof initCond (program c10 ) (termCond {c10})
    proof1 c10 =
        SeqRule {λ e → true} ( PrimRule (init-case {c10} ))
        $ SeqRule {λ e →  Equal (varn e) c10} ( PrimRule lemma1   )
        $ WeakeningRule {λ e → (Equal (varn e) c10) ∧ (Equal (vari e) 0)}  lemma2 (
                WhileRule {_} {λ e → Equal ((varn e) + (vari e)) c10}
                $ SeqRule (PrimRule {λ e →  whileInv e  ∧ lt zero (varn e) } lemma3 )
                         $ PrimRule {whileInv'} {_} {whileInv}  lemma4 ) lemma5
```

```AGDA
    program : ℕ → Comm
    program c10 = 
        Seq ( PComm (λ env → record env {varn = c10}))
        $ 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)} ))
```
proof1 は条件がつながるのに必要な条件を lemma で記述している(lemma は長いので省略)

部分正当性は示せている

全体がつながっているが証明にはなっていない


---
## Hoare Logic での健全性の証明
実際に正しく動作すること(健全性)を証明する必要がある

Satisfies は {P} C {Q} を受け取ってそれらが Comm で正しく成り立つ関係を返す

PrimSoundness は HTProof を受け取って Satisfies が成り立つことを Soundness を用いて実際に証明する
```AGDA
    PrimSoundness : {bPre : Cond} -> {cm : Comm} -> {bPost : Cond} ->
                HTProof bPre cm bPost -> Satisfies bPre cm bPost
    PrimSoundness {bPre} {cm} {bPost} ht = Soundness ht
```
Soundness は HTProof に対応した非常に複雑な証明

HTProof を渡すと Ruleに対応した証明を行う

proofOfProgram では 実際に構築した program と proof1 を使って健全性を証明している

```AGDA
    proofOfProgram : (c10 : ℕ) → (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
```

---
## Continuation based C について
Continuation based C (CbC) は当研究室で開発してるプログラミング言語

CbC では処理の単位を **CodeGear** 、データの単位を **DataGear** とする

CodeGear は引数として Input の DataGear を受け取り、 Output の DataGear を返す

Output の DataGear は次の CodeGear の Input として接続される


![](/attachment/5e42fdea7b378d004670d2fc)
![](./fig/cgdg-small.svg)
CodeGear の接続処理などのメタ計算は Meta CodeGear として定義

Meta CodeGear で信頼性の検証を行う





---
## Agda での CodeGear、 DataGear の記述

- Agda での CodeGear は継続渡しで記述された関数
```AGDA
     whileTest : {t : Set} → (c10 : Nat) 
                   → (Code : Env → t) → t
     whileTest c10 next = next (record {varn = c10 
                                        ; vari = 0} )
 ```
 - CodeGear の型は継続先を返す関数
 - **(Code : fa → t)** は継続先
 - 引数として継続先の CodeGear を受け取る







---
## CbC での Hoare Logic
CodeGear、DataGear を用いた Hoare Logic は図のようになる
![](/attachment/5e42baee7b378d004670d1f5)
![](./fig/hoare-cg-dg.svg)
CodeGear が条件を引数として受け、継続先の CodeGear が次の条件を満たす様になる

下のコードは CodeGear、 DataGear を用いた Hoare Logic ベースの記述例である

```AGDA
    whileTestPwP : {l : Level} {t : Set l} → (c10 : ℕ) → ((env : Envc ) 
        → (vari env ≡ 0) ∧ (varn env ≡ c10 env) → t) → t
    whileTestPwP c10 next = next (whileTestP c10 ( λ env → env )) 
        record { pi1 = refl ; pi2 = refl } 
```












---
## CbC での while program
```C
    n = 10;
    i = 0;

    while (n>0)
    {
      i++;
      n--;
    }
```

CbC での while program 
```AGDA
    whileTestPCall : (c10 :  ℕ ) → Envc
    whileTestPCall c10 = whileTestP' {_} {_} c10 (λ env → loopP' env (λ env →  env))
```
- whileTestP' が n = c10、 i = 0 の代入、 loopP' が while loop に対応している
- CbC での Hoare Logic 上でコマンドは CodeGear そのもの
  - CodeGear は Hoare Logic のコマンドより自由な記述


---
## CbC での Hoare Logic 記述
CbC での Hoare Logic 記述では CodeGear が条件を受け取る

whileTestPwP は代入を行う CodeGear

```AGDA
    whileTestPwP : {l : Level} {t : Set l} → (c10 : ℕ) 
      → ((env : Envc ) → (vari env ≡ 0) ∧ (varn env ≡ c10 env) → t) → t
    whileTestPwP c10 next = 
      next (whileTestP c10 ( λ env → env )) (record { pi1 = refl ; pi2 = refl })
```
loopPwP' は while loop をするための条件を持ち、ループをする CodeGear

n と (n ≡ varn env) を受け取り varn でのパターンマッチをしている

suc n の場合はループを抜けるか判断する CodeGear に継続する

更に継続先で loopPwP' を呼ぶことで再帰的にループする
```AGDA
    loopPwP' : {l : Level} {t : Set l} → (n : ℕ) → (env : Envc ) 
        → (n ≡ varn env) → (vari env + varn env ≡ c10 env) → 
        (exit : (env : Envc ) → (vari env ≡ c10 env) → t) → t
    loopPwP' zero env refl refl exit = exit env refl
    loopPwP' (suc n) env refl refl exit = 
        whileLoopPwP' (suc n) env refl refl 
        (λ env x y → loopPwP' n env x y exit) exit
```
whileLoopPwP' は while loop を抜けるか判断する CodeGear

loopPwP'から呼ばれている
```AGDA
    whileLoopPwP' : {l : Level} {t : Set l} → (n : ℕ) → (env : Envc ) 
      → (n ≡ varn env) → (vari env + varn env ≡ c10 env)
      → (next : (env : Envc ) → (pred n ≡ varn env) 
          → (vari env + varn env ≡ c10 env) → t)
      → (exit : (env : Envc ) → (vari env ≡ c10 env) → t) → t
    whileLoopPwP' zero env refl refl _ exit = exit env refl
    whileLoopPwP' (suc n) env refl refl next _ = 
        next (record env {varn = pred (varn env) ; vari = suc (vari env)})
        refl (+-suc n (vari env))
```

conv は whileTestPwP の事後条件から while loop のための loop invaliant に変更する

```AGDA
    conv : (env : Envc ) → (vari env ≡ 0) /\ (varn env ≡ c10 env) 
        → varn env + vari env ≡ c10 env
    conv e record { pi1 = refl ; pi2 = refl } = +zero
```

whileTestPCallwP' は先程までの Hoare Logic の記述をつなげたもの

継続先の CodeGear に渡す条件が
```AGDA
    whileTestPCallwP' : (c :  ℕ ) → Set
    whileTestPCallwP' c = whileTestPwP {_} {_} c (
        λ env s → loopPwP' (varn env) env refl (conv env s) 
          ( λ env s → vari env ≡ c10 env )  )
```

whileTestPCallwP' では Hoare Logic の条件が接続できた

---

## Hoare Logic をベースにした CbC での while loop
先程条件を接続した whileTestPCallwP' を型に入れ、実際に実行してみる
```AGDA
    whileCallwP : (c : ℕ) → whileTestPCallwP' c
    whileCallwP c = whileTestPwP {_} {_} c (λ env s →
            loopPwP' (c10 env) env (sym (pi2 s)) (conv env s) {!!})
```
loopPwP'は任意の値を取ってループを行う CodeGear であった

しかし、引数で受け取った任意の自然数で実行するとループが停まらない

任意の自然数回ループする loopPwP' が停まることを補助する loopHelper を記述した
```AGDA
     loopHelper : (n : ℕ) → (env : Envc ) → (eq : varn env ≡ n) 
       → (varn env + vari env ≡ c10 env)
       → loopPwP' n env (sym eq) seq (λ env₁ x → (vari env₁ ≡ c10 env₁))
     loopHelper zero env eq refl rewrite eq = refl
     loopHelper (suc n) env eq refl rewrite eq = loopHelper n 
         (record { c10 = suc (n + vari env) ; varn = n ; vari = suc (vari env) }) 
           refl (+-suc n (vari env))
```
loopHelper を用いて記述した実行は実際に停止した
```AGDA
    helperCallwP : (c : ℕ) → whileTestPCallwP' c
    helperCallwP c = whileTestPwP {_} {_} c 
        (λ env s → loopHelper c (record { c10 = c ; varn = c ; vari = zero }) refl +zero)
```

---
## CbC での Hoare Logic の健全性

implies という data を用いて健全性の証明を行う

implies の型は A と B の条件を受け取る

このとき proof として A → B が存在すれば A implies B が証明できる
```AGDA
    data _implies_  (A B : Set ) : Set (succ Zero) where
        proof : ( A → B ) → A implies B
```
代入を行う CodeGear である **whileTestP** を実行したとき、\
常に真の命題 **⊤** と代入を終えたときの事後条件である\
**(vari env ≡ 0) ∧ (varn env ≡ c10 env)**
を implies に入れた型を記述する

```AGDA
    whileTestPSem :  (c : ℕ) → whileTestP c 
        ( λ env → ⊤ implies (vari env ≡ 0) ∧ (varn env ≡ c10 env) )
    whileTestPSem c = proof ( λ _ → record { pi1 = refl ; pi2 = refl } )
```

証明では proof に( ⊤ → (vari env ≡ 0) ∧ (varn env ≡ c10 env) )であると記述できればよく\
ここでは λ _ → record { pi1 = refl ; pi2 = refl } がこれに対応する

**whileTestPSemSound** は output ≡ whileTestP c (λ e → e)  を受け取ることで whileTestP の実行が終わった結果、つまり停止した CodeGear の実行結果が事後条件を満たしていることを証明している

```AGDA
    whileTestPSemSound : (c : ℕ ) (output : Envc ) → 
        output ≡ whileTestP c (λ e → e) 
        → ⊤ implies ((vari output ≡ 0) ∧ (varn output ≡ c))
    whileTestPSemSound c output refl = whileTestPSem c
```

同様に他の CodeGear に対しても健全性の証明が可能

whileConvPSemSound は制約を緩める conversion の健全性の証明
```AGDA
whileConvPSemSound : {l : Level} → (input : Envc) → ((vari input ≡ 0) ∧ (varn input ≡ c)) implies (varn input + vari input ≡ c10 input)
whileConvPSemSound input = proof λ x → (conversion input x) where
  conversion : (env : Envc ) → (vari env ≡ 0) /\ (varn env ≡ c10 env) → varn env + vari env ≡ c10 env
  conversion e record { pi1 = refl ; pi2 = refl } = +zero
```

whileLoopPSemSound は ループを行う CodeGear の 健全性の証明

```AGDA
whileLoopPSemSound : {l : Level} → (input output : Envc )
   → (varn input + vari input ≡ c10 input)
   →  output ≡ loopPP (varn input) input refl
   → (varn input + vari input ≡ c10 input) implies (vari output ≡ c10 output)
whileLoopPSemSound {l} input output pre eq = loopPPSem input output eq pre
```

loopPPSem を使って証明を行っている

```AGDA
loopPPSem : (input output : Envc ) →  output ≡ loopPP (varn input)  input refl
    → (varn input + vari input ≡ c10 input ) 
    → (varn input + vari input ≡ c10 input ) implies (vari output ≡ c10 output)
loopPPSem input output refl s2p = loopPPSemInduct (varn input) input  refl refl s2p
```

---
## まとめと今後の課題
- CodeGear、 DataGear を用いた Hoare Logic ベースの仕様記述を導入した
- Hoare Logic ベースの検証で停止性を含めて検証できた
- Hoare Logic ベースの検証の健全性を証明できた
    - while Program で使用した CodeGear を使って証明できた
- 今後の課題
  - BinaryTree の有限ループに対する証明
  - Hoare Logic で検証されたコードの CbC 変換
  - 並列実行での検証

---

## Comm の実行
Comm で記述した program を解釈して実行する関数 interpet を記述した

interpret は 停止性を考慮していないため{-# TERMINATING #-}タグを付けてエラーを回避している
```AGDA
{-# TERMINATING #-}
interpret : Env → Comm → Env
interpret env Skip = env
interpret env Abort = env
interpret env (PComm x) = x env
interpret env (Seq comm comm1) = interpret (interpret env comm) comm1
interpret env (If x then else) with x env
... | true = interpret env then
... | false = interpret env else
interpret env (While x comm) with x env
... | true = interpret (interpret env comm) (While x comm)
... | false = env
```
実行する際は test1 のように interpret に Env と Comm を渡してやる
```AGDA
test1 : Env
test1 =  interpret ( record { vari = 0  ; varn = 0 } ) (program 10)
```
実行結果は以下のようになる
```AGDA
record { varn = 0 ; vari = 10 }
```