1階命題論理でresolutionが成り立つ事を示す
まずAかBかで場合を分けて、Aのときは¬AかCかで場合分けすればできる。Aと¬Aが同時に成り立つとなんでも証明できてしまうということを利用しよう。排中律は別に必要なく証明できる。
Proposition p09 : forall A B C, (A \/ B) /\ (~A \/ C) -> B \/ C. Proof. intros A B C H; elim H; intros. elim H0. elim H1. intros H2 H3; elim H2. apply H3. intros H2 _; right; apply H2. intro H2; left; apply H2. Qed.
あるソート関数がちゃんとソートする事を証明
以前Merge Sort を実装して証明した。
http://d.hatena.ne.jp/yoshihiro503/20090923
リストの結合関数 ++ の結合則 l1 ++ (l2 ++ l3) == (l1 ++ l2) ++ l3
リストのappendの結合則は非常に便利だが、証明は簡単だ。こういった性質はテストでは網羅的にチェックできないため、証明という検証方法がプログラムの品質を高める上で非常に有効だと思う。
Require Import List. Proposition p06 : forall {A} (l1 l2 l3: list A), l1 ++ (l2 ++ l3) = (l1 ++ l2) ++ l3. Proof. intros A l1 l2 l3; induction l1; simpl in |- *. reflexivity. rewrite IHl1 in |- *. reflexivity. Qed.
中間値の定理(The Intermediate Value Theorem)
中間値の定理もCoqの標準ライブラリに存在する。Rsqrt_def.vの中にIVTという名前で見つけることができる。
Lemma IVT : forall (f:R -> R) (x y:R), continuity f -> x < y -> f x < 0 -> 0 < f y -> { z:R | x <= z <= y /\ f z = 0 }.
ただ、中間値が f x と f y の間の任意の値というわけではなく、0固定だったので、そこを任意の値が取れるように改良した。
Require Import Reals. Require Import FunctionalExtensionality. Open Scope R_scope. Proposition p05 : forall (f:R -> R) a b y, continuity f -> a < b -> f a < y -> y < f b -> (exists c, a <= c <= b /\ f c = y). Proof. intros. elim (IVT (fun x => f x - y) a b). intros c H3; elim H3; intros; exists c. split. apply H4. apply (Rplus_eq_reg_l (- y)). rewrite Rplus_opp_l in |- *. rewrite Rplus_comm in |- *. apply H5. rewrite (functional_extensionality (fun x : R => f x - y) (f - (fun _ => y))%F) in |- *. apply continuity_minus. apply H. apply continuity_const. intros p q; reflexivity. intro x; reflexivity. apply H0. apply (Rlt_minus (f a) y H1). apply (Rlt_Rminus y (f b) H2). Qed.
Bolzano & Weierstrassの定理(有界な数列は収束する部分列を持つ)
Bolzano Weierstrass の定理はCoqではもう既に証明されていて、しかもそれは標準ライブラリに備わっている!
Rtopology.vというライブラリのソースを見ればこの定理を見つけることができる。
Theorem Bolzano_Weierstrass : forall (un:nat -> R) (X:R -> Prop), compact X -> (forall n:nat, X (un n)) -> exists l : R, ValAdh un l.
実数列unは nat -> R 型で、領域 X ⊂ R はR -> Prop 型で表現しているようだ。
ValAdh un lの定義は以下のとおりで、lに収束するunの部分列が存在することと同等の命題みたいだ。
Definition ValAdh (un:nat -> R) (x:R) : Prop := forall (V:R -> Prop) (N:nat), neighbourhood V x -> exists p : nat, (N <= p)%nat /\ V (un p).
実数の構成について
Coqでの実数は9つの項と17の公理で定義されている。項の型と意味はだいたい次の様な感じ。
Parameter R : Set. (* 実数全体 *) Parameter R0 : R. (* 実数の0 *) Parameter R1 : R. (* 実数の1 *) Parameter Rplus : R -> R -> R. (* 実数上での足し算 *) Parameter Rmult : R -> R -> R. (* 実数上での掛け算 *) Parameter Ropp : R -> R. (* 足し算に関する逆元 *) Parameter Rinv : R -> R. (* 掛け算に関する逆元 *) Parameter Rlt : R -> R -> Prop. (* 実数上の"より大きい"を表す述語 *) Parameter up : R -> Z. (* up x はx以上の最小の整数 *)
17の公理は、大きく見て4つの部分に分けられる。
- 実数Rは非自明な体である
Axiom Rplus_comm : forall r1 r2:R, r1 + r2 = r2 + r1. Axiom Rplus_assoc : forall r1 r2 r3:R, r1 + r2 + r3 = r1 + (r2 + r3). Axiom Rplus_opp_r : forall r:R, r + - r = 0. Axiom Rplus_0_l : forall r:R, 0 + r = r. Axiom Rmult_comm : forall r1 r2:R, r1 * r2 = r2 * r1. Axiom Rmult_assoc : forall r1 r2 r3:R, r1 * r2 * r3 = r1 * (r2 * r3). Axiom Rinv_l : forall r:R, r <> 0 -> / r * r = 1. Axiom Rmult_1_l : forall r:R, 1 * r = r. Axiom R1_neq_R0 : 1 <> 0. Axiom Rmult_plus_distr_l : forall r1 r2 r3:R, r1 * (r2 + r3) = r1 * r2 + r1 * r3.
- 実数Rは全順序集合である
Axiom total_order_T : forall r1 r2:R, {r1 < r2} + {r1 = r2} + {r1 > r2}. Axiom Rlt_asym : forall r1 r2:R, r1 < r2 -> ~ r2 < r1. Axiom Rlt_trans : forall r1 r2 r3:R, r1 < r2 -> r2 < r3 -> r1 < r3. Axiom Rplus_lt_compat_l : forall r r1 r2:R, r1 < r2 -> r + r1 < r + r2. Axiom Rmult_lt_compat_l : forall r r1 r2:R, 0 < r -> r1 < r2 -> r * r1 < r * r2.
- アルキメデスの原理(いかなる実数に対してもそれより大きい整数が存在する。)
up xは天井関数、IZRは整数Zからの包含写像
Axiom archimed : forall r:R, IZR (up r) > r /\ IZR (up r) - r <= 1.
- 実数Rの連続性(上に有界な領域 E ⊂ R には常に上限が存在する)。
Axiom completeness : forall E:R -> Prop, bound E -> (exists x : R, E x) -> { m:R | is_lub E m }.