Theory Pointer_Map

theory Pointer_Map
imports Main
section‹Pointermap›
theory Pointer_Map
imports Main
begin

text‹
  We need a datastructure that supports the following two operations:
  \begin{itemize}
    \item Given an element, it can construct a pointer (i.e., a small representation) of that element. It will always construct the same pointer for equal elements.
    \item Given a pointer, we can retrieve the element
  \end{itemize}
›

record 'a pointermap = 
  entries :: "'a list"
  getentry :: "'a ⇒ nat option"
  
definition "pointermap_sane m ≡ (distinct (entries m) ∧ 
  (∀n ∈ {..<length (entries m)}. getentry m (entries m ! n) = Some n) ∧ 
  (∀p i. getentry m p = Some i ⟶ entries m ! i = p ∧ i < length (entries m)))"

definition "empty_pointermap ≡ ⦇entries = [], getentry = λp. None ⦈"
lemma pointermap_empty_sane[simp, intro!]: "pointermap_sane empty_pointermap" unfolding empty_pointermap_def pointermap_sane_def by simp

definition "pointermap_insert a m ≡ ⦇entries = (entries m)@[a], getentry = (getentry m)(a ↦ length (entries m))⦈"

definition "pm_pth m p ≡ entries m ! p"

definition "pointermap_p_valid p m ≡ p < length (entries m)"

definition "pointermap_getmk a m ≡ (case getentry m a of Some p ⇒ (p,m) | None ⇒ let u = pointermap_insert a m in (the (getentry u a), u))"  

lemma pointermap_sane_appendD: "pointermap_sane s ⟹ m ∉ set (entries s) ⟹ pointermap_sane (pointermap_insert m s)"
unfolding pointermap_sane_def pointermap_insert_def
proof(intro conjI[rotated],goal_cases)
  case 3 thus ?case by simp
next
  case 2
  {
    fix n
    have " ⟦distinct (entries s) ∧ (∀x. x ∈ {..<length (entries s)} ⟶ getentry s (entries s ! x) = Some x) ∧ (∀p i. getentry s p = Some i ⟶ entries s ! i = p ∧ i < length (entries s)); m ∉ set (entries s);
          n ∈ {..<length (entries ⦇entries = entries s @ [m], getentry = getentry s(m ↦ length (entries s))⦈)}; n < length (entries s)⟧
         ⟹ getentry ⦇entries = entries s @ [m], getentry = getentry s(m ↦ length (entries s))⦈ (entries ⦇entries = entries s @ [m], getentry = getentry s(m ↦ length (entries s))⦈ ! n) = Some n"
         "⟦distinct (entries s) ∧ (∀x. x ∈ {..<length (entries s)} ⟶ getentry s (entries s ! x) = Some x) ∧ (∀p i. getentry s p = Some i ⟶ entries s ! i = p ∧ i < length (entries s)); m ∉ set (entries s);
          n ∈ {..<length (entries ⦇entries = entries s @ [m], getentry = getentry s(m ↦ length (entries s))⦈)}; ¬ n < length (entries s)⟧
         ⟹ getentry ⦇entries = entries s @ [m], getentry = getentry s(m ↦ length (entries s))⦈ (entries ⦇entries = entries s @ [m], getentry = getentry s(m ↦ length (entries s))⦈ ! n) = Some n"
      proof(goal_cases)
        case 1 note goal1 = 1
        from goal1(4) have sa: "⋀a. (entries s @ a) ! n = entries s ! n" by (simp add: nth_append)
        from goal1(1,4) have ih: "getentry s (entries s ! n) = Some n" by simp
        from goal1(2,4) have ne: "entries s ! n ≠ m" using nth_mem by fastforce
        from sa ih ne show ?case by simp
      next
        case 2 note goal2 = 2
        from goal2(3,4) have ln: "n = length (entries s)" by simp
        hence sa: "⋀a. (entries s @ [a]) ! n = a" by simp
        from sa ln show ?case by simp
      qed
  } note h = this
  with 2 show ?case by blast
    (*apply(unfold Ball_def) 
    apply(rule)
    apply(rule)
    apply(rename_tac n)
    apply(case_tac "n < length (entries s)")
  by(fact h)+*)
next
  case 1 thus ?case
    by(clarsimp simp add: nth_append fun_upd_same Ball_def) force
qed

lemma luentries_noneD: "getentry s a = None ⟹ pointermap_sane s ⟹ a ∉ set (entries s)"
unfolding pointermap_sane_def
proof(rule ccontr, goal_cases)
  case 1
  from 1(3) obtain n where "n < length (entries s)" "entries s ! n = a" unfolding in_set_conv_nth by blast
  with 1(2,1) show False by force
qed

lemma pm_pth_append: "pointermap_p_valid p m ⟹ pm_pth (pointermap_insert a m) p = pm_pth m p"
  unfolding pointermap_p_valid_def pm_pth_def pointermap_insert_def
  by(simp add: nth_append)

lemma pointermap_insert_in: "u = (pointermap_insert a m) ⟹ pm_pth u (the (getentry u a)) = a"
unfolding pointermap_insert_def pm_pth_def
by(simp)

lemma pointermap_insert_p_validI: "pointermap_p_valid p m ⟹ pointermap_p_valid p (pointermap_insert a m)"
  unfolding pointermap_insert_def pointermap_p_valid_def
  by simp

thm nth_eq_iff_index_eq
lemma pth_eq_iff_index_eq: "pointermap_sane m ⟹ pointermap_p_valid p1 m ⟹ pointermap_p_valid p2 m ⟹ (pm_pth m p1 = pm_pth m p2) ⟷ (p1 = p2)"
  unfolding pointermap_sane_def pointermap_p_valid_def pm_pth_def
  using nth_eq_iff_index_eq by blast
  
lemma pointermap_p_valid_updateI: "pointermap_sane m ⟹ getentry m a = None ⟹ u = pointermap_insert a m ⟹ p = the (getentry u a) ⟹ pointermap_p_valid p u"
by(simp add: pointermap_sane_def pointermap_p_valid_def pointermap_insert_def)

lemma pointermap_get_validI: "pointermap_sane m ⟹ getentry m a = Some p ⟹ pointermap_p_valid p m"
by(simp add: pointermap_sane_def pointermap_p_valid_def)

lemma pointermap_sane_getmkD: 
  assumes sn: "pointermap_sane m"
  assumes res: "pointermap_getmk a m = (p,u)"
  shows "pointermap_sane u ∧ pointermap_p_valid p u"
using sn res[symmetric]
  apply(cases "getentry m a")
   apply(simp_all add: pointermap_getmk_def Let_def split: option.split)
   apply(rule)
    apply(rule pointermap_sane_appendD)
     apply(clarify;fail)+
    apply(rule luentries_noneD)
     apply(clarify;fail)+
   apply(rule pointermap_p_valid_updateI[OF _ _ refl refl])
    apply(clarify;fail)+
  apply(erule pointermap_get_validI)
  by simp

lemma pointermap_update_pthI: 
  assumes sn: "pointermap_sane m"
  assumes res: "pointermap_getmk a m = (p,u)"
  shows "pm_pth u p = a"
using assms
  apply(simp add: pointermap_getmk_def Let_def split: option.splits)
   apply(meson pointermap_insert_in)
  apply(clarsimp simp: pointermap_sane_def pm_pth_def)
done

lemma pointermap_p_valid_inv:
  assumes "pointermap_p_valid p m"
  assumes "pointermap_getmk a m = (x,u)"
  shows "pointermap_p_valid p u"
using assms
by(simp add: pointermap_getmk_def Let_def split: option.splits) (meson pointermap_insert_p_validI)

lemma pointermap_p_pth_inv:
  assumes pv: "pointermap_p_valid p m"
  assumes u: "pointermap_getmk a m = (x,u)"
  shows "pm_pth u p = pm_pth m p"
using pm_pth_append[OF pv] u
by(clarsimp simp: pointermap_getmk_def Let_def split: option.splits)

lemma pointermap_backward_valid:
  assumes puv: "pointermap_p_valid p u"
  assumes u: "pointermap_getmk a m = (x,u)"
  assumes ne: "x ≠ p"
  shows "pointermap_p_valid p m"
(*using u
unfolding pointermap_getmk_def
apply(simp add: Let_def split: option.splits)
prefer 2 using puv apply(simp)
apply(clarify)
apply(simp add: pointermap_insert_def)
using puv apply(clarify)
apply(simp add: pointermap_p_valid_def)
using ne by linarith
*)
using assms
by (auto simp: Let_def pointermap_getmk_def pointermap_p_valid_def pointermap_insert_def split: option.splits)

end