Built with Alectryon, running Coq+SerAPI v8.19.0+0.19.3. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑ Ctrl+↓ to navigate, Ctrl+🖱️ to focus. On Mac, use instead of Ctrl.

Lecture 7: Big-step semantics

Set Nested Proofs Allowed.
Require Import Compare.

[Loading ML file ring_plugin.cmxs (using legacy method) ... done]
Open Scope string_scope. (* Lets us write strings literals as "x" *) Require Import List. Import ListNotations. Open Scope list_scope. (* Lets us write lists as [1; 2; 3] *) Require Import Arith.
[Loading ML file zify_plugin.cmxs (using legacy method) ... done]
[Loading ML file micromega_plugin.cmxs (using legacy method) ... done]

Defining Recursive Functions

We've seen how we can define some recursive functions in Coq, provided that it passes the termination checker. But what if we have a more complicated function? As an example, let's look at implementing merge sort for lists of natural numbers, using the standard ordering.

First, we need to define a function to merge two (already sorted lists). Normally, we'd write this as follows:

Definition nat_lte := Compare_dec.le_gt_dec.

Recursive definition of merge is ill-formed. In environment merge : list nat -> list nat -> list nat xs : list nat ys : list nat x : nat xs' : list nat y : nat ys' : list nat g : x > y Recursive call to merge has principal argument equal to "xs" instead of "xs'". Recursive definition is: "fun xs ys : list nat => match xs with | [] => ys | x :: xs' => match ys with | [] => xs | y :: ys' => if nat_lte x y then x :: merge xs' ys else y :: merge xs ys' end end".

Unfortunately, Coq will reject this because it's the case that xs is always getting smaller, nor the case that ys is always getting smaller. Of course, one of them is always getting smaller, so eventually, this will terminate. But in this case, we can hack around the problem by simply re-organizing the function as follows.

Fixpoint merge (xs:list nat) : list nat -> list nat :=
  match xs with
  | nil => fun ys => ys
  | x::xs' =>
      (fix inner_merge (ys:list nat) : list nat :=
         match ys with
         | nil => x::xs'
         | y::ys' =>
             if nat_lte x y then
               x :: (merge xs' ys)
             else
               y :: (inner_merge ys')
         end)
  end.

We can write some examples to test that merge works as expected.

= [1; 2; 3; 4; 5; 6] : list nat
= [1; 3; 4] : list nat

Recursive functions with explicit measures

[Loading ML file extraction_plugin.cmxs (using legacy method) ... done]
Program Fixpoint merge' (xs ys:list nat) {measure (length xs + length ys)} : list nat := match xs, ys with | [], ys => ys | xs, [] => xs | x::xs', y::ys' => if nat_lte x y then x :: (merge' xs' ys) else y :: (merge' xs ys') (* Generates a proof obligation *) end.
y: nat
ys': list nat
x: nat
xs': list nat
merge': forall xs ys : list nat, Datatypes.length xs + Datatypes.length ys < Datatypes.length (x :: xs') + Datatypes.length (y :: ys') -> list nat
g: x > y

Datatypes.length (x :: xs') + Datatypes.length ys' < Datatypes.length (x :: xs') + Datatypes.length (y :: ys')
(* To show: length xs + length ys' < length xs + length ys *)
y: nat
ys': list nat
x: nat
xs': list nat
merge': forall xs ys : list nat, Datatypes.length xs + Datatypes.length ys < Datatypes.length (x :: xs') + Datatypes.length (y :: ys') -> list nat
g: x > y

S (Datatypes.length xs' + Datatypes.length ys') < S (Datatypes.length xs' + S (Datatypes.length ys'))
lia. Defined.
= [1; 2; 3; 4; 5; 6] : list nat
= [1; 3; 4] : list nat

It is also interesting to examine the objects that are generated by this definition.

merge' = fun xs ys : list nat => merge'_func (existT (fun _ : list nat => list nat) xs ys) : list nat -> list nat -> list nat Arguments merge' (xs ys)%list_scope
merge'_func = Fix_sub {_ : list nat & list nat} (MR lt (fun recarg : {_ : list nat & list nat} => let xs := projT1 recarg in let ys := projT2 recarg in Datatypes.length xs + Datatypes.length ys)) merge'_func_obligation_4 (fun recarg : {_ : list nat & list nat} => let xs := projT1 recarg in let ys := projT2 recarg in list nat) (fun (recarg : {_ : list nat & list nat}) (merge'' : forall recarg' : {recarg' : {_ : list nat & list nat} | (let xs := projT1 recarg' in let ys := projT2 recarg' in Datatypes.length xs + Datatypes.length ys) < (let xs := projT1 recarg in let ys := projT2 recarg in Datatypes.length xs + Datatypes.length ys)}, let xs := projT1 (proj1_sig recarg') in let ys := projT2 (proj1_sig recarg') in list nat) => let xs := projT1 recarg in let ys := projT2 recarg in let merge' := fun (xs0 ys0 : list nat) (recproof : Datatypes.length xs0 + Datatypes.length ys0 < Datatypes.length xs + Datatypes.length ys) => merge'' (exist (fun recarg' : {_ : list nat & list nat} => (let xs1 := projT1 recarg' in let ys1 := projT2 recarg' in Datatypes.length xs1 + Datatypes.length ys1) < (let xs1 := projT1 recarg in let ys1 := projT2 recarg in Datatypes.length xs1 + Datatypes.length ys1)) (existT (fun _ : list nat => list nat) xs0 ys0) recproof) in let program_branch_0 := fun (ys0 : list nat) (_ : [] = xs) (_ : ys0 = ys) => ys0 in let program_branch_1 := fun (xs0 : list nat) (_ : forall ys0 : list nat, ~ ([] = xs0 /\ ys0 = [])) (_ : xs0 = xs) (_ : [] = ys) => xs0 in let program_branch_2 := fun (x : nat) (xs' : list nat) (y : nat) (ys' : list nat) (Heq_xs : x :: xs' = xs) (Heq_ys : y :: ys' = ys) => match nat_lte x y with | left x0 => x :: merge' xs' ys ((fun (xs0 ys0 : list nat) (merge'0 : forall xs1 ys1 : list nat, Datatypes.length xs1 + Datatypes.length ys1 < Datatypes.length xs0 + Datatypes.length ys0 -> list nat) (x1 : nat) (xs'0 : list nat) (y0 : nat) (ys'0 : list nat) (Heq_xs0 : x1 :: xs'0 = xs0) (Heq_ys0 : y0 :: ys'0 = ys0) (_ : x1 <= y0) => merge'_func_obligation_1 xs0 ys0 merge'0 x1 xs'0 y0 ys'0 Heq_xs0 Heq_ys0) xs ys merge' x xs' y ys' Heq_xs Heq_ys x0) | right x0 => y :: merge' xs ys' ((fun (xs0 ys0 : list nat) (merge'0 : forall xs1 ys1 : list nat, Datatypes.length xs1 + Datatypes.length ys1 < Datatypes.length xs0 + Datatypes.length ys0 -> list nat) (x1 : nat) (xs'0 : list nat) (y0 : nat) (ys'0 : list nat) (Heq_xs0 : x1 :: xs'0 = xs0) (Heq_ys0 : y0 :: ys'0 = ys0) (g : x1 > y0) => merge'_func_obligation_2 xs0 ys0 merge'0 x1 xs'0 y0 ys'0 Heq_xs0 Heq_ys0 g) xs ys merge' x xs' y ys' Heq_xs Heq_ys x0) end in match xs as ys' return (ys' = xs -> ys = ys -> list nat) with | [] => program_branch_0 ys | x :: xs' => match ys as xs'0 return (x :: xs' = xs -> xs'0 = ys -> list nat) with | [] => program_branch_1 (x :: xs') ((fun (xs0 ys0 : list nat) (_ : forall xs1 ys1 : list nat, Datatypes.length xs1 + Datatypes.length ys1 < Datatypes.length xs0 + Datatypes.length ys0 -> list nat) (n : nat) (l ys1 : list nat) => merge'_func_obligation_3 n l ys1) xs ys merge' x xs') | y :: ys' => program_branch_2 x xs' y ys' end end eq_refl eq_refl) : forall recarg : {_ : list nat & list nat}, let xs := projT1 recarg in let ys := projT2 recarg in list nat Arguments merge'_func recarg
Fix_sub : forall (A : Type) (R : A -> A -> Prop), well_founded R -> forall P : A -> Type, (forall x : A, (forall y : {y : A | R y x}, P (proj1_sig y)) -> P x) -> forall x : A, P x
merge'_func_obligation_4 : well_founded (MR lt (fun recarg : {_ : list nat & list nat} => let xs := projT1 recarg in let ys := projT2 recarg in Datatypes.length xs + Datatypes.length ys))
merge'_func_obligation_4 = measure_wf lt_wf (fun recarg : {_ : list nat & list nat} => Datatypes.length (projT1 recarg) + Datatypes.length (projT2 recarg)) : well_founded (MR lt (fun recarg : {_ : list nat & list nat} => let xs := projT1 recarg in let ys := projT2 recarg in Datatypes.length xs + Datatypes.length ys)) Arguments merge'_func_obligation_4 a
lt_wf : well_founded lt
well_founded = fun (A : Type) (R : A -> A -> Prop) => forall a : A, Acc R a : forall A : Type, (A -> A -> Prop) -> Prop Arguments well_founded [A]%type_scope R%function_scope
Inductive Acc (A : Type) (R : A -> A -> Prop) (x : A) : Prop := Acc_intro : (forall y : A, R y x -> Acc R y) -> Acc R x. Arguments Acc [A]%type_scope R%function_scope x Arguments Acc_intro [A]%type_scope [R]%function_scope x _%function_scope

Merge sort

Now let's write a pair of helper functions, one that takes a list of list of naturals and merges consecutive elements, and another that transforms a list into a list of singleton lists.

Fixpoint merge_pairs (xs:list (list nat)) : list (list nat) :=
  match xs with
  | h1::h2::t => (merge h1 h2) :: (merge_pairs t)
  | xs' => xs'
  end.

Definition make_lists (xs:list nat) : list (list nat) :=
  List.map (fun x => x::nil) xs.

Here are some examples to illustrate what these helper functions do.

= [[5]; [1]; [4]; [2]; [3]] : list (list nat)
= [[1; 2; 3; 4; 9]; [0; 2; 3]] : list (list nat)
= [[1; 2; 3; 4; 9]; [0]] : list (list nat)
= [[1; 2; 3; 4; 5]] : list (list nat)

Next we will prove an important lemma that relate the length of the list computed by merge_pairs to the length of its argument. Note that we prove a conjunction to get a strong enough induction hypothesis. (As a fun exercise, try to prove just the first conjunct by induction and see where you get stuck.)


forall xs : list (list nat), (forall h1 h2 : list nat, Datatypes.length (merge_pairs (h1 :: h2 :: xs)) < Datatypes.length (h1 :: h2 :: xs)) /\ (forall h : list nat, Datatypes.length (merge_pairs (h :: xs)) <= Datatypes.length (h :: xs))

forall xs : list (list nat), (forall h1 h2 : list nat, Datatypes.length (merge_pairs (h1 :: h2 :: xs)) < Datatypes.length (h1 :: h2 :: xs)) /\ (forall h : list nat, Datatypes.length (merge_pairs (h :: xs)) <= Datatypes.length (h :: xs))

(forall h1 h2 : list nat, Datatypes.length (merge_pairs [h1; h2]) < Datatypes.length [h1; h2]) /\ (forall h : list nat, Datatypes.length (merge_pairs [h]) <= Datatypes.length [h])
x: list nat
xs: list (list nat)
H1: forall h1 h2 : list nat, Datatypes.length (merge_pairs (h1 :: h2 :: xs)) < Datatypes.length (h1 :: h2 :: xs)
H2: forall h : list nat, Datatypes.length (merge_pairs (h :: xs)) <= Datatypes.length (h :: xs)
(forall h1 h2 : list nat, Datatypes.length (merge_pairs (h1 :: h2 :: x :: xs)) < Datatypes.length (h1 :: h2 :: x :: xs)) /\ (forall h : list nat, Datatypes.length (merge_pairs (h :: x :: xs)) <= Datatypes.length (h :: x :: xs))

(forall h1 h2 : list nat, Datatypes.length (merge_pairs [h1; h2]) < Datatypes.length [h1; h2]) /\ (forall h : list nat, Datatypes.length (merge_pairs [h]) <= Datatypes.length [h])

(list nat -> list nat -> 1 < 2) /\ (list nat -> 1 <= 1)
split; lia.
x: list nat
xs: list (list nat)
H1: forall h1 h2 : list nat, Datatypes.length (merge_pairs (h1 :: h2 :: xs)) < Datatypes.length (h1 :: h2 :: xs)
H2: forall h : list nat, Datatypes.length (merge_pairs (h :: xs)) <= Datatypes.length (h :: xs)

(forall h1 h2 : list nat, Datatypes.length (merge_pairs (h1 :: h2 :: x :: xs)) < Datatypes.length (h1 :: h2 :: x :: xs)) /\ (forall h : list nat, Datatypes.length (merge_pairs (h :: x :: xs)) <= Datatypes.length (h :: x :: xs))
x: list nat
xs: list (list nat)
H1: forall h1 h2 : list nat, Datatypes.length (merge_pairs (h1 :: h2 :: xs)) < Datatypes.length (h1 :: h2 :: xs)
H2: forall h : list nat, Datatypes.length (merge_pairs (h :: xs)) <= Datatypes.length (h :: xs)

forall h1 h2 : list nat, Datatypes.length (merge_pairs (h1 :: h2 :: x :: xs)) < Datatypes.length (h1 :: h2 :: x :: xs)
x: list nat
xs: list (list nat)
H1: forall h1 h2 : list nat, Datatypes.length (merge_pairs (h1 :: h2 :: xs)) < Datatypes.length (h1 :: h2 :: xs)
H2: forall h : list nat, Datatypes.length (merge_pairs (h :: xs)) <= Datatypes.length (h :: xs)
forall h : list nat, Datatypes.length (merge_pairs (h :: x :: xs)) <= Datatypes.length (h :: x :: xs)
x: list nat
xs: list (list nat)
H1: forall h1 h2 : list nat, Datatypes.length (merge_pairs (h1 :: h2 :: xs)) < Datatypes.length (h1 :: h2 :: xs)
H2: forall h : list nat, Datatypes.length (merge_pairs (h :: xs)) <= Datatypes.length (h :: xs)

forall h1 h2 : list nat, Datatypes.length (merge_pairs (h1 :: h2 :: x :: xs)) < Datatypes.length (h1 :: h2 :: x :: xs)
x: list nat
xs: list (list nat)
H1: forall h1 h2 : list nat, Datatypes.length (merge_pairs (h1 :: h2 :: xs)) < Datatypes.length (h1 :: h2 :: xs)
H2: Datatypes.length (merge_pairs (x :: xs)) <= Datatypes.length (x :: xs)

forall h1 h2 : list nat, Datatypes.length (merge_pairs (h1 :: h2 :: x :: xs)) < Datatypes.length (h1 :: h2 :: x :: xs)
x: list nat
xs: list (list nat)
H1: list nat -> list nat -> S (Datatypes.length (merge_pairs xs)) < S (S (Datatypes.length xs))
H2: Datatypes.length match xs with | [] => x :: xs | h2 :: t => merge x h2 :: merge_pairs t end <= S (Datatypes.length xs)

list nat -> list nat -> S (Datatypes.length match xs with | [] => x :: xs | h2 :: t => merge x h2 :: merge_pairs t end) < S (S (S (Datatypes.length xs)))
lia.
x: list nat
xs: list (list nat)
H1: forall h1 h2 : list nat, Datatypes.length (merge_pairs (h1 :: h2 :: xs)) < Datatypes.length (h1 :: h2 :: xs)
H2: forall h : list nat, Datatypes.length (merge_pairs (h :: xs)) <= Datatypes.length (h :: xs)

forall h : list nat, Datatypes.length (merge_pairs (h :: x :: xs)) <= Datatypes.length (h :: x :: xs)
x: list nat
xs: list (list nat)
H1: forall h1 h2 : list nat, Datatypes.length (merge_pairs (h1 :: h2 :: xs)) < Datatypes.length (h1 :: h2 :: xs)
H2: forall h : list nat, Datatypes.length (merge_pairs (h :: xs)) <= Datatypes.length (h :: xs)
x': list nat

Datatypes.length (merge_pairs (x' :: x :: xs)) <= Datatypes.length (x' :: x :: xs)
x: list nat
xs: list (list nat)
x': list nat
H1: Datatypes.length (merge_pairs (x' :: x :: xs)) < Datatypes.length (x' :: x :: xs)
H2: forall h : list nat, Datatypes.length (merge_pairs (h :: xs)) <= Datatypes.length (h :: xs)

Datatypes.length (merge_pairs (x' :: x :: xs)) <= Datatypes.length (x' :: x :: xs)
lia. Qed.

Next, we can prove a corollary that captures the case we will need to define merge sort.


forall (h1 h2 : list nat) (xs : list (list nat)), Datatypes.length (merge_pairs (h1 :: h2 :: xs)) < Datatypes.length (h1 :: h2 :: xs)

forall (h1 h2 : list nat) (xs : list (list nat)), Datatypes.length (merge_pairs (h1 :: h2 :: xs)) < Datatypes.length (h1 :: h2 :: xs)
h1, h2: list nat
xs: list (list nat)

Datatypes.length (merge_pairs (h1 :: h2 :: xs)) < Datatypes.length (h1 :: h2 :: xs)
h1, h2: list nat
xs: list (list nat)

(forall h1 h2 : list nat, Datatypes.length (merge_pairs (h1 :: h2 :: xs)) < Datatypes.length (h1 :: h2 :: xs)) /\ (forall h : list nat, Datatypes.length (merge_pairs (h :: xs)) <= Datatypes.length (h :: xs)) -> Datatypes.length (merge_pairs (h1 :: h2 :: xs)) < Datatypes.length (h1 :: h2 :: xs)
h1, h2: list nat
xs: list (list nat)
H: forall h1 h2 : list nat, Datatypes.length (merge_pairs (h1 :: h2 :: xs)) < Datatypes.length (h1 :: h2 :: xs)

Datatypes.length (merge_pairs (h1 :: h2 :: xs)) < Datatypes.length (h1 :: h2 :: xs)
apply H. Qed.

Now we are ready to define our merge sort. We'll do it by iterating merge_pairs until we have a singleton list.

Program Fixpoint merge_iter (xs: list (list nat))
  { measure (length xs) } : list nat :=
  match xs with
  | nil => nil
  | x::nil => x
  | x1::x2::xs' => merge_iter (merge_pairs (x1::x2::xs'))
  end.
x1, x2: list nat
xs': list (list nat)
merge_iter: forall xs : list (list nat), Datatypes.length xs < Datatypes.length (x1 :: x2 :: xs') -> list nat

S (Datatypes.length (merge_pairs xs')) < Datatypes.length (x1 :: x2 :: xs')
x1, x2: list nat
xs': list (list nat)
merge_iter: forall xs : list (list nat), Datatypes.length xs < Datatypes.length (x1 :: x2 :: xs') -> list nat

S (Datatypes.length (merge_pairs xs')) < Datatypes.length (x1 :: x2 :: xs')
apply merge_pairs_length. Defined.

Note that we had to use merge_pairs_length before Coq was willing to accept our recursive definition.

With these pieces in hand, we can finally define our merge_sort function.

Definition merge_sort (xs:list nat) :=
  merge_iter (make_lists xs).

Let's test that is is working as expected:

= [1; 2; 3; 4; 5; 6; 7; 8] : list nat
= [2; 3; 7; 8] : list nat

Recap: arithmetic expressions

Axiom funext : forall {X Y: Type} (f g: X -> Y),
    (forall x, f x = g x) -> f = g.

Inductive expr : Type :=
  | Const : nat -> expr
  | Var : string -> expr
  | Plus : expr -> expr -> expr
  | Mult : expr -> expr -> expr
  | Minus : expr -> expr -> expr.

Fixpoint eval (env : string -> nat) (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.

While loops

A simple imperative programming language with While loops

Inductive stmt :=
  | Assign : string -> expr -> stmt
  | Seq : stmt -> stmt -> stmt
  | If : expr -> stmt -> stmt -> stmt
  | While : expr -> stmt -> stmt.

Big-step semantics

x, y: string

{x = y} + {x <> y}
x, y: string

{x = y} + {x <> y}
destruct (String.eqb_spec x y); auto. Defined.
x, y: string

(if string_eq x y then 0 else 1) = 1 -> (if string_eq y x then 1 else 0) = 0
x, y: string

(if string_eq x y then 0 else 1) = 1 -> (if string_eq y x then 1 else 0) = 0
x, y: string
H: (if string_eq x y then 0 else 1) = 1

(if string_eq y x then 1 else 0) = 0
x, y: string
e: x = y
H: 0 = 1

(if string_eq y x then 1 else 0) = 0
x, y: string
n: x <> y
H: 1 = 1
(if string_eq y x then 1 else 0) = 0
x, y: string
e: x = y
H: 0 = 1

(if string_eq y x then 1 else 0) = 0
discriminate.
x, y: string
n: x <> y
H: 1 = 1

(if string_eq y x then 1 else 0) = 0
x, y: string
n: x <> y
H: 1 = 1
e: y = x

1 = 0
x, y: string
n: x <> y
H: 1 = 1
n0: y <> x
0 = 0
x, y: string
n: x <> y
H: 1 = 1
e: y = x

1 = 0
congruence.
x, y: string
n: x <> y
H: 1 = 1
n0: y <> x

0 = 0
reflexivity. Qed. Ltac simpeq := repeat match goal with | _ => congruence || (progress subst) | H : ?x = ?x |- _ => clear H | H : _ = _ |- _ => progress injection H as H end.

Shorter proof

Ltac string_cases := repeat (destruct string_eq; simpeq; simpl).

x, y: string

(if string_eq x y then 0 else 1) = 1 -> (if string_eq y x then 1 else 0) = 0
x, y: string

(if string_eq x y then 0 else 1) = 1 -> (if string_eq y x then 1 else 0) = 0
string_cases. Qed.

Big-step semantics

Definition env := string -> nat.

Inductive big_step : env -> stmt -> env -> Prop :=
  | 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.

Determinism

env: lec07_big_step.env
s: stmt
env1, env2: lec07_big_step.env

big_step env s env1 -> big_step env s env2 -> env1 = env2
env: lec07_big_step.env
s: stmt
env1, env2: lec07_big_step.env

big_step env s env1 -> big_step env s env2 -> env1 = env2
env: lec07_big_step.env
s: stmt
env1, env2: lec07_big_step.env
H1: big_step env s env1

big_step env s env2 -> env1 = env2
env: lec07_big_step.env
s: stmt
env1: lec07_big_step.env
H1: big_step env s env1

forall env2 : lec07_big_step.env, big_step env s env2 -> env1 = env2
env0: env
x: string
e: expr
env2: env
H2: big_step env0 (Assign x e) env2

(fun var : string => if string_eq x var then eval env0 e else env0 var) = env2
env0, env', env'': env
s1, s2: stmt
H1_: big_step env0 s1 env'
H1_0: big_step env' s2 env''
IHbig_step1: forall env2 : env, big_step env0 s1 env2 -> env' = env2
IHbig_step2: forall env2 : env, big_step env' s2 env2 -> env'' = env2
env2: env
H2: big_step env0 (Seq s1 s2) env2
env'' = env2
env0: string -> nat
env': env
e: expr
s1, s2: stmt
H: eval env0 e <> 0
H1: big_step env0 s1 env'
IHbig_step: forall env2 : env, big_step env0 s1 env2 -> env' = env2
env2: env
H2: big_step env0 (If e s1 s2) env2
env' = env2
env0: string -> nat
env': env
e: expr
s1, s2: stmt
H: eval env0 e = 0
H1: big_step env0 s2 env'
IHbig_step: forall env2 : env, big_step env0 s2 env2 -> env' = env2
env2: env
H2: big_step env0 (If e s1 s2) env2
env' = env2
env0: string -> nat
env', env'': env
e: expr
s: stmt
H: eval env0 e <> 0
H1_: big_step env0 s env'
H1_0: big_step env' (While e s) env''
IHbig_step1: forall env2 : env, big_step env0 s env2 -> env' = env2
IHbig_step2: forall env2 : env, big_step env' (While e s) env2 -> env'' = env2
env2: env
H2: big_step env0 (While e s) env2
env'' = env2
env0: string -> nat
e: expr
s: stmt
H: eval env0 e = 0
env2: env
H2: big_step env0 (While e s) env2
env0 = env2
env0: env
x: string
e: expr
env2: env
H2: big_step env0 (Assign x e) env2

(fun var : string => if string_eq x var then eval env0 e else env0 var) = env2
env0: env
x: string
e: expr
env2: env
H2: big_step env0 (Assign x e) env2
env1: env
x0: string
e0: expr
H: env1 = env0
H1: x0 = x
H3: e0 = e
H0: (fun var : string => if string_eq x var then eval env0 e else env0 var) = env2

(fun var : string => if string_eq x var then eval env0 e else env0 var) = (fun var : string => if string_eq x var then eval env0 e else env0 var)
env0: env
x: string
e: expr
env2, env1: env
x0: string
e0: expr
H: env1 = env0
H1: x0 = x
H3: e0 = e
H0: (fun var : string => if string_eq x var then eval env0 e else env0 var) = env2

(fun var : string => if string_eq x var then eval env0 e else env0 var) = (fun var : string => if string_eq x var then eval env0 e else env0 var)
env0: env
x: string
e: expr

(fun var : string => if string_eq x var then eval env0 e else env0 var) = (fun var : string => if string_eq x var then eval env0 e else env0 var)
reflexivity.
env0, env', env'': env
s1, s2: stmt
H1_: big_step env0 s1 env'
H1_0: big_step env' s2 env''
IHbig_step1: forall env2 : env, big_step env0 s1 env2 -> env' = env2
IHbig_step2: forall env2 : env, big_step env' s2 env2 -> env'' = env2
env2: env
H2: big_step env0 (Seq s1 s2) env2

env'' = env2
env0, env', env'': env
s1, s2: stmt
H1_: big_step env0 s1 env'
H1_0: big_step env' s2 env''
IHbig_step1: forall env2 : env, big_step env0 s1 env2 -> env' = env2
IHbig_step2: forall env2 : env, big_step env' s2 env2 -> env'' = env2
env2: env
H2: big_step env0 (Seq s1 s2) env2
env1, env'0, env''0: env
s0, s3: stmt
H3: big_step env0 s1 env'0
H5: big_step env'0 s2 env2
H1: env1 = env0
H: s0 = s1
H0: s3 = s2
H4: env''0 = env2

env'' = env2
env0, env', env'': env
s1, s2: stmt
H1_: big_step env0 s1 env'
H1_0: big_step env' s2 env''
IHbig_step1: forall env2 : env, big_step env0 s1 env2 -> env' = env2
IHbig_step2: forall env2 : env, big_step env' s2 env2 -> env'' = env2
env2, env1, env'0, env''0: env
s0, s3: stmt
H3: big_step env0 s1 env'0
H5: big_step env'0 s2 env2
H1: env1 = env0
H: s0 = s1
H0: s3 = s2
H4: env''0 = env2

env'' = env2
env0, env', env'': env
s1, s2: stmt
H1_: big_step env0 s1 env'
H1_0: big_step env' s2 env''
IHbig_step1: forall env2 : env, big_step env0 s1 env2 -> env' = env2
IHbig_step2: forall env2 : env, big_step env' s2 env2 -> env'' = env2
env2, env'0: env
H3: big_step env0 s1 env'0
H5: big_step env'0 s2 env2

env'' = env2
env0, env', env'': env
s1, s2: stmt
H1_: big_step env0 s1 env'
H1_0: big_step env' s2 env''
IHbig_step1: forall env2 : env, big_step env0 s1 env2 -> env' = env2
IHbig_step2: forall env2 : env, big_step env' s2 env2 -> env'' = env2
env2, env'0: env
H3: big_step env0 s1 env'0
H5: big_step env'0 s2 env2

big_step env' s2 env2
env0, env', env'': env
s1, s2: stmt
H1_: big_step env0 s1 env'
H1_0: big_step env' s2 env''
IHbig_step1: forall env2 : env, big_step env0 s1 env2 -> env' = env2
IHbig_step2: forall env2 : env, big_step env' s2 env2 -> env'' = env2
env2, env'0: env
H3: env' = env'0
H5: big_step env'0 s2 env2

big_step env' s2 env2
env0, env'': env
s1, s2: stmt
env'0: env
IHbig_step2: forall env2 : env, big_step env'0 s2 env2 -> env'' = env2
IHbig_step1: forall env2 : env, big_step env0 s1 env2 -> env'0 = env2
H1_0: big_step env'0 s2 env''
H1_: big_step env0 s1 env'0
env2: env
H5: big_step env'0 s2 env2

big_step env'0 s2 env2
apply H5.
env0: string -> nat
env': env
e: expr
s1, s2: stmt
H: eval env0 e <> 0
H1: big_step env0 s1 env'
IHbig_step: forall env2 : env, big_step env0 s1 env2 -> env' = env2
env2: env
H2: big_step env0 (If e s1 s2) env2

env' = env2
env0: string -> nat
env': env
e: expr
s1, s2: stmt
H: eval env0 e <> 0
H1: big_step env0 s1 env'
IHbig_step: forall env2 : env, big_step env0 s1 env2 -> env' = env2
env2: env
H7: eval env0 e <> 0
H8: big_step env0 s1 env2

env' = env2
env0: string -> nat
env': env
e: expr
s1, s2: stmt
H: eval env0 e <> 0
H1: big_step env0 s1 env'
IHbig_step: forall env2 : env, big_step env0 s1 env2 -> env' = env2
env2: env
H7: eval env0 e = 0
H8: big_step env0 s2 env2
env' = env2
env0: string -> nat
env': env
e: expr
s1, s2: stmt
H: eval env0 e <> 0
H1: big_step env0 s1 env'
IHbig_step: forall env2 : env, big_step env0 s1 env2 -> env' = env2
env2: env
H7: eval env0 e <> 0
H8: big_step env0 s1 env2

env' = env2
env0: string -> nat
env': env
e: expr
s1, s2: stmt
H: eval env0 e <> 0
H1: big_step env0 s1 env'
IHbig_step: forall env2 : env, big_step env0 s1 env2 -> env' = env2
env2: env
H7: eval env0 e <> 0
H8: big_step env0 s1 env2

big_step env0 s1 env2
apply H8.
env0: string -> nat
env': env
e: expr
s1, s2: stmt
H: eval env0 e <> 0
H1: big_step env0 s1 env'
IHbig_step: forall env2 : env, big_step env0 s1 env2 -> env' = env2
env2: env
H7: eval env0 e = 0
H8: big_step env0 s2 env2

env' = env2
congruence.
env0: string -> nat
env': env
e: expr
s1, s2: stmt
H: eval env0 e = 0
H1: big_step env0 s2 env'
IHbig_step: forall env2 : env, big_step env0 s2 env2 -> env' = env2
env2: env
H2: big_step env0 (If e s1 s2) env2

env' = env2
env0: string -> nat
env': env
e: expr
s1, s2: stmt
H: eval env0 e = 0
H1: big_step env0 s2 env'
IHbig_step: forall env2 : env, big_step env0 s2 env2 -> env' = env2
env2: env
H7: eval env0 e <> 0
H8: big_step env0 s1 env2

env' = env2
env0: string -> nat
env': env
e: expr
s1, s2: stmt
H: eval env0 e = 0
H1: big_step env0 s2 env'
IHbig_step: forall env2 : env, big_step env0 s2 env2 -> env' = env2
env2: env
H7: eval env0 e = 0
H8: big_step env0 s2 env2
env' = env2
env0: string -> nat
env': env
e: expr
s1, s2: stmt
H: eval env0 e = 0
H1: big_step env0 s2 env'
IHbig_step: forall env2 : env, big_step env0 s2 env2 -> env' = env2
env2: env
H7: eval env0 e <> 0
H8: big_step env0 s1 env2

env' = env2
congruence.
env0: string -> nat
env': env
e: expr
s1, s2: stmt
H: eval env0 e = 0
H1: big_step env0 s2 env'
IHbig_step: forall env2 : env, big_step env0 s2 env2 -> env' = env2
env2: env
H7: eval env0 e = 0
H8: big_step env0 s2 env2

env' = env2
env0: string -> nat
env': env
e: expr
s1, s2: stmt
H: eval env0 e = 0
H1: big_step env0 s2 env'
IHbig_step: forall env2 : env, big_step env0 s2 env2 -> env' = env2
env2: env
H7: eval env0 e = 0
H8: big_step env0 s2 env2

big_step env0 s2 env2
apply H8.
env0: string -> nat
env', env'': env
e: expr
s: stmt
H: eval env0 e <> 0
H1_: big_step env0 s env'
H1_0: big_step env' (While e s) env''
IHbig_step1: forall env2 : env, big_step env0 s env2 -> env' = env2
IHbig_step2: forall env2 : env, big_step env' (While e s) env2 -> env'' = env2
env2: env
H2: big_step env0 (While e s) env2

env'' = env2
env0: string -> nat
env', env'': env
e: expr
s: stmt
H: eval env0 e <> 0
H1_: big_step env0 s env'
H1_0: big_step env' (While e s) env''
IHbig_step1: forall env2 : env, big_step env0 s env2 -> env' = env2
IHbig_step2: forall env2 : env, big_step env' (While e s) env2 -> env'' = env2
env2, env'0: env
H3: eval env0 e <> 0
H5: big_step env0 s env'0
H7: big_step env'0 (While e s) env2

env'' = env2
env', env'': env
e: expr
s: stmt
env2: env
H1_: big_step env2 s env'
H: eval env2 e <> 0
H1_0: big_step env' (While e s) env''
IHbig_step1: forall env3 : env, big_step env2 s env3 -> env' = env3
IHbig_step2: forall env2 : env, big_step env' (While e s) env2 -> env'' = env2
H5: eval env2 e = 0
env'' = env2
env0: string -> nat
env', env'': env
e: expr
s: stmt
H: eval env0 e <> 0
H1_: big_step env0 s env'
H1_0: big_step env' (While e s) env''
IHbig_step1: forall env2 : env, big_step env0 s env2 -> env' = env2
IHbig_step2: forall env2 : env, big_step env' (While e s) env2 -> env'' = env2
env2, env'0: env
H3: eval env0 e <> 0
H5: big_step env0 s env'0
H7: big_step env'0 (While e s) env2

env'' = env2
env0: string -> nat
env', env'': env
e: expr
s: stmt
H: eval env0 e <> 0
H1_: big_step env0 s env'
H1_0: big_step env' (While e s) env''
IHbig_step1: forall env2 : env, big_step env0 s env2 -> env' = env2
IHbig_step2: forall env2 : env, big_step env' (While e s) env2 -> env'' = env2
env2, env'0: env
H3: eval env0 e <> 0
H5: big_step env0 s env'0
H7: big_step env'0 (While e s) env2

big_step env' (While e s) env2
env0: string -> nat
env', env'': env
e: expr
s: stmt
H: eval env0 e <> 0
H1_: big_step env0 s env'
H1_0: big_step env' (While e s) env''
IHbig_step1: forall env2 : env, big_step env0 s env2 -> env' = env2
IHbig_step2: forall env2 : env, big_step env' (While e s) env2 -> env'' = env2
env2, env'0: env
H3: eval env0 e <> 0
H5: env' = env'0
H7: big_step env'0 (While e s) env2

big_step env' (While e s) env2
env0: string -> nat
env'': env
e: expr
s: stmt
H: eval env0 e <> 0
env'0: env
IHbig_step2: forall env2 : env, big_step env'0 (While e s) env2 -> env'' = env2
IHbig_step1: forall env2 : env, big_step env0 s env2 -> env'0 = env2
H1_0: big_step env'0 (While e s) env''
H1_: big_step env0 s env'0
env2: env
H3: eval env0 e <> 0
H7: big_step env'0 (While e s) env2

big_step env'0 (While e s) env2
apply H7.
env', env'': env
e: expr
s: stmt
env2: env
H1_: big_step env2 s env'
H: eval env2 e <> 0
H1_0: big_step env' (While e s) env''
IHbig_step1: forall env3 : env, big_step env2 s env3 -> env' = env3
IHbig_step2: forall env2 : env, big_step env' (While e s) env2 -> env'' = env2
H5: eval env2 e = 0

env'' = env2
congruence.
env0: string -> nat
e: expr
s: stmt
H: eval env0 e = 0
env2: env
H2: big_step env0 (While e s) env2

env0 = env2
env0: string -> nat
e: expr
s: stmt
H: eval env0 e = 0
env2, env': env
H3: eval env0 e <> 0
H5: big_step env0 s env'
H7: big_step env' (While e s) env2

env0 = env2
e: expr
s: stmt
env2: env
H, H5: eval env2 e = 0
env2 = env2
env0: string -> nat
e: expr
s: stmt
H: eval env0 e = 0
env2, env': env
H3: eval env0 e <> 0
H5: big_step env0 s env'
H7: big_step env' (While e s) env2

env0 = env2
congruence.
e: expr
s: stmt
env2: env
H, H5: eval env2 e = 0

env2 = env2
reflexivity. Qed.

Shorter proof

Ltac inv H := inversion H; clear H; simpeq.

env: lec07_big_step.env
s: stmt
env1, env2: lec07_big_step.env

big_step env s env1 -> big_step env s env2 -> env1 = env2
env: lec07_big_step.env
s: stmt
env1, env2: lec07_big_step.env

big_step env s env1 -> big_step env s env2 -> env1 = env2
env: lec07_big_step.env
s: stmt
env1, env2: lec07_big_step.env
H1: big_step env s env1

big_step env s env2 -> env1 = env2
env: lec07_big_step.env
s: stmt
env1: lec07_big_step.env
H1: big_step env s env1

forall env2 : lec07_big_step.env, big_step env s env2 -> env1 = env2
induction H1; intros env2 H2; inv H2; auto; assert (env' = env'0) as ->; auto. Qed.

Equivalence of programs

Definition equiv (s1 s2 : stmt) : Prop :=
  forall env env',
    big_step env s1 env' <-> big_step env s2 env'.

s1, s2, s3: stmt

equiv (Seq (Seq s1 s2) s3) (Seq s1 (Seq s2 s3))
s1, s2, s3: stmt

equiv (Seq (Seq s1 s2) s3) (Seq s1 (Seq s2 s3))
s1, s2, s3: stmt

forall env0 env' : env, big_step env0 (Seq (Seq s1 s2) s3) env' <-> big_step env0 (Seq s1 (Seq s2 s3)) env'
s1, s2, s3: stmt
env0, env': env

big_step env0 (Seq (Seq s1 s2) s3) env' <-> big_step env0 (Seq s1 (Seq s2 s3)) env'
s1, s2, s3: stmt
env0, env': env
H: big_step env0 (Seq (Seq s1 s2) s3) env'

big_step env0 (Seq s1 (Seq s2 s3)) env'
s1, s2, s3: stmt
env0, env': env
H: big_step env0 (Seq s1 (Seq s2 s3)) env'
big_step env0 (Seq (Seq s1 s2) s3) env'
s1, s2, s3: stmt
env0, env': env
H: big_step env0 (Seq (Seq s1 s2) s3) env'

big_step env0 (Seq s1 (Seq s2 s3)) env'
s1, s2, s3: stmt
env0, env', env'0: env
H3: big_step env0 (Seq s1 s2) env'0
H5: big_step env'0 s3 env'

big_step env0 (Seq s1 (Seq s2 s3)) env'
s1, s2, s3: stmt
env0, env', env'0: env
H5: big_step env'0 s3 env'
env'1: env
H2: big_step env0 s1 env'1
H6: big_step env'1 s2 env'0

big_step env0 (Seq s1 (Seq s2 s3)) env'
s1, s2, s3: stmt
env0, env', env'0: env
H5: big_step env'0 s3 env'
env'1: env
H2: big_step env0 s1 env'1
H6: big_step env'1 s2 env'0

big_step env0 s1 ?env'
s1, s2, s3: stmt
env0, env', env'0: env
H5: big_step env'0 s3 env'
env'1: env
H2: big_step env0 s1 env'1
H6: big_step env'1 s2 env'0
big_step ?env' (Seq s2 s3) env'
s1, s2, s3: stmt
env0, env', env'0: env
H5: big_step env'0 s3 env'
env'1: env
H2: big_step env0 s1 env'1
H6: big_step env'1 s2 env'0

big_step env0 s1 ?env'
apply H2.
s1, s2, s3: stmt
env0, env', env'0: env
H5: big_step env'0 s3 env'
env'1: env
H2: big_step env0 s1 env'1
H6: big_step env'1 s2 env'0

big_step env'1 (Seq s2 s3) env'
s1, s2, s3: stmt
env0, env', env'0: env
H5: big_step env'0 s3 env'
env'1: env
H2: big_step env0 s1 env'1
H6: big_step env'1 s2 env'0

big_step env'1 s2 ?env'
s1, s2, s3: stmt
env0, env', env'0: env
H5: big_step env'0 s3 env'
env'1: env
H2: big_step env0 s1 env'1
H6: big_step env'1 s2 env'0
big_step ?env' s3 env'
s1, s2, s3: stmt
env0, env', env'0: env
H5: big_step env'0 s3 env'
env'1: env
H2: big_step env0 s1 env'1
H6: big_step env'1 s2 env'0

big_step env'1 s2 ?env'
apply H6.
s1, s2, s3: stmt
env0, env', env'0: env
H5: big_step env'0 s3 env'
env'1: env
H2: big_step env0 s1 env'1
H6: big_step env'1 s2 env'0

big_step env'0 s3 env'
apply H5.
s1, s2, s3: stmt
env0, env': env
H: big_step env0 (Seq s1 (Seq s2 s3)) env'

big_step env0 (Seq (Seq s1 s2) s3) env'
s1, s2, s3: stmt
env0, env', env'0: env
H3: big_step env0 s1 env'0
H5: big_step env'0 (Seq s2 s3) env'

big_step env0 (Seq (Seq s1 s2) s3) env'
s1, s2, s3: stmt
env0, env', env'0: env
H3: big_step env0 s1 env'0
env'1: env
H2: big_step env'0 s2 env'1
H6: big_step env'1 s3 env'

big_step env0 (Seq (Seq s1 s2) s3) env'
s1, s2, s3: stmt
env0, env', env'0: env
H3: big_step env0 s1 env'0
env'1: env
H2: big_step env'0 s2 env'1
H6: big_step env'1 s3 env'

big_step env0 (Seq s1 s2) ?env'
s1, s2, s3: stmt
env0, env', env'0: env
H3: big_step env0 s1 env'0
env'1: env
H2: big_step env'0 s2 env'1
H6: big_step env'1 s3 env'
big_step ?env' s3 env'
s1, s2, s3: stmt
env0, env', env'0: env
H3: big_step env0 s1 env'0
env'1: env
H2: big_step env'0 s2 env'1
H6: big_step env'1 s3 env'

big_step env0 (Seq s1 s2) ?env'
s1, s2, s3: stmt
env0, env', env'0: env
H3: big_step env0 s1 env'0
env'1: env
H2: big_step env'0 s2 env'1
H6: big_step env'1 s3 env'

big_step env0 s1 ?env'0
s1, s2, s3: stmt
env0, env', env'0: env
H3: big_step env0 s1 env'0
env'1: env
H2: big_step env'0 s2 env'1
H6: big_step env'1 s3 env'
big_step ?env'0 s2 ?env'
s1, s2, s3: stmt
env0, env', env'0: env
H3: big_step env0 s1 env'0
env'1: env
H2: big_step env'0 s2 env'1
H6: big_step env'1 s3 env'

big_step env0 s1 ?env'0
apply H3.
s1, s2, s3: stmt
env0, env', env'0: env
H3: big_step env0 s1 env'0
env'1: env
H2: big_step env'0 s2 env'1
H6: big_step env'1 s3 env'

big_step env'0 s2 ?env'
apply H2.
s1, s2, s3: stmt
env0, env', env'0: env
H3: big_step env0 s1 env'0
env'1: env
H2: big_step env'0 s2 env'1
H6: big_step env'1 s3 env'

big_step env'1 s3 env'
apply H6. Qed.

Shorter proof

s1, s2, s3: stmt

equiv (Seq (Seq s1 s2) s3) (Seq s1 (Seq s2 s3))
s1, s2, s3: stmt

equiv (Seq (Seq s1 s2) s3) (Seq s1 (Seq s2 s3))
s1, s2, s3: stmt

forall env0 env' : env, big_step env0 (Seq (Seq s1 s2) s3) env' <-> big_step env0 (Seq s1 (Seq s2 s3)) env'
s1, s2, s3: stmt
env0, env': env

big_step env0 (Seq (Seq s1 s2) s3) env' <-> big_step env0 (Seq s1 (Seq s2 s3)) env'
s1, s2, s3: stmt
env0, env', env'0: env
H3: big_step env0 (Seq s1 s2) env'0
H5: big_step env'0 s3 env'

big_step env0 (Seq s1 (Seq s2 s3)) env'
s1, s2, s3: stmt
env0, env', env'0: env
H3: big_step env0 s1 env'0
H5: big_step env'0 (Seq s2 s3) env'
big_step env0 (Seq (Seq s1 s2) s3) env'
s1, s2, s3: stmt
env0, env', env'0: env
H3: big_step env0 (Seq s1 s2) env'0
H5: big_step env'0 s3 env'

big_step env0 (Seq s1 (Seq s2 s3)) env'
s1, s2, s3: stmt
env0, env', env'0: env
H5: big_step env'0 s3 env'
env'1: env
H2: big_step env0 s1 env'1
H6: big_step env'1 s2 env'0

big_step env0 (Seq s1 (Seq s2 s3)) env'
eauto using big_step.
s1, s2, s3: stmt
env0, env', env'0: env
H3: big_step env0 s1 env'0
H5: big_step env'0 (Seq s2 s3) env'

big_step env0 (Seq (Seq s1 s2) s3) env'
s1, s2, s3: stmt
env0, env', env'0: env
H3: big_step env0 s1 env'0
env'1: env
H2: big_step env'0 s2 env'1
H6: big_step env'1 s3 env'

big_step env0 (Seq (Seq s1 s2) s3) env'
eauto using big_step. Qed.

Example: simple program

Definition ex1 :=
  Seq
    (Assign "x" (Plus (Var "x") (Var "x")))
    (Assign "x" (Plus (Var "x") (Var "x"))).

env, env': lec07_big_step.env

big_step env ex1 env' <-> (forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x))
env, env': lec07_big_step.env

big_step env ex1 env' <-> (forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x))
env, env': lec07_big_step.env

big_step env ex1 env' -> forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)
env, env': lec07_big_step.env
(forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)) -> big_step env ex1 env'
env, env': lec07_big_step.env

big_step env ex1 env' -> forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)
env, env': lec07_big_step.env
H: big_step env ex1 env'

forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)
env, env', env'0: lec07_big_step.env
H3: big_step env (Assign "x" (Plus (Var "x") (Var "x"))) env'0
H5: big_step env'0 (Assign "x" (Plus (Var "x") (Var "x"))) env'

forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)
env, env': lec07_big_step.env
H5: big_step (fun var : string => if string_eq "x" var then eval env (Plus (Var "x") (Var "x")) else env var) (Assign "x" (Plus (Var "x") (Var "x"))) env'

forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)
env: lec07_big_step.env

forall x : string, (if string_eq "x" x then eval (fun var : string => if string_eq "x" var then eval env (Plus (Var "x") (Var "x")) else env var) (Plus (Var "x") (Var "x")) else if string_eq "x" x then eval env (Plus (Var "x") (Var "x")) else env x) = (if string_eq x "x" then 4 * env "x" else env x)
env: lec07_big_step.env
x: string

(if string_eq "x" x then eval (fun var : string => if string_eq "x" var then eval env (Plus (Var "x") (Var "x")) else env var) (Plus (Var "x") (Var "x")) else if string_eq "x" x then eval env (Plus (Var "x") (Var "x")) else env x) = (if string_eq x "x" then 4 * env "x" else env x)
env: lec07_big_step.env

env "x" + env "x" + (env "x" + env "x") = env "x" + (env "x" + (env "x" + (env "x" + 0)))
lia.
env, env': lec07_big_step.env

(forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)) -> big_step env ex1 env'
env, env': lec07_big_step.env
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)

big_step env ex1 env'
env, env': lec07_big_step.env
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)

(exists env'' : lec07_big_step.env, big_step env ex1 env'' /\ env'' = env') -> big_step env ex1 env'
env, env': lec07_big_step.env
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)
exists env'' : lec07_big_step.env, big_step env ex1 env'' /\ env'' = env'
env, env': lec07_big_step.env
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)

(exists env'' : lec07_big_step.env, big_step env ex1 env'' /\ env'' = env') -> big_step env ex1 env'
env, env': lec07_big_step.env
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)
env'': lec07_big_step.env
H1: big_step env ex1 env''
H2: env'' = env'

big_step env ex1 env'
env, env': lec07_big_step.env
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)
H1: big_step env ex1 env'

big_step env ex1 env'
auto.
env, env': lec07_big_step.env
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)

exists env'' : lec07_big_step.env, big_step env ex1 env'' /\ env'' = env'
env, env': lec07_big_step.env
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)

big_step env ex1 ?env'' /\ ?env'' = env'
env, env': lec07_big_step.env
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)

big_step env ex1 ?env''
env, env': lec07_big_step.env
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)
?env'' = env'
env, env': lec07_big_step.env
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)

big_step env ex1 ?env''
eauto using big_step.
env, env': lec07_big_step.env
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)

(fun var : string => if string_eq "x" var then eval (fun var0 : string => if string_eq "x" var0 then eval env (Plus (Var "x") (Var "x")) else env var0) (Plus (Var "x") (Var "x")) else (fun var0 : string => if string_eq "x" var0 then eval env (Plus (Var "x") (Var "x")) else env var0) var) = env'
env, env': lec07_big_step.env
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)

forall x : string, (if string_eq "x" x then eval (fun var : string => if string_eq "x" var then eval env (Plus (Var "x") (Var "x")) else env var) (Plus (Var "x") (Var "x")) else if string_eq "x" x then eval env (Plus (Var "x") (Var "x")) else env x) = env' x
env, env': lec07_big_step.env
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)
x: string

(if string_eq "x" x then eval (fun var : string => if string_eq "x" var then eval env (Plus (Var "x") (Var "x")) else env var) (Plus (Var "x") (Var "x")) else if string_eq "x" x then eval env (Plus (Var "x") (Var "x")) else env x) = env' x
env, env': lec07_big_step.env
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)
x: string

(if string_eq "x" x then eval (fun var : string => if string_eq "x" var then eval env (Plus (Var "x") (Var "x")) else env var) (Plus (Var "x") (Var "x")) else if string_eq "x" x then eval env (Plus (Var "x") (Var "x")) else env x) = (if string_eq x "x" then 4 * env "x" else env x)
env, env': lec07_big_step.env
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)

env "x" + env "x" + (env "x" + env "x") = env "x" + (env "x" + (env "x" + (env "x" + 0)))
lia. Qed. Ltac run_big_step := match goal with | [ |- big_step ?env ?s ?env' ] => let H1 := fresh "H" in let H2 := fresh "H" in cut (exists env'', big_step env s env'' /\ env'' = env'); [ intros [env'' [H1 H2]]; subst; auto | eexists; split; eauto using big_step ] end.
env, env': string -> nat

(forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)) -> big_step env ex1 env'
env, env': string -> nat

(forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)) -> big_step env ex1 env'
env, env': string -> nat
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)

big_step env ex1 env'
env, env': string -> nat
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)

(fun var : string => if string_eq "x" var then eval (fun var0 : string => if string_eq "x" var0 then eval env (Plus (Var "x") (Var "x")) else env var0) (Plus (Var "x") (Var "x")) else (fun var0 : string => if string_eq "x" var0 then eval env (Plus (Var "x") (Var "x")) else env var0) var) = env'
env, env': string -> nat
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)

forall x : string, (if string_eq "x" x then eval (fun var : string => if string_eq "x" var then eval env (Plus (Var "x") (Var "x")) else env var) (Plus (Var "x") (Var "x")) else if string_eq "x" x then eval env (Plus (Var "x") (Var "x")) else env x) = env' x
env, env': string -> nat
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)
x: string

(if string_eq "x" x then eval (fun var : string => if string_eq "x" var then eval env (Plus (Var "x") (Var "x")) else env var) (Plus (Var "x") (Var "x")) else if string_eq "x" x then eval env (Plus (Var "x") (Var "x")) else env x) = env' x
env, env': string -> nat
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)
x: string

(if string_eq "x" x then eval (fun var : string => if string_eq "x" var then eval env (Plus (Var "x") (Var "x")) else env var) (Plus (Var "x") (Var "x")) else if string_eq "x" x then eval env (Plus (Var "x") (Var "x")) else env x) = (if string_eq x "x" then 4 * env "x" else env x)
env, env': string -> nat
H: forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)

env "x" + env "x" + (env "x" + env "x") = env "x" + (env "x" + (env "x" + (env "x" + 0)))
lia. Qed. (* Invert big step but only do it when it produces a single subgoal. *) Ltac inv_big_step := match goal with | [ H : big_step _ _ _ |- _ ] => inv H end.
env, env': lec07_big_step.env

big_step env ex1 env' -> forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)
env, env': lec07_big_step.env

big_step env ex1 env' -> forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)
env, env': lec07_big_step.env
H: big_step env ex1 env'

forall x : string, env' x = (if string_eq x "x" then 4 * env "x" else env x)
env: lec07_big_step.env

forall x : string, (if string_eq "x" x then eval (fun var : string => if string_eq "x" var then eval env (Plus (Var "x") (Var "x")) else env var) (Plus (Var "x") (Var "x")) else if string_eq "x" x then eval env (Plus (Var "x") (Var "x")) else env x) = (if string_eq x "x" then 4 * env "x" else env x)
env: lec07_big_step.env
x: string

(if string_eq "x" x then eval (fun var : string => if string_eq "x" var then eval env (Plus (Var "x") (Var "x")) else env var) (Plus (Var "x") (Var "x")) else if string_eq "x" x then eval env (Plus (Var "x") (Var "x")) else env x) = (if string_eq x "x" then 4 * env "x" else env x)
env: lec07_big_step.env

env "x" + env "x" + (env "x" + env "x") = env "x" + (env "x" + (env "x" + (env "x" + 0)))
lia. Qed.

Example: infinite loops

Definition ex2 body :=
  While (Const 1) body.

env, env': lec07_big_step.env
body: stmt

~ big_step env (ex2 body) env'
env, env': lec07_big_step.env
body: stmt

~ big_step env (ex2 body) env'
env, env': lec07_big_step.env
body: stmt
H: big_step env (ex2 body) env'

False
env, env': lec07_big_step.env
body, e: stmt
Heqe: e = ex2 body
H: big_step env e env'

False
body: stmt
e: expr
s: stmt
Heqe: While e s = ex2 body
env0: string -> nat
H: eval env0 e = 0

False
body: stmt
e: expr
s: stmt
Heqe: While e s = While (Const 1) body
env0: string -> nat
H: eval env0 e = 0

False
body: stmt
e: expr
s: stmt
HH: e = Const 1
H0: s = body
env0: string -> nat
H: eval env0 e = 0

False
body: stmt
env0: string -> nat
H: eval env0 (Const 1) = 0

False
body: stmt
env0: string -> nat
H: 1 = 0

False
discriminate. Qed.

Example: finite loops

Definition ex3:=
  While (Var "x")
    (Seq (Assign "y" (Plus (Var "y") (Var "z")))
         (Assign "x" (Minus (Var "x") (Const 1)))).

env, env': lec07_big_step.env

big_step env ex3 env' <-> env' "y" = env "y" + env "x" * env "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env x)
env, env': lec07_big_step.env

big_step env ex3 env' <-> env' "y" = env "y" + env "x" * env "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env x)
env, env': lec07_big_step.env

big_step env ex3 env' -> env' "y" = env "y" + env "x" * env "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env x)
env, env': lec07_big_step.env
env' "y" = env "y" + env "x" * env "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env x) -> big_step env ex3 env'
env, env': lec07_big_step.env

big_step env ex3 env' -> env' "y" = env "y" + env "x" * env "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env x)
env, env': lec07_big_step.env

big_step env (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env "y" + env "x" * env "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env x)
env, env': lec07_big_step.env
x: nat
Heqx: x = env "x"

big_step env (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env "y" + x * env "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env x)
x: nat

forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env0, env': env
Heqx: 0 = env0 "x"
H: big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'

env' "y" = env0 "y" + 0 * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env0, env': env
Heqx: S x = env0 "x"
H: big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env' "y" = env0 "y" + S x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env0, env': env
Heqx: 0 = env0 "x"
H: big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'

env' "y" = env0 "y" + 0 * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env0, env': env
Heqx: 0 = env0 "x"
env'0: env
H2: eval env0 (Var "x") <> 0
H4: big_step env0 (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1)))) env'0
H6: big_step env'0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'

env' "y" = env0 "y" + 0 * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env': env
Heqx: 0 = env' "x"
H4: eval env' (Var "x") = 0
env' "y" = env' "y" + 0 * env' "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env' x)
env0, env': env
Heqx: 0 = env0 "x"
env'0: env
H2: eval env0 (Var "x") <> 0
H4: big_step env0 (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1)))) env'0
H6: big_step env'0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'

env' "y" = env0 "y" + 0 * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env0, env': env
Heqx: 0 = env0 "x"
env'0: env
H2: env0 "x" <> 0
H4: big_step env0 (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1)))) env'0
H6: big_step env'0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'

env' "y" = env0 "y" + 0 /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
simpeq.
env': env
Heqx: 0 = env' "x"
H4: eval env' (Var "x") = 0

env' "y" = env' "y" + 0 * env' "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env' x)
env': env
Heqx: 0 = env' "x"
H4: env' "x" = 0

env' "y" = env' "y" + 0 /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env' x)
env': env
Heqx: 0 = env' "x"
H4: env' "x" = 0

env' "y" = env' "y" + 0
env': env
Heqx: 0 = env' "x"
H4: env' "x" = 0
env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env' x)
env': env
Heqx: 0 = env' "x"
H4: env' "x" = 0

env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env' x)
env': env
Heqx: 0 = env' "x"
H4: env' "x" = 0

env' "x" = 0
env': env
Heqx: 0 = env' "x"
H4: env' "x" = 0
forall x : string, x <> "x" -> x <> "y" -> env' x = env' x
env': env
Heqx: 0 = env' "x"
H4: env' "x" = 0

forall x : string, x <> "x" -> x <> "y" -> env' x = env' x
lia.
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env0, env': env
Heqx: S x = env0 "x"
H: big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'

env' "y" = env0 "y" + S x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env0, env': env
Heqx: S x = env0 "x"
env'0: env
H2: eval env0 (Var "x") <> 0
H4: big_step env0 (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1)))) env'0
H6: big_step env'0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'

env' "y" = env0 "y" + S x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env': env
Heqx: S x = env' "x"
H4: eval env' (Var "x") = 0
env' "y" = env' "y" + S x * env' "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env' x)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env0, env': env
Heqx: S x = env0 "x"
env'0: env
H2: eval env0 (Var "x") <> 0
H4: big_step env0 (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1)))) env'0
H6: big_step env'0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'

env' "y" = env0 "y" + S x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env0, env': env
Heqx: S x = env0 "x"
env'0: env
H2: eval env0 (Var "x") <> 0
H6: big_step env'0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env'1: env
H3: big_step env0 (Assign "y" (Plus (Var "y") (Var "z"))) env'1
H7: big_step env'1 (Assign "x" (Minus (Var "x") (Const 1))) env'0

env' "y" = env0 "y" + S x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env0, env': env
Heqx: S x = env0 "x"
env'0: env
H2: eval env0 (Var "x") <> 0
H6: big_step env'0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
H7: big_step (fun var : string => if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (Assign "x" (Minus (Var "x") (Const 1))) env'0

env' "y" = env0 "y" + S x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env0, env': env
Heqx: S x = env0 "x"
H2: eval env0 (Var "x") <> 0
H6: big_step (fun var : string => if string_eq "x" var then eval (fun var0 : string => if string_eq "y" var0 then eval env0 (Plus (Var "y") (Var "z")) else env0 var0) (Minus (Var "x") (Const 1)) else if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'

env' "y" = env0 "y" + S x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env0, env': env
Heqx: S x = env0 "x"
H2: env0 "x" <> 0
n: "x" <> "y"
n0: "x" <> "z"
n1: "y" <> "z"
H6: env' "y" = env0 "y" + env0 "z" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = (if string_eq "x" x then (if string_eq "y" "x" then env0 "y" + env0 "z" else env0 "x") - 1 else if string_eq "y" x then env0 "y" + env0 "z" else env0 x))

env' "y" = env0 "y" + (env0 "z" + x * env0 "z") /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env0, env': env
Heqx: S x = env0 "x"
H2: env0 "x" <> 0
n: "x" <> "y"
n0: "x" <> "z"
n1: "y" <> "z"
H: env' "y" = env0 "y" + env0 "z" + x * env0 "z"
H0: env' "x" = 0
H1: forall x : string, x <> "x" -> x <> "y" -> env' x = (if string_eq "x" x then (if string_eq "y" "x" then env0 "y" + env0 "z" else env0 "x") - 1 else if string_eq "y" x then env0 "y" + env0 "z" else env0 x)

env' "y" = env0 "y" + (env0 "z" + x * env0 "z") /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env0, env': env
Heqx: S x = env0 "x"
H2: env0 "x" <> 0
n: "x" <> "y"
n0: "x" <> "z"
n1: "y" <> "z"
H: env' "y" = env0 "y" + env0 "z" + x * env0 "z"
H0: env' "x" = 0
H1: forall x : string, x <> "x" -> x <> "y" -> env' x = (if string_eq "x" x then (if string_eq "y" "x" then env0 "y" + env0 "z" else env0 "x") - 1 else if string_eq "y" x then env0 "y" + env0 "z" else env0 x)

env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env0, env': env
Heqx: S x = env0 "x"
H2: env0 "x" <> 0
n: "x" <> "y"
n0: "x" <> "z"
n1: "y" <> "z"
H: env' "y" = env0 "y" + env0 "z" + x * env0 "z"
H0: env' "x" = 0
H1: forall x : string, x <> "x" -> x <> "y" -> env' x = (if string_eq "x" x then (if string_eq "y" "x" then env0 "y" + env0 "z" else env0 "x") - 1 else if string_eq "y" x then env0 "y" + env0 "z" else env0 x)

forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env0, env': env
Heqx: S x = env0 "x"
H2: env0 "x" <> 0
n: "x" <> "y"
n0: "x" <> "z"
n1: "y" <> "z"
H: env' "y" = env0 "y" + env0 "z" + x * env0 "z"
H0: env' "x" = 0
H1: forall x : string, x <> "x" -> x <> "y" -> env' x = (if string_eq "x" x then (if string_eq "y" "x" then env0 "y" + env0 "z" else env0 "x") - 1 else if string_eq "y" x then env0 "y" + env0 "z" else env0 x)
x0: string
H3: x0 <> "x"
H4: x0 <> "y"

env' x0 = env0 x0
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env0, env': env
Heqx: S x = env0 "x"
H2: env0 "x" <> 0
n: "x" <> "y"
n0: "x" <> "z"
n1: "y" <> "z"
H: env' "y" = env0 "y" + env0 "z" + x * env0 "z"
H0: env' "x" = 0
x0: string
H1: x0 <> "x" -> x0 <> "y" -> env' x0 = (if string_eq "x" x0 then (if string_eq "y" "x" then env0 "y" + env0 "z" else env0 "x") - 1 else if string_eq "y" x0 then env0 "y" + env0 "z" else env0 x0)
H3: x0 <> "x"
H4: x0 <> "y"

env' x0 = env0 x0
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env0, env': env
Heqx: S x = env0 "x"
H2: env0 "x" <> 0
n: "x" <> "y"
n0: "x" <> "z"
n1: "y" <> "z"
H: env' "y" = env0 "y" + env0 "z" + x * env0 "z"
H0: env' "x" = 0
x0: string
n2: "x" <> x0
n3: "y" <> x0
H1: x0 <> "x" -> x0 <> "y" -> env' x0 = env0 x0
H3: x0 <> "x"
H4: x0 <> "y"

env' x0 = env0 x0
auto.
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env': env
Heqx: S x = env' "x"
H4: eval env' (Var "x") = 0

env' "y" = env' "y" + S x * env' "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env' x)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
env': env
Heqx: S x = env' "x"
H4: env' "x" = 0

env' "y" = env' "y" + (env' "z" + x * env' "z") /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env' x)
simpeq.
env, env': lec07_big_step.env

env' "y" = env "y" + env "x" * env "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env x) -> big_step env ex3 env'
env, env': lec07_big_step.env

env' "y" = env "y" + env "x" * env "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env x) -> big_step env (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env, env': lec07_big_step.env
x: nat
Heqx: x = env "x"

env' "y" = env "y" + x * env "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env x) -> big_step env (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
x: nat

forall env0 env' : env, x = env0 "x" -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: 0 = env0 "x"
H: env' "y" = env0 "y" + 0 * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)

big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H: env' "y" = env0 "y" + S x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: 0 = env0 "x"
H: env' "y" = env0 "y" + 0 * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)

big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: 0 = env0 "x"
H: env' "y" = env0 "y" + 0 * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)

env0 = env'
env0, env': env
Heqx: 0 = env0 "x"
H: env' "y" = env0 "y" + 0 * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)

forall x : string, env0 x = env' x
env0, env': env
Heqx: 0 = env0 "x"
H: env' "y" = env0 "y" + 0 * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)
x: string

env0 x = env' x
env0, env': env
Heqx: 0 = env0 "x"
H1: env' "y" = env0 "y" + 0 * env0 "z"
H2: env' "x" = 0
H3: forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x
x: string

env0 x = env' x
env0, env': env
Heqx: 0 = env0 "x"
H1: env' "y" = env0 "y" + 0 * env0 "z"
H2: env' "x" = 0
x: string
H3: x <> "x" -> x <> "y" -> env' x = env0 x

env0 x = env' x
env0, env': env
Heqx: 0 = env0 "x"
H1: env' "y" = env0 "y" + 0 * env0 "z"
H2: env' "x" = 0
x: string
H3: x <> "x" -> x <> "y" -> env' x = env0 x
n: x <> "x"

env0 x = env' x
env0, env': env
Heqx: 0 = env0 "x"
H1: env' "y" = env0 "y" + 0 * env0 "z"
H2: env' "x" = 0
x: string
H3: x <> "x" -> x <> "y" -> env' x = env0 x
n: x <> "x"
n0: x <> "y"

env0 x = env' x
env0, env': env
Heqx: 0 = env0 "x"
H1: env' "y" = env0 "y" + 0 * env0 "z"
H2: env' "x" = 0
x: string
H3: x <> "x" -> x <> "y" -> env' x = env0 x
n: x <> "x"
n0: x <> "y"

env' x = env0 x
auto.
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H: env' "y" = env0 "y" + S x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x)

big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H1: env' "y" = env0 "y" + S x * env0 "z"
H2: env' "x" = 0
H3: forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x

big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H1: env' "y" = env0 "y" + (env0 "z" + x * env0 "z")
H2: env' "x" = 0
H3: forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x

big_step env0 (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1)))) ?env'
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H1: env' "y" = env0 "y" + (env0 "z" + x * env0 "z")
H2: env' "x" = 0
H3: forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x
big_step ?env' (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H1: env' "y" = env0 "y" + (env0 "z" + x * env0 "z")
H2: env' "x" = 0
H3: forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x

big_step env0 (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1)))) ?env'
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H1: env' "y" = env0 "y" + (env0 "z" + x * env0 "z")
H2: env' "x" = 0
H3: forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x

(fun var : string => if string_eq "x" var then eval (fun var0 : string => if string_eq "y" var0 then eval env0 (Plus (Var "y") (Var "z")) else env0 var0) (Minus (Var "x") (Const 1)) else (fun var0 : string => if string_eq "y" var0 then eval env0 (Plus (Var "y") (Var "z")) else env0 var0) var) = ?env'
reflexivity.
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H1: env' "y" = env0 "y" + (env0 "z" + x * env0 "z")
H2: env' "x" = 0
H3: forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x

big_step (fun var : string => if string_eq "x" var then eval (fun var0 : string => if string_eq "y" var0 then eval env0 (Plus (Var "y") (Var "z")) else env0 var0) (Minus (Var "x") (Const 1)) else if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H1: env' "y" = env0 "y" + (env0 "z" + x * env0 "z")
H2: env' "x" = 0
H3: forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x
n: "x" <> "y"
n0: "x" <> "z"
n1: "y" <> "z"
n2: "y" <> "x"

env' "y" = env0 "y" + env0 "z" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = (if string_eq "x" x then env0 "x" - 1 else if string_eq "y" x then env0 "y" + env0 "z" else env0 x))
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H1: env' "y" = env0 "y" + (env0 "z" + x * env0 "z")
H2: env' "x" = 0
H3: forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x
n: "x" <> "y"
n0: "x" <> "z"
n1: "y" <> "z"
n2: "y" <> "x"

env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = (if string_eq "x" x then env0 "x" - 1 else if string_eq "y" x then env0 "y" + env0 "z" else env0 x))
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H1: env' "y" = env0 "y" + (env0 "z" + x * env0 "z")
H2: env' "x" = 0
H3: forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x
n: "x" <> "y"
n0: "x" <> "z"
n1: "y" <> "z"
n2: "y" <> "x"

forall x : string, x <> "x" -> x <> "y" -> env' x = (if string_eq "x" x then env0 "x" - 1 else if string_eq "y" x then env0 "y" + env0 "z" else env0 x)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H1: env' "y" = env0 "y" + (env0 "z" + x * env0 "z")
H2: env' "x" = 0
H3: forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x
n: "x" <> "y"
n0: "x" <> "z"
n1: "y" <> "z"
n2: "y" <> "x"
x0: string
H: x0 <> "x"
H0: x0 <> "y"

env' x0 = (if string_eq "x" x0 then env0 "x" - 1 else if string_eq "y" x0 then env0 "y" + env0 "z" else env0 x0)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H1: env' "y" = env0 "y" + (env0 "z" + x * env0 "z")
H2: env' "x" = 0
x0: string
H3: x0 <> "x" -> x0 <> "y" -> env' x0 = env0 x0
n: "x" <> "y"
n0: "x" <> "z"
n1: "y" <> "z"
n2: "y" <> "x"
H: x0 <> "x"
H0: x0 <> "y"

env' x0 = (if string_eq "x" x0 then env0 "x" - 1 else if string_eq "y" x0 then env0 "y" + env0 "z" else env0 x0)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> env' "y" = env0 "y" + x * env0 "z" /\ env' "x" = 0 /\ (forall x : string, x <> "x" -> x <> "y" -> env' x = env0 x) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H1: env' "y" = env0 "y" + (env0 "z" + x * env0 "z")
H2: env' "x" = 0
x0: string
H3: x0 <> "x" -> x0 <> "y" -> env' x0 = env0 x0
n: "x" <> "y"
n0: "x" <> "z"
n1: "y" <> "z"
n2: "y" <> "x"
H: x0 <> "x"
H0: x0 <> "y"
n3: "x" <> x0
n4: "y" <> x0

env' x0 = env0 x0
auto. Qed.

Shorter proof

env, env': lec07_big_step.env

big_step env ex3 env' <-> (forall x : string, env' x = (if string_eq x "x" then 0 else if string_eq x "y" then env "y" + env "x" * env "z" else env x))
env, env': lec07_big_step.env

big_step env ex3 env' <-> (forall x : string, env' x = (if string_eq x "x" then 0 else if string_eq x "y" then env "y" + env "x" * env "z" else env x))
env, env': lec07_big_step.env

big_step env (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' <-> (forall x : string, env' x = (if string_eq x "x" then 0 else if string_eq x "y" then env "y" + env "x" * env "z" else env x))
env, env': lec07_big_step.env

big_step env (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> forall x : string, env' x = (if string_eq x "x" then 0 else if string_eq x "y" then env "y" + env "x" * env "z" else env x)
env, env': lec07_big_step.env
(forall x : string, env' x = (if string_eq x "x" then 0 else if string_eq x "y" then env "y" + env "x" * env "z" else env x)) -> big_step env (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env, env': lec07_big_step.env

big_step env (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> forall x : string, env' x = (if string_eq x "x" then 0 else if string_eq x "y" then env "y" + env "x" * env "z" else env x)
env, env': lec07_big_step.env
x: nat
Heqx: x = env "x"

big_step env (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env "y" + x * env "z" else env x0)
x: nat

forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)
env0, env': env
Heqx: 0 = env0 "x"
H: big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
x: string

env' x = (if string_eq x "x" then 0 else if string_eq x "y" then env0 "y" + 0 * env0 "z" else env0 x)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)
env0, env': env
Heqx: S x = env0 "x"
H: big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
x0: string
env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + S x * env0 "z" else env0 x0)
env0, env': env
Heqx: 0 = env0 "x"
H: big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
x: string

env' x = (if string_eq x "x" then 0 else if string_eq x "y" then env0 "y" + 0 * env0 "z" else env0 x)
env': env
Heqx: 0 = env' "x"
x: string
H4: env' "x" = 0

env' x = (if string_eq x "x" then 0 else if string_eq x "y" then env' "y" + 0 else env' x)
env': env
Heqx: 0 = env' "x"
H4: env' "x" = 0
n: "y" <> "x"

env' "y" = env' "y" + 0
lia.
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)
env0, env': env
Heqx: S x = env0 "x"
H: big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
x0: string

env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + S x * env0 "z" else env0 x0)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)
env0, env': env
Heqx: S x = env0 "x"
x0: string
env'0: env
H2: env0 "x" <> 0
H4: big_step env0 (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1)))) env'0
H6: big_step env'0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'

env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + (env0 "z" + x * env0 "z") else env0 x0)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)
env0, env': env
Heqx: S x = env0 "x"
x0: string
env'0: env
H2: env0 "x" <> 0
H6: big_step env'0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env'1: env
H3: big_step env0 (Assign "y" (Plus (Var "y") (Var "z"))) env'1
H7: big_step env'1 (Assign "x" (Minus (Var "x") (Const 1))) env'0

env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + (env0 "z" + x * env0 "z") else env0 x0)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)
env0, env': env
Heqx: S x = env0 "x"
x0: string
env'0: env
H2: env0 "x" <> 0
H6: big_step env'0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
H7: big_step (fun var : string => if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (Assign "x" (Minus (Var "x") (Const 1))) env'0

env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + (env0 "z" + x * env0 "z") else env0 x0)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)
env0, env': env
Heqx: S x = env0 "x"
x0: string
H2: env0 "x" <> 0
H6: big_step (fun var : string => if string_eq "x" var then eval (fun var0 : string => if string_eq "y" var0 then eval env0 (Plus (Var "y") (Var "z")) else env0 var0) (Minus (Var "x") (Const 1)) else if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'

env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + (env0 "z" + x * env0 "z") else env0 x0)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)
env0, env': env
Heqx: S x = env0 "x"
x0: string
H2: env0 "x" <> 0
H6: env' ?x = (if string_eq ?x "x" then 0 else if string_eq ?x "y" then (if string_eq "x" "y" then eval (fun var : string => if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (Minus (Var "x") (Const 1)) else if string_eq "y" "y" then eval env0 (Plus (Var "y") (Var "z")) else env0 "y") + x * (if string_eq "x" "z" then eval (fun var : string => if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (Minus (Var "x") (Const 1)) else if string_eq "y" "z" then eval env0 (Plus (Var "y") (Var "z")) else env0 "z") else if string_eq "x" ?x then eval (fun var : string => if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (Minus (Var "x") (Const 1)) else if string_eq "y" ?x then eval env0 (Plus (Var "y") (Var "z")) else env0 ?x)

env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + (env0 "z" + x * env0 "z") else env0 x0)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)
env0, env': env
Heqx: S x = env0 "x"
x0: string
H2: env0 "x" <> 0
H6: big_step (fun var : string => if string_eq "x" var then eval (fun var0 : string => if string_eq "y" var0 then eval env0 (Plus (Var "y") (Var "z")) else env0 var0) (Minus (Var "x") (Const 1)) else if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
x = (if string_eq "x" "x" then eval (fun var : string => if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (Minus (Var "x") (Const 1)) else if string_eq "y" "x" then eval env0 (Plus (Var "y") (Var "z")) else env0 "x")
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)
env0, env': env
Heqx: S x = env0 "x"
x0: string
H2: env0 "x" <> 0
H6: env' ?x = (if string_eq ?x "x" then 0 else if string_eq ?x "y" then (if string_eq "x" "y" then eval (fun var : string => if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (Minus (Var "x") (Const 1)) else if string_eq "y" "y" then eval env0 (Plus (Var "y") (Var "z")) else env0 "y") + x * (if string_eq "x" "z" then eval (fun var : string => if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (Minus (Var "x") (Const 1)) else if string_eq "y" "z" then eval env0 (Plus (Var "y") (Var "z")) else env0 "z") else if string_eq "x" ?x then eval (fun var : string => if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (Minus (Var "x") (Const 1)) else if string_eq "y" ?x then eval env0 (Plus (Var "y") (Var "z")) else env0 ?x)

env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + (env0 "z" + x * env0 "z") else env0 x0)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)
env0, env': env
Heqx: S x = env0 "x"
x0: string
H2: env0 "x" <> 0
H6: env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then (if string_eq "x" "y" then eval (fun var : string => if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (Minus (Var "x") (Const 1)) else if string_eq "y" "y" then eval env0 (Plus (Var "y") (Var "z")) else env0 "y") + x * (if string_eq "x" "z" then eval (fun var : string => if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (Minus (Var "x") (Const 1)) else if string_eq "y" "z" then eval env0 (Plus (Var "y") (Var "z")) else env0 "z") else if string_eq "x" x0 then eval (fun var : string => if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (Minus (Var "x") (Const 1)) else if string_eq "y" x0 then eval env0 (Plus (Var "y") (Var "z")) else env0 x0)

(if string_eq x0 "x" then 0 else if string_eq x0 "y" then (if string_eq "x" "y" then eval (fun var : string => if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (Minus (Var "x") (Const 1)) else if string_eq "y" "y" then eval env0 (Plus (Var "y") (Var "z")) else env0 "y") + x * (if string_eq "x" "z" then eval (fun var : string => if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (Minus (Var "x") (Const 1)) else if string_eq "y" "z" then eval env0 (Plus (Var "y") (Var "z")) else env0 "z") else if string_eq "x" x0 then eval (fun var : string => if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (Minus (Var "x") (Const 1)) else if string_eq "y" x0 then eval env0 (Plus (Var "y") (Var "z")) else env0 x0) = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + (env0 "z" + x * env0 "z") else env0 x0)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)
env0, env': env
Heqx: S x = env0 "x"
H2: env0 "x" <> 0
n: "y" <> "x"
n0: "x" <> "y"
n1: "x" <> "z"
n2: "y" <> "z"
H6: env' "y" = eval env0 (Plus (Var "y") (Var "z")) + x * env0 "z"

env0 "y" + env0 "z" + x * env0 "z" = env0 "y" + (env0 "z" + x * env0 "z")
lia.
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)
env0, env': env
Heqx: S x = env0 "x"
x0: string
H2: env0 "x" <> 0
H6: big_step (fun var : string => if string_eq "x" var then eval (fun var0 : string => if string_eq "y" var0 then eval env0 (Plus (Var "y") (Var "z")) else env0 var0) (Minus (Var "x") (Const 1)) else if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'

x = (if string_eq "x" "x" then eval (fun var : string => if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (Minus (Var "x") (Const 1)) else if string_eq "y" "x" then eval env0 (Plus (Var "y") (Var "z")) else env0 "x")
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env' -> forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)
env0, env': env
Heqx: S x = env0 "x"
x0: string
H2: env0 "x" <> 0
H6: big_step (fun var : string => if string_eq "x" var then eval (fun var0 : string => if string_eq "y" var0 then eval env0 (Plus (Var "y") (Var "z")) else env0 var0) (Minus (Var "x") (Const 1)) else if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
n: "y" <> "x"

x = env0 "x" - 1
lia.
env, env': lec07_big_step.env

(forall x : string, env' x = (if string_eq x "x" then 0 else if string_eq x "y" then env "y" + env "x" * env "z" else env x)) -> big_step env (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env, env': lec07_big_step.env
x: nat
Heqx: x = env "x"

(forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env "y" + x * env "z" else env x0)) -> big_step env (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
x: nat

forall env0 env' : env, x = env0 "x" -> (forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: 0 = env0 "x"
H: forall x : string, env' x = (if string_eq x "x" then 0 else if string_eq x "y" then env0 "y" + 0 * env0 "z" else env0 x)

big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> (forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H: forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + S x * env0 "z" else env0 x0)
big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: 0 = env0 "x"
H: forall x : string, env' x = (if string_eq x "x" then 0 else if string_eq x "y" then env0 "y" + 0 * env0 "z" else env0 x)

big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: 0 = env0 "x"
H: forall x : string, env' x = (if string_eq x "x" then 0 else if string_eq x "y" then env0 "y" + 0 * env0 "z" else env0 x)

env0 = env'
env0, env': env
Heqx: 0 = env0 "x"
H: forall x : string, env' x = (if string_eq x "x" then 0 else if string_eq x "y" then env0 "y" + 0 * env0 "z" else env0 x)

forall x : string, env0 x = env' x
env0, env': env
Heqx: 0 = env0 "x"
H: forall x : string, env' x = (if string_eq x "x" then 0 else if string_eq x "y" then env0 "y" + 0 * env0 "z" else env0 x)
x: string

env0 x = env' x
env0, env': env
Heqx: 0 = env0 "x"
x: string
H: env' x = (if string_eq x "x" then 0 else if string_eq x "y" then env0 "y" + 0 * env0 "z" else env0 x)

env0 x = env' x
env0, env': env
Heqx: 0 = env0 "x"
n: "y" <> "x"
H: env' "y" = env0 "y" + 0 * env0 "z"

env0 "y" = env' "y"
lia.
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> (forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H: forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + S x * env0 "z" else env0 x0)

big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> (forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H: forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + (env0 "z" + x * env0 "z") else env0 x0)

big_step env0 (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1)))) ?env'
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> (forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H: forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + (env0 "z" + x * env0 "z") else env0 x0)
big_step ?env' (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> (forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H: forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + (env0 "z" + x * env0 "z") else env0 x0)

big_step env0 (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1)))) ?env'
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> (forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H: forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + (env0 "z" + x * env0 "z") else env0 x0)

(fun var : string => if string_eq "x" var then eval (fun var0 : string => if string_eq "y" var0 then eval env0 (Plus (Var "y") (Var "z")) else env0 var0) (Minus (Var "x") (Const 1)) else (fun var0 : string => if string_eq "y" var0 then eval env0 (Plus (Var "y") (Var "z")) else env0 var0) var) = ?env'
reflexivity.
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> (forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H: forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + (env0 "z" + x * env0 "z") else env0 x0)

big_step (fun var : string => if string_eq "x" var then eval (fun var0 : string => if string_eq "y" var0 then eval env0 (Plus (Var "y") (Var "z")) else env0 var0) (Minus (Var "x") (Const 1)) else if string_eq "y" var then eval env0 (Plus (Var "y") (Var "z")) else env0 var) (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> (forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H: forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + (env0 "z" + x * env0 "z") else env0 x0)
n: "x" <> "y"
n0: "x" <> "z"
n1: "y" <> "z"
n2: "y" <> "x"

forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + env0 "z" + x * env0 "z" else if string_eq "x" x0 then env0 "x" - 1 else if string_eq "y" x0 then env0 "y" + env0 "z" else env0 x0)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> (forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
H: forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + (env0 "z" + x * env0 "z") else env0 x0)
n: "x" <> "y"
n0: "x" <> "z"
n1: "y" <> "z"
n2: "y" <> "x"
y: string

env' y = (if string_eq y "x" then 0 else if string_eq y "y" then env0 "y" + env0 "z" + x * env0 "z" else if string_eq "x" y then env0 "x" - 1 else if string_eq "y" y then env0 "y" + env0 "z" else env0 y)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> (forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
y: string
H: env' y = (if string_eq y "x" then 0 else if string_eq y "y" then env0 "y" + (env0 "z" + x * env0 "z") else env0 y)
n: "x" <> "y"
n0: "x" <> "z"
n1: "y" <> "z"
n2: "y" <> "x"

env' y = (if string_eq y "x" then 0 else if string_eq y "y" then env0 "y" + env0 "z" + x * env0 "z" else if string_eq "x" y then env0 "x" - 1 else if string_eq "y" y then env0 "y" + env0 "z" else env0 y)
x: nat
IHx: forall env0 env' : env, x = env0 "x" -> (forall x0 : string, env' x0 = (if string_eq x0 "x" then 0 else if string_eq x0 "y" then env0 "y" + x * env0 "z" else env0 x0)) -> big_step env0 (While (Var "x") (Seq (Assign "y" (Plus (Var "y") (Var "z"))) (Assign "x" (Minus (Var "x") (Const 1))))) env'
env0, env': env
Heqx: S x = env0 "x"
n3: "y" <> "x"
H: env' "y" = env0 "y" + (env0 "z" + x * env0 "z")
n: "x" <> "y"
n0: "x" <> "z"
n1: "y" <> "z"
n2: "y" <> "x"

env' "y" = env0 "y" + env0 "z" + x * env0 "z"
lia. Qed.