src/HOL/Data_Structures/Tries_Binary.thy
changeset 70250 20d819b0a29d
child 70267 9fa2cf7142b7
equal deleted inserted replaced
70249:4ce07be8ba17 70250:20d819b0a29d
       
     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