Theory ArityAnalysisFix

theory ArityAnalysisFix
imports ArityAnalysisSig ArityAnalysisAbinds
begin

context ArityAnalysis
begin

definition Afix ::  "heap  (AEnv  AEnv)"
  where "Afix Γ = (Λ ae. (μ  ae'. ABinds Γ  ae'  ae))"

lemma Afix_eq: "Afix Γae = (μ ae'. (ABinds Γae')  ae)"
  unfolding Afix_def by simp

lemma Afix_strict[simp]: "Afix Γ = "
  unfolding Afix_eq
  by (rule fix_eqI) auto

lemma Afix_least_below: "ABinds Γ  ae'  ae'  ae  ae'  Afix Γ  ae  ae'"
  unfolding Afix_eq
  by (auto intro: fix_least_below)

lemma Afix_unroll: "Afix Γae = ABinds Γ  (Afix Γae)  ae"
  unfolding Afix_eq
  apply (subst fix_eq)
  by simp

lemma Abinds_below_Afix: "ABinds Δ  Afix Δ"
  apply (rule cfun_belowI)
  apply (simp add: Afix_eq)
  apply (subst fix_eq, simp)
  apply (rule below_trans[OF _ join_above2])
  apply (rule monofun_cfun_arg)
  apply (subst fix_eq, simp)
  done

lemma Afix_above_arg: "ae  Afix Γ  ae"
  by (subst Afix_unroll) simp

lemma Abinds_Afix_below[simp]: "ABinds Γ(Afix Γae)  Afix Γae"
  apply (subst Afix_unroll) back
  apply simp
  done


(*lemma Abinds_Afix[simp]: "ABinds Γ⋅(Afix Γ⋅ae) = Afix Γ⋅ae"
  unfolding Afix_eq
  apply (subst fix_eq) back apply simp
  apply (rule below_trans[OF ABinds_above_arg monofun_cfun_arg])
  apply (subst fix_eq) apply simp
  done
*)

lemma Afix_reorder: "map_of Γ = map_of Δ  Afix Γ = Afix Δ"
  by (intro cfun_eqI)(simp add: Afix_eq cong: Abinds_reorder)

lemma Afix_repeat_singleton: "(μ xa. Afix Γ(esing x(n  xa x)  ae)) = Afix Γ(esing xn  ae)"
  apply (rule below_antisym)
  defer
  apply (subst fix_eq, simp)
  apply (intro monofun_cfun_arg join_mono below_refl join_above1)

  apply (rule fix_least_below, simp)
  apply (rule Afix_least_below, simp)
  apply (intro join_below below_refl iffD2[OF esing_below_iff] below_trans[OF _ fun_belowD[OF Afix_above_arg]]  below_trans[OF _ Afix_above_arg] join_above1)
  apply simp
  done

lemma Afix_join_fresh: "ae' ` (domA Δ)  {}    Afix Δ(ae  ae') = (Afix Δae)  ae'"
  apply (rule below_antisym)
  apply (rule Afix_least_below)
  apply (subst Abinds_join_fresh, simp)
  apply (rule below_trans[OF Abinds_Afix_below join_above1])
  apply (rule join_below)
  apply (rule below_trans[OF Afix_above_arg join_above1])
  apply (rule join_above2)
  apply (rule join_below[OF monofun_cfun_arg [OF join_above1]])
  apply (rule below_trans[OF join_above2 Afix_above_arg])
  done


lemma Afix_restr_fresh:
  assumes "atom ` S ♯* Γ"
  shows "Afix Γae f|` (- S) = Afix Γ(ae  f|` (- S)) f|` (- S)"
  unfolding Afix_eq
proof (rule parallel_fix_ind[where P = "λ x y . x f|` (- S) = y  f|` (- S)"], goal_cases)
  case 1
  show ?case by simp
next
  case 2
  show ?case ..
next
  case prems: (3 aeL aeR)
  have "(ABinds ΓaeL  ae) f|` (- S) = ABinds ΓaeL  f|` (- S)  ae  f|` (- S)" by (simp add: env_restr_join)
  also have " = ABinds Γ(aeL  f|` (- S)) f|` (- S)  ae  f|` (- S)" by (rule arg_cong[OF ABinds_restr_fresh[OF assms]])
  also have " = ABinds Γ(aeR  f|` (- S)) f|` (- S)  ae  f|` (- S)" unfolding prems ..
  also have " = ABinds ΓaeR f|` (- S)  ae  f|` (- S)" by (rule arg_cong[OF ABinds_restr_fresh[OF assms, symmetric]])
  also have " = (ABinds ΓaeR  ae f|` (- S)) f|` (- S)" by (simp add: env_restr_join)
  finally show ?case by simp
qed

lemma Afix_restr:
  assumes "domA Γ  S"
  shows "Afix Γae f|` S = Afix Γ(ae  f|` S) f|` S"
  unfolding Afix_eq
  apply (rule parallel_fix_ind[where P = "λ x y . x f|`S = y  f|` S"])
  apply simp
  apply rule
  apply (auto   simp add: env_restr_join)
  apply (metis  ABinds_restr[OF assms, symmetric])
  done

lemma Afix_restr_subst':
  assumes " x' e a. (x',e)  set Γ  Aexp e[x::=y]a f|` S = Aexp ea f|` S"
  assumes "x  S"
  assumes "y  S"
  assumes "domA Γ  S"
  shows "Afix Γ[x::h=y]ae f|` S = Afix Γ(ae f|` S) f|` S"
  unfolding Afix_eq
  apply (rule parallel_fix_ind[where P = "λ x y . x f|`S = y  f|` S"])
  apply simp
  apply rule
  apply (auto   simp add: env_restr_join)
  apply (subst ABinds_restr_subst[OF assms]) apply assumption
  apply (subst ABinds_restr[OF assms(4)]) back
  apply simp
  done

 
lemma Afix_subst_approx:
  assumes " v n. v  domA Γ  Aexp (the (map_of Γ v))[y::=x]n  (Aexp (the (map_of Γ v))n)(y := , x := up0)"
  assumes "x  domA Γ"
  assumes "y  domA Γ"
  shows "Afix Γ[y::h= x](ae(y := , x := up0))  (Afix Γae)(y := , x := up0)"
  unfolding Afix_eq
proof (rule parallel_fix_ind[where P = "λ aeL aeR . aeL  aeR(y := , x := up0)"], goal_cases)
  case 1
  show ?case by simp
next
  case 2
  show ?case..
next
  case (3 aeL aeR)
  hence "ABinds Γ[y::h=x]aeL  ABinds Γ[y::h=x](aeR (y := , x := up0))" by (rule monofun_cfun_arg)
  also have "   (ABinds ΓaeR)(y := , x := up0)"
    using assms
  proof (induction rule: ABinds.induct, goal_cases)
    case 1
    thus ?case by simp
  next
    case prems: (2 v e Γ)
    have "n. Aexp e[y::=x]n  (Aexp en)(y := , x := up0)" using prems(2)[where v = v] by auto
    hence IH1: " n. fup(Aexp e[y::=x])n  (fup(Aexp e)n)(y := , x := up0)"  by (case_tac n) auto

    have "ABinds (delete v Γ)[y::h=x](aeR(y := , x := up0))  (ABinds (delete v Γ)aeR)(y := , x := up0)"
      apply (rule prems) using prems(2,3,4) by fastforce+
    hence IH2: "ABinds (delete v Γ[y::h=x])(aeR(y := , x := up0))  (ABinds (delete v Γ)aeR)(y := , x := up0)"
       unfolding subst_heap_delete.
    
    have [simp]: "(aeR(y := , x := up0)) v = aeR v" using prems(3,4) by auto
   
    show ?case by (simp del: fun_upd_apply join_comm) (rule join_mono[OF IH1 IH2])
  qed
  finally have "ABinds Γ[y::h=x]aeL  (ABinds ΓaeR)(y := , x := up0)"
    by this simp
  thus ?case
    by (auto simp add: join_below_iff elim: below_trans)
qed

end

lemma Afix_eqvt[eqvt]: "π  (ArityAnalysis.Afix Aexp Γ) = ArityAnalysis.Afix  (π  Aexp) (π  Γ)"
  unfolding ArityAnalysis.Afix_def
  by perm_simp (simp add: Abs_cfun_eqvt)


lemma Afix_cong[fundef_cong]:
  " ( e. e  snd ` set heap2  aexp1 e = aexp2 e); heap1 = heap2 
       ArityAnalysis.Afix aexp1 heap1 = ArityAnalysis.Afix aexp2 heap2"
   unfolding ArityAnalysis.Afix_def by (metis Abinds_cong)


context EdomArityAnalysis
begin

lemma Afix_edom: "edom (Afix Γ  ae)  fv Γ  edom ae"
  unfolding Afix_eq
  by (rule fix_ind[where P = "λ ae' . edom ae'  fv Γ  edom ae"] )
     (auto dest: subsetD[OF edom_AnalBinds])

lemma ABinds_lookup_fresh:
  "atom v  Γ  (ABinds Γae) v = "
by (induct Γ rule: ABinds.induct) (auto simp add: fresh_Cons fresh_Pair fup_Aexp_lookup_fresh fresh_delete)

lemma Afix_lookup_fresh:
  assumes "atom v  Γ"
  shows "(Afix Γae) v = ae v"
  apply (rule below_antisym)
  apply (subst Afix_eq)
  apply (rule fix_ind[where  P = "λ ae'. ae' v  ae v"])
  apply (auto simp add: ABinds_lookup_fresh[OF assms] fun_belowD[OF Afix_above_arg])
  done

lemma Afix_comp2join_fresh:
  "atom ` (domA Δ) ♯* Γ  ABinds Δ(Afix Γae) = ABinds Δae"
proof (induct Δ rule: ABinds.induct)
  case 1 show ?case by (simp add: Afix_above_arg del: fun_meet_simp)
next
  case (2 v e Δ)
  from 2(2)
  have "atom v  Γ" and  "atom ` domA (delete v Δ) ♯* Γ"
    by (auto simp add: fresh_star_def)
  from 2(1)[OF this(2)]
  show ?case by (simp del: fun_meet_simp add: Afix_lookup_fresh[OF atom v  Γ])
qed

lemma Afix_append_fresh:
  assumes "atom ` domA Δ ♯* Γ"
  shows "Afix (Δ @ Γ)ae = Afix Γ(Afix Δae)"
proof (rule below_antisym)
  show *: "Afix (Δ @ Γ)ae  Afix Γ(Afix Δae)"
  apply (rule Afix_least_below)
  apply (simp add: Abinds_append_disjoint[OF fresh_distinct[OF assms]] Afix_comp2join_fresh[OF assms])
  apply (rule below_trans[OF join_mono[OF Abinds_Afix_below Abinds_Afix_below]])
  apply (simp_all add: Afix_above_arg  below_trans[OF Afix_above_arg Afix_above_arg])
  done
next
  show "Afix Γ(Afix Δae)  Afix (Δ @ Γ)ae"
  proof (rule Afix_least_below)
    show "ABinds Γ(Afix (Δ @ Γ)ae)  Afix (Δ @ Γ)ae"
      apply (rule below_trans[OF _ Abinds_Afix_below])
      apply (subst Abinds_append_disjoint[OF fresh_distinct[OF assms]])
      apply simp
      done
    have "ABinds Δ(Afix (Δ @ Γ)ae)  Afix (Δ @ Γ)ae"
      apply (rule below_trans[OF _ Abinds_Afix_below])
      apply (subst Abinds_append_disjoint[OF fresh_distinct[OF assms]])
      apply simp
      done
    thus "Afix Δae  Afix (Δ @ Γ)ae"
      apply (rule Afix_least_below)
      apply (rule Afix_above_arg)
      done
  qed
qed


lemma Afix_e_to_heap:
   "Afix (delete x Γ)(fup(Aexp e)n  ae)  Afix ((x, e) # delete x Γ)(esing xn  ae)"
    apply (simp add: Afix_eq)
    apply (rule fix_least_below, simp)
    apply (intro join_below)
    apply (subst fix_eq, simp)
    apply (subst fix_eq, simp)

    apply (rule below_trans[OF _ join_above2])
    apply (rule below_trans[OF _ join_above2])
    apply (rule below_trans[OF _ join_above2])
    apply (rule monofun_cfun_arg)
    apply (subst fix_eq, simp)
      
    apply (subst fix_eq, simp) back apply (simp add: below_trans[OF _ join_above2])
    done

lemma Afix_e_to_heap':
   "Afix (delete x Γ)(Aexp en)  Afix ((x, e) # delete x Γ)(esing x(upn))"
using Afix_e_to_heap[where ae =  and n = "upn"] by simp

end


end