Theory RBT_Map_Set_Extension
section ‹Accessing Values via Keys›
theory RBT_Map_Set_Extension
imports
Collections.RBTMapImpl
Collections.RBTSetImpl
Matrix.Utility
begin
text ‹
We provide two extensions of the red black tree implementation.
The first extension provides two convenience methods on sets which are represented by red black
trees: a check on subsets and the big union operator.
The second extension is to provide two operations @{term elem_list_to_rm} and @{term
rm_set_lookup} which can be used to index a set of values via keys. More precisely, given a list
of values of type @{typ "'v"} and a key function of type @{typ "'v => 'k"}, @{term
elem_list_to_rm} will generate a map of type @{typ "'k => 'v set"}. Then with @{term
rs_set_lookup} we can efficiently access all values which match a given key.
›
subsection ‹Subset and Union›
text ‹
For the subset operation @{term "r ⊆ s"} we provide two implementations. The first one (@{term
rs_subset}) traverses over @{term r} and then performs membership tests ‹∈ s›. Its
complexity is ${\cal O}(|r| \cdot log (|s|))$. The second one (@{term rs_subset_list}) generates
sorted lists for both @{term r} and @{term s} and then linearly checks the subset condition. Its
complexity is ${\cal O}(|r| + |s|)$.
›
text ‹
As union operator we use the standard fold function. Note that the order of the union is important
so that new sets are added to the big union.
›
definition rs_subset :: "('a :: linorder) rs ⇒ 'a rs ⇒ 'a option"
where
"rs_subset as bs = rs.iteratei
as
(λ maybe. case maybe of None ⇒ True | Some _ ⇒ False)
(λ a _. if rs.memb a bs then None else Some a)
None"
lemma rs_subset [simp]:
"rs_subset as bs = None ⟷ rs.α as ⊆ rs.α bs"
proof -
let ?abort = "λ maybe. case maybe of None ⇒ True | Some _ ⇒ False"
let ?I = "λ aas maybe. maybe = None ⟷ (∀ a. a ∈ rs.α as - aas ⟶ a ∈ rs.α bs)"
let ?it = "rs_subset as bs"
have "?I {} ?it ∨ (∃ it ⊆ rs.α as. it ≠ {} ∧ ¬ ?abort ?it ∧ ?I it ?it)"
unfolding rs_subset_def
by (rule rs.iteratei_rule_P [where I="?I"]) (auto simp: rs.correct)
then show ?thesis by auto
qed
definition rs_subset_list :: "('a :: linorder) rs ⇒ 'a rs ⇒ 'a option"
where
"rs_subset_list as bs = sorted_list_subset (rs.to_sorted_list as) (rs.to_sorted_list bs)"
lemma rs_subset_list [simp]:
"rs_subset_list as bs = None ⟷ rs.α as ⊆ rs.α bs"
unfolding rs_subset_list_def
sorted_list_subset[OF rs.to_sorted_list_correct(3)[OF rs.invar, of as]
rs.to_sorted_list_correct(3)[OF rs.invar, of bs]]
by (simp add: rs.to_sorted_list_correct)
definition rs_Union :: "('q :: linorder) rs list ⇒ 'q rs"
where
"rs_Union = foldl rs.union (rs.empty ())"
lemma rs_Union [simp]:
"rs.α (rs_Union qs) = ⋃ (rs.α ` set qs)"
proof -
{
fix start
have "rs.α (foldl rs.union start qs) = rs.α start ∪ ⋃ (rs.α ` set qs)"
by (induct qs arbitrary: start, auto simp: rs.correct)
} from this[of "rs.empty ()"]
show ?thesis unfolding rs_Union_def
by (auto simp: rs.correct)
qed
subsection ‹Grouping Values via Keys›
text ‹
The functions to produce the index (@{term elem_list_to_rm}) and the lookup function (@{term
rm_set_lookup}) are straight-forward, however it requires some tedious reasoning that they perform
as they should.
›
fun elem_list_to_rm :: "('d ⇒ 'k :: linorder) ⇒ 'd list ⇒ ('k, 'd list) rm"
where
"elem_list_to_rm key [] = rm.empty ()" |
"elem_list_to_rm key (d # ds) =
(let
rm = elem_list_to_rm key ds;
k = key d
in
(case rm.α rm k of
None ⇒ rm.update_dj k [d] rm
| Some data ⇒ rm.update k (d # data) rm))"
definition "rm_set_lookup rm = (λ a. (case rm.α rm a of None ⇒ [] | Some rules ⇒ rules))"
lemma rm_to_list_empty [simp]:
"rm.to_list (rm.empty ()) = []"
proof -
have "map_of (rm.to_list (rm.empty ())) = Map.empty"
by (simp add: rm.correct)
moreover have map_of_empty_iff: "⋀l. map_of l = Map.empty ⟷ l = []"
by (case_tac l) auto
ultimately show ?thesis by metis
qed
locale rm_set =
fixes rm :: "('k :: linorder, 'd list) rm"
and key :: "'d ⇒ 'k"
and data :: "'d set"
assumes rm_set_lookup: "⋀ k. set (rm_set_lookup rm k) = {d ∈ data. key d = k}"
begin
lemma data_lookup:
"data = ⋃ {set (rm_set_lookup rm k) | k. True}" (is "_ = ?R")
proof -
{
fix d
assume d: "d ∈ data"
then have d: "d ∈ {d' ∈ data. key d' = key d}" by auto
have "d ∈ ?R"
by (rule UnionI[OF _ d], rule CollectI, rule exI[of _ "key d"], unfold rm_set_lookup[of "key d"], simp)
}
moreover
{
fix d
assume "d ∈ ?R"
from this[unfolded rm_set_lookup]
have "d ∈ data" by auto
}
ultimately show ?thesis by blast
qed
lemma finite_data:
"finite data"
unfolding data_lookup
proof
show "finite {set (rm_set_lookup rm k) | k. True}" (is "finite ?L")
proof -
let ?rmset = "rm.α rm"
let ?M = "?rmset ` Map.dom ?rmset"
let ?N = "((λ e. set (case e of None ⇒ [] | Some ds ⇒ ds)) ` ?M)"
let ?K = "?N ∪ {{}}"
from rm.finite[of rm] have fin: "finite ?K" by auto
show ?thesis
proof (rule finite_subset[OF _ fin], rule)
fix ds
assume "ds ∈ ?L"
from this[unfolded rm_set_lookup_def]
obtain fn where ds: "ds = set (case rm.α rm fn of None ⇒ []
| Some ds ⇒ ds)" by auto
show "ds ∈ ?K"
proof (cases "rm.α rm fn")
case None
then show ?thesis unfolding ds by auto
next
case (Some rules)
from Some have fn: "fn ∈ Map.dom ?rmset" by auto
have "ds ∈ ?N"
unfolding ds
by (rule, rule refl, rule, rule refl, rule fn)
then show ?thesis by auto
qed
qed
qed
qed (force simp: rm_set_lookup_def)
end
interpretation elem_list_to_rm: rm_set "elem_list_to_rm key ds" key "set ds"
proof
fix k
show "set (rm_set_lookup (elem_list_to_rm key ds) k) = {d ∈ set ds. key d = k}"
proof (induct ds arbitrary: k)
case Nil
then show ?case unfolding rm_set_lookup_def
by (simp add: rm.correct)
next
case (Cons d ds k)
let ?el = "elem_list_to_rm key"
let ?l = "λk ds. set (rm_set_lookup (?el ds) k)"
let ?r = "λk ds. {d ∈ set ds. key d = k}"
from Cons have ind:
"⋀ k. ?l k ds = ?r k ds" by auto
show "?l k (d # ds) = ?r k (d # ds)"
proof (cases "rm.α (?el ds) (key d)")
case None
from None ind[of "key d"] have r: "{da ∈ set ds. key da = key d} = {}"
unfolding rm_set_lookup_def by auto
from None have el: "?el (d # ds) = rm.update_dj (key d) [d] (?el ds)"
by simp
from None have ndom: "key d ∉ Map.dom (rm.α (?el ds))" by auto
have r: "?r k (d # ds) = ?r k ds ∩ {da. key da ≠ key d} ∪ {da . key da = k ∧ da = d}" (is "_ = ?r1 ∪ ?r2") using r by auto
from ndom have l: "?l k (d # ds) =
set (case ((rm.α (elem_list_to_rm key ds))(key d ↦ [d])) k of None ⇒ []
| Some rules ⇒ rules)" (is "_ = ?l") unfolding el rm_set_lookup_def
by (simp add: rm.correct)
{
fix da
assume "da ∈ ?r1 ∪ ?r2"
then have "da ∈ ?l"
proof
assume "da ∈ ?r2"
then have da: "da = d" and k: "key d = k" by auto
show ?thesis unfolding da k by auto
next
assume "da ∈ ?r1"
from this[unfolded ind[symmetric] rm_set_lookup_def]
obtain das where rm: "rm.α (?el ds) k = Some das" and da: "da ∈ set das" and k: "key da ≠ key d" by (cases "rm.α (?el ds) k", auto)
from ind[of k, unfolded rm_set_lookup_def] rm da k have k: "key d ≠ k" by auto
have rm: "((rm.α (elem_list_to_rm key ds))(key d ↦ [d])) k = Some das"
unfolding rm[symmetric] using k by auto
show ?thesis unfolding rm using da by auto
qed
}
moreover
{
fix da
assume l: "da ∈ ?l"
let ?rm = "((rm.α (elem_list_to_rm key ds))(key d ↦ [d])) k"
from l obtain das where rm: "?rm = Some das" and da: "da ∈ set das"
by (cases ?rm, auto)
have "da ∈ ?r1 ∪ ?r2"
proof (cases "k = key d")
case True
with rm da have da: "da = d" by auto
then show ?thesis using True by auto
next
case False
with rm have "rm.α (?el ds) k = Some das" by auto
from ind[of k, unfolded rm_set_lookup_def this] da False
show ?thesis by auto
qed
}
ultimately have "?l = ?r1 ∪ ?r2" by blast
then show ?thesis unfolding l r .
next
case (Some das)
from Some ind[of "key d"] have das: "{da ∈ set ds. key da = key d} = set das"
unfolding rm_set_lookup_def by auto
from Some have el: "?el (d # ds) = rm.update (key d) (d # das) (?el ds)"
by simp
from Some have dom: "key d ∈ Map.dom (rm.α (?el ds))" by auto
from dom have l: "?l k (d # ds) =
set (case ((rm.α (elem_list_to_rm key ds))(key d ↦ (d # das))) k of None ⇒ []
| Some rules ⇒ rules)" (is "_ = ?l") unfolding el rm_set_lookup_def
by (simp add: rm.correct)
have r: "?r k (d # ds) = ?r k ds ∪ {da. key da = k ∧ da = d}" (is "_ = ?r1 ∪ ?r2") by auto
{
fix da
assume "da ∈ ?r1 ∪ ?r2"
then have "da ∈ ?l"
proof
assume "da ∈ ?r2"
then have da: "da = d" and k: "key d = k" by auto
show ?thesis unfolding da k by auto
next
assume "da ∈ ?r1"
from this[unfolded ind[symmetric] rm_set_lookup_def]
obtain das' where rm: "rm.α (?el ds) k = Some das'" and da: "da ∈ set das'" by (cases "rm.α (?el ds) k", auto)
from ind[of k, unfolded rm_set_lookup_def rm] have das': "set das' = {d ∈ set ds. key d = k}" by auto
show ?thesis
proof (cases "k = key d")
case True
show ?thesis using das' das da unfolding True by simp
next
case False
then show ?thesis using das' da rm by auto
qed
qed
}
moreover
{
fix da
assume l: "da ∈ ?l"
let ?rm = "((rm.α (elem_list_to_rm key ds))(key d ↦ d # das)) k"
from l obtain das' where rm: "?rm = Some das'" and da: "da ∈ set das'"
by (cases ?rm, auto)
have "da ∈ ?r1 ∪ ?r2"
proof (cases "k = key d")
case True
with rm da das have da: "da ∈ set (d # das)" by auto
then have "da = d ∨ da ∈ set das" by auto
then have k: "key da = k"
proof
assume "da = d"
then show ?thesis using True by simp
next
assume "da ∈ set das"
with das True show ?thesis by auto
qed
from da k show ?thesis using das by auto
next
case False
with rm have "rm.α (?el ds) k = Some das'" by auto
from ind[of k, unfolded rm_set_lookup_def this] da False
show ?thesis by auto
qed
}
ultimately have "?l = ?r1 ∪ ?r2" by blast
then show ?thesis unfolding l r .
qed
qed
qed
end