src/HOL/Hoare/Pointers.thy
changeset 13724 06ded8d18d02
parent 13723 c7d104550205
child 13737 e564c3d2d174
equal deleted inserted replaced
13723:c7d104550205 13724:06ded8d18d02
     6 How to use Hoare logic to verify pointer manipulating programs.
     6 How to use Hoare logic to verify pointer manipulating programs.
     7 The old idea: the store is a global mapping from pointers to values.
     7 The old idea: the store is a global mapping from pointers to values.
     8 Pointers are modelled by type 'a option, where None is Nil.
     8 Pointers are modelled by type 'a option, where None is Nil.
     9 Thus the heap is of type 'a \<leadsto> 'a (see theory Map).
     9 Thus the heap is of type 'a \<leadsto> 'a (see theory Map).
    10 
    10 
    11 The List reversal example is taken from Richard Bornat's paper
    11 The list reversal example is taken from Richard Bornat's paper
    12 Proving pointer programs in Hoare logic
    12 Proving pointer programs in Hoare logic
    13 What's new? We formalize the foundations, ie the abstraction from the pointer
    13 What's new? We formalize the foundations, ie the abstraction from the pointer
    14 chains to HOL lists. This is merely axiomatized by Bornat.
    14 chains to HOL lists. This is merely axiomatized by Bornat.
    15 *)
    15 *)
    16 
    16 
    59 section "The heap"
    59 section "The heap"
    60 
    60 
    61 subsection "Paths in the heap"
    61 subsection "Paths in the heap"
    62 
    62 
    63 consts
    63 consts
    64  path :: "('a \<leadsto> 'a) \<Rightarrow> 'a ref \<Rightarrow> 'a list \<Rightarrow> 'a ref \<Rightarrow> bool"
    64  Path :: "('a \<leadsto> 'a) \<Rightarrow> 'a ref \<Rightarrow> 'a list \<Rightarrow> 'a ref \<Rightarrow> bool"
    65 primrec
    65 primrec
    66 "path h x [] y = (x = y)"
    66 "Path h x [] y = (x = y)"
    67 "path h x (a#as) y = (x = Ref a \<and> path h (h a) as y)"
    67 "Path h x (a#as) y = (x = Ref a \<and> Path h (h a) as y)"
    68 
    68 
    69 lemma [iff]: "path h Null xs y = (xs = [] \<and> y = Null)"
    69 lemma [iff]: "Path h Null xs y = (xs = [] \<and> y = Null)"
    70 apply(case_tac xs)
    70 apply(case_tac xs)
    71 apply fastsimp
    71 apply fastsimp
    72 apply fastsimp
    72 apply fastsimp
    73 done
    73 done
    74 
    74 
    75 lemma [simp]: "path h (Ref a) as z =
    75 lemma [simp]: "Path h (Ref a) as z =
    76  (as = [] \<and> z = Ref a  \<or>  (\<exists>bs. as = a#bs \<and> path h (h a) bs z))"
    76  (as = [] \<and> z = Ref a  \<or>  (\<exists>bs. as = a#bs \<and> Path h (h a) bs z))"
    77 apply(case_tac as)
    77 apply(case_tac as)
    78 apply fastsimp
    78 apply fastsimp
    79 apply fastsimp
    79 apply fastsimp
    80 done
    80 done
    81 
    81 
    82 lemma [simp]: "\<And>x. path f x (as@bs) z = (\<exists>y. path f x as y \<and> path f y bs z)"
    82 lemma [simp]: "\<And>x. Path f x (as@bs) z = (\<exists>y. Path f x as y \<and> Path f y bs z)"
    83 by(induct as, simp+)
    83 by(induct as, simp+)
    84 
    84 
    85 lemma [simp]: "\<And>x. u \<notin> set as \<Longrightarrow> path (f(u\<mapsto>v)) x as y = path f x as y"
    85 lemma [simp]: "\<And>x. u \<notin> set as \<Longrightarrow> Path (f(u\<mapsto>v)) x as y = Path f x as y"
    86 by(induct as, simp, simp add:eq_sym_conv)
    86 by(induct as, simp, simp add:eq_sym_conv)
    87 
    87 
    88 subsection "Lists on the heap"
    88 subsection "Lists on the heap"
    89 
    89 
    90 subsubsection "Relational abstraction"
    90 subsubsection "Relational abstraction"
    91 
    91 
    92 constdefs
    92 constdefs
    93  list :: "('a \<leadsto> 'a) \<Rightarrow> 'a option \<Rightarrow> 'a list \<Rightarrow> bool"
    93  List :: "('a \<leadsto> 'a) \<Rightarrow> 'a option \<Rightarrow> 'a list \<Rightarrow> bool"
    94 "list h x as == path h x as Null"
    94 "List h x as == Path h x as Null"
    95 
    95 
    96 lemma [simp]: "list h x [] = (x = Null)"
    96 lemma [simp]: "List h x [] = (x = Null)"
    97 by(simp add:list_def)
    97 by(simp add:List_def)
    98 
    98 
    99 lemma [simp]: "list h x (a#as) = (x = Ref a \<and> list h (h a) as)"
    99 lemma [simp]: "List h x (a#as) = (x = Ref a \<and> List h (h a) as)"
   100 by(simp add:list_def)
   100 by(simp add:List_def)
   101 
   101 
   102 lemma [simp]: "list h Null as = (as = [])"
   102 lemma [simp]: "List h Null as = (as = [])"
   103 by(case_tac as, simp_all)
   103 by(case_tac as, simp_all)
   104 
   104 
   105 lemma list_Ref[simp]: "list h (Ref a) as = (\<exists>bs. as = a#bs \<and> list h (h a) bs)"
   105 lemma List_Ref[simp]: "List h (Ref a) as = (\<exists>bs. as = a#bs \<and> List h (h a) bs)"
   106 by(case_tac as, simp_all, fast)
   106 by(case_tac as, simp_all, fast)
   107 
   107 
   108 
   108 
   109 declare fun_upd_apply[simp del]fun_upd_same[simp] fun_upd_other[simp]
   109 declare fun_upd_apply[simp del]fun_upd_same[simp] fun_upd_other[simp]
   110 
   110 
   111 lemma list_unique: "\<And>x bs. list h x as \<Longrightarrow> list h x bs \<Longrightarrow> as = bs"
   111 lemma List_unique: "\<And>x bs. List h x as \<Longrightarrow> List h x bs \<Longrightarrow> as = bs"
   112 by(induct as, simp, clarsimp)
   112 by(induct as, simp, clarsimp)
   113 
   113 
   114 lemma list_unique1: "list h p as \<Longrightarrow> \<exists>!as. list h p as"
   114 lemma List_unique1: "List h p as \<Longrightarrow> \<exists>!as. List h p as"
   115 by(blast intro:list_unique)
   115 by(blast intro:List_unique)
   116 
   116 
   117 lemma list_app: "\<And>x. list h x (as@bs) = (\<exists>y. path h x as y \<and> list h y bs)"
   117 lemma List_app: "\<And>x. List h x (as@bs) = (\<exists>y. Path h x as y \<and> List h y bs)"
   118 by(induct as, simp, clarsimp)
   118 by(induct as, simp, clarsimp)
   119 
   119 
   120 lemma list_hd_not_in_tl[simp]: "list h (h a) as \<Longrightarrow> a \<notin> set as"
   120 lemma List_hd_not_in_tl[simp]: "List h (h a) as \<Longrightarrow> a \<notin> set as"
   121 apply (clarsimp simp add:in_set_conv_decomp)
   121 apply (clarsimp simp add:in_set_conv_decomp)
   122 apply(frule list_app[THEN iffD1])
   122 apply(frule List_app[THEN iffD1])
   123 apply(fastsimp dest: list_unique)
   123 apply(fastsimp dest: List_unique)
   124 done
   124 done
   125 
   125 
   126 lemma list_distinct[simp]: "\<And>x. list h x as \<Longrightarrow> distinct as"
   126 lemma List_distinct[simp]: "\<And>x. List h x as \<Longrightarrow> distinct as"
   127 apply(induct as, simp)
   127 apply(induct as, simp)
   128 apply(fastsimp dest:list_hd_not_in_tl)
   128 apply(fastsimp dest:List_hd_not_in_tl)
   129 done
   129 done
   130 
   130 
   131 theorem notin_list_update[simp]:
   131 theorem notin_List_update[simp]:
   132  "\<And>x. a \<notin> set as \<Longrightarrow> list (h(a := y)) x as = list h x as"
   132  "\<And>x. a \<notin> set as \<Longrightarrow> List (h(a := y)) x as = List h x as"
   133 apply(induct as)
   133 apply(induct as)
   134 apply simp
   134 apply simp
   135 apply(clarsimp simp add:fun_upd_apply)
   135 apply(clarsimp simp add:fun_upd_apply)
   136 done
   136 done
   137 
   137 
   138 subsection "Functional abstraction"
   138 subsection "Functional abstraction"
   139 
   139 
   140 constdefs
   140 constdefs
   141  islist :: "('a \<Rightarrow> 'a ref) \<Rightarrow> 'a ref \<Rightarrow> bool"
   141  islist :: "('a \<Rightarrow> 'a ref) \<Rightarrow> 'a ref \<Rightarrow> bool"
   142 "islist h p == \<exists>as. list h p as"
   142 "islist h p == \<exists>as. List h p as"
   143  mklist :: "('a \<Rightarrow> 'a ref) \<Rightarrow> 'a ref \<Rightarrow> 'a list"
   143  list :: "('a \<Rightarrow> 'a ref) \<Rightarrow> 'a ref \<Rightarrow> 'a list"
   144 "mklist h p == SOME as. list h p as"
   144 "list h p == SOME as. List h p as"
   145 
   145 
   146 lemma list_conv_islist_mklist: "list h p as = (islist h p \<and> as = mklist h p)"
   146 lemma List_conv_islist_list: "List h p as = (islist h p \<and> as = list h p)"
   147 apply(simp add:islist_def mklist_def)
   147 apply(simp add:islist_def list_def)
   148 apply(rule iffI)
   148 apply(rule iffI)
   149 apply(rule conjI)
   149 apply(rule conjI)
   150 apply blast
   150 apply blast
   151 apply(subst some1_equality)
   151 apply(subst some1_equality)
   152   apply(erule list_unique1)
   152   apply(erule List_unique1)
   153  apply assumption
   153  apply assumption
   154 apply(rule refl)
   154 apply(rule refl)
   155 apply simp
   155 apply simp
   156 apply(rule someI_ex)
   156 apply(rule someI_ex)
   157 apply fast
   157 apply fast
   161 by(simp add:islist_def)
   161 by(simp add:islist_def)
   162 
   162 
   163 lemma [simp]: "islist h (Some a) = islist h (h a)"
   163 lemma [simp]: "islist h (Some a) = islist h (h a)"
   164 by(simp add:islist_def)
   164 by(simp add:islist_def)
   165 
   165 
   166 lemma [simp]: "mklist h None = []"
   166 lemma [simp]: "list h None = []"
   167 by(simp add:mklist_def)
   167 by(simp add:list_def)
   168 
   168 
   169 lemma [simp]: "islist h (h a) \<Longrightarrow> mklist h (Some a) = a # mklist h (h a)"
   169 lemma [simp]: "islist h (h a) \<Longrightarrow> list h (Some a) = a # list h (h a)"
   170 apply(insert list_Ref[of h])
   170 apply(insert List_Ref[of h])
   171 apply(fastsimp simp:list_conv_islist_mklist)
   171 apply(fastsimp simp:List_conv_islist_list)
   172 done
   172 done
   173 
   173 
   174 lemma [simp]: "islist h (h a) \<Longrightarrow> a \<notin> set(mklist h (h a))"
   174 lemma [simp]: "islist h (h a) \<Longrightarrow> a \<notin> set(list h (h a))"
   175 apply(insert list_hd_not_in_tl[of h])
   175 apply(insert List_hd_not_in_tl[of h])
   176 apply(simp add:list_conv_islist_mklist)
   176 apply(simp add:List_conv_islist_list)
   177 done
   177 done
   178 
   178 
   179 lemma [simp]:
   179 lemma [simp]:
   180  "islist h p \<Longrightarrow> y \<notin> set(mklist h p) \<Longrightarrow> mklist (h(y := q)) p = mklist h p"
   180  "islist h p \<Longrightarrow> y \<notin> set(list h p) \<Longrightarrow> list (h(y := q)) p = list h p"
   181 apply(drule notin_list_update[of _ _ h q p])
   181 apply(drule notin_List_update[of _ _ h q p])
   182 apply(simp add:list_conv_islist_mklist)
   182 apply(simp add:List_conv_islist_list)
   183 done
   183 done
   184 
   184 
   185 lemma [simp]:
   185 lemma [simp]:
   186  "islist h p \<Longrightarrow> y \<notin> set(mklist h p) \<Longrightarrow> islist (h(y := q)) p"
   186  "islist h p \<Longrightarrow> y \<notin> set(list h p) \<Longrightarrow> islist (h(y := q)) p"
   187 apply(frule notin_list_update[of _ _ h q p])
   187 apply(frule notin_List_update[of _ _ h q p])
   188 apply(simp add:list_conv_islist_mklist)
   188 apply(simp add:List_conv_islist_list)
   189 done
   189 done
   190 
   190 
   191 
   191 
   192 section "Verifications"
   192 section "Verifications"
   193 
   193 
   194 subsection "List reversal"
   194 subsection "List reversal"
   195 
   195 
   196 text "A short but unreadable proof:"
   196 text "A short but unreadable proof:"
   197 
   197 
   198 lemma "|- VARS tl p q r.
   198 lemma "|- VARS tl p q r.
   199   {list tl p Ps \<and> list tl q Qs \<and> set Ps \<inter> set Qs = {}}
   199   {List tl p Ps \<and> List tl q Qs \<and> set Ps \<inter> set Qs = {}}
   200   WHILE p \<noteq> Null
   200   WHILE p \<noteq> Null
   201   INV {\<exists>ps qs. list tl p ps \<and> list tl q qs \<and> set ps \<inter> set qs = {} \<and>
   201   INV {\<exists>ps qs. List tl p ps \<and> List tl q qs \<and> set ps \<inter> set qs = {} \<and>
   202                  rev ps @ qs = rev Ps @ Qs}
   202                  rev ps @ qs = rev Ps @ Qs}
   203   DO r := p; p := p^.tl; r^.tl := q; q := r OD
   203   DO r := p; p := p^.tl; r^.tl := q; q := r OD
   204   {list tl q (rev Ps @ Qs)}"
   204   {List tl q (rev Ps @ Qs)}"
   205 apply vcg_simp
   205 apply vcg_simp
   206   apply fastsimp
   206   apply fastsimp
   207  apply clarify
   207  apply clarify
   208  apply(rename_tac ps b qs)
   208  apply(rename_tac ps b qs)
   209  apply clarsimp
   209  apply clarsimp
   217 
   217 
   218 
   218 
   219 text "A longer readable version:"
   219 text "A longer readable version:"
   220 
   220 
   221 lemma "|- VARS tl p q r.
   221 lemma "|- VARS tl p q r.
   222   {list tl p Ps \<and> list tl q Qs \<and> set Ps \<inter> set Qs = {}}
   222   {List tl p Ps \<and> List tl q Qs \<and> set Ps \<inter> set Qs = {}}
   223   WHILE p \<noteq> Null
   223   WHILE p \<noteq> Null
   224   INV {\<exists>ps qs. list tl p ps \<and> list tl q qs \<and> set ps \<inter> set qs = {} \<and>
   224   INV {\<exists>ps qs. List tl p ps \<and> List tl q qs \<and> set ps \<inter> set qs = {} \<and>
   225                rev ps @ qs = rev Ps @ Qs}
   225                rev ps @ qs = rev Ps @ Qs}
   226   DO r := p; p := p^.tl; r^.tl := q; q := r OD
   226   DO r := p; p := p^.tl; r^.tl := q; q := r OD
   227   {list tl q (rev Ps @ Qs)}"
   227   {List tl q (rev Ps @ Qs)}"
   228 proof vcg
   228 proof vcg
   229   fix tl p q r
   229   fix tl p q r
   230   assume "list tl p Ps \<and> list tl q Qs \<and> set Ps \<inter> set Qs = {}"
   230   assume "List tl p Ps \<and> List tl q Qs \<and> set Ps \<inter> set Qs = {}"
   231   thus "\<exists>ps qs. list tl p ps \<and> list tl q qs \<and> set ps \<inter> set qs = {} \<and>
   231   thus "\<exists>ps qs. List tl p ps \<and> List tl q qs \<and> set ps \<inter> set qs = {} \<and>
   232                 rev ps @ qs = rev Ps @ Qs" by fastsimp
   232                 rev ps @ qs = rev Ps @ Qs" by fastsimp
   233 next
   233 next
   234   fix tl p q r
   234   fix tl p q r
   235   assume "(\<exists>ps qs. list tl p ps \<and> list tl q qs \<and> set ps \<inter> set qs = {} \<and>
   235   assume "(\<exists>ps qs. List tl p ps \<and> List tl q qs \<and> set ps \<inter> set qs = {} \<and>
   236                    rev ps @ qs = rev Ps @ Qs) \<and> p \<noteq> Null"
   236                    rev ps @ qs = rev Ps @ Qs) \<and> p \<noteq> Null"
   237          (is "(\<exists>ps qs. ?I ps qs) \<and> _")
   237          (is "(\<exists>ps qs. ?I ps qs) \<and> _")
   238   then obtain ps qs a where I: "?I ps qs \<and> p = Ref a"
   238   then obtain ps qs a where I: "?I ps qs \<and> p = Ref a"
   239     by fast
   239     by fast
   240   then obtain ps' where "ps = a # ps'" by fastsimp
   240   then obtain ps' where "ps = a # ps'" by fastsimp
   241   hence "list (tl(p \<rightarrow> q)) (p^.tl) ps' \<and>
   241   hence "List (tl(p \<rightarrow> q)) (p^.tl) ps' \<and>
   242          list (tl(p \<rightarrow> q)) p       (a#qs) \<and>
   242          List (tl(p \<rightarrow> q)) p       (a#qs) \<and>
   243          set ps' \<inter> set (a#qs) = {} \<and>
   243          set ps' \<inter> set (a#qs) = {} \<and>
   244          rev ps' @ (a#qs) = rev Ps @ Qs"
   244          rev ps' @ (a#qs) = rev Ps @ Qs"
   245     using I by fastsimp
   245     using I by fastsimp
   246   thus "\<exists>ps' qs'. list (tl(p \<rightarrow> q)) (p^.tl) ps' \<and>
   246   thus "\<exists>ps' qs'. List (tl(p \<rightarrow> q)) (p^.tl) ps' \<and>
   247                   list (tl(p \<rightarrow> q)) p       qs' \<and>
   247                   List (tl(p \<rightarrow> q)) p       qs' \<and>
   248                   set ps' \<inter> set qs' = {} \<and>
   248                   set ps' \<inter> set qs' = {} \<and>
   249                   rev ps' @ qs' = rev Ps @ Qs" by fast
   249                   rev ps' @ qs' = rev Ps @ Qs" by fast
   250 next
   250 next
   251   fix tl p q r
   251   fix tl p q r
   252   assume "(\<exists>ps qs. list tl p ps \<and> list tl q qs \<and> set ps \<inter> set qs = {} \<and>
   252   assume "(\<exists>ps qs. List tl p ps \<and> List tl q qs \<and> set ps \<inter> set qs = {} \<and>
   253                    rev ps @ qs = rev Ps @ Qs) \<and> \<not> p \<noteq> Null"
   253                    rev ps @ qs = rev Ps @ Qs) \<and> \<not> p \<noteq> Null"
   254   thus "list tl q (rev Ps @ Qs)" by fastsimp
   254   thus "List tl q (rev Ps @ Qs)" by fastsimp
   255 qed
   255 qed
   256 
   256 
   257 
   257 
   258 text{* Finaly, the functional version. A bit more verbose, but automatic! *}
   258 text{* Finaly, the functional version. A bit more verbose, but automatic! *}
   259 
   259 
   260 lemma "|- VARS tl p q r.
   260 lemma "|- VARS tl p q r.
   261   {islist tl p \<and> islist tl q \<and>
   261   {islist tl p \<and> islist tl q \<and>
   262    Ps = mklist tl p \<and> Qs = mklist tl q \<and> set Ps \<inter> set Qs = {}}
   262    Ps = list tl p \<and> Qs = list tl q \<and> set Ps \<inter> set Qs = {}}
   263   WHILE p \<noteq> Null
   263   WHILE p \<noteq> Null
   264   INV {islist tl p \<and> islist tl q \<and>
   264   INV {islist tl p \<and> islist tl q \<and>
   265        set(mklist tl p) \<inter> set(mklist tl q) = {} \<and>
   265        set(list tl p) \<inter> set(list tl q) = {} \<and>
   266        rev(mklist tl p) @ (mklist tl q) = rev Ps @ Qs}
   266        rev(list tl p) @ (list tl q) = rev Ps @ Qs}
   267   DO r := p; p := p^.tl; r^.tl := q; q := r OD
   267   DO r := p; p := p^.tl; r^.tl := q; q := r OD
   268   {islist tl q \<and> mklist tl q = rev Ps @ Qs}"
   268   {islist tl q \<and> list tl q = rev Ps @ Qs}"
   269 apply vcg_simp
   269 apply vcg_simp
   270   apply clarsimp
   270   apply clarsimp
   271  apply clarsimp
   271  apply clarsimp
   272 apply clarsimp
   272 apply clarsimp
   273 done
   273 done
   276 subsection "Searching in a list"
   276 subsection "Searching in a list"
   277 
   277 
   278 text{*What follows is a sequence of successively more intelligent proofs that
   278 text{*What follows is a sequence of successively more intelligent proofs that
   279 a simple loop finds an element in a linked list.
   279 a simple loop finds an element in a linked list.
   280 
   280 
   281 We start with a proof based on the @{term list} predicate. This means it only
   281 We start with a proof based on the @{term List} predicate. This means it only
   282 works for acyclic lists. *}
   282 works for acyclic lists. *}
   283 
   283 
   284 lemma "|- VARS tl p. 
   284 lemma "|- VARS tl p. 
   285   {list tl p Ps \<and> X \<in> set Ps}
   285   {List tl p Ps \<and> X \<in> set Ps}
   286   WHILE p \<noteq> Null \<and> p \<noteq> Ref X
   286   WHILE p \<noteq> Null \<and> p \<noteq> Ref X
   287   INV {p \<noteq> Null \<and> (\<exists>ps. list tl p ps \<and> X \<in> set ps)}
   287   INV {p \<noteq> Null \<and> (\<exists>ps. List tl p ps \<and> X \<in> set ps)}
   288   DO p := p^.tl OD
   288   DO p := p^.tl OD
   289   {p = Ref X}"
   289   {p = Ref X}"
   290 apply vcg_simp
   290 apply vcg_simp
   291   apply(case_tac p)
   291   apply(case_tac p)
   292    apply clarsimp
   292    apply clarsimp
   294  apply clarsimp
   294  apply clarsimp
   295  apply fastsimp
   295  apply fastsimp
   296 apply clarsimp
   296 apply clarsimp
   297 done
   297 done
   298 
   298 
   299 text{*Using @{term path} instead of @{term list} generalizes the correctness
   299 text{*Using @{term Path} instead of @{term List} generalizes the correctness
   300 statement to cyclic lists as well: *}
   300 statement to cyclic lists as well: *}
   301 
   301 
   302 lemma "|- VARS tl p. 
   302 lemma "|- VARS tl p. 
   303   {path tl p Ps (Ref X)}
   303   {Path tl p Ps (Ref X)}
   304   WHILE p \<noteq> Null \<and> p \<noteq> Ref X
   304   WHILE p \<noteq> Null \<and> p \<noteq> Ref X
   305   INV {p \<noteq> Null \<and> (\<exists>ps. path tl p ps (Ref X))}
   305   INV {p \<noteq> Null \<and> (\<exists>ps. Path tl p ps (Ref X))}
   306   DO p := p^.tl OD
   306   DO p := p^.tl OD
   307   {p = Ref X}"
   307   {p = Ref X}"
   308 apply vcg_simp
   308 apply vcg_simp
   309   apply(case_tac p)
   309   apply(case_tac p)
   310    apply clarsimp
   310    apply clarsimp
   380 by blast
   380 by blast
   381 
   381 
   382 declare imp_disjL[simp del] imp_disjCL[simp]
   382 declare imp_disjL[simp del] imp_disjCL[simp]
   383 
   383 
   384 lemma "|- VARS hd tl p q r s.
   384 lemma "|- VARS hd tl p q r s.
   385  {list tl p Ps \<and> list tl q Qs \<and> set Ps \<inter> set Qs = {} \<and>
   385  {List tl p Ps \<and> List tl q Qs \<and> set Ps \<inter> set Qs = {} \<and>
   386   (p \<noteq> Null \<or> q \<noteq> Null)}
   386   (p \<noteq> Null \<or> q \<noteq> Null)}
   387  IF if q = Null then True else p \<noteq> Null \<and> p^.hd \<le> q^.hd
   387  IF if q = Null then True else p \<noteq> Null \<and> p^.hd \<le> q^.hd
   388  THEN r := p; p := p^.tl ELSE r := q; q := q^.tl FI;
   388  THEN r := p; p := p^.tl ELSE r := q; q := q^.tl FI;
   389  s := r;
   389  s := r;
   390  WHILE p \<noteq> Null \<or> q \<noteq> Null
   390  WHILE p \<noteq> Null \<or> q \<noteq> Null
   391  INV {EX rs ps qs a. path tl r rs s \<and> list tl p ps \<and> list tl q qs \<and>
   391  INV {EX rs ps qs a. Path tl r rs s \<and> List tl p ps \<and> List tl q qs \<and>
   392       distinct(a # ps @ qs @ rs) \<and> s = Ref a \<and>
   392       distinct(a # ps @ qs @ rs) \<and> s = Ref a \<and>
   393       merge(Ps,Qs,\<lambda>x y. hd x \<le> hd y) =
   393       merge(Ps,Qs,\<lambda>x y. hd x \<le> hd y) =
   394       rs @ a # merge(ps,qs,\<lambda>x y. hd x \<le> hd y) \<and>
   394       rs @ a # merge(ps,qs,\<lambda>x y. hd x \<le> hd y) \<and>
   395       (tl a = p \<or> tl a = q)}
   395       (tl a = p \<or> tl a = q)}
   396  DO IF if q = Null then True else p \<noteq> Null \<and> p^.hd \<le> q^.hd
   396  DO IF if q = Null then True else p \<noteq> Null \<and> p^.hd \<le> q^.hd
   397     THEN s^.tl := p; p := p^.tl ELSE s^.tl := q; q := q^.tl FI;
   397     THEN s^.tl := p; p := p^.tl ELSE s^.tl := q; q := q^.tl FI;
   398     s := s^.tl
   398     s := s^.tl
   399  OD
   399  OD
   400  {list tl r (merge(Ps,Qs,\<lambda>x y. hd x \<le> hd y))}"
   400  {List tl r (merge(Ps,Qs,\<lambda>x y. hd x \<le> hd y))}"
   401 apply vcg_simp
   401 apply vcg_simp
   402 
   402 
   403 apply (fastsimp)
   403 apply (fastsimp)
   404 
   404 
   405 apply clarsimp
   405 apply clarsimp
   445 apply (simp add:eq_sym_conv)
   445 apply (simp add:eq_sym_conv)
   446 apply(rule_tac x = bs in exI)
   446 apply(rule_tac x = bs in exI)
   447 apply (simp add:eq_sym_conv)
   447 apply (simp add:eq_sym_conv)
   448 apply fast
   448 apply fast
   449 
   449 
   450 apply(clarsimp simp add:list_app)
   450 apply(clarsimp simp add:List_app)
   451 done
   451 done
   452 
   452 
   453 (* TODO: functional version of merging *)
   453 (* TODO: functional version of merging *)
   454 
   454 
   455 end
   455 end