Theory Maximal_Path_Trie
section ‹Maximal Path Tries›
text ‹Drastically reduced implementation of tries that consider only maximum length sequences as elements.
Inserting a sequence that is prefix of some already contained sequence does not alter the trie.
Intended to store IO-sequences to apply in testing, as in this use-case proper prefixes need not be applied separately.›
theory Maximal_Path_Trie
imports "../Util"
begin
subsection ‹Utils for Updating Associative Lists›
fun update_assoc_list_with_default :: "'a ⇒ ('b ⇒ 'b) ⇒ 'b ⇒ ('a × 'b) list ⇒ ('a × 'b) list" where
"update_assoc_list_with_default k f d [] = [(k,f d)]" |
"update_assoc_list_with_default k f d ((x,y)#xys) = (if k = x
then ((x,f y)#xys)
else (x,y) # (update_assoc_list_with_default k f d xys))"
lemma update_assoc_list_with_default_key_found :
assumes "distinct (map fst xys)"
and "i < length xys"
and "fst (xys ! i) = k"
shows "update_assoc_list_with_default k f d xys =
((take i xys) @ [(k, f (snd (xys ! i)))] @ (drop (Suc i) xys))"
using assms proof (induction xys arbitrary: i)
case Nil
then show ?case by auto
next
case (Cons a xys)
show ?case
proof (cases i)
case 0
then have "fst a = k" using Cons.prems(3) by auto
then have "update_assoc_list_with_default k f d (a#xys) = (k, f (snd a)) # xys"
unfolding 0 by (metis prod.collapse update_assoc_list_with_default.simps(2))
then show ?thesis unfolding 0 by auto
next
case (Suc j)
then have "fst a ≠ k"
using Cons.prems by auto
have "distinct (map fst xys)"
and "j < length xys"
and "fst (xys ! j) = k"
using Cons.prems unfolding Suc by auto
then have "update_assoc_list_with_default k f d xys = take j xys @ [(k, f (snd (xys ! j)))] @ drop (Suc j) xys"
using Cons.IH[of j] by auto
then show ?thesis unfolding Suc using ‹fst a ≠ k›
by (metis append_Cons drop_Suc_Cons nth_Cons_Suc prod.collapse take_Suc_Cons update_assoc_list_with_default.simps(2))
qed
qed
lemma update_assoc_list_with_default_key_not_found :
assumes "distinct (map fst xys)"
and "k ∉ set (map fst xys)"
shows "update_assoc_list_with_default k f d xys = xys @ [(k,f d)]"
using assms by (induction xys; auto)
lemma update_assoc_list_with_default_key_distinct :
assumes "distinct (map fst xys)"
shows "distinct (map fst (update_assoc_list_with_default k f d xys))"
proof (cases "k ∈ set (map fst xys)")
case True
then obtain i where "i < length xys" and "fst (xys ! i) = k"
by (metis in_set_conv_nth length_map nth_map)
then have *: "(map fst (take i xys @ [(k, f (snd (xys ! i)))] @ drop (Suc i) xys)) = (map fst xys)"
proof -
have "xys ! i # drop (Suc i) xys = drop i xys"
using Cons_nth_drop_Suc ‹i < length xys› by blast
then show ?thesis
by (metis (no_types) ‹fst (xys ! i) = k› append_Cons append_self_conv2 append_take_drop_id fst_conv list.simps(9) map_append)
qed
show ?thesis
unfolding update_assoc_list_with_default_key_found[OF assms ‹i < length xys› ‹fst (xys ! i) = k›] *
using assms by assumption
next
case False
have *: "(map fst (xys @ [(k, f d)])) = (map fst xys)@[k]" by auto
show ?thesis
using assms False
unfolding update_assoc_list_with_default_key_not_found[OF assms False] * by auto
qed
subsection ‹Maximum Path Trie Implementation›