(** ** Definition of the variant 
  Given a program [p] and a boolean expression [cond], the relation on environment 
  "[reduces cond p]" is the variant required by "[synt_wp (Iwhile cond p)]".

  I prove below that this relation is well-founded.
*) 
Definition reduces cond p e1 e0 :=
  (E.eval cond e0)=true /\ (exec e0 p e1) /\ exists ef, (exec e1 (Iwhile cond p) ef).(** To prove that "[reduces cond p]" is well-founded, I want to count  
    the number of execution of [p] in the computation of "[Iwhile cond p]".
    Indeed, as the language is deterministic, this number is unique.

    Hence, "[execn n e (Iwhile cond p) e']" means that "[exec e (Iwhile cond p) e']" 
    in a sequence of [n] execution of [p]. 
 *)
Inductive execn: nat -> E.Env -> ImpProg -> E.Env -> Prop :=
 | execn_Iskip:
    forall e, (execn 0 e Iskip e)
 | execn_Iset:
    forall (A:Type) e x (expr: E.Expr A),
     (execn 0 e (Iset x expr) (E.upd x (E.eval expr e) e))
 | execn_Iif:
    forall n e (cond: E.Expr bool) p1 p2 e',
       (execn n e (if (E.eval cond e) then p1 else p2) e')
         -> (execn n e (Iif cond p1 p2) e')
 | execn_Iseq:
    forall n e p1 p2 e' e'',
      (exec e p1 e')
       -> (execn n e' p2 e'')
         -> (execn n e (Iseq p1 p2) e'')
 | execn_Iwhile:
    forall n e cond p e',
     (execn n e (Iif cond (Iseq p (Iwhile cond p)) Iskip) e')
        -> (execn (S n) e (Iwhile cond p) e').(** To prove that "[reduces cond p]" is well-founded, I want to count  
    the number of execution of [p] in the computation of "[Iwhile cond p]".
    Indeed, as the language is deterministic, this number is unique.

    Hence, "[execn n e (Iwhile cond p) e']" means that "[exec e (Iwhile cond p) e']" 
    in a sequence of [n] execution of [p]. 
 *)
Inductive execn: nat -> E.Env -> ImpProg -> E.Env -> Prop :=
 | execn_Iskip:
    forall e, (execn 0 e Iskip e)
 | execn_Iset:
    forall (A:Type) e x (expr: E.Expr A),
     (execn 0 e (Iset x expr) (E.upd x (E.eval expr e) e))
 | execn_Iif:
    forall n e (cond: E.Expr bool) p1 p2 e',
       (execn n e (if (E.eval cond e) then p1 else p2) e')
         -> (execn n e (Iif cond p1 p2) e')
 | execn_Iseq:
    forall n e p1 p2 e' e'',
      (exec e p1 e')
       -> (execn n e' p2 e'')
         -> (execn n e (Iseq p1 p2) e'')
 | execn_Iwhile:
    forall n e cond p e',
     (execn n e (Iif cond (Iseq p (Iwhile cond p)) Iskip) e')
        -> (execn (S n) e (Iwhile cond p) e').(** To prove that "[reduces cond p]" is well-founded, I want to count  
    the number of execution of [p] in the computation of "[Iwhile cond p]".
    Indeed, as the language is deterministic, this number is unique.

    Hence, "[execn n e (Iwhile cond p) e']" means that "[exec e (Iwhile cond p) e']" 
    in a sequence of [n] execution of [p]. 
 *)
Inductive execn: nat -> E.Env -> ImpProg -> E.Env -> Prop :=
 | execn_Iskip:
    forall e, (execn 0 e Iskip e)
 | execn_Iset:
    forall (A:Type) e x (expr: E.Expr A),
     (execn 0 e (Iset x expr) (E.upd x (E.eval expr e) e))
 | execn_Iif:
    forall n e (cond: E.Expr bool) p1 p2 e',
       (execn n e (if (E.eval cond e) then p1 else p2) e')
         -> (execn n e (Iif cond p1 p2) e')
 | execn_Iseq:
    forall n e p1 p2 e' e'',
      (exec e p1 e')
       -> (execn n e' p2 e'')
         -> (execn n e (Iseq p1 p2) e'')
 | execn_Iwhile:
    forall n e cond p e',
     (execn n e (Iif cond (Iseq p (Iwhile cond p)) Iskip) e')
        -> (execn (S n) e (Iwhile cond p) e').(** To prove that "[reduces cond p]" is well-founded, I want to count  
    the number of execution of [p] in the computation of "[Iwhile cond p]".
    Indeed, as the language is deterministic, this number is unique.

    Hence, "[execn n e (Iwhile cond p) e']" means that "[exec e (Iwhile cond p) e']" 
    in a sequence of [n] execution of [p]. 
 *)
Inductive execn: nat -> E.Env -> ImpProg -> E.Env -> Prop :=
 | execn_Iskip:
    forall e, (execn 0 e Iskip e)
 | execn_Iset:
    forall (A:Type) e x (expr: E.Expr A),
     (execn 0 e (Iset x expr) (E.upd x (E.eval expr e) e))
 | execn_Iif:
    forall n e (cond: E.Expr bool) p1 p2 e',
       (execn n e (if (E.eval cond e) then p1 else p2) e')
         -> (execn n e (Iif cond p1 p2) e')
 | execn_Iseq:
    forall n e p1 p2 e' e'',
      (exec e p1 e')
       -> (execn n e' p2 e'')
         -> (execn n e (Iseq p1 p2) e'')
 | execn_Iwhile:
    forall n e cond p e',
     (execn n e (Iif cond (Iseq p (Iwhile cond p)) Iskip) e')
        -> (execn (S n) e (Iwhile cond p) e').(** To prove that "[reduces cond p]" is well-founded, I want to count  
    the number of execution of [p] in the computation of "[Iwhile cond p]".
    Indeed, as the language is deterministic, this number is unique.

    Hence, "[execn n e (Iwhile cond p) e']" means that "[exec e (Iwhile cond p) e']" 
    in a sequence of [n] execution of [p]. 
 *)
Inductive execn: nat -> E.Env -> ImpProg -> E.Env -> Prop :=
 | execn_Iskip:
    forall e, (execn 0 e Iskip e)
 | execn_Iset:
    forall (A:Type) e x (expr: E.Expr A),
     (execn 0 e (Iset x expr) (E.upd x (E.eval expr e) e))
 | execn_Iif:
    forall n e (cond: E.Expr bool) p1 p2 e',
       (execn n e (if (E.eval cond e) then p1 else p2) e')
         -> (execn n e (Iif cond p1 p2) e')
 | execn_Iseq:
    forall n e p1 p2 e' e'',
      (exec e p1 e')
       -> (execn n e' p2 e'')
         -> (execn n e (Iseq p1 p2) e'')
 | execn_Iwhile:
    forall n e cond p e',
     (execn n e (Iif cond (Iseq p (Iwhile cond p)) Iskip) e')
        -> (execn (S n) e (Iwhile cond p) e').(** To prove that "[reduces cond p]" is well-founded, I want to count  
    the number of execution of [p] in the computation of "[Iwhile cond p]".
    Indeed, as the language is deterministic, this number is unique.

    Hence, "[execn n e (Iwhile cond p) e']" means that "[exec e (Iwhile cond p) e']" 
    in a sequence of [n] execution of [p]. 
 *)
Inductive execn: nat -> E.Env -> ImpProg -> E.Env -> Prop :=
 | execn_Iskip:
    forall e, (execn 0 e Iskip e)
 | execn_Iset:
    forall (A:Type) e x (expr: E.Expr A),
     (execn 0 e (Iset x expr) (E.upd x (E.eval expr e) e))
 | execn_Iif:
    forall n e (cond: E.Expr bool) p1 p2 e',
       (execn n e (if (E.eval cond e) then p1 else p2) e')
         -> (execn n e (Iif cond p1 p2) e')
 | execn_Iseq:
    forall n e p1 p2 e' e'',
      (exec e p1 e')
       -> (execn n e' p2 e'')
         -> (execn n e (Iseq p1 p2) e'')
 | execn_Iwhile:
    forall n e cond p e',
     (execn n e (Iif cond (Iseq p (Iwhile cond p)) Iskip) e')
        -> (execn (S n) e (Iwhile cond p) e').

Lemma exec_execn: forall ei p ef, (exec ei p ef) -> (exists n, execn n ei p ef).