theory Memories
imports
QTRS.Util
begin
datatype comparison = Less | Equal | More
record ('m,'a,'b)memory =
empty :: "unit ⇒ 'm"
lookup :: "'m ⇒ 'a ⇒ 'b option"
store :: "'m ⇒ ('a × 'b) ⇒ 'm"
definition singleton :: "('m,'a,'b)memory ⇒ ('a × 'b) ⇒ 'm" where
"singleton model = memory.store model (memory.empty model ())"
definition valid :: "('m,'a,'b)memory ⇒ 'm ⇒ ('a ⇒ 'b) ⇒ bool" where
"valid model M f ≡ (∀a b. memory.lookup model M a = Some b ⟶ f a = b)"
definition satisfactory where
"satisfactory P model ≡ (∀f. P model (memory.empty model ()) f)
∧ (∀f a M. P model M f ⟶ P model (memory.store model M (a, f a)) f)
∧ (∀M f. P model M f ⟶ valid model M f)"
declare satisfactory_def[simp]
lemma singleton_valid:
assumes "satisfactory P model"
and "f k = v"
shows "P model (singleton model (k, v)) f"
using assms unfolding singleton_def by auto
fun lm_store_acc :: "('k × 'v) list ⇒ ('k × 'v) ⇒ ('k × 'v) list ⇒ ('k × 'v) list" where
"lm_store_acc [] kv accu = kv # accu" |
"lm_store_acc ((a,_) # rec) (k,v) accu = (
case k = a of True ⇒ accu | False ⇒ lm_store_acc rec (k,v) accu)"
definition lm_store where "lm_store M kv = lm_store_acc M kv M"
lemma lm_store_acc_sound1:
assumes "∃b. (k, b) ∈ set M"
shows "lm_store_acc M (k, v) rec = rec"
using assms proof (induct M)
case Nil thus ?case by simp
next
case (Cons afa M)
obtain a fa where Hafa: "afa = (a, fa)" by (cases afa) auto
with Cons show ?case by (cases "a = k") simp_all
qed
lemma lm_store_sound1:
assumes "∃b. (k, b) ∈ set M"
shows "lm_store M (k, v) = M"
using assms lm_store_acc_sound1 by (simp add: lm_store_def)
lemma lm_store_acc_sound2:
assumes "¬ (∃b. (k, b) ∈ set M)"
shows "lm_store_acc M (k, v) rec = (k, v) # rec"
using assms proof (induct M)
case Nil thus ?case by simp
next
case (Cons afa M)
obtain a fa where Hafa: "afa = (a, fa)" by (cases afa) auto
with Cons show ?case by (cases "a = k") auto
qed
lemma lm_store_sound2:
assumes "¬ (∃b. (k, b) ∈ set M)"
shows "lm_store M (k, v) = (k,v) # M"
using assms lm_store_acc_sound2 by (simp add: lm_store_def)
definition lm :: "(('k × 'v) list, 'k, 'v) memory" where
"lm ≡ ⦇ empty = (λ_. []), lookup = map_of, store = lm_store ⦈"
lemma satisfactory_lm: "satisfactory valid lm"
proof-
have lm_empty: "∀f. valid lm (memory.empty lm ()) f" by (simp add: lm_def valid_def)
{
fix f a M k v
assume M_valid: "valid lm M f"
and Hlkp: "memory.lookup lm (store lm M (a, f a)) k = Some v"
have "f k = v"
proof (cases "∃b. (a, b) ∈ set M")
case True
from M_valid lm_store_sound1[OF this] Hlkp
show ?thesis by (simp add: valid_def lm_def)
next
case False
from M_valid lm_store_sound2[OF this] Hlkp
show ?thesis by (cases "k = a") (simp_all add: valid_def lm_def)
qed
}
hence lm_store: "∀f a b M. valid lm M f ⟶ f a = b ⟶ valid lm (memory.store lm M (a,b)) f"
by (auto simp: valid_def)
from lm_empty lm_store show ?thesis unfolding satisfactory_def by fast
qed
fun l2m_lookup :: "('k1 × ('k2 × 'v) list) list ⇒ ('k1 × 'k2) ⇒ 'v option" where
"l2m_lookup [] _ = None"
| "l2m_lookup ((a, kvs) # rec) (k1, k2) =
(case k1 = a of
True ⇒ map_of kvs k2
| False ⇒ l2m_lookup rec (k1, k2))"
fun l2m_store :: "('k1 × ('k2 × 'v) list) list ⇒ (('k1 × 'k2) × 'v) ⇒ ('k1 × ('k2 × 'v) list) list" where
"l2m_store [] ((k1, k2), v) = [ (k1, [(k2, v)]) ]" |
"l2m_store ((a, kvs) # rec) ((k1, k2), v) =
(case k1 = a of
True ⇒ (a, lm_store kvs (k2, v)) # rec
| False ⇒ (a, kvs) # (l2m_store rec ((k1, k2), v)))"
definition l2m :: "(('k1 × ('k2 × 'v) list) list, 'k1 × 'k2, 'v)memory" where
"l2m ≡ ⦇ empty = λ_. [], lookup = l2m_lookup, store = l2m_store ⦈"
definition l2m_valid :: "(('k1 × ('k2 × 'v) list) list, 'k1 × 'k2, 'v)memory ⇒
('k1 × ('k2 × 'v) list) list ⇒ (('k1 × 'k2) ⇒ 'v) ⇒ bool" where
"l2m_valid _ M f ≡ ∀ (k1, kvs) ∈ set M. ∀ (k2, v) ∈ set kvs. f (k1, k2) = v"
lemma satisfactory_l2m: "satisfactory l2m_valid l2m"
proof-
have l2m_empty: "∀f. l2m_valid l2m (memory.empty l2m ()) f" by (simp add: l2m_def l2m_valid_def)
{
fix f k1 k2 M
assume M_valid: "l2m_valid l2m M f"
from M_valid have "l2m_valid l2m (memory.store l2m M ((k1, k2), f (k1, k2))) f"
proof (induct M)
case Nil thus ?case by (simp add: l2m_valid_def l2m_def)
next
case (Cons akvs rec)
obtain a kvs where akvs: "akvs = (a, kvs)" by (cases akvs) auto
show ?case
proof (cases "k1 = a")
case True note Hk1a = this
show ?thesis
proof (cases "∃b. (k2, b) ∈ set kvs")
case True
from lm_store_sound1[OF this] Cons(2) akvs Hk1a
show ?thesis by (simp add: l2m_valid_def l2m_def)
next
case False
from lm_store_sound2[OF this] Cons(2) akvs Hk1a
show ?thesis by (simp add: l2m_valid_def l2m_def)
qed
next
case False
with akvs have store_rew: "memory.store l2m (akvs # rec) ((k1, k2), f (k1, k2)) ≡
akvs # (memory.store l2m rec ((k1, k2), f (k1, k2)))" by (simp add: l2m_def)
from Cons(2) have "l2m_valid l2m rec f" by (simp add: l2m_valid_def)
from Cons(1)[OF this] Cons(2) False akvs store_rew
show ?thesis by (simp add: l2m_valid_def)
qed
qed
}
hence l2m_store: "∀f a M. l2m_valid l2m M f
⟶ l2m_valid l2m (memory.store l2m M (a, f a)) f" by fast
{
fix M f k b
assume l2m_valid: "l2m_valid l2m M f" and Hget: "memory.lookup l2m M k = Some b"
obtain k1 k2 where kkk: "k = (k1, k2)" by (cases k) auto
from l2m_valid Hget have "f k = b"
proof (induct M)
case Nil thus ?case by (simp add: l2m_def)
next
case (Cons akvs rec)
obtain a kvs where akvs: "akvs = (a, kvs)" by (cases "akvs") auto
show ?case
proof (cases "k1 = a")
case True
with Cons(2) akvs kkk Cons(3) map_of_SomeD[of kvs k2 b]
show ?thesis by (auto simp: l2m_valid_def l2m_def)
next
case False
from Cons(2) have "l2m_valid l2m rec f" by (simp add: l2m_valid_def)
from Cons(1)[OF this] Cons(3) False akvs kkk show ?thesis by (simp add: l2m_def)
qed
qed
}
hence l2m_valid: "∀M f. l2m_valid l2m M f ⟶ valid l2m M f" by (auto simp: valid_def)
with l2m_empty l2m_store show ?thesis unfolding satisfactory_def by fast
qed
"approx_tree"">datatype ('a,'m)"approx_tree" =
Leaf 'a 'm
| Node 'a "('a,'m)approx_tree" "('a, 'm)approx_tree"
definition atm_empty :: "('m, 'k, 'v)memory ⇒ 'a ⇒ unit ⇒ ('a, 'm)approx_tree" where
"atm_empty model def _ ≡ Leaf def (memory.empty model ())"
fun atm_store_rec :: "('m, 'k, 'v)memory ⇒ ('a ⇒ 'a ⇒ comparison) ⇒
('a,'m)approx_tree ⇒ 'a ⇒ ('k × 'v) ⇒ ('a,'m)approx_tree" where
"atm_store_rec model cmp (Leaf a1 M) a2 kv =
(case cmp a1 a2 of
Less ⇒ Node a1 (Leaf a1 M) (Leaf a2 (singleton model kv))
| Equal ⇒ Leaf a1 (memory.store model M kv)
| More ⇒ Node a2 (Leaf a2 (singleton model kv)) (Leaf a1 M))" |
"atm_store_rec model cmp (Node a1 AT1 AT2) a2 kv =
(case cmp a1 a2 of
Less ⇒ Node a1 AT1 (atm_store_rec model cmp AT2 a2 kv)
| _ ⇒ Node a1 (atm_store_rec model cmp AT1 a2 kv) AT2)"
definition atm_store :: "('m, 'k, 'v)memory ⇒ ('k ⇒ 'a) ⇒ ('a ⇒ 'a ⇒ comparison) ⇒
('a,'m)approx_tree ⇒ ('k × 'v) ⇒ ('a, 'm)approx_tree" where
"atm_store model approx cmp M kv ≡ atm_store_rec model cmp M (approx (fst kv)) kv"
fun atm_lookup_rec :: "('m, 'k, 'v)memory ⇒ ('a ⇒ 'a ⇒ comparison) ⇒
('a,'m)approx_tree ⇒ 'a ⇒ 'k ⇒ 'v option" where
"atm_lookup_rec model cmp (Leaf a1 M) a2 k =
(case cmp a1 a2 of
Equal ⇒ memory.lookup model M k
| _ ⇒ None)" |
"atm_lookup_rec model cmp (Node a1 AT1 AT2) a2 k =
(case cmp a1 a2 of
Less ⇒ atm_lookup_rec model cmp AT2 a2 k
| _ ⇒ atm_lookup_rec model cmp AT1 a2 k)"
definition atm_lookup :: "('m, 'k, 'v)memory ⇒ ('k ⇒ 'a) ⇒ ('a ⇒ 'a ⇒ comparison) ⇒
('a, 'm)approx_tree ⇒ 'k ⇒ 'v option" where
"atm_lookup model approx cmp M k ≡ atm_lookup_rec model cmp M (approx k) k"
definition atm :: "('m, 'k, 'v)memory ⇒ ('k ⇒ 'a) ⇒ ('a ⇒ 'a ⇒ comparison) ⇒ 'a ⇒
(('a, 'm)approx_tree,'k,'v)memory"
where "atm model approx cmp df ≡ ⦇ empty = atm_empty model df,
lookup = atm_lookup model approx cmp , store = atm_store model approx cmp ⦈"
fun atm_valid :: "('m, 'k, 'v)memory ⇒ (('m, 'k, 'v)memory ⇒ 'm ⇒ ('k ⇒ 'v) ⇒ bool) ⇒
('a, 'm) approx_tree ⇒ ('k ⇒ 'v) ⇒ bool" where
"atm_valid model model_P (Leaf a kvs) f = (model_P model kvs f)" |
"atm_valid model model_P (Node a lst rst) f = (
(atm_valid model model_P lst f) ∧ (atm_valid model model_P rst f))"
locale approximation_tree =
fixes model :: "('m, 'k, 'v)memory"
fixes model_P :: "('m, 'k, 'v)memory ⇒ 'm ⇒ ('k ⇒ 'v) ⇒ bool"
fixes approx :: "'k ⇒ 'a"
fixes comp :: "'a ⇒ 'a ⇒ comparison"
fixes default :: "'a"
assumes comp_eq: "∀ h i. (comp h i = Equal) = (h = i)"
and comp_lt_gt: "∀ h i. (comp h i = Less) = (comp i h = More)"
and model_satisfactory: "satisfactory model_P model"
begin
definition atm_inst where "atm_inst = atm model approx comp default"
lemma satisfactory_atm: "satisfactory (λ_. atm_valid model model_P) atm_inst"
proof-
from model_satisfactory[unfolded satisfactory_def]
have atm_empty: "∀ f. atm_valid model model_P (memory.empty atm_inst ()) f"
by (simp add: atm_inst_def atm_def atm_empty_def)
{
fix M :: "('a, 'm)approx_tree" and f ak k
assume M_valid: "atm_valid model model_P M f"
hence "atm_valid model model_P (atm_store_rec model comp M ak (k, f k)) f"
proof (induct M)
case (Leaf a kvs)
thus ?case
proof (cases "comp a ak")
case Equal note Haak = this
thus ?thesis
using Leaf model_satisfactory[unfolded satisfactory_def]
by simp
next
case Less note Haak = this
thus ?thesis
using Leaf comp_eq comp_lt_gt[rule_format, of a ak]
singleton_valid[OF model_satisfactory, of f k "f k"]
by simp
next
case More note Haak = this
thus ?thesis
using Leaf comp_eq singleton_valid[OF model_satisfactory, of f k "f k"]
by simp
qed
next
case (Node a lst rst) thus ?case by (cases "comp a ak") auto
qed
}
hence atm_store: "∀f a M. atm_valid model model_P M f ⟶
atm_valid model model_P (memory.store atm_inst M (a, f a)) f"
by (auto simp: atm_inst_def atm_def atm_store_def)
{
fix M f ak k v
assume "atm_valid model model_P M f"
and "atm_lookup_rec model comp M ak k = Some v"
hence "f k = v"
proof (induct M)
case (Leaf a kvs)
show ?case
proof (cases "comp a ak = Equal")
case True
with Leaf model_satisfactory[unfolded satisfactory_def valid_def]
show ?thesis by auto
next
case False
with Leaf(2) show ?thesis by (cases "comp a ak") auto
qed
next
case (Node a lst rst) thus ?case by (cases "comp a ak") auto
qed
}
hence atm_valid: "∀f M. atm_valid model model_P M f ⟶ valid atm_inst M f"
by (simp add: atm_inst_def atm_def valid_def atm_lookup_def)
from atm_empty atm_store atm_valid show ?thesis by simp
qed
end
hide_const (open) More Less Equal
end