Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
Require Import ZArith Extraction. From mathcomp Require Import all_ssreflect. (* Simple Calculator *) Module Simple. Inductive expr : Set := | Cst of Z | Var of nat | Add of expr & expr | Min of expr | Mul of expr & expr. Fixpoint eval (env : list Z) (e : expr) : Z := match e with | Cst x => x | Var n => nth 0 env n | Add e1 e2 => eval env e1 + eval env e2 | Min e1 => 0-eval env e1 | Mul e1 e2 => eval env e1 * eval env e2 end%Z. Inductive code : Set := | Cimm of Z | Cget of nat | Cadd | Cmin | Cmul. Fixpoint eval_code (stack : list Z) (l : list code) := match l with | nil => stack | c :: l' => let stack' := match c, stack with | Cimm x, _ => x :: stack | Cget n, _ => nth 0 stack n :: stack | Cadd, x :: y :: st => x+y :: st | Cmin, x :: st => 0-x :: st | Cmul, x :: y :: st => x*y :: st | _, _ => nil end%Z in eval_code stack' l' end. Fixpoint compile d (e : expr) : list code := match e with | Cst x => [:: Cimm x] | Var n => [:: Cget (d+n)] | Add e1 e2 => compile d e2 ++ compile (S d) e1 ++ [:: Cadd] | Min e1 => compile d e1 ++ [:: Cmin] | Mul e1 e2 => compile d e2 ++ compile (S d) e1 ++ [:: Cmul] end. Lemma eval_code_cat stack l1 l2 : eval_code stack (l1 ++ l2) = eval_code (eval_code stack l1) l2. Proof. by elim: l1 stack => //=. Qed. Theorem compile_correct e d stack : eval_code stack (compile d e) = eval (drop d stack) e :: stack. Proof. elim: e d stack => //= [n|e1 IHe1 e2 IHe2|e IHe|e1 IHe1 e2 IHe2] d stack. by rewrite nth_drop. by rewrite eval_code_cat IHe2 eval_code_cat IHe1. by rewrite eval_code_cat IHe. by rewrite eval_code_cat IHe2 eval_code_cat IHe1. Qed. End Simple. (* Iterating calculator *) Module Iterator. Inductive expr : Set := | Cst of Z | Var of nat | Add of expr & expr | Min of expr | Mul of expr & expr. Fixpoint eval (env : list Z) (e : expr) : Z := match e with | Cst x => x | Var n => nth 0 env n | Add e1 e2 => eval env e1 + eval env e2 | Min e1 => 0-eval env e1 | Mul e1 e2 => eval env e1 * eval env e2 end%Z. Inductive cmd : Set := | Assign of nat & expr (* env[n] に結果を入れる *) | Seq of cmd & cmd (* 順番に実行 *) | Repeat of expr & cmd. (* n 回繰り返す *) Fixpoint eval_cmd (env : list Z) (c : cmd) : list Z := match c with | Assign n e => set_nth 0%Z env n (eval env e) | Seq c1 c2 => eval_cmd (eval_cmd env c1) c2 | Repeat e c => if eval env e is Zpos n then iter (Pos.to_nat n) (fun e => eval_cmd e c) env else env end. Inductive code : Set := | Cimm of Z | Cget of nat | Cadd | Cmin | Cmul | Cset of nat | Crep of nat (* ループの長さ(Cnextまでの命令数) *) | Cnext. Fixpoint eval_code (stack : list Z) (l : list code) := match l with | nil => stack | c :: l' => let stack' := match c, stack with | Cimm x, _ => x :: stack | Cget n, _ => nth 0 stack n :: stack | Cadd, x :: y :: st => x+y :: st | Cmin, x :: st => 0-x :: st | Cmul, x :: y :: st => x*y :: st | Cset n, x :: st => set_nth 0%Z st n x | Crep _, Zpos n :: st => (* seq の iter を使う *) iter (Pos.to_nat n) (fun st => eval_code st l') st | Crep _, _ :: st => st | Cnext, _ => stack | _, _ => nil end%Z in match c with | Crep n => eval_drop n stack' l' | Cnext => stack' | _ => eval_code stack' l' end end with eval_drop n st (l : list code) := (* 相互再帰 *) match l, n with | _ :: l', 0 => eval_code st l' | _ :: l', S n' => eval_drop n' st l' | [::], _ => st end. Fixpoint compile d (e : expr) : list code := match e with | Cst x => [:: Cimm x] | Var n => [:: Cget (d+n)] | Add e1 e2 => compile d e2 ++ compile (S d) e1 ++ [:: Cadd] | Min e1 => compile d e1 ++ [:: Cmin] | Mul e1 e2 => compile d e2 ++ compile (S d) e1 ++ [:: Cmul] end. Fixpoint compile_cmd (c : cmd) : list code := match c with | Assign n e => compile 0 e ++ [:: Cset n] | Seq c1 c2 => compile_cmd c1 ++ compile_cmd c2 | Repeat e c => let l := compile_cmd c in compile 0 e ++ [:: Crep (length l)] ++ l ++ [:: Cnext] end. Definition neutral c := match c with Cnext | Crep _ => false | _ => true end. Inductive balanced : list code -> Prop := | Bneutral : forall c, neutral c = true -> balanced [:: c] | Bcat : forall l1 l2, balanced l1 -> balanced l2 -> balanced (l1 ++ l2) | Brep : forall l, balanced l -> balanced (Crep (length l) :: l ++ [:: Cnext]). Lemma eval_drop_cat st l1 l2 : eval_drop (length l1) st (l1 ++ Cnext :: l2) = eval_code st l2. Proof. by induction l1. Qed. Lemma eval_code_cat stack (l1 l2 : seq code) : balanced l1 -> eval_code stack (l1 ++ l2) = eval_code (eval_code stack l1) l2. Proof. move=> Hbal. elim: {l1} Hbal stack l2. by destruct c. move=> l1 l2 Hbal1 IHl1 Hbal2 IHl2 st l'. by rewrite -catA !IHl1 IHl2. move=> l1 Hbal IHl1 st l'. destruct st => /=. by rewrite -catA /= !eval_drop_cat. destruct z => //=; rewrite -catA /= !eval_drop_cat //=. f_equal. apply eq_iter => st'. by rewrite !IHl1. Qed. Hint Constructors balanced. Lemma compile_balanced n e : balanced (compile n e). Proof. by elim: e n => /=; auto. Qed. Theorem compile_correct e d stack : eval_code stack (compile d e) = eval (drop d stack) e :: stack. Proof. move: d stack. induction e; simpl; intros; auto. by rewrite nth_drop. by rewrite eval_code_cat ?IHe2 ?eval_code_cat ?IHe1 //; apply compile_balanced. by rewrite eval_code_cat ?IHe //; apply compile_balanced. by rewrite eval_code_cat ?IHe2 ?eval_code_cat ?IHe1 //; apply compile_balanced. Qed. Lemma compile_cmd_balanced c : balanced (compile_cmd c). Proof. by elim: c => /=; auto using compile_balanced. Qed. Hint Resolve compile_balanced compile_cmd_balanced. Theorem compile_cmd_correct c stack : eval_code stack (compile_cmd c) = eval_cmd stack c. Proof. move: stack. induction c => stack /=. by rewrite eval_code_cat ?compile_correct ?drop0. by rewrite eval_code_cat ?compile_correct ?drop0 // IHc1 IHc2. rewrite eval_code_cat ?compile_correct ?drop0 //. rewrite /= eval_drop_cat //=. case: (eval stack e) => //. move=> p. apply eq_iter => st. by rewrite eval_code_cat //=. Qed. End Iterator. (* While calculator *) Module While. Inductive expr : Set := | Cst of Z | Var of nat | Add of expr & expr | Min of expr | Mul of expr & expr. Fixpoint eval (env : list Z) (e : expr) : Z := match e with | Cst x => x | Var n => nth 0 env n | Add e1 e2 => eval env e1 + eval env e2 | Min e1 => 0-eval env e1 | Mul e1 e2 => eval env e1 * eval env e2 end%Z. Inductive cmd : Set := | Assign of nat & expr (* env[n] に結果を入れる *) | Seq of cmd & cmd (* 順番に実行 *) | While of nat & cmd. (* env[n] が0になるまで繰り返す *) Section limited. Variable h : nat. Fixpoint iter_until0 h n f (env : list Z) := if nth 0%Z env n is Z0 then Some env else if h is h.+1 then obind (iter_until0 h n f) (f env) else None. Fixpoint eval_cmd (c : cmd) (env : list Z) : option (list Z) := match c with | Assign n e => Some (set_nth 0%Z env n (eval env e)) | Seq c1 c2 => obind (eval_cmd c2) (eval_cmd c1 env) | While n c1 => iter_until0 h n (eval_cmd c1) env end. Inductive code : Set := | Cimm of Z | Cget of nat | Cadd | Cmin | Cmul | Cset of nat | Cwhl of nat & nat (* 監視する変数とループの長さ(Cnextまでの命令数) *) | Cnext. Fixpoint eval_code (l : list code) (stack : list Z) : option (list Z) := match l with | nil => Some stack | c :: l' => let ev := eval_code l' in match c, stack with | Cimm x, _ => ev (x :: stack) | Cget n, _ => ev (nth 0 stack n :: stack) | Cadd, x :: y :: st => ev (x+y :: st) | Cmin, x :: st => ev (0-x :: st) | Cmul, x :: y :: st => ev (x*y :: st) | Cset n, x :: st => ev (set_nth 0%Z st n x) | Cwhl n len, _ => obind (eval_drop len l') (iter_until0 h n ev stack) | Cnext, _ => Some stack | _, _ => None end%Z end with eval_drop n l st := (* 相互再帰 *) match l, n with | _ :: l', 0 => eval_code l' st | _ :: l', S n' => eval_drop n' l' st | [::], _ => None end. Fixpoint compile d (e : expr) : list code := match e with | Cst x => [:: Cimm x] | Var n => [:: Cget (d+n)] | Add e1 e2 => compile d e2 ++ compile (S d) e1 ++ [:: Cadd] | Min e1 => compile d e1 ++ [:: Cmin] | Mul e1 e2 => compile d e2 ++ compile (S d) e1 ++ [:: Cmul] end. Fixpoint compile_cmd (c : cmd) : list code := match c with | Assign n e => compile 0 e ++ [:: Cset n] | Seq c1 c2 => compile_cmd c1 ++ compile_cmd c2 | While n c => let l := compile_cmd c in [:: Cwhl n (length l)] ++ l ++ [:: Cnext] end. Definition neutral c := match c with Cnext | Cwhl _ _ => false | _ => true end. Inductive balanced : list code -> Prop := | Bneutral : forall c, neutral c -> balanced [:: c] | Bcat : forall l1 l2, balanced l1 -> balanced l2 -> balanced (l1 ++ l2) | Bwhl : forall n l, balanced l -> balanced (Cwhl n (length l) :: l ++ [:: Cnext]). Lemma eval_drop_cat st l1 l2 : eval_drop (length l1) (l1 ++ Cnext :: l2) st = eval_code l2 st. Proof. by induction l1. Qed. Lemma eq_iter_until0 n f g : f =1 g -> iter_until0 h n f =1 iter_until0 h n g. Proof. move=> Efg. elim: h => //= h' IH st. case: (nth _ _ _) => // _; rewrite Efg; by case: (g st). Qed. Lemma eval_code_cat stack (l1 l2 : seq code) : balanced l1 -> eval_code (l1 ++ l2) stack = obind (eval_code l2) (eval_code l1 stack). Proof. move=> Hbal. elim: {l1} Hbal stack l2. by destruct c => //= _ [|a[]]. move=> l1 l2 Hbal1 IHl1 Hbal2 IHl2 st l'. rewrite -catA !IHl1. by case: (eval_code l1 st) => //=. move=> len l1 Hbal IHl1 st l' /=. set lhs := iter_until0 _ _ _ _. set rhs := iter_until0 _ _ _ _. have -> : lhs = rhs. apply eq_iter_until0 => st'. rewrite -catA !IHl1. by case: (eval_code l1 st'). case: rhs => //= a. by rewrite -catA /= !eval_drop_cat. Qed. Hint Constructors balanced. Lemma compile_balanced n e : balanced (compile n e). Proof. by elim: e n => /=; auto. Qed. Theorem compile_correct e d stack : eval_code (compile d e) stack = Some (eval (drop d stack) e :: stack). Proof. move: d stack. induction e; simpl; intros; auto. - by rewrite nth_drop. - by rewrite eval_code_cat ?IHe2 /= ?eval_code_cat ?IHe1 //; apply compile_balanced. - by rewrite eval_code_cat ?IHe //; apply compile_balanced. - by rewrite eval_code_cat ?IHe2 /= ?eval_code_cat ?IHe1 //; apply compile_balanced. Qed. Lemma compile_cmd_balanced c : balanced (compile_cmd c). Proof. by elim: c => /=; auto using compile_balanced. Qed. Hint Resolve compile_balanced compile_cmd_balanced. Theorem compile_cmd_correct c stack : eval_code (compile_cmd c) stack = eval_cmd c stack. Proof. move: stack. induction c => stack /=. by rewrite eval_code_cat ?compile_correct ?drop0. rewrite eval_code_cat ?compile_correct ?drop0 // IHc1. by case: (eval_cmd c1 stack). rewrite (eq_iter_until0 _ _ (eval_cmd c)). case: (iter_until0 _ _ _ _) => //= st. by rewrite eval_drop_cat. move=> st. rewrite eval_code_cat // IHc. by case: (eval_cmd c st). Qed. End limited. End While.