(* Import necessary libraries *)Open Scope string_scope. Require Import List. Import ListNotations. Open Scope list_scope. Require Import Arith.(* Helper function for string equality *)x, y: string{x = y} + {x <> y}destruct (String.eqb_spec x y); auto. Defined. (* Useful tactics for simplifying equalities *) Ltac simpeq := repeat match goal with | _ => congruence || (progress subst) | H : ?x = ?x |- _ => clear H | H : _ = _ |- _ => progress injection H as H end. Ltac inv H := inversion H; clear H; simpeq.x, y: string{x = y} + {x <> y}
(* Axiom for function extensionality *) Axiom funext : forall {X Y: Type} (f g: X -> Y), (forall x, f x = g x) -> f = g. (* Type abbreviation for environments *) Definition env := string -> nat. (* Definition of arithmetic expressions *) Inductive expr : Type := | Const : nat -> expr | Var : string -> expr | Plus : expr -> expr -> expr | Mult : expr -> expr -> expr | Minus : expr -> expr -> expr. (* Evaluation function for expressions *) Fixpoint eval (env : env) (e : expr) : nat := match e with | Const n => n | Var x => env x | Plus e1 e2 => eval env e1 + eval env e2 | Mult e1 e2 => eval env e1 * eval env e2 | Minus e1 e2 => eval env e1 - eval env e2 end.
(* Definition of statements *) Inductive stmt := | Assign : string -> expr -> stmt | Seq : stmt -> stmt -> stmt | If : expr -> stmt -> stmt -> stmt | While : expr -> stmt -> stmt | Skip : stmt. (* For small-step semantics, we need Skip *)
(* Small-step semantics for statements *) Inductive small_step : env -> stmt -> env -> stmt -> Prop := | small_Assign env x e : small_step env (Assign x e) (fun var => if string_eq x var then eval env e else env var) Skip | small_Seq1 env s1 s1' s2 env' : small_step env s1 env' s1' -> small_step env (Seq s1 s2) env' (Seq s1' s2) | small_SeqSkip env s2 : small_step env (Seq Skip s2) env s2 | small_IfTrue env e s1 s2 : eval env e <> 0 -> small_step env (If e s1 s2) env s1 | small_IfFalse env e s1 s2 : eval env e = 0 -> small_step env (If e s1 s2) env s2 | small_WhileTrue env e s : eval env e <> 0 -> small_step env (While e s) env (Seq s (While e s)) | small_WhileFalse env e s : eval env e = 0 -> small_step env (While e s) env Skip.
(* Tactic to invert small step hypotheses *) Ltac inv_small_step := match goal with | [ H : small_step _ _ _ _ |- _ ] => (inv H; [|]) || (inv H; []) || (inv H; fail) (* inv only when there are <= 2 subgoals *) end. (* Proof of determinism for small-step semantics *)env, env1, env2: lec08_small_step.env
s, s1, s2: stmtsmall_step env s env1 s1 -> small_step env s env2 s2 -> env1 = env2 /\ s1 = s2env, env1, env2: lec08_small_step.env
s, s1, s2: stmtsmall_step env s env1 s1 -> small_step env s env2 s2 -> env1 = env2 /\ s1 = s2env, env1, env2: lec08_small_step.env
s, s1, s2: stmt
H1: small_step env s env1 s1small_step env s env2 s2 -> env1 = env2 /\ s1 = s2env, env1: lec08_small_step.env
s, s1: stmt
H1: small_step env s env1 s1forall (env2 : lec08_small_step.env) (s2 : stmt), small_step env s env2 s2 -> env1 = env2 /\ s1 = s2env0: env
s1, s1', s2: stmt
env': env
H1: small_step env0 s1 env' s1'
IHsmall_step: forall (env2 : env) (s2 : stmt), small_step env0 s1 env2 s2 -> env' = env2 /\ s1' = s2
env2: env
s1'0: stmt
H6: small_step env0 s1 env2 s1'0env' = env2 /\ Seq s1' s2 = Seq s1'0 s2env0: env
s1, s1', s2: stmt
env': env
H1: small_step env0 s1 env' s1'
IHsmall_step: forall (env2 : env) (s2 : stmt), small_step env0 s1 env2 s2 -> env' = env2 /\ s1' = s2
env2: env
s1'0: stmt
H6: small_step env0 s1 env2 s1'0
H: env' = env2
H0: s1' = s1'0env' = env2 /\ Seq s1' s2 = Seq s1'0 s2eauto. Qed.env0: env
s1, s2: stmt
env2: env
s1'0: stmt
H1: small_step env0 s1 env2 s1'0
IHsmall_step: forall (env3 : env) (s2 : stmt), small_step env0 s1 env3 s2 -> env2 = env3 /\ s1'0 = s2
H6: small_step env0 s1 env2 s1'0env2 = env2 /\ Seq s1'0 s2 = Seq s1'0 s2
(* Definition of progress *) Definition progress (env : string -> nat) (s : stmt) : Prop := exists env' s', small_step env s env' s'. (* Tactic for destructing hypotheses *) Ltac destr := match goal with | [ H : ?P \/ ?Q |- _ ] => destruct H | [ H : exists _, _ |- _ ] => destruct H end. (* Proof that all states either progress or are Skip *)env: string -> nat
s: stmtprogress env s \/ s = Skipinduction s; eauto; left; unfold progress in *; do 9 try destr; simpeq; eauto using small_step; destruct (Nat.eq_dec (eval env e) 0); eauto using small_step. Qed.env: string -> nat
s: stmtprogress env s \/ s = Skip
(* Definition of multi-step small-step semantics *) Inductive small_steps : env -> stmt -> env -> stmt -> Prop := | small_steps_refl env s : small_steps env s env s | small_steps_step env env' env'' s s' s'' : small_step env s env' s' -> small_steps env' s' env'' s'' -> small_steps env s env'' s''. (* Proof of transitivity for small_steps *)env: lec08_small_step.env
s: stmt
env': lec08_small_step.env
s': stmt
env'': lec08_small_step.env
s'': stmtsmall_steps env s env' s' -> small_steps env' s' env'' s'' -> small_steps env s env'' s''env: lec08_small_step.env
s: stmt
env': lec08_small_step.env
s': stmt
env'': lec08_small_step.env
s'': stmtsmall_steps env s env' s' -> small_steps env' s' env'' s'' -> small_steps env s env'' s''induction H1; eauto using small_steps, small_step. Qed. Require Import Coq.Program.Equality. (* Lemma: Skip doesn't change the environment *)env: lec08_small_step.env
s: stmt
env': lec08_small_step.env
s': stmt
env'': lec08_small_step.env
s'': stmt
H1: small_steps env s env' s'small_steps env' s' env'' s'' -> small_steps env s env'' s''env, env': lec08_small_step.env
s: stmtsmall_steps env Skip env' s -> env' = env /\ s = Skipenv, env': lec08_small_step.env
s: stmtsmall_steps env Skip env' s -> env' = env /\ s = Skipenv, env': lec08_small_step.env
s: stmt
H: small_steps env Skip env' senv' = env /\ s = Skipinv_small_step. Qed.env0, env', env'': env
s', s'': stmt
H: small_step env0 Skip env' s'
H0: small_steps env' s' env'' s''
IHsmall_steps: s' = Skip -> env'' = env' /\ s'' = Skipenv'' = env0 /\ s'' = Skip
Multi-step determinism
env, env1, env2: lec08_small_step.env
s: stmtsmall_steps env s env1 Skip -> small_steps env s env2 Skip -> env1 = env2env, env1, env2: lec08_small_step.env
s: stmtsmall_steps env s env1 Skip -> small_steps env s env2 Skip -> env1 = env2env, env1, env2: lec08_small_step.env
s: stmt
H: small_steps env s env1 Skipsmall_steps env s env2 Skip -> env1 = env2env, env1: lec08_small_step.env
s: stmt
H: small_steps env s env1 Skipforall env2 : lec08_small_step.env, small_steps env s env2 Skip -> env1 = env2env0, env2: env
H: small_steps env0 Skip env2 Skipenv0 = env2env0, env', env'': env
s, s': stmt
H: small_step env0 s env' s'
H0: small_steps env' s' env'' Skip
IHsmall_steps: Skip = Skip -> forall env2 : env, small_steps env' s' env2 Skip -> env'' = env2
env2: env
H1: small_steps env0 s env2 Skipenv'' = env2env0, env2: env
H: small_steps env0 Skip env2 Skipenv0 = env2auto.env0, env2: env
H: env2 = env0
H0: Skip = Skipenv0 = env2env0, env', env'': env
s, s': stmt
H: small_step env0 s env' s'
H0: small_steps env' s' env'' Skip
IHsmall_steps: Skip = Skip -> forall env2 : env, small_steps env' s' env2 Skip -> env'' = env2
env2: env
H1: small_steps env0 s env2 Skipenv'' = env2env', env'': env
s': stmt
env2: env
H: small_step env2 Skip env' s'
H0: small_steps env' s' env'' Skip
IHsmall_steps: Skip = Skip -> forall env2 : env, small_steps env' s' env2 Skip -> env'' = env2env'' = env2env0, env', env'': env
s, s': stmt
H: small_step env0 s env' s'
H0: small_steps env' s' env'' Skip
IHsmall_steps: Skip = Skip -> forall env2 : env, small_steps env' s' env2 Skip -> env'' = env2
env2, env'0: env
s'0: stmt
H2: small_step env0 s env'0 s'0
H3: small_steps env'0 s'0 env2 Skipenv'' = env2inv_small_step.env', env'': env
s': stmt
env2: env
H: small_step env2 Skip env' s'
H0: small_steps env' s' env'' Skip
IHsmall_steps: Skip = Skip -> forall env2 : env, small_steps env' s' env2 Skip -> env'' = env2env'' = env2env0, env', env'': env
s, s': stmt
H: small_step env0 s env' s'
H0: small_steps env' s' env'' Skip
IHsmall_steps: Skip = Skip -> forall env2 : env, small_steps env' s' env2 Skip -> env'' = env2
env2, env'0: env
s'0: stmt
H2: small_step env0 s env'0 s'0
H3: small_steps env'0 s'0 env2 Skipenv'' = env2env0, env', env'': env
s, s': stmt
H0: small_steps env' s' env'' Skip
IHsmall_steps: Skip = Skip -> forall env2 : env, small_steps env' s' env2 Skip -> env'' = env2
env2, env'0: env
s'0: stmt
H2: small_step env0 s env'0 s'0
H3: small_steps env'0 s'0 env2 Skip
H: env'0 = env'
H1: s'0 = s'env'' = env2eauto. Qed.env0, env', env'': env
s, s': stmt
H0: small_steps env' s' env'' Skip
IHsmall_steps: Skip = Skip -> forall env2 : env, small_steps env' s' env2 Skip -> env'' = env2
env2: env
H2: small_step env0 s env' s'
H3: small_steps env' s' env2 Skipenv'' = env2
(* Definition of big-step semantics *) Inductive big_step : env -> stmt -> env -> Prop := | big_Skip env : big_step env Skip env | big_Assign env x e : big_step env (Assign x e) (fun var => if string_eq x var then eval env e else env var) | big_Seq env env' env'' s1 s2 : big_step env s1 env' -> big_step env' s2 env'' -> big_step env (Seq s1 s2) env'' | big_IfTrue env env' e s1 s2 : eval env e <> 0 -> big_step env s1 env' -> big_step env (If e s1 s2) env' | big_IfFalse env env' e s1 s2 : eval env e = 0 -> big_step env s2 env' -> big_step env (If e s1 s2) env' | big_WhileTrue env env' env'' e s : eval env e <> 0 -> big_step env s env' -> big_step env' (While e s) env'' -> big_step env (While e s) env'' | big_WhileFalse env e s : eval env e = 0 -> big_step env (While e s) env. (* Lemma: small_steps for sequences *)env: lec08_small_step.env
s1, s2: stmt
env': lec08_small_step.env
s1': stmtsmall_steps env s1 env' s1' -> small_steps env (Seq s1 s2) env' (Seq s1' s2)env: lec08_small_step.env
s1, s2: stmt
env': lec08_small_step.env
s1': stmtsmall_steps env s1 env' s1' -> small_steps env (Seq s1 s2) env' (Seq s1' s2)induction H; eauto using small_steps, small_step. Qed. (* Proof that big-step implies small-steps *)env: lec08_small_step.env
s1, s2: stmt
env': lec08_small_step.env
s1': stmt
H: small_steps env s1 env' s1'small_steps env (Seq s1 s2) env' (Seq s1' s2)env: lec08_small_step.env
s: stmt
env': lec08_small_step.envbig_step env s env' -> small_steps env s env' Skipenv: lec08_small_step.env
s: stmt
env': lec08_small_step.envbig_step env s env' -> small_steps env s env' Skipinduction H; eauto 10 using small_steps, small_step, small_steps_trans, small_steps_Seq. Qed. (* Lemma: single small-step preserves big-step *)env: lec08_small_step.env
s: stmt
env': lec08_small_step.env
H: big_step env s env'small_steps env s env' Skipenv: lec08_small_step.env
s: stmt
env': lec08_small_step.env
s': stmt
env'': lec08_small_step.envsmall_step env s env' s' -> big_step env' s' env'' -> big_step env s env''env: lec08_small_step.env
s: stmt
env': lec08_small_step.env
s': stmt
env'': lec08_small_step.envsmall_step env s env' s' -> big_step env' s' env'' -> big_step env s env''env: lec08_small_step.env
s: stmt
env': lec08_small_step.env
s': stmt
env'': lec08_small_step.env
H1: small_step env s env' s'
H2: big_step env' s' env''big_step env s env''induction H2; intros; inv H1; eauto using big_step. Qed. (* Proof that small-steps implies big-step *)env': env
s': stmt
env'': env
H2: big_step env' s' env''forall (env : env) (s : stmt), small_step env s env' s' -> big_step env s env''env: lec08_small_step.env
s: stmt
env': lec08_small_step.envsmall_steps env s env' Skip -> big_step env s env'env: lec08_small_step.env
s: stmt
env': lec08_small_step.envsmall_steps env s env' Skip -> big_step env s env'dependent induction H; eauto using big_step, small_step_big_step. Qed.env: lec08_small_step.env
s: stmt
env': lec08_small_step.env
H: small_steps env s env' Skipbig_step env s env'
(* Definition of concurrent statements *) Inductive cstmt := | CSkip : cstmt | CAssign : string -> expr -> cstmt | CSeq : cstmt -> cstmt -> cstmt | CIf : expr -> cstmt -> cstmt -> cstmt | CWhile : expr -> cstmt -> cstmt | CPar : cstmt -> cstmt -> cstmt. (* Small-step semantics for concurrent statements *) Inductive csmall_step : env -> cstmt -> env -> cstmt -> Prop := | csmall_Assign env x e : csmall_step env (CAssign x e) (fun var => if string_eq x var then eval env e else env var) CSkip | csmall_Seq1 env s1 s1' s2 env' : csmall_step env s1 env' s1' -> csmall_step env (CSeq s1 s2) env' (CSeq s1' s2) | csmall_SeqSkip env s2 : csmall_step env (CSeq CSkip s2) env s2 | csmall_IfTrue env e s1 s2 : eval env e <> 0 -> csmall_step env (CIf e s1 s2) env s1 | csmall_IfFalse env e s1 s2 : eval env e = 0 -> csmall_step env (CIf e s1 s2) env s2 | csmall_WhileTrue env e s : eval env e <> 0 -> csmall_step env (CWhile e s) env (CSeq s (CWhile e s)) | csmall_WhileFalse env e s : eval env e = 0 -> csmall_step env (CWhile e s) env CSkip | csmall_Par1 env s1 s1' s2 env' : csmall_step env s1 env' s1' -> csmall_step env (CPar s1 s2) env' (CPar s1' s2) | csmall_Par2 env s2 s2' s1 env' : csmall_step env s2 env' s2' -> csmall_step env (CPar s1 s2) env' (CPar s1 s2') | csmall_ParSkip1 env s2 : csmall_step env (CPar CSkip s2) env s2 | csmall_ParSkip2 env s1 : csmall_step env (CPar s1 CSkip) env s1.
(* Definition of evaluation contexts *) Inductive ctx : (cstmt -> cstmt) -> Type := | CSeq1 s2 : ctx (fun x => CSeq x s2) | CPar1 s2 : ctx (fun x => CPar x s2) | CPar2 s1 : ctx (fun x => CPar s1 x). (* Small-step semantics with contexts *) Inductive ccsmall_step : env -> cstmt -> env -> cstmt -> Prop := | ccsmall_Assign env x e : ccsmall_step env (CAssign x e) (fun var => if string_eq x var then eval env e else env var) CSkip | ccsmall_SeqSkip env s2 : ccsmall_step env (CSeq CSkip s2) env s2 | ccsmall_IfTrue env e s1 s2 : eval env e <> 0 -> ccsmall_step env (CIf e s1 s2) env s1 | ccsmall_IfFalse env e s1 s2 : eval env e = 0 -> ccsmall_step env (CIf e s1 s2) env s2 | ccsmall_WhileTrue env e s : eval env e <> 0 -> ccsmall_step env (CWhile e s) env (CSeq s (CWhile e s)) | ccsmall_WhileFalse env e s : eval env e = 0 -> ccsmall_step env (CWhile e s) env CSkip | ccsmall_ParSkip1 env s2 : ccsmall_step env (CPar CSkip s2) env s2 | ccsmall_ParSkip2 env s1 : ccsmall_step env (CPar s1 CSkip) env s1 | ccsmall_Ctx K s1 s2 s1' s2' env env' : (* This is to make eauto work better *) ctx K -> s1' = K s1 -> s2' = K s2 -> ccsmall_step env s1 env' s2 -> ccsmall_step env s1' env' s2'.
Equivalence with previous small-step semantics
env1: env
s1: cstmt
env2: env
s2: cstmtcsmall_step env1 s1 env2 s2 <-> ccsmall_step env1 s1 env2 s2env1: env
s1: cstmt
env2: env
s2: cstmtcsmall_step env1 s1 env2 s2 <-> ccsmall_step env1 s1 env2 s2env1: env
s1: cstmt
env2: env
s2: cstmt
H: csmall_step env1 s1 env2 s2ccsmall_step env1 s1 env2 s2env1: env
s1: cstmt
env2: env
s2: cstmt
H: ccsmall_step env1 s1 env2 s2csmall_step env1 s1 env2 s2induction H; eauto using ccsmall_step, ctx.env1: env
s1: cstmt
env2: env
s2: cstmt
H: csmall_step env1 s1 env2 s2ccsmall_step env1 s1 env2 s2env1: env
s1: cstmt
env2: env
s2: cstmt
H: ccsmall_step env1 s1 env2 s2csmall_step env1 s1 env2 s2K: cstmt -> cstmt
s1, s2, s1', s2': cstmt
env0, env': env
H: ctx K
H0: s1' = K s1
H1: s2' = K s2
H2: ccsmall_step env0 s1 env' s2
IHccsmall_step: csmall_step env0 s1 env' s2csmall_step env0 s1' env' s2'inv H; eauto using csmall_step. Qed.K: cstmt -> cstmt
s1, s2: cstmt
env0, env': env
H: ctx K
H2: ccsmall_step env0 s1 env' s2
IHccsmall_step: csmall_step env0 s1 env' s2csmall_step env0 (K s1) env' (K s2)