diff --git a/thys/Separation_Logic_Imperative_HOL/Examples/Hash_Map_Impl.thy b/thys/Separation_Logic_Imperative_HOL/Examples/Hash_Map_Impl.thy --- a/thys/Separation_Logic_Imperative_HOL/Examples/Hash_Map_Impl.thy +++ b/thys/Separation_Logic_Imperative_HOL/Examples/Hash_Map_Impl.thy @@ -1,84 +1,84 @@ section "Hash-Maps (Interface Instantiations)" theory Hash_Map_Impl imports Imp_Map_Spec Hash_Map begin lemma hm_map_impl: "imp_map is_hashmap" apply unfold_locales apply (rule is_hashmap_prec) done interpretation hm: imp_map is_hashmap by (rule hm_map_impl) lemma hm_empty_impl: "imp_map_empty is_hashmap hm_new" apply unfold_locales apply (sep_auto heap: hm_new_rule) done interpretation hm: imp_map_empty is_hashmap hm_new by (rule hm_empty_impl) lemma hm_lookup_impl: "imp_map_lookup is_hashmap hm_lookup" apply unfold_locales apply (sep_auto heap: hm_lookup_rule) done interpretation hm: imp_map_lookup is_hashmap hm_lookup by (rule hm_lookup_impl) lemma hm_update_impl: "imp_map_update is_hashmap hm_update" apply unfold_locales apply (sep_auto heap: hm_update_rule) done interpretation hm: imp_map_update is_hashmap hm_update by (rule hm_update_impl) lemma hm_delete_impl: "imp_map_delete is_hashmap hm_delete" apply unfold_locales apply (sep_auto heap: hm_delete_rule) done interpretation hm: imp_map_delete is_hashmap hm_delete by (rule hm_delete_impl) lemma hm_is_empty_impl: "imp_map_is_empty is_hashmap hm_isEmpty" apply unfold_locales apply (sep_auto heap: hm_isEmpty_rule) done interpretation hm: imp_map_is_empty is_hashmap hm_isEmpty by (rule hm_is_empty_impl) lemma hm_size_impl: "imp_map_size is_hashmap hm_size" apply unfold_locales apply (sep_auto heap: hm_size_rule) done interpretation hm: imp_map_size is_hashmap hm_size by (rule hm_size_impl) lemma hm_iterate_impl: "imp_map_iterate is_hashmap hm_is_it hm_it_init hm_it_has_next hm_it_next" apply unfold_locales apply (rule hm_it_init_rule) - apply (erule hm_it_next_rule) - apply (rule hm_it_has_next_rule) + apply (sep_auto heap add: hm_it_next_rule) + apply (sep_auto heap add: hm_it_has_next_rule) apply (rule ent_frame_fwd[OF hm_it_finish]) apply (frame_inference) apply solve_entails done interpretation hm: imp_map_iterate is_hashmap hm_is_it hm_it_init hm_it_has_next hm_it_next by (rule hm_iterate_impl) (* definition "hm_is_it'' m ht l' it \ \\<^sub>Al. hm_is_it' l ht l' it * \(map_of (concat l) = m)" lemma hm_iterate'_impl: "imp_map_iterate' is_hashmap hm_is_it'' hm_it_init hm_it_has_next hm_it_next" apply unfold_locales apply (rule hm_it_init_rule) apply (erule hm_it_next_rule) apply (rule hm_it_has_next_rule) apply (rule ent_frame_fwd[OF hm_it_finish]) apply (frame_inference) apply solve_entails done *) export_code hm_new hm_lookup hm_update hm_delete hm_isEmpty hm_size hm_it_init hm_it_has_next hm_it_next checking SML_imp end diff --git a/thys/Separation_Logic_Imperative_HOL/Examples/Idioms.thy b/thys/Separation_Logic_Imperative_HOL/Examples/Idioms.thy --- a/thys/Separation_Logic_Imperative_HOL/Examples/Idioms.thy +++ b/thys/Separation_Logic_Imperative_HOL/Examples/Idioms.thy @@ -1,257 +1,257 @@ section \Common Proof Methods and Idioms\ theory Idioms imports "../Sep_Main" Open_List Circ_List Hash_Set_Impl begin text_raw\\label{thy:ex:idioms}\ text \ This theory gives a short documentation of common proof techniques and idioms for the separation logic framework. For this purpose, it presents some proof snippets (inspired by the other example theories), and heavily comments on them. \ subsection \The Method \sep_auto\\ text \The most versatile method of our framework is \sep_auto\, which integrates the verification condition generator, the entailment solver and some pre- and postprocessing tactics based on the simplifier and classical reasoner. It can be applied to a Hoare-triple or entailment subgoal, and will try to solve it, and any emerging new goals. It stops when the goal is either solved or it gets stuck somewhere.\ text \As a simple example for \sep_auto\ consider the following program that does some operations on two circular lists:\ definition "test \ do { l1 \ cs_empty; l2 \ cs_empty; l1 \ cs_append ''a'' l1; l2 \ cs_append ''c'' l2; l1 \ cs_append ''b'' l1; l2 \ cs_append ''e'' l2; l2 \ cs_prepend ''d'' l2; l2 \ cs_rotate l2; return (l1,l2) }" text \The \sep_auto\ method does all the necessary frame-inference automatically, and thus manages to prove the following lemma in one step:\ lemma " test <\(l1,l2). cs_list [''a'',''b''] l1 * cs_list [''c'',''e'',''d''] l2>\<^sub>t" unfolding test_def apply (sep_auto) done text \\sep_auto\ accepts all the section-options of the classical reasoner and simplifier, e.g., \simp add/del:\, \intro:\. Moreover, it has some more section options, the most useful being \heap add/del:\ to add or remove Hoare-rules that are applied with frame-inference. A complete documentation of the accepted options can be found in Section~\ref{sec:auto:overview}. \ text \As a typical example, consider the following proof:\ lemma complete_ht_rehash: " ht_rehash ht <\r. is_hashtable l ht * is_hashtable (ls_rehash l) r>" proof - have LEN: " l \ [] \ Suc 0 < 2 * length l" by (cases l) auto show ?thesis apply (rule cons_pre_rule[OF ht_imp_len]) unfolding ht_rehash_def apply (sep_auto heap: complete_ht_new_sz complete_ht_copy simp: ls_rehash_def LEN ) \ \Here we add a heap-rule, and some simp-rules\ done qed subsection \Applying Single Rules\ text \\paragraph{Hoare Triples} In this example, we show how to do a proof step-by-step.\ lemma " os_prepend x n " unfolding os_prepend_def txt \The rules to deconstruct compound statements are contained in the \sep_decon_rules\ collection\ thm sep_decon_rules apply (rule sep_decon_rules) txt \The rules for statement that deend on the heap are contained in the \sep_heap_rules\ collection. The \fi_rule\-lemma prepares frame inference for them\ apply (rule sep_heap_rules[THEN fi_rule]) apply frame_inference \ \This method does the frame-inference\ txt \The consequence rule comes in three versions, \const_rule\, \cons_pre_rule\, and \cons_post_rule\\ apply (rule cons_post_rule) apply (rule sep_decon_rules) txt \A simplification unfolds \os_list\ and extract the pure part of the assumption\ apply (clarsimp) txt \We can use \ent_ex_postI\ to manually introduce existentials in entailsments\ apply (rule_tac x=xa in ent_ex_postI) apply (rule_tac x=n in ent_ex_postI) txt \The simplifier has a setup for assertions, so it will do the rest\ apply simp done text \Note that the proof above can be done with \sep_auto\, the "Swiss army knife" of our framework\ lemma " os_prepend x n " unfolding os_prepend_def by sep_auto text \\paragraph{Entailment} This example presents an actual proof from the circular list theory, where we have to manually apply a rule and give some hints to frame inference\ lemma cs_append_rule: " cs_append x p " apply (cases p) apply (sep_auto simp: cs_append.simps) apply (sep_auto simp: cs_append.simps heap: lseg_append) txt \At this point, we are left with an entailment subgoal that sep-auto cannot solve. A closer look reveals that we could use the rule \lseg_append\. With the \ent_frame_fwd\-rule, we can manually apply a rule to solve an entailment, involving frame inference. In this case, we have the additional problem that frame-inference guesses a wrong instantiation, and is not able to infer the frame. So we have to pre-instantiate the rule, as done below.\ apply (rule_tac s1=a in ent_frame_fwd[OF lseg_append]) apply frame_inference \ \Now frame-inference is able to infer the frame\ txt \Now we are left with a trivial entailment, modulo commutativity of star. This can be handled by the entailment solver:\ apply solve_entails done subsection \Functions with Explicit Recursion\ text \If the termination argument of a function depends on one of its parameters, we can use the function package. For example, the following function inserts elements from a list into a hash-set:\ fun ins_from_list :: "('x::{heap,hashable}) list \ 'x hashset \ 'x hashset Heap" where "ins_from_list [] hs = return hs" | "ins_from_list (x # l) hs = do { hs \ hs_ins x hs; ins_from_list l hs }" text \Proofs over such functions are usually done by structural induction on the explicit parameter, in this case, on the list\ lemma ins_from_list_correct: " ins_from_list l hs set l)>\<^sub>t" proof (induction l arbitrary: hs s) case (Cons x l) txt \In the induction step, the induction hypothesis has to be declared as a heap-rule, as \sep_auto\ currently does not look for potential heap-rules among the premises of the subgoal\ show ?case by (sep_auto heap: Cons.IH) qed sep_auto subsection \ Functions with Recursion Involving the Heap \ text \If the termination argument of a function depends on data stored on the heap, \partial_function\ is a useful tool. Note that, despite the name, proving a Hoare-Triple \<\> \ <\>\ for something defined with \partial_function\ implies total correctness. \ text \In the following example, we compute the sum of a list, using an iterator. Note that the partial-function package does not provide a code generator setup by default, so we have to add a \[code]\ attribute manually\ partial_function (heap) os_sum' :: "int os_list_it \ int \ int Heap" where [code]: "os_sum' it s = do { b \ os_it_has_next it; if b then do { (x,it') \ os_it_next it; os_sum' it' (s+x) } else return s }" text \The proof that the function is correct can be done by induction over the representation of the list that we still have to iterate over. Note that for iterators over sets, we need induction on finite sets, cf. also \To_List_Ga.thy\\ lemma os_sum'_rule: " os_sum' it s <\r. os_list l p * \(r = s + sum_list l')>\<^sub>t" proof (induct l' arbitrary: it s) case Nil thus ?case txt \To unfold the definition of a partial function, we have to use \subst\. Note that \simp\ would loop, unfolding the function arbitrarily deep\ apply (subst os_sum'.simps) txt \\sep_auto\ accepts all the section parameters that \auto\ does, eg. \intro:\\ - apply (sep_auto intro: os.quit_iteration) + apply (sep_auto intro: os.quit_iteration ent_true_drop) done next case (Cons x l') show ?case apply (subst os_sum'.simps) txt \Additionally, \sep_auto\ accepts some more section parameters. The most common one, \heap:\, declares rules to be used with frame inference. See Section~\ref{sec:auto:overview} for a complete overview.\ apply (sep_auto heap: Cons.hyps) done qed subsection \Precision Proofs\ text \ Precision lemmas show that an assertion uniquely determines some of its parameters. Our example shows that two list segments from the same start pointer and with the same list, also have to end at the same end pointer. \ lemma lseg_prec3: "\q q'. h \ (lseg l p q * F1) \\<^sub>A (lseg l p q' * F2) \ q=q'" apply (intro allI) proof (induct l arbitrary: p F1 F2) case Nil thus ?case apply simp \ \A precision solver for references and arrays is included in the standard simplifier setup. Building a general precision solver remains future work.\ by metis \ \Unfortunately, the simplifier cannot cope with arbitrarily directed equations, so we have to use some more powerful tool\ next case (Cons x l) show ?case apply clarsimp apply (subgoal_tac "na=n") txt \The \prec_frame\ and \prec_frame'\ rules are useful to do precision proofs\ apply (erule prec_frame'[OF Cons.hyps]) apply frame_inference apply frame_inference apply (drule prec_frame[OF sngr_prec]) apply frame_inference apply frame_inference apply simp done qed end diff --git a/thys/Separation_Logic_Imperative_HOL/Examples/Imp_List_Spec.thy b/thys/Separation_Logic_Imperative_HOL/Examples/Imp_List_Spec.thy --- a/thys/Separation_Logic_Imperative_HOL/Examples/Imp_List_Spec.thy +++ b/thys/Separation_Logic_Imperative_HOL/Examples/Imp_List_Spec.thy @@ -1,85 +1,85 @@ section \Interface for Lists\ theory Imp_List_Spec imports "../Sep_Main" begin text \ This file specifies an abstract interface for list data structures. It can be implemented by concrete list data structures, as demonstrated in the open and circular singly linked list examples. \ locale imp_list = fixes is_list :: "'a list \ 'l \ assn" assumes precise: "precise is_list" (*"\l l'. h\(is_list l p * F1) \\<^sub>A (is_list l' p * F2) \ l=l'"*) locale imp_list_empty = imp_list + constrains is_list :: "'a list \ 'l \ assn" fixes empty :: "'l Heap" assumes empty_rule[sep_heap_rules]: " empty \<^sub>t" locale imp_list_is_empty = imp_list + constrains is_list :: "'a list \ 'l \ assn" fixes is_empty :: "'l \ bool Heap" assumes is_empty_rule[sep_heap_rules]: " is_empty p <\r. is_list l p * \(r \ l=[])>\<^sub>t" locale imp_list_append = imp_list + constrains is_list :: "'a list \ 'l \ assn" fixes append :: "'a \ 'l \ 'l Heap" assumes append_rule[sep_heap_rules]: " append a p \<^sub>t" locale imp_list_prepend = imp_list + constrains is_list :: "'a list \ 'l \ assn" fixes prepend :: "'a \ 'l \ 'l Heap" assumes prepend_rule[sep_heap_rules]: " prepend a p \<^sub>t" locale imp_list_head = imp_list + constrains is_list :: "'a list \ 'l \ assn" fixes head :: "'l \ 'a Heap" assumes head_rule[sep_heap_rules]: "l\[] \ head p <\r. is_list l p * \(r=hd l)>\<^sub>t" locale imp_list_pop = imp_list + constrains is_list :: "'a list \ 'l \ assn" fixes pop :: "'l \ ('a\'l) Heap" assumes pop_rule[sep_heap_rules]: "l\[] \ pop p <\(r,p'). is_list (tl l) p' * \(r=hd l)>\<^sub>t" locale imp_list_rotate = imp_list + constrains is_list :: "'a list \ 'l \ assn" fixes rotate :: "'l \ 'l Heap" assumes rotate_rule[sep_heap_rules]: " rotate p \<^sub>t" locale imp_list_reverse = imp_list + constrains is_list :: "'a list \ 'l \ assn" fixes reverse :: "'l \ 'l Heap" assumes reverse_rule[sep_heap_rules]: " reverse p \<^sub>t" locale imp_list_iterate = imp_list + constrains is_list :: "'a list \ 'l \ assn" fixes is_it :: "'a list \ 'l \ 'a list \ 'it \ assn" fixes it_init :: "'l \ ('it) Heap" fixes it_has_next :: "'it \ bool Heap" fixes it_next :: "'it \ ('a\'it) Heap" assumes it_init_rule[sep_heap_rules]: " it_init p \<^sub>t" assumes it_next_rule[sep_heap_rules]: "l'\[] \ it_next it - <\(a,it'). is_it l p (tl l') it' * \(a=hd l')>" + <\(a,it'). is_it l p (tl l') it' * \(a=hd l')>\<^sub>t" assumes it_has_next_rule[sep_heap_rules]: " it_has_next it - <\r. is_it l p l' it * \(r\l'\[])>" + <\r. is_it l p l' it * \(r\l'\[])>\<^sub>t" assumes quit_iteration: "is_it l p l' it \\<^sub>A is_list l p * true" end diff --git a/thys/Separation_Logic_Imperative_HOL/Examples/Imp_Map_Spec.thy b/thys/Separation_Logic_Imperative_HOL/Examples/Imp_Map_Spec.thy --- a/thys/Separation_Logic_Imperative_HOL/Examples/Imp_Map_Spec.thy +++ b/thys/Separation_Logic_Imperative_HOL/Examples/Imp_Map_Spec.thy @@ -1,92 +1,92 @@ section \Interface for Maps\ theory Imp_Map_Spec imports "../Sep_Main" begin text \ This file specifies an abstract interface for map data structures. It can be implemented by concrete map data structures, as demonstrated in the hash map example. \ locale imp_map = fixes is_map :: "('k \ 'v) \ 'm \ assn" assumes precise: "precise is_map" locale imp_map_empty = imp_map + constrains is_map :: "('k \ 'v) \ 'm \ assn" fixes empty :: "'m Heap" assumes empty_rule[sep_heap_rules]: " empty \<^sub>t" locale imp_map_is_empty = imp_map + constrains is_map :: "('k \ 'v) \ 'm \ assn" fixes is_empty :: "'m \ bool Heap" assumes is_empty_rule[sep_heap_rules]: " is_empty p <\r. is_map m p * \(r \ m=Map.empty)>\<^sub>t" locale imp_map_lookup = imp_map + constrains is_map :: "('k \ 'v) \ 'm \ assn" fixes lookup :: "'k \ 'm \ ('v option) Heap" assumes lookup_rule[sep_heap_rules]: " lookup k p <\r. is_map m p * \(r = m k)>\<^sub>t" locale imp_map_update = imp_map + constrains is_map :: "('k \ 'v) \ 'm \ assn" fixes update :: "'k \ 'v \ 'm \ 'm Heap" assumes update_rule[sep_heap_rules]: " update k v p v))>\<^sub>t" locale imp_map_delete = imp_map + constrains is_map :: "('k \ 'v) \ 'm \ assn" fixes delete :: "'k \ 'm \ 'm Heap" assumes delete_rule[sep_heap_rules]: " delete k p \<^sub>t" locale imp_map_add = imp_map + constrains is_map :: "('k \ 'v) \ 'm \ assn" fixes add :: "'m \ 'm \ 'm Heap" assumes add_rule[sep_heap_rules]: " add p p' <\r. is_map m p * is_map m' p' * is_map (m ++ m') r>\<^sub>t" locale imp_map_size = imp_map + constrains is_map :: "('k \ 'v) \ 'm \ assn" fixes size :: "'m \ nat Heap" assumes size_rule[sep_heap_rules]: " size p <\r. is_map m p * \(r = card (dom m))>\<^sub>t" locale imp_map_iterate = imp_map + constrains is_map :: "('k \ 'v) \ 'm \ assn" fixes is_it :: "('k \ 'v) \ 'm \ ('k \ 'v) \ 'it \ assn" fixes it_init :: "'m \ ('it) Heap" fixes it_has_next :: "'it \ bool Heap" fixes it_next :: "'it \ (('k\'v)\'it) Heap" assumes it_init_rule[sep_heap_rules]: " it_init p \<^sub>t" assumes it_next_rule[sep_heap_rules]: "m'\Map.empty \ it_next it - <\((k,v),it'). is_it m p (m' |` (-{k})) it' * \(m' k = Some v)>" + <\((k,v),it'). is_it m p (m' |` (-{k})) it' * \(m' k = Some v)>\<^sub>t" assumes it_has_next_rule[sep_heap_rules]: - " it_has_next it <\r. is_it m p m' it * \(r\m'\Map.empty)>" + " it_has_next it <\r. is_it m p m' it * \(r\m'\Map.empty)>\<^sub>t" assumes quit_iteration: "is_it m p m' it \\<^sub>A is_map m p * true" locale imp_map_iterate' = imp_map + constrains is_map :: "('k \ 'v) \ 'm \ assn" fixes is_it :: "('k \ 'v) \ 'm \ ('k\'v) list \ 'it \ assn" fixes it_init :: "'m \ ('it) Heap" fixes it_has_next :: "'it \ bool Heap" fixes it_next :: "'it \ (('k\'v)\'it) Heap" assumes it_init_rule[sep_heap_rules]: " it_init p <\r. \\<^sub>Al. \(map_of l = s) * is_it s p l r>\<^sub>t" assumes it_next_rule[sep_heap_rules]: " it_next it <\(kv',it'). is_it m p l it' * \(kv'=kv)>" assumes it_has_next_rule[sep_heap_rules]: " it_has_next it <\r. is_it m p l it * \(r\l\[])>" assumes quit_iteration: "is_it m p l it \\<^sub>A is_map m p * true" end diff --git a/thys/Separation_Logic_Imperative_HOL/Examples/Imp_Set_Spec.thy b/thys/Separation_Logic_Imperative_HOL/Examples/Imp_Set_Spec.thy --- a/thys/Separation_Logic_Imperative_HOL/Examples/Imp_Set_Spec.thy +++ b/thys/Separation_Logic_Imperative_HOL/Examples/Imp_Set_Spec.thy @@ -1,67 +1,67 @@ section \Interface for Sets\ theory Imp_Set_Spec imports "../Sep_Main" begin text \ This file specifies an abstract interface for set data structures. It can be implemented by concrete set data structures, as demonstrated in the hash set example. \ locale imp_set = fixes is_set :: "'a set \ 's \ assn" assumes precise: "precise is_set" locale imp_set_empty = imp_set + constrains is_set :: "'a set \ 's \ assn" fixes empty :: "'s Heap" assumes empty_rule[sep_heap_rules]: " empty \<^sub>t" locale imp_set_is_empty = imp_set + constrains is_set :: "'a set \ 's \ assn" fixes is_empty :: "'s \ bool Heap" assumes is_empty_rule[sep_heap_rules]: " is_empty p <\r. is_set s p * \(r \ s={})>\<^sub>t" locale imp_set_memb = imp_set + constrains is_set :: "'a set \ 's \ assn" fixes memb :: "'a \ 's \ bool Heap" assumes memb_rule[sep_heap_rules]: " memb a p <\r. is_set s p * \(r \ a \ s)>\<^sub>t" locale imp_set_ins = imp_set + constrains is_set :: "'a set \ 's \ assn" fixes ins :: "'a \ 's \ 's Heap" assumes ins_rule[sep_heap_rules]: " ins a p \<^sub>t" locale imp_set_delete = imp_set + constrains is_set :: "'a set \ 's \ assn" fixes delete :: "'a \ 's \ 's Heap" assumes delete_rule[sep_heap_rules]: " delete a p \<^sub>t" locale imp_set_size = imp_set + constrains is_set :: "'a set \ 's \ assn" fixes size :: "'s \ nat Heap" assumes size_rule[sep_heap_rules]: " size p <\r. is_set s p * \(r = card s)>\<^sub>t" locale imp_set_iterate = imp_set + constrains is_set :: "'a set \ 's \ assn" fixes is_it :: "'a set \ 's \ 'a set \ 'it \ assn" fixes it_init :: "'s \ ('it) Heap" fixes it_has_next :: "'it \ bool Heap" fixes it_next :: "'it \ ('a\'it) Heap" assumes it_init_rule[sep_heap_rules]: " it_init p \<^sub>t" assumes it_next_rule[sep_heap_rules]: "s'\{} \ it_next it - <\(a,it'). is_it s p (s' - {a}) it' * \(a \ s')>" + <\(a,it'). is_it s p (s' - {a}) it' * \(a \ s')>\<^sub>t" assumes it_has_next_rule[sep_heap_rules]: - " it_has_next it <\r. is_it s p s' it * \(r\s'\{})>" + " it_has_next it <\r. is_it s p s' it * \(r\s'\{})>\<^sub>t" assumes quit_iteration: "is_it s p s' it \\<^sub>A is_set s p * true" end diff --git a/thys/Separation_Logic_Imperative_HOL/Examples/Open_List.thy b/thys/Separation_Logic_Imperative_HOL/Examples/Open_List.thy --- a/thys/Separation_Logic_Imperative_HOL/Examples/Open_List.thy +++ b/thys/Separation_Logic_Imperative_HOL/Examples/Open_List.thy @@ -1,302 +1,303 @@ section \Open Singly Linked Lists\ theory Open_List imports List_Seg Imp_List_Spec begin subsection \Definitions\ type_synonym 'a os_list = "'a node ref option" abbreviation os_list :: "'a list \ ('a::heap) os_list \ assn" where "os_list l p \ lseg l p None" subsection \Precision\ lemma os_prec: "precise os_list" by rule (simp add: lseg_prec2) lemma os_imp_list_impl: "imp_list os_list" apply unfold_locales apply (rule os_prec) done interpretation os: imp_list os_list by (rule os_imp_list_impl) subsection \Operations\ subsubsection \Allocate Empty List\ definition os_empty :: "'a::heap os_list Heap" where "os_empty \ return None" lemma os_empty_rule: " os_empty " unfolding os_empty_def apply sep_auto done lemma os_empty_impl: "imp_list_empty os_list os_empty" apply unfold_locales apply (sep_auto heap add: os_empty_rule) done interpretation os: imp_list_empty os_list os_empty by (rule os_empty_impl) subsubsection \Emptiness check\ text \A linked list is empty, iff it is the null pointer.\ definition os_is_empty :: "'a::heap os_list \ bool Heap" where "os_is_empty b \ return (b = None)" lemma os_is_empty_rule: " os_is_empty b <\r. os_list xs b * \(r \ xs = [])>" unfolding os_is_empty_def apply sep_auto done lemma os_is_empty_impl: "imp_list_is_empty os_list os_is_empty" apply unfold_locales apply (sep_auto heap add: os_is_empty_rule) done interpretation os: imp_list_is_empty os_list os_is_empty by (rule os_is_empty_impl) subsubsection \Prepend\ text \To push an element to the front of a list we allocate a new node which stores the element and the old list as successor. The new list is the new allocated reference.\ definition os_prepend :: "'a \ 'a::heap os_list \ 'a os_list Heap" where "os_prepend a n = do { p \ ref (Node a n); return (Some p) }" lemma os_prepend_rule: " os_prepend x n " unfolding os_prepend_def apply sep_auto done lemma os_prepend_impl: "imp_list_prepend os_list os_prepend" apply unfold_locales apply (sep_auto heap add: os_prepend_rule) done interpretation os: imp_list_prepend os_list os_prepend by (rule os_prepend_impl) subsubsection\Pop\ text \To pop the first element out of the list we look up the value and the reference of the node and return the pair of those.\ fun os_pop :: "'a::heap os_list \ ('a \ 'a os_list) Heap" where "os_pop None = raise STR ''Empty Os_list''" | "os_pop (Some p) = do {m \ !p; return (val m, next m)}" declare os_pop.simps[simp del] lemma os_pop_rule: "xs \ [] \ os_pop r <\(x,r'). os_list (tl xs) r' * (the r) \\<^sub>r (Node x r') * \(x = hd xs)>" apply (cases r, simp_all) apply (cases xs, simp_all) apply (sep_auto simp: os_pop.simps) done lemma os_pop_impl: "imp_list_pop os_list os_pop" apply unfold_locales apply (sep_auto heap add: os_pop_rule) done interpretation os: imp_list_pop os_list os_pop by (rule os_pop_impl) subsubsection \Reverse\ text \The following reversal function is equivalent to the one from Imperative HOL. And gives a more difficult example.\ partial_function (heap) os_reverse_aux :: "'a::heap os_list \ 'a os_list \ 'a os_list Heap" where [code]: "os_reverse_aux q p = (case p of None \ return q | Some r \ do { v \ !r; r := Node (val v) q; os_reverse_aux p (next v) })" lemma [simp, sep_dflt_simps]: "os_reverse_aux q None = return q" "os_reverse_aux q (Some r) = do { v \ !r; r := Node (val v) q; os_reverse_aux (Some r) (next v) }" apply (subst os_reverse_aux.simps) apply simp apply (subst os_reverse_aux.simps) apply simp done definition "os_reverse p = os_reverse_aux None p" lemma os_reverse_aux_rule: " os_reverse_aux q p " proof (induct xs arbitrary: p q ys) case Nil thus ?case apply sep_auto done next case (Cons x xs) show ?case apply (cases p, simp_all) apply (sep_auto heap add: cons_pre_rule[OF _ Cons.hyps]) done qed lemma os_reverse_rule: " os_reverse p " unfolding os_reverse_def apply (auto simp: os_reverse_aux_rule[where ys="[]", simplified, rule_format]) done lemma os_reverse_impl: "imp_list_reverse os_list os_reverse" apply unfold_locales apply (sep_auto heap add: os_reverse_rule) done interpretation os: imp_list_reverse os_list os_reverse by (rule os_reverse_impl) subsubsection \Remove\ text \Remove all appearances of an element from a linked list.\ partial_function (heap) os_rem :: "'a::heap \ 'a node ref option \ 'a node ref option Heap" where [code]: "os_rem x b = (case b of None \ return None | Some p \ do { n \ !p; q \ os_rem x (next n); (if (val n = x) then return q else do { p := Node (val n) q; return (Some p) }) })" lemma [simp, sep_dflt_simps]: "os_rem x None = return None" "os_rem x (Some p) = do { n \ !p; q \ os_rem x (next n); (if (val n = x) then return q else do { p := Node (val n) q; return (Some p) }) }" apply (subst os_rem.simps, simp)+ done lemma os_rem_rule[sep_heap_rules]: " os_rem x b <\r. os_list (removeAll x xs) r * true>" proof (induct xs arbitrary: b x) (* Have to generalize over x, as sep_auto preprocessor introduces a new variable. Alternative: No preprocessing. (See alternative proof below) *) case Nil show ?case apply sep_auto done next case (Cons y xs) show ?case by (sep_auto heap add: Cons.hyps) qed lemma os_rem_rule_alt_proof: " os_rem x b <\r. os_list (removeAll x xs) r * true>" proof (induct xs arbitrary: b) case Nil show ?case apply sep_auto done next case (Cons y xs) show ?case by (sep_auto (nopre) heap add: Cons.hyps) (* Switching off preprocessor *) qed subsubsection \Iterator\ type_synonym 'a os_list_it = "'a os_list" definition "os_is_it l p l2 it \ \\<^sub>Al1. \(l=l1@l2) * lseg l1 p it * os_list l2 it" definition os_it_init :: "'a os_list \ ('a os_list_it) Heap" where "os_it_init l = return l" fun os_it_next where "os_it_next (Some p) = do { n \ !p; return (val n,next n) }" definition os_it_has_next :: "'a os_list_it \ bool Heap" where "os_it_has_next it \ return (it\None)" lemma os_iterate_impl: "imp_list_iterate os_list os_is_it os_it_init os_it_has_next os_it_next" apply unfold_locales unfolding os_it_init_def os_is_it_def[abs_def] apply sep_auto apply (case_tac it, simp) apply (case_tac l', simp) apply sep_auto apply (rule ent_frame_fwd[OF lseg_append]) apply frame_inference apply simp + apply (sep_auto) unfolding os_it_has_next_def apply (sep_auto elim!: neq_NilE) apply solve_entails apply (rule ent_frame_fwd[OF lseg_conc]) apply frame_inference apply solve_entails done interpretation os: imp_list_iterate os_list os_is_it os_it_init os_it_has_next os_it_next by (rule os_iterate_impl) subsubsection \List-Sum\ partial_function (heap) os_sum' :: "int os_list_it \ int \ int Heap" where [code]: "os_sum' it s = do { b \ os_it_has_next it; if b then do { (x,it') \ os_it_next it; os_sum' it' (s+x) } else return s }" lemma os_sum'_rule[sep_heap_rules]: " os_sum' it s <\r. os_list l p * \(r = s + sum_list l')>\<^sub>t" proof (induct l' arbitrary: it s) case Nil thus ?case apply (subst os_sum'.simps) - apply (sep_auto intro: os.quit_iteration) + apply (sep_auto intro: os.quit_iteration ent_true_drop(1)) done next case (Cons x l') show ?case apply (subst os_sum'.simps) apply (sep_auto heap: Cons.hyps) done qed definition "os_sum p \ do { it \ os_it_init p; os_sum' it 0}" lemma os_sum_rule[sep_heap_rules]: " os_sum p <\r. os_list l p * \(r=sum_list l)>\<^sub>t" unfolding os_sum_def by sep_auto end