Isabelle/HOLの基本 その3
これは一人Computer Scienceアドベントカレンダー 4日目の記事です。
テキスト代わりのチュートリアル: prog-prove.pdf
前回はHOLと自動証明についてやりました。 今回やる4章では、Isarという新しい言語(?)について見ていきます。
4. Isar: A Language for Structured Proofs
IsabelleはIsarという、structured proofを記述するための言語を別に提供している。 これはapplyを繋げて証明をするのとは違い、構造化された証明をキーワードを組み合わせて記述する、より自然言語による証明に近い記述を可能にする言語である。
Isarのsyntaxのコアは次のようになっている(実際はもっと膨大):
proof
= 'by' method
| 'proof' [method] step* 'qed'
step
= 'fix' variables
| 'assume' proposition
| ['from' fact+] ('have' | 'show') proposition proof
proposition = [name :] "formula"
4.1 Isar by Example
初めにIsarによる証明を見せるので眺めてみよう。
lemma "¬ surj (f :: 'a ⇒ 'a set)"
proof -
assume srjf: "surj f"
from srjf have fa: "∀A. ∃a. A = f a" by (simp add: surj_def)
from fa have fa2: "∃a. {x. x ∉ f x} = f a" by blast
from fa2 show False by blast
qed
assumeによって仮定を導入し、その後はfrom..have..を繰り返して最後にshowで締めているのが分かる。 各have/showの部分では命題を宣言し、その後に証明をかくという仕方で証明を進めている。
また、proofの直後にはproof methodを並べて事前に何かを適用することができるが(proof (rule A; simp)
とかけば、証明を始める前に rule A; simp
を適用できる)何も適用したくない場合はハイフンをつけると良い。
this/then/hence/thus
まず、全ての命題に名前を付ける必要があるのは不便だろう。直前に示した命題は this
という名前で参照できる。
上の最初の部分は
assume "surj f"
from this have ...
と書き換えられる。
そしてthisを用いて
-
then
=from this
-
thus
=then show
-
hence
=then have
と定められているので、上の証明は次のように簡単に書ける。
proof
assume "surj f"
hence "∀A. ∃a. A = f a" by (simp add: surj_def)
hence "∃a. {x. x ∉ f x} = f a" by blast
thus False by blast
qed
また、 from
のように使用する定理を前置するのではなく後置する方法もある。
-
'have' prop 'using' fact
='from' fact 'have' prop
-
'have' prop 'with' fact
='from' fact this 'have' prop
structured lemma
証明だけではなく補題ももう少し構造化された方法で宣言できる。
lemma
fixes f :: "'a => 'a set"
assumes s: "surj f"
shows False
-
fixes は変数を固定し、型を宣言するために使う。通常省略することも多い。
-
assumes/shows は仮定と結論を述べるために使う。仮定が複数ある場合はandで繋ぐ。
[| A; B; C |] ==> D
を assumes A and B and C / shows D
とかけるようになるということを覚えておけばよい。
4.2 Proof Patterns
next
ゴールが複数ある場合、proofのセクションをnextで区切って書く:
lemma P
proof
...
show P1
next
...
show P2
next
...
show P3
qed
obtain
existを使った定理から一時的に変数を束縛して使用するためにobtainを使う。
have p: "∃x. P(x)" ...
obtain x where k: "P (x)" using p by auto
obtain…where… それ自体命題の宣言なのでこれにも証明が必要なことに注意。 obtain以降の行では束縛したxが変数として使えるようになる。
4.3 Streamlining Proofs
pattern matching
宣言する命題の部分に is
を用いて名前を付けることができる。(名前は ?
から始める必要がある)
show "form1 <--> form2" (is "?L <--> ?R")
このように名前をつけると、showの中のproof…qedセクションではform1の代わりに ?L
などと書けるようになる。
このisはパターンマッチを行い、無視したい(利用しない)パターンはアンダーバーで潰すことができる。
また、showおよびlemmaの中では宣言した命題全体を ?thesis
で参照できる。
つまり上の例では ?thesis
は form1 <--> form2
のことである。
quotation
haveなどで示した命題は、名前をつけていなくてもクオートで囲むことで参照できる。
have "x > 0"
...
from `x > 0` ...
moreover
thenなどにより直前の命題は参照できるがそれ以前の命題は参照できない。 moreover/ultimatelyというキーワードを使うと、それまでに示された全ての命題を仮定に追加して証明ができる。
have P1 ...
moreover have P2 ...
moreover
...
moreover have Pn ...
ultimatery have .. (* ここで、P1 .. Pnの全ての命題が仮定に追加される *)
proof block
証明のスコープを明示するのに {}
で囲むことができる。
proof-
{ fix k
assume ...
...
have ... }
then show ... (* ここのthenでは直前のproof block {}部分全体を参照する *)
複数のゴールを示す際にnextで区切る代わりにproof blockを並べることもできる。
4.4 Case Analysis and Induction
cases/inducts
場合分けを行う場合、casesコマンドを用いてコンストラクタごとにゴールを分離する。 このときIsar proofでもcaseというキーワードで場合分けを使った証明を書くことができる。
proof (cases xs)
case Nil
...
next
case (Cons y ys)
...
qed
これは帰納法を使った時も同じことが出来る。
まとめ
4章では証明記述言語Isarについて見ました。
というわけで長かったですがチュートリアルはこれで一通り終わったことになります。 (重要度が低いと判断したところは飛ばしたりしているので、時間がある人は元のpdfにもあたっておいた方がいいかもしれません)
チュートリアル prog-prove.pdfは終わったので入門編は今日でおしまいとなり、明日からはいよいよ実践的な証明を書いていく予定です。