Theory Nielson_Hoare

theory Nielson_Hoare
imports Big_StepT 
begin

section "Nielson Style Hoare Logic with logical variables"

abbreviation "eq a b == (And (Not (Less a b)) (Not (Less b a)))"
   
type_synonym lvname = string
type_synonym assn2 = "(lvname  nat)  state  bool"
type_synonym tbd = "state  nat" (* time bound *)

subsection ‹The support of an assn2›

definition support :: "assn2  string set" where
"support P = {x. l1 l2 s. (y. y  x  l1 y = l2 y)  P l1 s  P l2 s}"


lemma support_and: "support (λl s. P l s  Q l s)  support P  support Q"
unfolding support_def by blast
  
lemma support_impl: "support (λl s. P s  Q l s)  support Q"
unfolding support_def by blast
  
lemma support_exist: "support (λl s.  z::nat. Q z l s)  (UN n. support (Q n))"
  unfolding support_def apply(auto)
  by blast+   

    
lemma support_all: "support (λl s. z. Q z l s)  (UN n. support (Q n))"
  unfolding support_def apply(auto)
  by blast+  
    
    
lemma support_single: "support (λl s. P (l a) s)  {a}"
  unfolding support_def by fastforce
    
lemma support_inv: "P. support (λl s. P s) = {}"
unfolding support_def by blast 

lemma assn2_lupd: "x  support Q  Q (l(x:=n)) = Q l"
by(simp add: support_def fun_upd_other fun_eq_iff)
  (metis (no_types, lifting) fun_upd_def)

subsection "Validity"
  
abbreviation state_subst :: "state  aexp  vname  state"
  (‹_[_'/_] [1000,0,0] 999)
where "s[a/x] == s(x := aval a s)"

definition hoare1_valid :: "assn2  com  tbd  assn2  bool"
  (1 {(1_)}/ (_)/ { _ (1_)} 50) where
"1 {P} c {q  Q}    (k>0. (l s. P l s  (t p. ((c,s)  p  t)   p  k * (q s)  Q l t)))"


subsection "Hoare rules"
  
inductive
  hoare1 :: "assn2  com  tbd  assn2  bool" (1 ({(1_)}/ (_)/ { _  (1_)}) 50)
where

Skip:  "1 {P} SKIP { (%s. Suc 0)  P}"  |

Assign:  "1 {λl s. P l (s[a/x])} x::=a {  (%s. Suc 0)  P}"  |

If: " 1 {λl s. P l s  bval b s} c1 { e1  Q};
       1 {λl s. P l s  ¬ bval b s} c2 { e1  Q} 
   1 {P} IF b THEN c1 ELSE c2 { (λs. e1 s + Suc 0 )  Q}"  |

Seq: " 1 { (%l s. P1 l s  l x = e2' s ) } c1 { e1  (%l s. P2 l s   e2 s  l x )};
         1 {P2} c2 { e2  P3}; x  support P1; x  support P2;
         l s. P1 l s  e1 s + e2' s  e s
           1 {P1} c1;;c2 { e  P3}"  |

While:
  " 1 {λl s. P l s  bval b s  e' s = l y} c {  e''  λl s. P l s  e s  l y};
       l s. bval b s  P l s   e s  1  +  e' s + e'' s  ; 
     l s. ~ bval b s  P l s  1  e s;
     y  support P  
    1 {P} WHILE b DO c { e  λl s. P l s  ¬ bval b s}" |

conseq: " k>0. l s. P' l s  ( e s  k * (e' s) (t. l'. P l' s  ( Q l' t  Q' l t) ));
           1 {P}c{ e  Q}    
           1 {P'}c{e'  Q'}"  
  
  
text‹Derived Rules:›

lemma conseq_old: "k>0. l s. P' l s  (P l s  ( e' s   k * (e s))); 1 {P}c{ e'   Q}; l s. Q l s  Q' l s   
           1 {P'}c{e  Q'}"
  using conseq apply(metis) done

lemma If2: " 1 {λl s. P l s  bval b s} c1 { e  Q}; 1 {λl s. P l s  ¬ bval b s} c2 { e  Q};
        l s. P l s  e s + 1 = e' s 
   1 {P} IF b THEN c1 ELSE c2 { e'  Q}"
apply(rule conseq[OF _ If, where P=P and P'=P]) by(auto)

lemma strengthen_pre:
  " l s. P' l s  P l s ;  1 {P} c { e  Q}   1 {P'} c { e  Q}"
  apply(rule conseq_old[where e'=e and Q=Q and P=P])
    by(auto)

lemma weaken_post:
  " 1 {P} c {e  Q};  l s. Q l s  Q' l s    1 {P} c {e  Q'}"
  apply(rule conseq_old[where   e'=e and Q=Q and P=P])
    by(auto)

lemma ub_cost:
  " (k>0. l s. P l s  e' s  k * (e s));  1 {P} c {e'  Q}    1 {P} c {e  Q}"
  apply(rule conseq_old[where e'=e' and Q=Q and P=P])
  by(auto) 

lemma Assign': "l s. P l s  Q l (s[a/x])  (1 {P} x ::= a { (%s. 1)  Q})"
using strengthen_pre[OF _ Assign] 
by (simp )

 
subsection "Soundness"
  
text‹The soundness theorem:›

theorem hoare1_sound: "1 {P}c{e  Q}    1 {P}c{e  Q}"
apply(unfold hoare1_valid_def)
proof(  induction  rule: hoare1.induct)
  case (Skip P)
  show ?case  by fastforce
next
  case (Assign P a x)
  show ?case  by fastforce 
next
  case (Seq P1 x e2' c1 e1 P2 e2 c2 P3 e)
  from Seq(6) obtain k where k: "k>0" and  S6: "l s. P1 l s  l x = e2' s  (t p. (c1, s)  p  t  p  k * e1 s  P2 l t  e2 t  l x)" by auto
  from Seq(7) obtain k' where k': "k'>0" and  S7:  "l s. P2 l s  (t p. (c2, s)  p  t  p  k' * e2 s  P3 l t)" by auto
  from k k' have "0 < max k k'" by auto
  show ?case 
  proof (rule exI[where x="max k k'"], safe)
    fix l s 
    have x_supp: "x  support P1" by fact
    have x_supp2: "x  support P2" by fact

    from S6 have S: "P1 (l(x := e2' s)) s  (l(x := e2' s)) x = e2' s  (t p. (c1, s)  p  t   p  k * e1 s  P2 (l(x := e2' s)) t  e2 t  (l(x := e2' s)) x) "
       by blast
     
    assume a: "P1 l s"

    with Seq(5) have 1: " e1 s + e2' s    e s" by simp 
    with a S assn2_lupd[OF x_supp] have "(t p. (c1, s)  p  t  p  k * e1 s  P2 (l(x := e2' s)) t  e2 t  (l(x := e2' s)) x)" by simp
    then obtain t p where c1: "(c1, s)  p  t" and cost1: " p  k * e1 s" and P2': "P2 (l(x := e2' s)) t" and 31: "e2 t  (l(x := e2' s)) x" by blast
    from P2' assn2_lupd[OF x_supp2] have P2: "P2 l t" by auto
    from 31 have 3: "e2 t  e2' s" by simp 
    from S7 P2 have "(t' p'. ((c2, t)  p'  t')    p'  k' * e2 t  P3 l t')" by blast
    then obtain t' p'  where c2: "(c2, t)  p'  t'" and cost2: " p'  k' * (e2 t)" and P3: "P3 l t'" by blast

    from c1 c2 have weg: "(c1;; c2, s)  p + p'  t'"  
      apply (rule Big_StepT.Seq) by simp
    from cost1 cost2 3 have " (p+p')  k * (e1 s) + k' * (e2' s)"
      by (meson add_mono mult_le_mono2 order_subst1)  
    also have "  (max k k') * (e1 s) + (max k k') * (e2' s)"
      by (simp add: add_mono) 
    also have "  (max k k') * (e1 s + e2' s)"
      by (simp add: add_mult_distrib2)      
    also have "  (max k k') * (e s)" using 1 by simp
  finally
    have cost: " (p + p')  (max k k') * (e s)" .
      
    from weg cost P3
    have "(c1;; c2, s)  p+p'  t'    (p+p')  (max k k') * (e s)  P3 l t'" by blast
    then show "(t p. (c1;; c2, s)  p  t   p  (max k k') * (e s)  P3 l t)" by metis
  qed fact
next
  case (If P b c1 e Q c2)
  from If(3) obtain k1 where k1: "k1>0" and If1: "l s. P l s  bval b s  (t p. (c1, s)  p  t  p  k1 * e s  Q l t)" by auto
  from If(4) obtain k2 where  k2: "k2>0" and If2: "l s. P l s  ¬ bval b s  (t p. (c2, s)  p  t  p  k2 * e s  Q l t)" by auto
  let ?k' = "max (k1+1) (k2+1)"
  have "?k'>0" by auto  
  show ?case
  proof (rule exI[where x="?k'"], safe)
    fix l s
    assume P1: "P l s"
    show "t p. (IF b THEN c1 ELSE c2, s)  p  t   p  ?k' * (e s + Suc 0)  Q l t"
    proof (cases "bval b s")
      case True
      with If1 P1 obtain t p where "(c1, s)  p  t" "p  k1 * (e s)" "Q l t" by blast
      with True have 1: "(IF b THEN c1 ELSE c2, s)  p+1  t" "(p + 1)  (k1+1) * (e s  + Suc 0)"
          "Q l t"
        by auto  
      have "(k1+1) * (e s  + Suc 0)  ?k' * (e s  + Suc 0)"
        by (simp add: nat_mult_max_left) 
      with 1 have 2: "p+1    ?k' * (e s  + Suc 0)"
        by linarith
      from 1 2 show "t p. (IF b THEN c1 ELSE c2, s)  p  t  p  ?k' * (e s + Suc 0)  Q l t" by metis
    next
      case False
      with If2 P1 obtain t p where "(c2, s)  p  t" "p  k2 * (e s)" "Q l t" by blast
      with False have 1: "(IF b THEN c1 ELSE c2, s)  p+1  t" "(p + 1)  (k2+1) * ( e s  + Suc 0)"
          "Q l t"
        by auto 
      have "(k2+1) * (e s  + Suc 0)  ?k' * (e s  + Suc 0)"
        by (simp add: nat_mult_max_left)  
      with 1 have 2: "p+1    ?k' * (e s  + Suc 0)"
        by linarith
      from 1 2 show "t p. (IF b THEN c1 ELSE c2, s)  p  t   p  ?k' * (e s + Suc 0)  Q l t" by metis
    qed
  qed fact
next
  case (conseq P' e e' P Q Q' c)
  from conseq(1) obtain k1 where k1: "k1>0" and c1: "l s. P' l s  e s  k1 * e' s  (t. l'. P l' s  (Q l' t  Q' l t))" by auto
  then have c1': "l s. P' l s  e s  k1 * e' s  (t. l'. P l' s  (Q l' t  Q' l t))"
    by auto
  from conseq(3) obtain k2 where k2: "k2>0" and c2: "l s. P l s  (t p. (c, s)  p  t  p  k2 * e s  Q l t)" by auto
  then have c2': "l s.  P l s  (t p. (c, s)  p  t  p  k2 * e s  Q l t)" by auto
  have "k2*k1 > 0" using k1 k2 by auto
  show ?case 
  proof (rule exI[where x="k2*k1"], safe)
    fix l s
    assume "P' l s"
    with c1' have A: "e s  k1 * e' s" and "t. l'. P l' s  (Q l' t  Q' l t)" by auto
    then obtain fl where "t. P (fl t) s" and B: "t. Q (fl t) t  Q' l t" by metis
    with c2' obtain ft fp where i: "t. (c, s)  (fp t)  (ft t)" and ii: "t. (fp t)  k2 * e s"
        and iii: "t. Q (fl t) (ft t)" 
      by meson
    from i obtain t p where tt: "x. ft x = t" "x. fp x = p" using big_step_t_determ2
      by meson
    with i have c: "(c, s)  p  t" by simp   
    from tt ii iii have p: "p  k2 * e s" and Q: "x. Q (fl x) t" by auto
    have p: "p  k2 * k1 * e' s" using p A
      by (metis le_trans mult.assoc mult_le_mono2)  
    from B Q have q: "Q' l t" by fast
    
    from c p q
    show "t p. (c, s)  p  t  p   k2 *k1 * e' s  Q' l t" 
      by blast
  qed fact  
next
  case (While INV b e' y c e'' e)  
  from While(5) obtain k where W6: "l s. INV l s  bval b s  e' s = l y  (t p. (c, s)  p  t  p  k * e'' s  INV l t  e t  l y)" by auto 
  let ?k' = "k+1"
  {
    fix n l s
    have " e s = n; INV l s   t p. (WHILE b DO c, s)  p  t  p  ?k' * e s  INV l t  ¬ bval b t"
    proof(induction "n" arbitrary: l s rule: less_induct)
      case (less x)
        
      show ?case
      proof (cases "bval b s")
        case False
        with less(2,3) While(3) have  b: "1  e s" by auto

        show ?thesis
          apply(rule exI[where x=s])
          apply(rule exI[where x=1]) apply safe
          subgoal using  WhileFalse[OF False] by simp 
          subgoal using b by auto 
          subgoal using less by auto
          subgoal using False by auto
          done
            
      next 
      case True
      with less(2,3) While(2) have bT: "bval b s" and cost1: "  1 + e' s + e'' s  e s" by auto 
      let ?l' = "l(y := e' s)"

      have y_supp: "y  support INV" by fact 
 
      from cost1 have Z: "e' s < x" using less(2) by auto
      from W6
      have "INV ?l' s  bval b s  e' s = ?l' y
             (t p. (c, s)  p  t    p  k * e'' s   INV ?l' t  e t  ?l' y)"
          by blast
      with less(3) bT
      have "(t p. ((c, s)  p  t)    p  k * e'' s   INV ?l' t  e t  e' s)"
            using   assn2_lupd[OF y_supp] 
        by(auto)  
      then obtain t p   where ceff: "(c, s)  p  t" and cost2: " p   k * e'' s" 
                    and INVz': "INV ?l' t" and cost3: "  e t    e' s"
        by blast 

      from INVz' have INVz: "INV l t" using assn2_lupd[OF y_supp] by auto 
      have "e t < x" using Z cost3 by auto
      with less(1)[OF _ _ INVz, of "e t"]  obtain t' p' 
        where weff: "(WHILE b DO c, t)  p'  t'" and cost4: " p'  ?k' *  e t" and INV0: "INV l t'"
            and nb: "¬ bval b t'"
          by fastforce      

      have "(WHILE b DO c, s)  1 + p + p'   t'"
        apply(rule WhileTrue)
          apply fact
          apply (fact ceff) 
          apply (fact weff) by simp
    moreover
      note INV0 nb
      moreover
      {
        have "(1 + p + p')  1 + k * e'' s + ?k' * e t" using cost2 cost4 by linarith
        also have "   1 + k * e'' s + ?k' * e' s" using cost3
          using add_left_mono mult_le_mono2 by blast 
        also have "  ?k'*1 + ?k'* e'' s + ?k' * e' s " by force 
        also have " = ?k' * (1+ e' s + e'' s)" by algebra
        also have "  ?k' * e s" using cost1
          using mult_le_mono2 by blast            
        finally have " (1 + p + p')  ?k' * e s" .
      }
    ultimately  
      show ?thesis by metis
    qed 
    qed
  }  
  then have erg: "l s. INV l s  t p. (WHILE b DO c, s)  p  t  p  (k + 1) * e s  INV l t  ¬ bval b t" by auto
  show ?case apply(rule exI[where x="?k'"]) using erg by fastforce
qed 

subsection "Completeness"

definition wp1 :: "com  assn2  assn2" (wp1) where
"wp1 c Q  =  (λl s. t p. (c,s)  p  t  Q l t)"
 

lemma support_wpt: "support (wp1 c Q)  support Q"
by(simp add: support_def wp1_def) blast

  
lemma wp1_terminates: "wp1 c Q l s   (c, s)" unfolding wp1_def by auto

    
lemma wp1_SKIP[simp]: "wp1 SKIP Q = Q" by(auto intro!: ext simp: wp1_def)

lemma wp1_Assign[simp]: "wp1 (x ::= e) Q = (λl s. Q l (s(x := aval e s)))" by(auto intro!: ext simp: wp1_def)

lemma wp1_Seq[simp]: "wp1 (c1;;c2) Q = wp1 c1 (wp1 c2 Q)" by (auto simp: wp1_def fun_eq_iff)

lemma wp1_If[simp]: "wp1 (IF b THEN c1 ELSE c2) Q = (λl s. wp1 (if bval b s then c1 else c2) Q l s)" by (auto simp: wp1_def fun_eq_iff)

    
definition "prec c E == %s. E (THE t. (p. (c,s)  p  t))"
  
lemma wp1_prec_Seq_correct: "wp1 (c1;;c2) Q l s  t (c1, s) + prec c1 (λs. t (c2, s)) s  t (c1;; c2, s)"
proof -
  assume "wp1 (c1;;c2) Q l s"
  then have wp: "wp1 c1 (wp1 c2 Q) l s" by simp
  then obtain t p where c1_term: "(c1, s)  p  t" and "(ta p. (c2, t)  p  ta  Q l ta)" unfolding wp1_def by blast
  then obtain t' p' where c2_term: "(c2, t)  p'  t'" and  "Q l t'" by blast

  have p: "t (c1, s) = p" using c1_term bigstepT_the_cost by simp
  have "t (c2, t) = p'" using c2_term bigstepT_the_cost by simp

  have f: "(THE t. p. (c1, s)  p  t) = t" using c1_term bigstepT_the_state by simp

  have " prec c1 (λs. t (c2, s)) s = p'" unfolding prec_def f using c2_term bigstep_det by blast
  then have p': " prec c1 (λs.  (THE n. a. (c2, s)  n  a)) s
        =  p'" unfolding prec_def by blast

  from wp have "wp1 (c1;;c2) Q l s" by simp
  then obtain T P where c12_term: "(c1;;c2, s)  P  T" and "Q l T" unfolding wp1_def by blast

  have P: "(THE n. (a. (c1;;c2, s)  n  a)) = P" using c12_term bigstepT_the_cost by simp

  from c12_term have Ppp': "P = p + p'"
    apply(elim Seq_tE)
    using c1_term bigstep_det c2_term by blast

  have " (THE n. a. (c1, s)  n  a) + prec c1 (λs.  (THE n. a. (c2, s)  n  a)) s
        =  p +  p'" using p p' by auto
  also have " =  P" using Ppp' by auto
  also have " =  (THE n. (a. (c1;;c2, s)  n  a))" using P by auto
  finally
  show "t (c1, s) + prec c1 (λs. t (c2, s)) s  t (c1;; c2, s)"
    by simp
qed 
  


abbreviation "new Q  SOME x. x  support Q"

lemma bigstep_det: "(c1, s)  p1  t1  (c1, s)  p  t  p1=p  t1=t"
  using big_step_t_determ2 by simp

lemma bigstepT_the_cost: "(c, s)  P  T  (THE n. a. (c, s)  n  a) = P"
  using bigstep_det by blast 

lemma bigstepT_the_state: "(c, s)  P  T  (THE a. n. (c, s)  n  a) = T"
  using bigstep_det by blast 
   
lemma assumes b: "bval b s"
  shows wp1WhileTrue': "wp1 (WHILE b DO c) Q l s = wp1 c (wp1 (WHILE b DO c) Q) l s"
proof 
  assume "wp1 c (wp1 (WHILE b DO c) Q) l s"
  from this[unfolded wp1_def]
  obtain t s' t' s'' where "(c, s)  t  s'" "(WHILE b DO c, s')  t'  s''" and Q: "Q l s''" by blast
  with b have "(WHILE b DO c, s)  1+t+t'  s''" by auto
  with Q show "wp1 (WHILE b DO c) Q l s" unfolding wp1_def by auto
next
  assume "wp1 (WHILE b DO c) Q l s"
  from this[unfolded wp1_def]
  obtain t s'' where "(WHILE b DO c, s)  t  s''" and Q: "Q l s''" by blast
  with b  obtain t1 t2 s' where "(c, s)  t1  s'" "(WHILE b DO c, s')  t2  s''" by auto
  with Q show "wp1 c (wp1 (WHILE b DO c) Q) l s " unfolding wp1_def by auto
qed
  
lemma assumes b: "~ bval b s"
  shows wp1WhileFalse': "wp1 (WHILE b DO c) Q l s =  Q l s"
proof 
  assume "wp1 (WHILE b DO c) Q l s"
  from this[unfolded wp1_def]
  obtain t s' where "(WHILE b DO c, s)  t  s'" and Q: "Q l s'" by blast
  with b  have "s=s'" by auto
  with Q show "Q l s" by auto
next
  assume "Q l s"
  with b show  "wp1 (WHILE b DO c) Q l s" unfolding wp1_def by auto
qed
  
lemma wp1While: "wp1 (WHILE b DO c) Q l s = (if bval b s then wp1 c (wp1 (WHILE b DO c) Q) l s else Q l s)"  
  apply(cases "bval b s")      
  using wp1WhileTrue' apply simp
  using wp1WhileFalse' apply simp   done 
  
lemma wp1_prec2: fixes e::tbd
    shows "(wp1 c1 Q l s 
           l x = prec c1 e s) = wp1 c1 (λl s. Q l s  e s = l x) l s"
      by (metis (mono_tags, lifting) Big_StepT.bigstepT_the_state prec_def wp1_def)
      
      
lemma wp1_prec: fixes e::tbd
    shows "wp1 c1 Q l s 
           l x = prec c1 e s  wp1 c1 (λl s. Q l s  e s = l x) l s"
unfolding wp1_def prec_def apply(auto) 
proof -
  fix p t
  assume "l x = e (THE t. p. (c1, s)  p  t)"
  assume 2: "Q l t"
  assume 1: "(c1, s)  p  t "
  show "t. (p. (c1, s)  p  t)  Q l t  e t = e (THE t. p. (c1, s)  p  t) "
    apply(rule exI[where x=t])
    apply(safe)
      apply(rule exI[where x=p]) using 1 apply simp
      apply(fact)
      using 1 by(simp add: bigstepT_the_state)
qed 
  

lemma wp1_is_pre: "finite (support Q)  1 {wp1 c Q} c { λs. t (c, s)  Q}"
proof (induction c arbitrary: Q)
  case SKIP
  have ff: "s n. (a. (SKIP, s)  n  a) = (n=Suc 0)" by blast  
  show ?case apply (auto intro:hoare1.Skip simp add: ff) using ff done
next
  have gg: "x1 x2 s n. (a. (x1 ::= x2, s)  n  a) = (n=Suc 0)" by blast
  case Assign show ?case apply (auto intro:hoare1.Assign simp add: gg) done
next
  case (Seq c1 c2)  
  ― ‹choose a fresh logical variable x›
  let ?x = "new Q"
  have "x. x  support Q" using Seq.prems infinite_UNIV_listI
    using ex_new_if_finite by blast
  hence  "?x  support Q" by (rule someI_ex) 
  then have x2: "?x  support (wp1 c2 Q)"  using support_wpt by (fast)
  then have x12: "?x  support (wp1 (c1;;c2) Q)" apply simp using support_wpt by fast

  ― ‹assemble a postcondition Q1 that ensures the weakest precondition of Q before c2
        and saves the running time of c2 into the logical variable x›
  let ?Q1 = "(λl s. (wp1 c2 Q) l s   t (c2, s) = l ?x)"
  have "finite (support ?Q1)" apply(rule rev_finite_subset[OF _ support_and])
     apply(rule finite_UnI)
      apply(rule rev_finite_subset[OF _ support_wpt]) apply(fact)
    apply(rule rev_finite_subset[OF _ support_single]) by simp
  ― ‹we can now specify this Q1 in the first Induction Hypothesis›    
  then have pre: "u. 1 {wp1 c1 ?Q1 } c1 { λs. t (c1, s)   ?Q1  }"
    using Seq(1) by simp  

  ― ‹we can rewrite this into the form we need for the Seq rule›
  have A: " 1 {λl s. wp1 (c1;;c2) Q l s  l ?x = (prec c1 (%s. t (c2, s))) s} c1 { λs. t (c1, s)  λl s. wp1 c2 Q l s   t (c2, s)  l ?x}"
    apply(rule conseq_old[OF _ pre ])
    by(auto simp add: wp1_prec) 

  ― ‹we can now apply the Seq rule with the first IH (in the right shape A) and the second IH›
  show "1 {wp1 (c1;; c2) Q} c1;; c2 { λs. t (c1;; c2, s)  Q}"
    apply(rule hoare1.Seq[OF A Seq(2)])  
       ― ‹finally some side conditions have to be proven› 
       using Seq(3) x12 x2 wp1_prec_Seq_correct .
next
  case (If b c1 c2)
    
  show ?case apply(simp)
  apply(rule If2[where e="%s. if bval b s then t (c1, s) else t (c2, s)"]) 
    apply(simp_all  cong:rev_conj_cong)
    apply(rule conseq_old[where Q=Q and Q'=Q])
      prefer 2
      apply(rule If.IH(1)) apply(fact)
      apply(simp_all) apply(auto)[1]
    apply(rule conseq_old[where Q=Q and Q'=Q])
      prefer 2
      apply(rule If.IH(2)) apply(fact)
      apply(simp_all) apply(auto)[1]
      apply (blast intro: If_THE_True wp1_terminates If_THE_False) 
     done
 
next
  case (While b c)
 
      let ?y = "(new (wp1 (WHILE b DO c) Q))"
    have "finite (support (wp1 (WHILE b DO c) Q))"
      apply(rule finite_subset[OF support_wpt]) apply fact done
    then have "x. x  support (wp1 (WHILE b DO c) Q)" using infinite_UNIV_listI
      using ex_new_if_finite by blast
    hence yQx: "?y  support (wp1 (WHILE b DO c) Q)" by (rule someI_ex)

  show ?case
  proof (rule conseq_old[OF _  hoare1.While], safe )
    show "k>0. l s. wp1 (WHILE b DO c) Q l s  wp1 (WHILE b DO c) Q l s   t (WHILE b DO c, s)  k * t (WHILE b DO c, s)"
      apply auto done
  next
    fix l s
    assume "wp1 (WHILE b DO c) Q l s" "¬ bval b s"
    then show "Q l s" by (simp add: wp1While)
  next
    fix l s
    assume "wp1 (WHILE b DO c) Q l s"
    from this[unfolded wp1_def] obtain t s' where t: "(WHILE b DO c, s)  t  s'" and "Q l s'" by blast
    then have r: "t (WHILE b DO c, s) = t" using Nielson_Hoare.bigstepT_the_cost by auto 
    assume "¬ bval b s"
    with r t have   t2: "t=1" by auto 
    from r t2 show "1  t (WHILE b DO c, s)" by auto 
  next
    fix l s
    assume "wp1 (WHILE b DO c) Q l s"
    from this[unfolded wp1_def] obtain t s'' where t: "(WHILE b DO c, s)  t  s''" "Q l s''" by blast
    then have r: "t (WHILE b DO c, s) = t" using Nielson_Hoare.bigstepT_the_cost by auto 
    assume "bval b s" 
    with t obtain t1 t2 s' where 1: "(c,s)  t1  s'" and 2: "(WHILE b DO c, s')  t2  s''" and sum: "t=t1+t2+1" and "bval b s" by auto
    from 1 have A: "t (c,s) = t1" and s': "s (c,s) = s'" using Nielson_Hoare.bigstepT_the_cost bigstepT_the_state by auto
    from 2 s' have B: "t (WHILE b DO c, s(c,s)) = t2" using Nielson_Hoare.bigstepT_the_cost by auto

    show "1 + (%s. t (WHILE b DO c, s(c,s))) s  + (%s. t (c,s)) s  t (WHILE b DO c, s)"
      apply(simp add: r A B sum) done
  next 
    
    
    show "1 {λl s. wp1 (WHILE b DO c) Q l s  bval b s  t (WHILE b DO c, s (c, s)) = l ?y} c
         { λs. t (c, s)  λl s. wp1 (WHILE b DO c) Q l s  t (WHILE b DO c, s)  l ?y}"
       apply(rule conseq_old[OF _ While(1), of _ "%l s. wp1 (WHILE b DO c) Q l s  t (WHILE b DO c, s) = l ?y"])
        apply(rule exI[where x=1]) apply simp
      subgoal apply safe
        apply(subst (asm) wp1While) apply simp
      proof - fix l s
        assume 1: "wp1 c (wp1 (WHILE b DO c) Q) l s"
        assume 2: "t (WHILE b DO c, s (c, s)) = l ?y" 
        then have "l ?y = prec c (%s. t (WHILE b DO c, s)) s" unfolding prec_def by auto
        with 1 wp1_prec2[of c "(wp1 (WHILE b DO c) Q)" l s _ "(λs. t (WHILE b DO c, s))"]
          show "wp1 c (λl s. wp1 (WHILE b DO c) Q l s   t (WHILE b DO c, s) = l ?y) l s" by auto
        qed
        subgoal apply(rule finite_subset[OF support_and]) apply auto
           apply(rule finite_subset[OF support_wpt]) apply fact
             apply(rule finite_subset) apply(rule support_single)  by auto
        apply auto done 
    next
      assume "new (wp1 (WHILE b DO c) Q)  support (wp1 (WHILE b DO c) Q)"
      with yQx show "False"  
        by blast
       
    qed
  qed

    
lemma valid_wp: "1 {P}c{p  Q}  (k>0. (l s. P l s  (wp1 c Q l s  ((THE n. ( t. ((c,s)  n  t))))  k * p s)))"
  apply(rule)
   apply(auto simp: hoare1_valid_def wp1_def)    
  subgoal for k apply(rule exI[where x=k]) using bigstepT_the_cost by fast       
  subgoal for k apply(rule exI[where x=k]) using bigstepT_the_cost by fast
  done
    
    
theorem hoare1_complete: "finite (support Q)  1 {P}c{p  Q}  1 {P}c{p  Q}"   
  apply(rule conseq_old[OF _ wp1_is_pre, where Q'=Q and Q=Q, simplified]) 
  by (auto simp: valid_wp)   
  
    
corollary hoare1_sound_complete: "finite (support Q)  1 {P}c{p  Q}  1 {P}c{p  Q}"
  by (metis hoare1_sound hoare1_complete)
    
end