| author | haftmann | 
| Fri, 04 Aug 2017 08:12:54 +0200 | |
| changeset 66335 | a849ce33923d | 
| parent 63684 | 905d3fc815ff | 
| child 67091 | 1393c2340eec | 
| permissions | -rw-r--r-- | 
| 46237 | 1 | (* Title: HOL/Library/DAList.thy | 
| 58806 | 2 | Author: Lukas Bulwahn, TU Muenchen | 
| 3 | *) | |
| 46167 | 4 | |
| 58881 | 5 | section \<open>Abstract type of association lists with unique keys\<close> | 
| 46167 | 6 | |
| 46237 | 7 | theory DAList | 
| 46238 
9ace9e5b79be
renaming theory AList_Impl back to AList (reverting 1fec5b365f9b; AList with distinct key invariant is called DAList)
 bulwahn parents: 
46237diff
changeset | 8 | imports AList | 
| 46167 | 9 | begin | 
| 10 | ||
| 58806 | 11 | text \<open>This was based on some existing fragments in the AFP-Collection framework.\<close> | 
| 46167 | 12 | |
| 58806 | 13 | subsection \<open>Preliminaries\<close> | 
| 47143 
212f7a975d49
association lists with distinct keys uses the quotient infrastructure to obtain code certificates;
 bulwahn parents: 
46507diff
changeset | 14 | |
| 
212f7a975d49
association lists with distinct keys uses the quotient infrastructure to obtain code certificates;
 bulwahn parents: 
46507diff
changeset | 15 | lemma distinct_map_fst_filter: | 
| 58806 | 16 | "distinct (map fst xs) \<Longrightarrow> distinct (map fst (List.filter P xs))" | 
| 17 | by (induct xs) auto | |
| 18 | ||
| 47143 
212f7a975d49
association lists with distinct keys uses the quotient infrastructure to obtain code certificates;
 bulwahn parents: 
46507diff
changeset | 19 | |
| 61585 | 20 | subsection \<open>Type \<open>('key, 'value) alist\<close>\<close>
 | 
| 46167 | 21 | |
| 58806 | 22 | typedef ('key, 'value) alist = "{xs :: ('key \<times> 'value) list. (distinct \<circ> map fst) xs}"
 | 
| 46507 | 23 | morphisms impl_of Alist | 
| 24 | proof | |
| 58806 | 25 |   show "[] \<in> {xs. (distinct o map fst) xs}"
 | 
| 26 | by simp | |
| 46507 | 27 | qed | 
| 46167 | 28 | |
| 47143 
212f7a975d49
association lists with distinct keys uses the quotient infrastructure to obtain code certificates;
 bulwahn parents: 
46507diff
changeset | 29 | setup_lifting type_definition_alist | 
| 
212f7a975d49
association lists with distinct keys uses the quotient infrastructure to obtain code certificates;
 bulwahn parents: 
46507diff
changeset | 30 | |
| 46167 | 31 | lemma alist_ext: "impl_of xs = impl_of ys \<Longrightarrow> xs = ys" | 
| 58806 | 32 | by (simp add: impl_of_inject) | 
| 46167 | 33 | |
| 34 | lemma alist_eq_iff: "xs = ys \<longleftrightarrow> impl_of xs = impl_of ys" | |
| 58806 | 35 | by (simp add: impl_of_inject) | 
| 46167 | 36 | |
| 37 | lemma impl_of_distinct [simp, intro]: "distinct (map fst (impl_of xs))" | |
| 58806 | 38 | using impl_of[of xs] by simp | 
| 46167 | 39 | |
| 40 | lemma Alist_impl_of [code abstype]: "Alist (impl_of xs) = xs" | |
| 58806 | 41 | by (rule impl_of_inverse) | 
| 46167 | 42 | |
| 58806 | 43 | |
| 44 | subsection \<open>Primitive operations\<close> | |
| 46167 | 45 | |
| 55565 
f663fc1e653b
simplify proofs because of the stronger reflexivity prover
 kuncar parents: 
51143diff
changeset | 46 | lift_definition lookup :: "('key, 'value) alist \<Rightarrow> 'key \<Rightarrow> 'value option" is map_of  .
 | 
| 46167 | 47 | |
| 58806 | 48 | lift_definition empty :: "('key, 'value) alist" is "[]"
 | 
| 49 | by simp | |
| 46167 | 50 | |
| 47308 | 51 | lift_definition update :: "'key \<Rightarrow> 'value \<Rightarrow> ('key, 'value) alist \<Rightarrow> ('key, 'value) alist"
 | 
| 52 | is AList.update | |
| 58806 | 53 | by (simp add: distinct_update) | 
| 46167 | 54 | |
| 55 | (* FIXME: we use an unoptimised delete operation. *) | |
| 47308 | 56 | lift_definition delete :: "'key \<Rightarrow> ('key, 'value) alist \<Rightarrow> ('key, 'value) alist"
 | 
| 57 | is AList.delete | |
| 58806 | 58 | by (simp add: distinct_delete) | 
| 46167 | 59 | |
| 58806 | 60 | lift_definition map_entry :: | 
| 61 |     "'key \<Rightarrow> ('value \<Rightarrow> 'value) \<Rightarrow> ('key, 'value) alist \<Rightarrow> ('key, 'value) alist"
 | |
| 47308 | 62 | is AList.map_entry | 
| 58806 | 63 | by (simp add: distinct_map_entry) | 
| 46167 | 64 | |
| 47308 | 65 | lift_definition filter :: "('key \<times> 'value \<Rightarrow> bool) \<Rightarrow> ('key, 'value) alist \<Rightarrow> ('key, 'value) alist"
 | 
| 66 | is List.filter | |
| 58806 | 67 | by (simp add: distinct_map_fst_filter) | 
| 46167 | 68 | |
| 58806 | 69 | lift_definition map_default :: | 
| 70 |     "'key \<Rightarrow> 'value \<Rightarrow> ('value \<Rightarrow> 'value) \<Rightarrow> ('key, 'value) alist \<Rightarrow> ('key, 'value) alist"
 | |
| 47308 | 71 | is AList.map_default | 
| 58806 | 72 | by (simp add: distinct_map_default) | 
| 46167 | 73 | |
| 58806 | 74 | |
| 75 | subsection \<open>Abstract operation properties\<close> | |
| 46167 | 76 | |
| 77 | (* FIXME: to be completed *) | |
| 78 | ||
| 79 | lemma lookup_empty [simp]: "lookup empty k = None" | |
| 63684 | 80 | by (simp add: empty_def lookup_def Alist_inverse) | 
| 81 | ||
| 82 | lemma lookup_update: | |
| 83 | "lookup (update k1 v xs) k2 = (if k1 = k2 then Some v else lookup xs k2)" | |
| 84 | by(transfer)(simp add: update_conv') | |
| 85 | ||
| 86 | lemma lookup_update_eq [simp]: | |
| 87 | "k1 = k2 \<Longrightarrow> lookup (update k1 v xs) k2 = Some v" | |
| 88 | by(simp add: lookup_update) | |
| 89 | ||
| 90 | lemma lookup_update_neq [simp]: | |
| 91 | "k1 \<noteq> k2 \<Longrightarrow> lookup (update k1 v xs) k2 = lookup xs k2" | |
| 92 | by(simp add: lookup_update) | |
| 93 | ||
| 94 | lemma update_update_eq [simp]: | |
| 95 | "k1 = k2 \<Longrightarrow> update k2 v2 (update k1 v1 xs) = update k2 v2 xs" | |
| 96 | by(transfer)(simp add: update_conv') | |
| 46167 | 97 | |
| 98 | lemma lookup_delete [simp]: "lookup (delete k al) = (lookup al)(k := None)" | |
| 58806 | 99 | by (simp add: lookup_def delete_def Alist_inverse distinct_delete delete_conv') | 
| 46167 | 100 | |
| 58806 | 101 | |
| 102 | subsection \<open>Further operations\<close> | |
| 46167 | 103 | |
| 58806 | 104 | subsubsection \<open>Equality\<close> | 
| 46167 | 105 | |
| 58806 | 106 | instantiation alist :: (equal, equal) equal | 
| 107 | begin | |
| 46167 | 108 | |
| 109 | definition "HOL.equal (xs :: ('a, 'b) alist) ys == impl_of xs = impl_of ys"
 | |
| 110 | ||
| 111 | instance | |
| 60679 | 112 | by standard (simp add: equal_alist_def impl_of_inject) | 
| 46167 | 113 | |
| 114 | end | |
| 115 | ||
| 58806 | 116 | |
| 117 | subsubsection \<open>Size\<close> | |
| 46167 | 118 | |
| 58806 | 119 | instantiation alist :: (type, type) size | 
| 120 | begin | |
| 46167 | 121 | |
| 122 | definition "size (al :: ('a, 'b) alist) = length (impl_of al)"
 | |
| 123 | ||
| 124 | instance .. | |
| 125 | ||
| 126 | end | |
| 127 | ||
| 58806 | 128 | |
| 129 | subsection \<open>Quickcheck generators\<close> | |
| 46167 | 130 | |
| 131 | notation fcomp (infixl "\<circ>>" 60) | |
| 132 | notation scomp (infixl "\<circ>\<rightarrow>" 60) | |
| 133 | ||
| 134 | definition (in term_syntax) | |
| 135 |   valterm_empty :: "('key :: typerep, 'value :: typerep) alist \<times> (unit \<Rightarrow> Code_Evaluation.term)"
 | |
| 58806 | 136 | where "valterm_empty = Code_Evaluation.valtermify empty" | 
| 46167 | 137 | |
| 138 | definition (in term_syntax) | |
| 139 | valterm_update :: "'key :: typerep \<times> (unit \<Rightarrow> Code_Evaluation.term) \<Rightarrow> | |
| 140 | 'value :: typerep \<times> (unit \<Rightarrow> Code_Evaluation.term) \<Rightarrow> | |
| 141 |   ('key, 'value) alist \<times> (unit \<Rightarrow> Code_Evaluation.term) \<Rightarrow>
 | |
| 142 |   ('key, 'value) alist \<times> (unit \<Rightarrow> Code_Evaluation.term)" where
 | |
| 143 |   [code_unfold]: "valterm_update k v a = Code_Evaluation.valtermify update {\<cdot>} k {\<cdot>} v {\<cdot>}a"
 | |
| 144 | ||
| 58806 | 145 | fun (in term_syntax) random_aux_alist | 
| 46167 | 146 | where | 
| 58806 | 147 | "random_aux_alist i j = | 
| 148 | (if i = 0 then Pair valterm_empty | |
| 149 | else Quickcheck_Random.collapse | |
| 150 | (Random.select_weight | |
| 151 | [(i, Quickcheck_Random.random j \<circ>\<rightarrow> (\<lambda>k. Quickcheck_Random.random j \<circ>\<rightarrow> | |
| 152 | (\<lambda>v. random_aux_alist (i - 1) j \<circ>\<rightarrow> (\<lambda>a. Pair (valterm_update k v a))))), | |
| 153 | (1, Pair valterm_empty)]))" | |
| 46167 | 154 | |
| 155 | instantiation alist :: (random, random) random | |
| 156 | begin | |
| 157 | ||
| 158 | definition random_alist | |
| 159 | where | |
| 160 | "random_alist i = random_aux_alist i i" | |
| 58806 | 161 | |
| 46167 | 162 | instance .. | 
| 163 | ||
| 164 | end | |
| 165 | ||
| 166 | no_notation fcomp (infixl "\<circ>>" 60) | |
| 167 | no_notation scomp (infixl "\<circ>\<rightarrow>" 60) | |
| 168 | ||
| 169 | instantiation alist :: (exhaustive, exhaustive) exhaustive | |
| 170 | begin | |
| 171 | ||
| 58806 | 172 | fun exhaustive_alist :: | 
| 173 |   "(('a, 'b) alist \<Rightarrow> (bool \<times> term list) option) \<Rightarrow> natural \<Rightarrow> (bool \<times> term list) option"
 | |
| 46167 | 174 | where | 
| 58806 | 175 | "exhaustive_alist f i = | 
| 176 | (if i = 0 then None | |
| 177 | else | |
| 178 | case f empty of | |
| 179 | Some ts \<Rightarrow> Some ts | |
| 180 | | None \<Rightarrow> | |
| 181 | exhaustive_alist | |
| 182 | (\<lambda>a. Quickcheck_Exhaustive.exhaustive | |
| 183 | (\<lambda>k. Quickcheck_Exhaustive.exhaustive (\<lambda>v. f (update k v a)) (i - 1)) (i - 1)) | |
| 184 | (i - 1))" | |
| 46167 | 185 | |
| 186 | instance .. | |
| 187 | ||
| 188 | end | |
| 189 | ||
| 190 | instantiation alist :: (full_exhaustive, full_exhaustive) full_exhaustive | |
| 191 | begin | |
| 192 | ||
| 58806 | 193 | fun full_exhaustive_alist :: | 
| 194 |   "(('a, 'b) alist \<times> (unit \<Rightarrow> term) \<Rightarrow> (bool \<times> term list) option) \<Rightarrow> natural \<Rightarrow>
 | |
| 195 | (bool \<times> term list) option" | |
| 46167 | 196 | where | 
| 58806 | 197 | "full_exhaustive_alist f i = | 
| 198 | (if i = 0 then None | |
| 199 | else | |
| 200 | case f valterm_empty of | |
| 201 | Some ts \<Rightarrow> Some ts | |
| 202 | | None \<Rightarrow> | |
| 203 | full_exhaustive_alist | |
| 204 | (\<lambda>a. | |
| 205 | Quickcheck_Exhaustive.full_exhaustive | |
| 206 | (\<lambda>k. Quickcheck_Exhaustive.full_exhaustive (\<lambda>v. f (valterm_update k v a)) (i - 1)) | |
| 207 | (i - 1)) | |
| 208 | (i - 1))" | |
| 46167 | 209 | |
| 210 | instance .. | |
| 211 | ||
| 212 | end | |
| 213 | ||
| 59581 | 214 | |
| 215 | section \<open>alist is a BNF\<close> | |
| 216 | ||
| 60919 | 217 | lift_bnf (dead 'k, set: 'v) alist [wits: "[] :: ('k \<times> 'v) list"] for map: map rel: rel
 | 
| 218 | by auto | |
| 59581 | 219 | |
| 46167 | 220 | hide_const valterm_empty valterm_update random_aux_alist | 
| 221 | ||
| 46171 
19f68d7671f0
proper hiding of facts and constants in AList_Impl and AList theory
 bulwahn parents: 
46167diff
changeset | 222 | hide_fact (open) lookup_def empty_def update_def delete_def map_entry_def filter_def map_default_def | 
| 59581 | 223 | hide_const (open) impl_of lookup empty update delete map_entry filter map_default map set rel | 
| 46167 | 224 | |
| 46238 
9ace9e5b79be
renaming theory AList_Impl back to AList (reverting 1fec5b365f9b; AList with distinct key invariant is called DAList)
 bulwahn parents: 
46237diff
changeset | 225 | end |