|
1 (* Author: Tobias Nipkow *) |
|
2 |
|
3 section "Binary Tries and Patricia Tries" |
|
4 |
|
5 theory Tries_Binary |
|
6 imports Set_Specs |
|
7 begin |
|
8 |
|
9 hide_const (open) insert |
|
10 |
|
11 declare Let_def[simp] |
|
12 |
|
13 fun sel2 :: "bool \<Rightarrow> 'a * 'a \<Rightarrow> 'a" where |
|
14 "sel2 b (a1,a2) = (if b then a2 else a1)" |
|
15 |
|
16 fun mod2 :: "('a \<Rightarrow> 'a) \<Rightarrow> bool \<Rightarrow> 'a * 'a \<Rightarrow> 'a * 'a" where |
|
17 "mod2 f b (a1,a2) = (if b then (a1,f a2) else (f a1,a2))" |
|
18 |
|
19 |
|
20 subsection "Trie" |
|
21 |
|
22 datatype trie = Lf | Nd bool "trie * trie" |
|
23 |
|
24 fun isin :: "trie \<Rightarrow> bool list \<Rightarrow> bool" where |
|
25 "isin Lf ks = False" | |
|
26 "isin (Nd b lr) ks = |
|
27 (case ks of |
|
28 [] \<Rightarrow> b | |
|
29 k#ks \<Rightarrow> isin (sel2 k lr) ks)" |
|
30 |
|
31 fun insert :: "bool list \<Rightarrow> trie \<Rightarrow> trie" where |
|
32 "insert [] Lf = Nd True (Lf,Lf)" | |
|
33 "insert [] (Nd b lr) = Nd True lr" | |
|
34 "insert (k#ks) Lf = Nd False (mod2 (insert ks) k (Lf,Lf))" | |
|
35 "insert (k#ks) (Nd b lr) = Nd b (mod2 (insert ks) k lr)" |
|
36 |
|
37 lemma isin_insert: "isin (insert as t) bs = (as = bs \<or> isin t bs)" |
|
38 apply(induction as t arbitrary: bs rule: insert.induct) |
|
39 apply (auto split: list.splits if_splits) |
|
40 done |
|
41 |
|
42 text \<open>A simple implementation of delete; does not shrink the trie!\<close> |
|
43 |
|
44 fun delete0 :: "bool list \<Rightarrow> trie \<Rightarrow> trie" where |
|
45 "delete0 ks Lf = Lf" | |
|
46 "delete0 ks (Nd b lr) = |
|
47 (case ks of |
|
48 [] \<Rightarrow> Nd False lr | |
|
49 k#ks' \<Rightarrow> Nd b (mod2 (delete0 ks') k lr))" |
|
50 |
|
51 lemma isin_delete0: "isin (delete0 as t) bs = (as \<noteq> bs \<and> isin t bs)" |
|
52 apply(induction as t arbitrary: bs rule: delete0.induct) |
|
53 apply (auto split: list.splits if_splits) |
|
54 done |
|
55 |
|
56 text \<open>Now deletion with shrinking:\<close> |
|
57 |
|
58 fun node :: "bool \<Rightarrow> trie * trie \<Rightarrow> trie" where |
|
59 "node b lr = (if \<not> b \<and> lr = (Lf,Lf) then Lf else Nd b lr)" |
|
60 |
|
61 fun delete :: "bool list \<Rightarrow> trie \<Rightarrow> trie" where |
|
62 "delete ks Lf = Lf" | |
|
63 "delete ks (Nd b lr) = |
|
64 (case ks of |
|
65 [] \<Rightarrow> node False lr | |
|
66 k#ks' \<Rightarrow> node b (mod2 (delete ks') k lr))" |
|
67 |
|
68 lemma isin_delete: "isin (delete as t) bs = (as \<noteq> bs \<and> isin t bs)" |
|
69 apply(induction as t arbitrary: bs rule: delete.induct) |
|
70 apply simp |
|
71 apply (auto split: list.splits if_splits) |
|
72 apply (metis isin.simps(1)) |
|
73 apply (metis isin.simps(1)) |
|
74 done |
|
75 |
|
76 definition set_trie :: "trie \<Rightarrow> bool list set" where |
|
77 "set_trie t = {xs. isin t xs}" |
|
78 |
|
79 lemma set_trie_insert: "set_trie(insert xs t) = set_trie t \<union> {xs}" |
|
80 by(auto simp add: isin_insert set_trie_def) |
|
81 |
|
82 interpretation S: Set |
|
83 where empty = Lf and isin = isin and insert = insert and delete = delete |
|
84 and set = set_trie and invar = "\<lambda>t. True" |
|
85 proof (standard, goal_cases) |
|
86 case 1 show ?case by (simp add: set_trie_def) |
|
87 next |
|
88 case 2 thus ?case by(simp add: set_trie_def) |
|
89 next |
|
90 case 3 thus ?case by(auto simp: set_trie_insert) |
|
91 next |
|
92 case 4 thus ?case by(auto simp: isin_delete set_trie_def) |
|
93 qed (rule TrueI)+ |
|
94 |
|
95 |
|
96 subsection "Patricia Trie" |
|
97 |
|
98 datatype ptrie = LfP | NdP "bool list" bool "ptrie * ptrie" |
|
99 |
|
100 fun isinP :: "ptrie \<Rightarrow> bool list \<Rightarrow> bool" where |
|
101 "isinP LfP ks = False" | |
|
102 "isinP (NdP ps b lr) ks = |
|
103 (let n = length ps in |
|
104 if ps = take n ks |
|
105 then case drop n ks of [] \<Rightarrow> b | k#ks' \<Rightarrow> isinP (sel2 k lr) ks' |
|
106 else False)" |
|
107 |
|
108 fun split where |
|
109 "split [] ys = ([],[],ys)" | |
|
110 "split xs [] = ([],xs,[])" | |
|
111 "split (x#xs) (y#ys) = |
|
112 (if x\<noteq>y then ([],x#xs,y#ys) |
|
113 else let (ps,xs',ys') = split xs ys in (x#ps,xs',ys'))" |
|
114 |
|
115 |
|
116 lemma mod2_cong[fundef_cong]: |
|
117 "\<lbrakk> lr = lr'; k = k'; \<And>a b. lr'=(a,b) \<Longrightarrow> f (a) = f' (a) ; \<And>a b. lr'=(a,b) \<Longrightarrow> f (b) = f' (b) \<rbrakk> |
|
118 \<Longrightarrow> mod2 f k lr= mod2 f' k' lr'" |
|
119 by(cases lr, cases lr', auto) |
|
120 |
|
121 fun insertP :: "bool list \<Rightarrow> ptrie \<Rightarrow> ptrie" where |
|
122 "insertP ks LfP = NdP ks True (LfP,LfP)" | |
|
123 "insertP ks (NdP ps b lr) = |
|
124 (case split ks ps of |
|
125 (qs,k#ks',p#ps') \<Rightarrow> |
|
126 let tp = NdP ps' b lr; tk = NdP ks' True (LfP,LfP) in |
|
127 NdP qs False (if k then (tp,tk) else (tk,tp)) | |
|
128 (qs,k#ks',[]) \<Rightarrow> |
|
129 NdP ps b (mod2 (insertP ks') k lr) | |
|
130 (qs,[],p#ps') \<Rightarrow> |
|
131 let t = NdP ps' b lr in |
|
132 NdP qs True (if p then (LfP,t) else (t,LfP)) | |
|
133 (qs,[],[]) \<Rightarrow> NdP ps True lr)" |
|
134 |
|
135 |
|
136 fun nodeP :: "bool list \<Rightarrow> bool \<Rightarrow> ptrie * ptrie \<Rightarrow> ptrie" where |
|
137 "nodeP ps b lr = (if \<not> b \<and> lr = (LfP,LfP) then LfP else NdP ps b lr)" |
|
138 |
|
139 fun deleteP :: "bool list \<Rightarrow> ptrie \<Rightarrow> ptrie" where |
|
140 "deleteP ks LfP = LfP" | |
|
141 "deleteP ks (NdP ps b lr) = |
|
142 (case split ks ps of |
|
143 (qs,ks',p#ps') \<Rightarrow> NdP ps b lr | |
|
144 (qs,k#ks',[]) \<Rightarrow> nodeP ps b (mod2 (deleteP ks') k lr) | |
|
145 (qs,[],[]) \<Rightarrow> nodeP ps False lr)" |
|
146 |
|
147 |
|
148 subsubsection \<open>Functional Correctness\<close> |
|
149 |
|
150 text \<open>First step: @{typ ptrie} implements @{typ trie} via the abstraction function \<open>abs_ptrie\<close>:\<close> |
|
151 |
|
152 fun prefix_trie :: "bool list \<Rightarrow> trie \<Rightarrow> trie" where |
|
153 "prefix_trie [] t = t" | |
|
154 "prefix_trie (k#ks) t = |
|
155 (let t' = prefix_trie ks t in Nd False (if k then (Lf,t') else (t',Lf)))" |
|
156 |
|
157 fun abs_ptrie :: "ptrie \<Rightarrow> trie" where |
|
158 "abs_ptrie LfP = Lf" | |
|
159 "abs_ptrie (NdP ps b (l,r)) = prefix_trie ps (Nd b (abs_ptrie l, abs_ptrie r))" |
|
160 |
|
161 |
|
162 text \<open>Correctness of @{const isinP}:\<close> |
|
163 |
|
164 lemma isin_prefix_trie: |
|
165 "isin (prefix_trie ps t) ks |
|
166 = (ps = take (length ps) ks \<and> isin t (drop (length ps) ks))" |
|
167 apply(induction ps arbitrary: ks) |
|
168 apply(auto split: list.split) |
|
169 done |
|
170 |
|
171 lemma isinP: |
|
172 "isinP t ks = isin (abs_ptrie t) ks" |
|
173 apply(induction t arbitrary: ks rule: abs_ptrie.induct) |
|
174 apply(auto simp: isin_prefix_trie split: list.split) |
|
175 done |
|
176 |
|
177 |
|
178 text \<open>Correctness of @{const insertP}:\<close> |
|
179 |
|
180 lemma prefix_trie_Lfs: "prefix_trie ks (Nd True (Lf,Lf)) = insert ks Lf" |
|
181 apply(induction ks) |
|
182 apply auto |
|
183 done |
|
184 |
|
185 lemma insert_prefix_trie_same: |
|
186 "insert ps (prefix_trie ps (Nd b lr)) = prefix_trie ps (Nd True lr)" |
|
187 apply(induction ps) |
|
188 apply auto |
|
189 done |
|
190 |
|
191 lemma insert_append: "insert (ks @ ks') (prefix_trie ks t) = prefix_trie ks (insert ks' t)" |
|
192 apply(induction ks) |
|
193 apply auto |
|
194 done |
|
195 |
|
196 lemma prefix_trie_append: "prefix_trie (ps @ qs) t = prefix_trie ps (prefix_trie qs t)" |
|
197 apply(induction ps) |
|
198 apply auto |
|
199 done |
|
200 |
|
201 lemma split_if: "split ks ps = (qs, ks', ps') \<Longrightarrow> |
|
202 ks = qs @ ks' \<and> ps = qs @ ps' \<and> (ks' \<noteq> [] \<and> ps' \<noteq> [] \<longrightarrow> hd ks' \<noteq> hd ps')" |
|
203 apply(induction ks ps arbitrary: qs ks' ps' rule: split.induct) |
|
204 apply(auto split: prod.splits if_splits) |
|
205 done |
|
206 |
|
207 lemma abs_ptrie_insertP: |
|
208 "abs_ptrie (insertP ks t) = insert ks (abs_ptrie t)" |
|
209 apply(induction t arbitrary: ks) |
|
210 apply(auto simp: prefix_trie_Lfs insert_prefix_trie_same insert_append prefix_trie_append |
|
211 dest!: split_if split: list.split prod.split if_splits) |
|
212 done |
|
213 |
|
214 |
|
215 text \<open>Correctness of @{const deleteP}:\<close> |
|
216 |
|
217 lemma prefix_trie_Lf: "prefix_trie xs t = Lf \<longleftrightarrow> xs = [] \<and> t = Lf" |
|
218 by(cases xs)(auto) |
|
219 |
|
220 lemma abs_ptrie_Lf: "abs_ptrie t = Lf \<longleftrightarrow> t = LfP" |
|
221 by(cases t) (auto simp: prefix_trie_Lf) |
|
222 |
|
223 lemma delete_prefix_trie: |
|
224 "delete xs (prefix_trie xs (Nd b (l,r))) |
|
225 = (if (l,r) = (Lf,Lf) then Lf else prefix_trie xs (Nd False (l,r)))" |
|
226 by(induction xs)(auto simp: prefix_trie_Lf) |
|
227 |
|
228 lemma delete_append_prefix_trie: |
|
229 "delete (xs @ ys) (prefix_trie xs t) |
|
230 = (if delete ys t = Lf then Lf else prefix_trie xs (delete ys t))" |
|
231 by(induction xs)(auto simp: prefix_trie_Lf) |
|
232 |
|
233 lemma delete_abs_ptrie: |
|
234 "delete ks (abs_ptrie t) = abs_ptrie (deleteP ks t)" |
|
235 apply(induction t arbitrary: ks) |
|
236 apply(auto simp: delete_prefix_trie delete_append_prefix_trie |
|
237 prefix_trie_append prefix_trie_Lf abs_ptrie_Lf |
|
238 dest!: split_if split: if_splits list.split prod.split) |
|
239 done |
|
240 |
|
241 |
|
242 text \<open>The overall correctness proof. Simply composes correctness lemmas.\<close> |
|
243 |
|
244 definition set_ptrie :: "ptrie \<Rightarrow> bool list set" where |
|
245 "set_ptrie = set_trie o abs_ptrie" |
|
246 |
|
247 lemma set_ptrie_insertP: "set_ptrie (insertP xs t) = set_ptrie t \<union> {xs}" |
|
248 by(simp add: abs_ptrie_insertP set_trie_insert set_ptrie_def) |
|
249 |
|
250 interpretation SP: Set |
|
251 where empty = LfP and isin = isinP and insert = insertP and delete = deleteP |
|
252 and set = set_ptrie and invar = "\<lambda>t. True" |
|
253 proof (standard, goal_cases) |
|
254 case 1 show ?case by (simp add: set_ptrie_def set_trie_def) |
|
255 next |
|
256 case 2 thus ?case by(simp add: isinP set_ptrie_def set_trie_def) |
|
257 next |
|
258 case 3 thus ?case by (auto simp: set_ptrie_insertP) |
|
259 next |
|
260 case 4 thus ?case |
|
261 by(auto simp: isin_delete set_ptrie_def set_trie_def simp flip: delete_abs_ptrie) |
|
262 qed (rule TrueI)+ |
|
263 |
|
264 end |