Theory Time_Locale_Example
section ‹Time Functions in Locales --- An Example›
theory Time_Locale_Example
imports
"HOL-Library.Time_Functions"
"HOL-Library.AList"
Map_Specs
begin
text ‹If you want to reason about the time complexity of functions in a locale,
you need to parameterize the locale with time functions for all functions that are utilized.
More precisely, if you are in a locale parameterized by some function ‹f›
and you define a function ‹g› that uses ‹f›, and you want to define ‹T_g›, it will
depend on ‹T_f›, which you have to make an additional parameter of the locale.
Only then will ‹time_fun g› work. Below we show a realistic example.›
subsection ‹Basic Time Functions›
time_fun AList.update
text ‹‹time_fun› needs uncurried defining equations›
lemma
map_of_simps': "map_of [] (x::'a) = (None :: 'b option)"
"map_of ((a::'a,b::'b)#ps) x = (if x=a then Some b else map_of ps x)"
by auto
time_fun map_of equations map_of_simps'
lemma T_map_ub: "T_map_of ps a ≤ length ps + 1"
by(induction ps) auto
lemma T_update_ub: "T_update a b ps ≤ length ps + 1"
by(induction ps) auto
lemma length_AList_update_ub: "length (AList.update a b ps) ≤ length ps + 1"
by(induction ps) auto
subsection ‹Locale›
text ‹Counting the elements in a list by means of a map
that associates elements with their multiplicities in the list, like a `histogram'.
The locale is parameterized with the map ADT and the timing functions for ‹lookup› and ‹update›.›
locale Count_List = Map where update = update for update :: "'a ⇒ nat ⇒ 'm ⇒ 'm" +
fixes T_lookup :: "'m ⇒ 'a ⇒ nat"
and T_update :: "'a ⇒ nat ⇒ 'm ⇒ nat"
begin
definition lookup_nat :: "'m ⇒ 'a ⇒ nat" where
"lookup_nat m x = (case lookup m x of None ⇒ 0 | Some n ⇒ n)"
time_definition lookup_nat
fun count :: "'m ⇒ 'a list ⇒ 'm" where
"count m [] = m" |
"count m (x#xs) = count (update x (lookup_nat m x + 1) m) xs"
time_fun count
end
subsection ‹Interpretation›
text ‹Interpretation of ‹Count_List› with association lists as maps.›
lemma map_of_AList_update: "map_of (AList.update a b ps) = ((map_of ps)(a ↦ b))"
by(induction ps) auto
lemma map_of_AList_delete: "map_of (AList.delete a ps) = (map_of ps)(a := None)"
by(induction ps) auto
global_interpretation CL: Count_List
where empty = "[]" and lookup = map_of
and update = AList.update and delete = AList.delete and invar = "λ_. True"
and T_lookup = T_map_of and T_update = T_update
defines CL_count = CL.count and CL_T_count = CL.T_count
proof (standard, goal_cases)
case 1
show ?case by (rule ext) simp
next
case (2 m a b)
show ?case by (rule map_of_AList_update)
next
case (3 m a)
show ?case by (rule map_of_AList_delete)
next
case 4
show ?case by(rule TrueI)
next
case (5 m a b)
show ?case by(rule TrueI)
next
case (6 m a)
show ?case by(rule TrueI)
qed
subsection ‹Complexity Proof›
lemma "CL.T_count ps xs ≤ 2 * length xs * (length xs + length ps + 1) + 1"
proof(induction xs arbitrary: ps)
case Nil
then show ?case by simp
next
case (Cons a xs)
let ?lps' = "length ps + 1"
let ?na' = "CL.lookup_nat ps a + 1"
let ?ps' = "AList.update a ?na' ps"
have "CL_T_count ps (a # xs) =
T_map_of ps a + T_update a ?na' ps + CL_T_count (AList.update a ?na' ps) xs + 1"
by simp
also have "… ≤ 2 * ?lps' + CL_T_count ?ps' xs + 1"
using T_map_ub T_update_ub add_mono by (fastforce simp: mult_2)
also have "… ≤ 2 * ?lps' + 2 * length xs * (length xs + length ?ps' + 1) + 1 + 1"
using Cons.IH by (metis (no_types, lifting) add.assoc add_mono_thms_linordered_semiring(3)
nat_add_left_cancel_le)
also have "… ≤ 2 * ?lps' + 2 * length xs * (length xs + ?lps' + 1) + 1 + 1"
using length_AList_update_ub
by (metis add_mono_thms_linordered_semiring(2) add_right_mono mult_le_mono2)
also have "… ≤ 2 * length (a # xs) * (length (a # xs) + length ps + 1) + 1"
by (auto simp: algebra_simps)
finally show ?case .
qed
end