Theory SestoftConf

theory SestoftConf
imports Launchbury.Terms Launchbury.Substitution
begin

datatype stack_elem = Alts exp exp | Arg var | Upd var | Dummy var

instantiation stack_elem :: pt
begin
definition  "π  x = (case x of (Alts e1 e2)  Alts (π  e1) (π  e2) | (Arg v)  Arg (π  v) | (Upd v)  Upd (π  v) | (Dummy v)  Dummy (π  v))"
instance
  by standard (auto simp add: permute_stack_elem_def split:stack_elem.split)
end

lemma Alts_eqvt[eqvt]: "π  (Alts e1 e2) = Alts (π  e1) (π  e2)"
  and Arg_eqvt[eqvt]: "π  (Arg v) = Arg (π  v)"
  and Upd_eqvt[eqvt]: "π  (Upd v) = Upd (π  v)"
  and Dummy_eqvt[eqvt]: "π  (Dummy v) = Dummy (π  v)"
  by (auto simp add: permute_stack_elem_def split:stack_elem.split)

lemma supp_Alts[simp]: "supp (Alts e1 e2) = supp e1  supp e2" unfolding supp_def by (auto simp add: Collect_imp_eq Collect_neg_eq)
lemma supp_Arg[simp]: "supp (Arg v) = supp v"  unfolding supp_def by auto
lemma supp_Upd[simp]: "supp (Upd v) = supp v"  unfolding supp_def by auto
lemma supp_Dummy[simp]: "supp (Dummy v) = supp v"  unfolding supp_def by auto
lemma fresh_Alts[simp]: "a  Alts e1 e2 = (a  e1  a  e2)" unfolding fresh_def by auto
lemma fresh_star_Alts[simp]: "a ♯* Alts e1 e2 = (a ♯* e1  a ♯* e2)" unfolding fresh_star_def by auto
lemma fresh_Arg[simp]: "a  Arg v = a  v" unfolding fresh_def by auto
lemma fresh_Upd[simp]: "a  Upd v = a  v" unfolding fresh_def by auto
lemma fresh_Dummy[simp]: "a  Dummy v = a  v" unfolding fresh_def by auto
lemma fv_Alts[simp]: "fv (Alts e1 e2) = fv e1  fv e2"  unfolding fv_def by auto
lemma fv_Arg[simp]: "fv (Arg v) = fv v"  unfolding fv_def by auto
lemma fv_Upd[simp]: "fv (Upd v) = fv v"  unfolding fv_def by auto
lemma fv_Dummy[simp]: "fv (Dummy v) = fv v"  unfolding fv_def by auto

instance stack_elem :: fs
  by standard (case_tac x, auto simp add: finite_supp)

type_synonym stack = "stack_elem list"

fun ap :: "stack  var set" where
  "ap [] = {}"
| "ap (Alts e1 e2 # S) = ap S"
| "ap (Arg x # S) = insert x (ap S)"
| "ap (Upd x # S) = ap S"
| "ap (Dummy x # S) = ap S"
fun upds :: "stack  var set" where
  "upds [] = {}"
| "upds (Alts e1 e2 # S) = upds S"
| "upds (Upd x # S) = insert x (upds S)"
| "upds (Arg x # S) = upds S"
| "upds (Dummy x # S) = upds S"
fun dummies :: "stack  var set" where
  "dummies [] = {}"
| "dummies (Alts e1 e2 # S) = dummies S"
| "dummies (Upd x # S) = dummies S"
| "dummies (Arg x # S) = dummies S"
| "dummies (Dummy x # S) = insert x (dummies S)"
fun flattn :: "stack  var list" where
  "flattn [] = []"
| "flattn (Alts e1 e2 # S) = fv_list e1 @ fv_list e2 @ flattn S"
| "flattn (Upd x # S) = x # flattn S"
| "flattn (Arg x # S) = x # flattn S"
| "flattn (Dummy x # S) = x # flattn S"
fun upds_list :: "stack  var list" where
  "upds_list [] = []"
| "upds_list (Alts e1 e2 # S) = upds_list S"
| "upds_list (Upd x # S) = x # upds_list S"
| "upds_list (Arg x # S) = upds_list S"
| "upds_list (Dummy x # S) = upds_list S"

lemma set_upds_list[simp]:
  "set (upds_list S) = upds S"
  by (induction S rule: upds_list.induct) auto

lemma ups_fv_subset: "upds S  fv S"
  by (induction S rule: upds.induct) auto
lemma fresh_distinct_ups: "atom ` V ♯* S  V  upds S = {}"
   by (auto dest!: fresh_distinct_fv subsetD[OF ups_fv_subset])
lemma ap_fv_subset: "ap S  fv S"
  by (induction S rule: upds.induct) auto
lemma dummies_fv_subset: "dummies S  fv S"
  by (induction S rule: dummies.induct) auto

lemma fresh_flattn[simp]: "atom (a::var)  flattn S  atom a  S"
  by (induction S rule:flattn.induct) (auto simp add: fresh_Nil fresh_Cons fresh_append fresh_fv[OF finite_fv])
lemma fresh_star_flattn[simp]: "atom ` (as:: var set) ♯* flattn S  atom ` as ♯* S"
  by (auto simp add: fresh_star_def)
lemma fresh_upds_list[simp]: "atom a  S  atom (a::var)  upds_list S"
  by (induction S rule:upds_list.induct) (auto simp add: fresh_Nil fresh_Cons fresh_append fresh_fv[OF finite_fv])
lemma fresh_star_upds_list[simp]: "atom ` (as:: var set) ♯* S  atom ` (as:: var set) ♯* upds_list S"
  by (auto simp add: fresh_star_def)

lemma upds_append[simp]: "upds (S@S') = upds S  upds S'"
  by (induction S rule: upds.induct) auto
lemma upds_map_Dummy[simp]: "upds (map Dummy l) = {}"
  by (induction l) auto

lemma upds_list_append[simp]: "upds_list (S@S') = upds_list S @ upds_list S'"
  by (induction S rule: upds.induct) auto
lemma upds_list_map_Dummy[simp]: "upds_list (map Dummy l) = []"
  by (induction l) auto

lemma dummies_append[simp]: "dummies (S@S') = dummies S  dummies S'"
  by (induction S rule: dummies.induct) auto
lemma dummies_map_Dummy[simp]: "dummies (map Dummy l) = set l"
  by (induction l) auto

lemma map_Dummy_inj[simp]: "map Dummy l = map Dummy l'  l = l'"
  apply (induction l arbitrary: l')
  apply (case_tac [!] l')
  apply auto
  done

type_synonym conf = "(heap × exp × stack)"

inductive boring_step where
  "isVal e  boring_step (Γ, e, Upd x # S)"


fun restr_stack :: "var set  stack  stack"
  where "restr_stack V [] = []"
      | "restr_stack V (Alts e1 e2 # S) = Alts e1 e2 # restr_stack V S"
      | "restr_stack V (Arg x # S) = Arg x # restr_stack V S"
      | "restr_stack V (Upd x # S) = (if x  V then Upd x # restr_stack V S else restr_stack V S)"
      | "restr_stack V (Dummy x # S) = Dummy x # restr_stack V S"

lemma restr_stack_cong:
  "( x. x  upds S  x  V  x  V')  restr_stack V S = restr_stack V' S"
  by (induction V S rule: restr_stack.induct) auto

lemma upds_restr_stack[simp]: "upds (restr_stack V S) = upds S  V"
  by (induction V S rule: restr_stack.induct) auto

lemma fresh_star_restict_stack[intro]:
  "a ♯* S  a ♯* restr_stack V S"
  by (induction V S rule: restr_stack.induct) (auto simp add: fresh_star_Cons)

lemma restr_stack_restr_stack[simp]:
  "restr_stack V (restr_stack V' S) = restr_stack (V  V') S"
  by (induction V S rule: restr_stack.induct) auto

lemma Upd_eq_restr_stackD:
  assumes "Upd x # S = restr_stack V S'"
  shows "x  V"
  using arg_cong[where f = upds, OF assms]
  by auto
lemma Upd_eq_restr_stackD2:
  assumes "restr_stack V S' = Upd x # S"
  shows "x  V"
  using arg_cong[where f = upds, OF assms]
  by auto


lemma restr_stack_noop[simp]:
  "restr_stack V S = S  upds S  V"
  by (induction V S rule: restr_stack.induct)
     (auto dest: Upd_eq_restr_stackD2)
  

subsubsection ‹Invariants of the semantics›

inductive invariant :: "('a  'a  bool)  ('a  bool)  bool"
  where "( x y. rel x y  I x  I y)  invariant rel I"

lemmas invariant.intros[case_names step]

lemma invariantE:
  "invariant rel I  rel x y  I x  I y" by (auto elim: invariant.cases)

lemma invariant_starE:
  "rtranclp rel x y  invariant rel I   I x  I y"
  by (induction rule: rtranclp.induct) (auto elim: invariantE)

lemma invariant_True:
  "invariant rel (λ _. True)"
by (auto intro: invariant.intros)

lemma invariant_conj:
  "invariant rel I1  invariant rel I2  invariant rel (λ x. I1 x  I2 x)"
by (auto simp add: invariant.simps)


lemma rtranclp_invariant_induct[consumes 3, case_names base step]:
  assumes "r** a b"
  assumes "invariant r I"
  assumes "I a"
  assumes "P a"
  assumes "(y z. r** a y  r y z  I y  I z  P y  P z)"
  shows "P b"
proof-
  from assms(1,3)
  have "P b" and "I b"
  proof(induction)
    case base
    from P a show "P a".
    from I a show "I a".
  next
    case (step y z)
    with I a have "P y" and "I y" by auto

    from assms(2) r y z I y
    show "I z" by (rule invariantE)

    from r** a y r y z I y I z P y
    show "P z" by (rule assms(5))
  qed
  thus "P b" by-
qed


fun closed :: "conf  bool"
  where "closed (Γ, e, S)  fv (Γ, e, S)  domA Γ  upds S"

fun heap_upds_ok where "heap_upds_ok (Γ,S)  domA Γ  upds S = {}  distinct (upds_list S)"

abbreviation heap_upds_ok_conf :: "conf  bool"
  where "heap_upds_ok_conf c  heap_upds_ok (fst c, snd (snd c))"

lemma heap_upds_okE: "heap_upds_ok (Γ, S)  x  domA Γ  x  upds S"
  by auto

lemma heap_upds_ok_Nil[simp]: "heap_upds_ok (Γ, [])" by auto
lemma heap_upds_ok_app1: "heap_upds_ok (Γ, S)  heap_upds_ok (Γ,Arg x # S)" by auto
lemma heap_upds_ok_app2: "heap_upds_ok (Γ, Arg x # S)  heap_upds_ok (Γ, S)" by auto
lemma heap_upds_ok_alts1: "heap_upds_ok (Γ, S)  heap_upds_ok (Γ,Alts e1 e2 # S)" by auto
lemma heap_upds_ok_alts2: "heap_upds_ok (Γ, Alts e1 e2 # S)  heap_upds_ok (Γ, S)" by auto

lemma heap_upds_ok_append:
  assumes "domA Δ  upds S = {}"
  assumes "heap_upds_ok (Γ,S)"
  shows "heap_upds_ok (Δ@Γ, S)"
  using assms
  unfolding heap_upds_ok.simps
  by auto

lemma heap_upds_ok_let:
  assumes "atom ` domA Δ ♯* S"
  assumes "heap_upds_ok (Γ, S)"
  shows "heap_upds_ok (Δ @ Γ, S)"
using assms(2) fresh_distinct_fv[OF assms(1)]
by (auto intro: heap_upds_ok_append dest: subsetD[OF ups_fv_subset])

lemma heap_upds_ok_to_stack:
  "x  domA Γ  heap_upds_ok (Γ, S)  heap_upds_ok (delete x Γ, Upd x #S)"
  by (auto)

lemma heap_upds_ok_to_stack':
  "map_of Γ x = Some e  heap_upds_ok (Γ, S)  heap_upds_ok (delete x Γ, Upd x #S)"
  by (metis Domain.DomainI domA_def fst_eq_Domain heap_upds_ok_to_stack map_of_SomeD)

lemma heap_upds_ok_delete:
  "heap_upds_ok (Γ, S)  heap_upds_ok (delete x Γ, S)"
  by auto

lemma heap_upds_ok_restrictA:
  "heap_upds_ok (Γ, S)  heap_upds_ok (restrictA V Γ, S)"
  by auto

lemma heap_upds_ok_restr_stack:
  "heap_upds_ok (Γ, S)  heap_upds_ok (Γ, restr_stack V S)"
  apply auto
  by (induction V S rule: restr_stack.induct) auto

lemma heap_upds_ok_to_heap:
  "heap_upds_ok (Γ, Upd x # S)  heap_upds_ok ((x,e) # Γ, S)"
  by auto

lemma heap_upds_ok_reorder:
  "x  domA Γ  heap_upds_ok (Γ, S)  heap_upds_ok ((x,e) # delete x Γ, S)"
  by (intro heap_upds_ok_to_heap heap_upds_ok_to_stack)

lemma heap_upds_ok_upd:
"heap_upds_ok (Γ, Upd x # S)  x  domA Γ  x  upds S"
  by auto


lemmas heap_upds_ok_intros[intro] =
  heap_upds_ok_to_heap heap_upds_ok_to_stack heap_upds_ok_to_stack' heap_upds_ok_reorder
  heap_upds_ok_app1 heap_upds_ok_app2 heap_upds_ok_alts1 heap_upds_ok_alts2 heap_upds_ok_delete
  heap_upds_ok_restrictA heap_upds_ok_restr_stack
  heap_upds_ok_let
lemmas heap_upds_ok.simps[simp del]


end