Coqで”無限オブ無限”(証明部分)
ヒビルテで、さかいさんが興味深いCoqのコードを紹介していた。
⇒ λ. Coqで“無限オブ無限”
どうやら元ネタはここ(derive your dreams)らしい。
おもしろそうなので、さかいさんのコードを証明してみた。
証明した定理は以下。
Theorem main : forall m n:nat, m >= 1 -> n >= 1 -> Str_in (m,n) (iflatten ss).
但し、
ss = [[(1,1); (1,2); ...]; [(2,1); (2,2); ...]; : : ]
とする。
(*=====まず、ちょっと準備=====*) Lemma p_split : forall (X Y:Set)(x1 x2:X)(y1 y2:Y), x1 = x2 -> y1 = y2 -> (x1, y1) = (x2, y2). Proof. intros X Y x1 x2 y1 y2 eqx eqy. rewrite eqx. rewrite eqy. reflexivity. Qed. Definition comp (X Y Z:Set)(f:X->Y)(g:Y->Z)(x:X) := g (f x). Implicit Arguments comp [X Y Z]. Fixpoint times (S:Set)(f:S->S) (n:nat)(x:S) : S := match n with | O => x | S p => times S f p (f x) end. Implicit Arguments times [S]. Lemma times_plus : forall (S:Set)(f:S->S)(i j:nat)(x:S), times f (i+j) x = comp (times f i) (times f j) x. Proof. intros S f i; induction i; intros j x. (* sub1 *) simpl. unfold comp. reflexivity. (* sub2 *) simpl. unfold comp. rewrite IHi. unfold comp. reflexivity. Qed. Definition f1 (X A B:Set)(f:X->A*B)(x:X) : A := match f x with | (a,_) => a end. Definition f2 (X A B:Set)(f:X->A*B)(x:X) : B := match f x with | (_,b) => b end. Implicit Arguments f1 [X A B]. Implicit Arguments f2 [X A B]. Axiom Extensionality_of_functions: forall (A B:Set) (f g:A -> B), (forall x, f(x)=g(x)) -> f=g. (*=====準備終わり=====*)
(*=====ここからさかいさんのソースコード======*) (* IFlatten.v *) Section IFlatten. Require Import List. Require Import Streams. (* anamorphisms (co-iteration) *) CoFixpoint unfold (A X : Set) (phi : X -> A*X) (x : X) : Stream A := match phi x with | (a, x) => Cons a (unfold A X phi x) end. Implicit Arguments unfold [A X]. Inductive CV (A X : Set) : Set := | CVLast : X -> CV A X | CVCons : A * CV A X -> CV A X. Implicit Arguments CVLast [A X]. Implicit Arguments CVCons [A X]. (* futumorphisms (cource-of-value co-iteration) *) Definition futu (A X : Set) (phi : X -> A * CV A X) (x : X) : Stream A := let psi cv := match cv with | CVLast x => phi x | CVCons p => p end in unfold psi (CVLast x) . Implicit Arguments futu [A X]. Definition add_prefix (A : Set) (xs : list A) (X : Set) (cv : CV A X) : CV A X := fold_right (fun a cv => CVCons (a, cv)) cv xs. Implicit Arguments add_prefix [A X]. Definition iflatten (A : Set) (ss : Stream (Stream A)) : Stream A := let phi x := match x with | (ss, ls) => let s := hd ss in let ss2 := tl ss in let ls2 := tl s :: List.map (fun x => tl x) ls in ( hd s , add_prefix (List.map (fun x => hd x) ls) (CVLast (ss2, ls2)) ) end in futu phi (ss, nil). Implicit Arguments iflatten [A]. (*End IFlatten.*) (*=======さかいさんのコード ここまで=========*)
(*========ここから証明===========*) (* まずは定義 *) (* 自然数のくみを要素に持つ無限無限リストStream (Stream M)を考える *) Definition M := (nat * nat)%type. CoFixpoint from (i j:nat) := Cons (i,j) (from i (1+j)). CoFixpoint fromfrom i j := Cons (from i j) (fromfrom (1+i) j). Fixpoint ls i j {struct i} := match i with | O => nil | S i' => from i j :: (ls i' (1+j)) end. Definition ss := fromfrom 1 1. Definition CVm := CV M (Stream (Stream M) * list (Stream M)). Definition phi' (x:Stream(Stream M) * list(Stream M)) := match x with | (ss, ls) => let s := hd ss in let ss2 := tl ss in let ls2 := tl s :: List.map (fun x => tl x) ls in ( hd s , add_prefix (List.map (fun x => hd x) ls) (CVLast (ss2, ls2)) ) end. Definition phi (cv : CVm) := match cv with | CVLast (ss, ls) => phi' (ss, ls) | CVCons (m, cvtl) => (m, cvtl) end. Definition futu_phi x := unfold phi (CVLast x). (** 証明のために独自に定義したもうひとつのiflatten。 * のちにさかいさんのiflattenと等しいことを証明する. *) Definition iflatten' (ss : Stream (Stream M)) : Stream M := futu_phi (ss, nil).
(* 定義した項目に関する簡単な補題たち *) Lemma unfold_fromfrom : forall i j:nat, fromfrom i j = Cons (Cons (i,j) (from i (1+j))) (fromfrom (1+i) j). Proof. intros. rewrite (unfold_Stream (fromfrom i j)). unfold fromfrom at 1. rewrite (unfold_Stream (from i j)). unfold from at 1. reflexivity. Qed. Lemma unfold_from : forall i j:nat, ls (1+i) j = from (1+i) j :: List.map (fun s => tl s) (ls i j). intro i; induction i; intro j. (* sub 1 *)simpl; reflexivity. (* sub 2 *)simpl; simpl in IHi. rewrite <- (IHi (S j)). reflexivity. Qed. Lemma unfold_unfold : forall(X A:Set)(f:X->A*X)(x:X), unfold f x = Cons (f1 f x) (unfold f (f2 f x)). intros X A f x; rewrite (unfold_Stream (unfold f x)). unfold f1; unfold f2. unfold unfold. induction (f x). fold unfold. reflexivity. Qed. Lemma nth_unfold : forall (X A:Set)(f:X->A*X)(n:nat)(x:X), Str_nth n (unfold f x) = f1 f (times (f2 f) n x). Proof. intros X A f. intro n; induction n. intro x. rewrite unfold_unfold. simpl. unfold Str_nth. simpl. reflexivity. (* subgoal2 *)intro x. unfold times. fold times. rewrite <- (IHn (f2 f x)). rewrite unfold_unfold. unfold Str_nth. unfold Str_nth_tl at 1. reflexivity. Qed.
(* 独自に定義したiflatten'とさかいさんのiflattenの等価性 *) Lemma eq_iflatten : iflatten ss = iflatten' ss. Proof. unfold iflatten'. unfold iflatten. unfold futu_phi. unfold futu. Check f_equal2. Check unfold. apply (f_equal2 (fun (f:CVm->M*CVm) (x:CVm) => unfold f x)). (* sub1 *) apply Extensionality_of_functions. intro x. case x. (* sub11 *) simpl. reflexivity. (* sub12 *) simpl. intro p; case p. reflexivity. (* sub2 *) reflexivity. Qed.
(* ここからCVやリストに関する長さを扱う *) Require Import Arith. Fixpoint cvlength (A X:Set)(cv:CV A X) : nat := match cv with | CVLast _ => O | CVCons (_, cvtl) => S (cvlength A X cvtl) end. Implicit Arguments cvlength [A X]. Definition cv0 : CVm := CVLast (ss, nil). (* cvの末尾を取り出す関数 *) Fixpoint last_of (cv:CVm) : CVm := match cv with | CVLast xxx => CVLast xxx | CVCons (_, cvtl) => last_of cvtl end. (* 和を計算する関数 (sumk n = 0+1+2+...+n) *) Fixpoint sumk n:nat := match n with | O => O | S p => n + sumk p end. Fixpoint cv (n:nat) := match n with | O => cv0 | S p => f2 phi (cv p) end. (* 以上の定義により * iflatten ss = phi1 (cv^n CVLast(ss,nil)) * みたいに思うことができる *)
(* 諸性質の証明 *) Lemma unfold_phi_cons : forall (m:M)(cv:CVm), phi (CVCons(m,cv)) = (m,cv). Proof. intros m cv; unfold phi; reflexivity. Qed. (* 高校で習った数列の足し算の公式 Σk = (1/2)n(n+1) *) Fact fsumk : forall n:nat, 2 * sumk n = n*(1+n). Proof. intro n; induction n. simpl; reflexivity. unfold sumk; fold sumk; unfold sumk in IHn; fold sumk in IHn. rewrite mult_plus_distr_l. rewrite IHn. ring. Qed. Lemma unfold_phi_last : forall (m:M)(s2:Stream M)(ss2:Stream(Stream M))(ls:list(Stream M)), phi (CVLast (Cons(Cons m s2) ss2, ls)) = (m, add_prefix (List.map (fun s => hd s) ls) (CVLast(ss2, s2::List.map (fun s => tl s) ls))). Proof. intros m s2 ss2 ls0. unfold phi. unfold phi'. reflexivity. Qed. Lemma cv_times_phi2 : forall (n:nat), cv n = times (f2 phi) n cv0. intro n. induction n. simpl. reflexivity. unfold cv; fold cv. cut (S n = n+1). intro eq; rewrite eq. rewrite IHn. rewrite times_plus. unfold comp. unfold times at 2. reflexivity. rewrite Plus.plus_comm. simpl. reflexivity. Qed.
Lemma len : forall (k n:nat) (cvn:CVm), k = cvlength (cv n) -> cvn = cv n -> cv (k+n) = last_of (cv n). Proof. intro k; induction k. (* subgoal 1 *) intros n cvn H. simpl. induction (cv n). (* subgoal 11 *) simpl; reflexivity. (* subgoal 12 False *) induction p. inversion H. (* subgoal 2 *) intros Pn cvPn. rewrite Plus.plus_Snm_nSm. intros H1 H2. rewrite (IHk (S Pn) (cv (S Pn))). (* sub 21 *) simpl. induction (cv Pn). (* sub 211 False *) inversion H1. (* sub 212 *) induction p. unfold f2. rewrite unfold_phi_cons. simpl; reflexivity. (* sub 22 *) simpl. induction (cv Pn). (* sub 221 False *) inversion H1. (* sub 222 *) induction p. unfold f2. rewrite unfold_phi_cons. inversion H1. reflexivity. (* sub 23 *) reflexivity. Qed. Lemma phi2_last : forall (k:nat), f2 phi (CVLast (fromfrom(1+k) 1, ls k 2)) = add_prefix (List.map (fun s => hd s) (ls k 2)) (CVLast(fromfrom (2+k) 1, ls (1+k) 2)). intro k. rewrite unfold_fromfrom. unfold f2. rewrite unfold_phi_last. rewrite unfold_from. reflexivity. Qed. Lemma cvlenlen : forall (x:Stream (Stream M) * list (Stream M))(l:list M), cvlength (add_prefix l (CVLast x)) = List.length l. intros x list. induction list. (* sub 1 *) simpl; reflexivity. (* sub 2 *) simpl. rewrite IHlist; reflexivity. Qed. Lemma lslen : forall i j : nat, length (ls i j) = i. intro i; induction i. (* sub 1*) simpl; reflexivity. (* sub 2 *) simpl. intro j. rewrite IHi. reflexivity. Qed. Lemma cv_sumk_last : forall i:nat, cv (sumk i) = CVLast(fromfrom (1+i) 1, ls i 2). intro i; induction i. (* sub 1 *) reflexivity. (* sub 2 *) unfold sumk; fold sumk. rewrite plus_Snm_nSm. rewrite (len i (S (sumk i)) (cv (S (sumk i)))). (* sub 21 *) unfold cv; fold cv. rewrite IHi. rewrite (phi2_last i). induction (List.map (fun s => hd s) (ls i 2)). simpl; reflexivity. simpl. simpl in IHl. rewrite IHl. reflexivity. (* sub 22 *) unfold cv; fold cv. rewrite IHi. rewrite (phi2_last i). rewrite cvlenlen. rewrite map_length. rewrite lslen. reflexivity. (* sub 23 *) reflexivity. Qed. Lemma unfold_Str_nth_tl : forall (X:Set)(k:nat)(s:Stream X), Str_nth_tl (S k) s = tl (Str_nth_tl k s). Proof. intros X k s. rewrite tl_nth_tl. rewrite (unfold_Stream s). unfold tl. unfold Str_nth_tl at 1. reflexivity. Qed. Lemma nth_iflatten : forall n:nat, Str_nth n (iflatten' ss) = f1 phi (cv n). Proof. intros n. rewrite cv_times_phi2. rewrite <- nth_unfold. unfold iflatten. unfold futu. unfold phi. unfold cv0. simpl. reflexivity. Qed. Lemma addpref_cons : forall (l:list M)(m:M)(cv:CVm), add_prefix (m::l) cv = CVCons (m, (add_prefix l cv)). Proof. intro l. induction l; intros m mmm. (* sub1 *) simpl. reflexivity. (* sub2 *) simpl. reflexivity. Qed. Lemma addpref_nth : forall (default:M)(n:nat)(x:Stream(Stream M)*list(Stream M)) (l:list M), n < length l -> f1 phi (times (f2 phi) n (add_prefix l (CVLast (x)))) = List.nth n l default. Proof. intros mmm n. induction n; intros mmmm l. (* sub1 *) case l. intro H. inversion H. intros m tl H. unfold f1. simpl. reflexivity. (* sub2 *) case l. intro H. inversion H. intros m l' H. rewrite (addpref_cons). cut (S n = 1 + n). intro eq; rewrite eq. rewrite times_plus. unfold comp. unfold times at 2. unfold f2 at 2. rewrite unfold_phi_cons. rewrite IHn. simpl. reflexivity. simpl in H. apply lt_S_n. apply H. simpl. reflexivity. Qed. Lemma nth_map_ls : forall (default:M)(k i j:nat), k < length (ls i j) -> nth k (List.map (fun s=>hd s) (ls i j)) default = (i-k, j+k). Proof. intros mmm k. induction k; intros i j. (* sub1 *) case i. intro H. inversion H. intros i' H. simpl. apply p_split. reflexivity. ring. (* sub2 *) case i. intro H. inversion H. simpl. intros i' H. rewrite IHk. apply p_split. reflexivity. ring. apply lt_S_n. apply H. Qed. Lemma h2 : forall (n i j:nat)(x:Stream(Stream M)*list(Stream M)), n < length (ls i j) -> f1 phi (times (f2 phi) n (add_prefix (List.map (fun s=>hd s) (ls i j)) (CVLast x))) = (i-n, j+n). Proof. intros. rewrite (addpref_nth (0,0)). rewrite nth_map_ls. reflexivity. apply H. rewrite map_length. apply H. Qed. Inductive Str_in (X:Set) : X -> Stream X -> Prop :=
inhd : forall (x:X)(tl:Stream X), Str_in X x (Cons x tl) |
intl : forall (x y:X)(tl:Stream X), Str_in X x tl -> Str_in X x (Cons y tl). |
(** ここがメインの定理! **) Theorem main : forall m n:nat, m >= 1 -> n >= 1 -> Str_in (m,n) (iflatten ss). Proof. intros m n Hm Hn. apply (Str_in_nth (sumk (m+n-2)+(n-1)) (m,n)). rewrite eq_iflatten. rewrite nth_iflatten. elim Hn. (* sub1 *) cut (forall k:nat, sumk k + (1-1) = sumk k). (* sub 11 *) intro eq; rewrite eq. rewrite cv_sumk_last. rewrite unfold_fromfrom. unfold f1. rewrite unfold_phi_last. elim Hm. (* sub 111 *) simpl. reflexivity. (* sub 112 *) intros m' Hm' meq. simpl. inversion meq. rewrite H0. cut (m' + 1 - 1 = m'). (* sub 1121 *) intro m'eq; rewrite m'eq; reflexivity. (* sub 1122 *) case m'. simpl. reflexivity. intro. simpl. rewrite <- minus_n_O. ring. (* sub 12 *) intro k. auto with arith. (* sub2 *) intros n' Hn' mmm. rewrite cv_times_phi2. rewrite times_plus. unfold comp. rewrite <- cv_times_phi2. rewrite cv_sumk_last. cut (S n' - 1 = S (n'-1)). (* sub 21 *) intro n'eq; rewrite n'eq. unfold times. fold times. unfold f2 at 2. rewrite unfold_fromfrom. rewrite unfold_phi_last. Check h2. rewrite h2. (* sub 211 *) Require Import Omega. apply p_split; omega. (* sub 212 *) rewrite lslen. omega. (* sub 22 *) omega. Qed. (*##############メインの定理証明終わり########################*) End IFlatten.