Theory NU_Substs

(*<*)
theory NU_Substs
imports NU_Equ
begin
(*>*)

section ‹Substitutions›

text ‹
  Defines substitutions and composition of substitutions, and establishes some 
  facts of substitution and the equivalence relation.
›

type_synonym substs = "(string × trm) list"

fun look_up :: "string  substs  trm" where
  "look_up X []     = Susp [] X" |
  "look_up X (x#xs) = (if (X = fst x) then (snd x) else look_up X xs)"

fun subst :: "substs  trm  trm" where
  subst_unit: "subst s (Unit)          = Unit" |
  subst_susp: "subst s (Susp pi X)     = swap pi (look_up X s)" |
  subst_atom: "subst s (Atom a)        = Atom a" |
  subst_abst: "subst s (Abst a t)      = Abst a (subst s t)" |
  subst_paar: "subst s (Paar t1 t2)    = Paar (subst s t1) (subst s t2)" |
  subst_func: "subst s (Func F t)      = Func F (subst s t)"

declare subst_susp [simp del]

text ‹
 The notion of composition of substitutions (adapted from Martin Coen's Classical 
 Computational Logic).
›

fun alist_rec :: "substs  substs  (stringtrmsubstssubstssubsts)  substs" where
  "alist_rec [] c d = c" |
  "alist_rec (p # al) c d = d (fst p) (snd p) al (alist_rec al c d)"

definition comp ::  "substs  substs  substs" (infixl  81) where
 "s1  s2  alist_rec s2 s1 (λ x y xs g. (x,subst s1 y) # g)"

text ‹
  The domain of substitutions.
›

definition domn :: "(trm  trm)  string set" where
  "domn s  {X. (s (Susp [] X))  (Susp [] X)}" 

text ‹
  substitutions extend freshness environments.
›

definition ext_subst :: "fresh_envs  (trm  trm)  fresh_envs  bool" (" _  _ _ " [80,80,80] 80) where
  "nabla1  s nabla2  ((a,X)nabla2. nabla1a s (Susp [] X))"

text ‹
  Alpha-equality for substitutions 
›

definition subst_equ :: "fresh_envs  (trmtrm)  (trmtrm)  bool" (" _  _  _" [80,80,80] 80)
  where
  "nabla  s1  s2   X(domn s1domn s2). (nabla  s1 (Susp [] X)  s2 (Susp [] X))"

lemma subst_equ_symm: 
  assumes "nabla  s1  s2"
  shows "nabla  s2  s1"
  using assms equ_symm subst_equ_def[of nabla s1 s2]
    subst_equ_def[of nabla s2 s1] Un_commute[of domn s1 domn s2] by blast

lemma subst_equ_refl:
  shows "nabla  s  s"
  using equ_refl subst_equ_def Un_absorb by simp

lemma not_in_domn: 
  assumes "X  (domn s)"
  shows "s (Susp [] X) = (Susp [] X)"
  using assms domn_def by simp

lemma subst_swap_comm: 
  shows "subst s (swap pi t) = swap pi (subst s t)"
  using swap_append subst_susp by (induct t) auto

lemma subst_not_occurs: 
  assumes "¬(occurs X t)"
  shows "subst [(X,t2)] t = t"
proof-
  have i: "¬(occurs X t)  subst [(X,t2)] t = t"
    using subst_susp by (induct t) auto
  then show ?thesis using assms by simp
qed

lemma id_subst [simp]: 
  shows "subst [] t = t"
  using subst_susp by (induct t) auto

lemma subst_comp_id [simp]: 
  shows "subst (s  []) = subst s"
  using comp_def by simp

lemma id_comp_subst [simp]: 
  shows "subst ([]  s) = subst s"
proof(rule ext)
  fix t
  show "subst ([]  s) t = subst s t"
  proof(induction t arbitrary: s)
    case (Susp pi X)
    then show ?case using comp_def subst_susp
    proof (induction s)
      case Nil
      then show ?case
        using comp_def subst_susp by simp
    next
      case (Cons a s)
      then show ?case 
        using comp_def subst_susp by simp
    qed
  qed (simp_all)
qed

lemma subst_comp_expand: 
  shows "subst (s1  s2) t = subst s1 (subst s2 t)"
proof(induct t)
  case (Susp x1 x2)
  then show ?case 
   proof(induct s2)
      case Nil
      then show ?case using comp_def subst_susp subst_swap_comm by simp
   next
    case (Cons a s2)
    then show ?case using comp_def subst_susp subst_swap_comm by simp
  qed
qed (simp_all)

lemma subst_assoc: 
  shows "subst (s1  (s2  s3)) = subst ((s1  s2)  s3)"
proof(rule ext)
  fix t 
  show "subst (s1  (s2  s3)) t = subst (s1  s2  s3) t"
  proof(induct t)
    case (Susp pi X)
    then show ?case using subst_comp_expand by simp
  qed (simp_all)
qed

lemma fresh_subst:
  assumes "nabla1  a  t"
    and "nabla2  (subst s) nabla1"
  shows "nabla2  a  subst s t"
  using assms
proof(induction rule: fresh.induct)
  case (fresh_susp pi a X nabla)
  then show ?case 
    using ext_subst_def subst_susp fresh_swap_right 
    by auto
qed (auto)

lemma equ_subst:
  assumes "nabla1 t1 t2"
    and "nabla2  (subst s) nabla1"
  shows "nabla2 (subst s t1)(subst s t2)"
  using assms
proof(induction rule: equ.induct)
  case (equ_abst_ab a b nabla t2 t1)
  then show ?case 
    using subst_swap_comm fresh_subst equ.equ_abst_ab by simp 
next
  case (equ_susp pi1 pi2 X nabla)
  then show ?case 
    using subst_susp equ_pi1_pi2_add ext_subst_def subst_susp
    by fastforce
qed (auto)

lemma unif_1: 
  assumes "nabla  subst s (Susp pi X)  subst s t"
  shows "nabla  subst (s  [(X, swap (rev pi) t)])  subst s"
  using assms
  apply(simp only: subst_equ_def)
proof
  fix Xa
  assume hyps: "nabla  subst s (Susp pi X)  subst s t"
   "Xa  domn (subst (s  [(X, swap (rev pi) t)]))  domn (subst s)"
  show "nabla  subst (s  [(X, swap (rev pi) t)]) (Susp [] Xa)  subst s (Susp [] Xa)"
  proof-
    have one: 
      "nabla  subst (s  [(X, swap (rev pi) t)]) (Susp pi Xa)  
       subst s (subst [(X, swap (rev pi) t)] (Susp pi Xa))"
      using subst_comp_expand equ_refl by simp
    have two: 
      "nabla  subst s (subst [(X, swap (rev pi) t)] (Susp pi Xa))  
      subst s (swap pi (look_up Xa [(X, swap (rev pi) t)]))"
      using equ_refl subst_susp[of [(X, swap (rev pi)t)] pi Xa] 
      by simp
    have "nabla  subst (s  [(X, swap (rev pi) t)]) (Susp pi Xa)  
    subst s (swap pi (look_up Xa [(X, swap (rev pi) t)]))"
      using equ_trans[OF one two] by simp
    hence  "nabla  swap pi (look_up Xa (s  [(X, swap (rev pi) t)]))  
    subst s (swap pi (look_up Xa [(X, swap (rev pi) t)]))"
      using subst_susp[of (s  [(X, swap (rev pi) t)])] by simp
    hence swap_pi_outside:  "nabla  swap pi (look_up Xa (s  [(X, swap (rev pi) t)]))  
    swap pi (subst s (look_up Xa [(X, swap (rev pi) t)]))"
      using subst_swap_comm by simp
    hence "nabla  (look_up Xa (s  [(X, swap (rev pi) t)]))  
    (subst s (look_up Xa [(X, swap (rev pi) t)]))"
      using equ_dec_pi[OF swap_pi_outside] by simp
    hence three: 
    "nabla  subst (s  [(X, swap (rev pi) t)]) (Susp [] Xa)  
    (subst s (look_up Xa [(X, swap (rev pi) t)]))" 
      using subst_susp by simp
    then show ?thesis
      proof(cases "Xa = X")
        case True
        hence "subst s (look_up Xa [(X, swap (rev pi) t)]) = subst s (swap (rev pi) t)"
          by simp
        with three have
          "nabla  subst (s  [(X, swap (rev pi) t)]) (Susp [] Xa)  swap (rev pi) (subst s t)"
          using subst_swap_comm by auto
        hence i: "nabla  swap pi (subst (s  [(X, swap (rev pi) t)]) (Susp [] Xa))
           subst s t" using swap_inv_side by simp
        hence "nabla  swap pi (subst (s  [(X, swap (rev pi) t)]) (Susp [] Xa))
           subst s (Susp pi Xa)"
          using True equ_trans[OF i equ_symm[OF assms(1)]] by simp
        hence "nabla  swap pi (subst (s  [(X, swap (rev pi) t)]) (Susp [] Xa))
           swap pi (look_up Xa s)"
          using subst_susp by simp
        then show "nabla  (subst (s  [(X, swap (rev pi) t)]) (Susp [] Xa))
           subst s (Susp [] Xa)"
          using equ_dec_pi subst_susp by simp
      next
        case False
        hence "subst s (look_up Xa [(X, swap (rev pi) t)]) = subst s (Susp [] Xa)"
          by simp
        with three show ?thesis by auto
      qed
    qed
  qed

lemma subst_equ_a:
  assumes "nabla  (subst s1)  (subst s2)"
    and "nabla  (subst s2 t1)  t2"
  shows "nabla  (subst s1 t1)  t2"
  using assms
proof(induct t1 arbitrary: t2)
  case (Abst a t1')
  then obtain t2' b 
    where t2: "t2 = Abst b t2'"
    by(auto elim: equ.cases)
  with Abst(3) have
    i: "nabla  Abst a (subst s2 t1')  Abst b t2'"
    using subst_abst by simp
  then show ?case 
  proof(cases "a=b")
    case True
    hence "nabla  (subst s2 t1')  t2'" 
      using Equ_elims(7)[OF i] by auto
    with Abst(1)[OF Abst(2), of t2']
    have "nabla  subst s1 t1'  t2'" 
      by simp
    hence "nabla  Abst a (subst s1 t1')  Abst b t2'"
      using True equ_abst_aa by simp
    with t2 show ?thesis
      using subst_abst[of s1 a t1'] by simp
  next
    case False
    hence "nabla  (subst s2 t1')  swap [(a,b)] t2'"
          and fresh: "nabla  a  t2'"
      using Equ_elims(7)[OF i] by auto
     with Abst(1)[OF Abst(2), of swap [(a,b)] t2']
    have "nabla  subst s1 t1'   swap [(a,b)] t2'" 
      by simp
    hence "nabla  Abst a (subst s1 t1')  Abst b t2'"
      using equ_abst_ab[OF False fresh] by simp
    with t2 show ?thesis
      using subst_abst[of s1 a t1'] by simp
  qed
next
  case (Susp pi X)
  hence "nabla  swap pi (look_up X s2)  t2"
    using subst_susp by simp
  hence "nabla  (look_up X s2)  swap (rev pi) t2"
    using subst_susp swap_inv_side by simp
  hence i: "nabla  subst s2 (Susp [] X)  swap (rev pi) t2"
    using subst_susp[of s2 []] by simp

  with Susp(1) subst_equ_def[of nabla subst s1 subst s2]
  have "nabla  subst s1 (Susp [] X)  subst s2 (Susp [] X)"
    using UnCI equ_refl not_in_domn by metis

  with i have "nabla  subst s1 (Susp [] X)  swap (rev pi) t2"
    using equ_trans by blast
  hence "nabla  (look_up X s1)  swap (rev pi) t2"
    using subst_susp by simp
  hence "nabla  swap pi (look_up X s1)   t2"
    using swap_inv_side by simp
    then show ?case 
      using subst_susp by simp
next
  case (Paar t11 t12)
  then obtain t21 t22
    where t2: "t2 = Paar t21 t22"
    by(auto elim: equ.cases)
  with Paar(4) 
  have paar_i: "nabla  subst s2 t11  t21"
    and paar_ii: "nabla  subst s2 t12  t22"
    by (auto elim: equ.cases)
  from t2 show ?case
    using equ_paar[OF Paar(1)[OF Paar(3) paar_i] Paar(2)[OF Paar(3) paar_ii]]
    subst_paar by simp
next
  case (Func f t1')
  then obtain t2' 
    where t2: "t2 = Func f t2'"
    by(auto elim: equ.cases)
   with Func(3) 
   have func: "nabla  subst s2 t1'  t2'"
   by (auto elim: equ.cases)
  from t2 show ?case
    using equ_func[OF Func(1)[OF Func(2) func], of f] by simp
qed (simp_all)

lemma unif_2a: 
  assumes "nablasubst s1subst s2"
  and "(nablasubst s2 t1  subst s2 t2)"             
shows"(nablasubst s1 t1  subst s1 t2)"
proof-
  have i: "(nablasubst s1 t1  subst s2 t2)"
    using subst_equ_a[OF assms(1,2)] by simp
  show "(nablasubst s1 t1  subst s1 t2)"
    using subst_equ_a[OF assms(1) equ_symm[OF i]] equ_symm by auto
qed

lemma unif_2b:
  assumes "nabla  subst s1  subst s2" 
  and "nabla  a  subst s2 t"
shows "nabla  a  subst s1 t" 
  using assms
proof(induct t)
  case (Abst b t')
  then show ?case
  proof(cases "a=b")
    case True
    then show ?thesis 
      using fresh_abst_aa by simp 
  next
    case False
    with Abst show ?thesis 
      using Fresh_elims(1) subst_abst fresh_abst_ab
      by metis
  qed
next
  case (Susp pi X)
  then show ?case
    using equ_refl equ_symm l3_jud subst_equ_a by meson
next
  case (Paar t1 t2)
  then show ?case 
    using Fresh_elims(5) subst_paar fresh_paar 
    by metis
next
  case (Func f t')
  then show ?case
    using Fresh_elims(6) subst_func fresh_func
    by metis
qed (simp_all)

lemma subst_equ_to_trm: 
  assumes "nabla  subst s1  subst s2"
  shows "nablasubst s1 t  subst s2 t"
  using assms equ_refl subst_equ_a by simp

lemma subst_cancel_right: 
  assumes "nabla(subst s1)(subst s2)"
  shows "nabla(subst (s1s))(subst (s2s))" 
  using assms subst_comp_expand subst_equ_def subst_equ_to_trm
  by simp

lemma subst_trans: 
  assumes "nablasubst s1  subst s2" "nabla  subst s2  subst s3"
  shows "nablasubst s1subst s3"
  using assms equ_trans subst_equ_def subst_equ_to_trm by meson

text ‹
  If occurs holds, then one subterm is equal to (subst s (Susp pi X))
›

lemma occurs_sub_trm_equ: 
  assumes "occurs X t1"
  shows " t2  sub_trms (subst s t1). (pi.(nablasubst s (Susp pi1 X)(swap pi t2)))" 
  using assms
proof(induct t1)
  case (Susp pi' X)
  then show ?case 
    using equ_pi_to_left equ_involutive_left 
      equ_refl subst_susp swap_append t_sub_trms_t
    occurs.simps(3) by metis
next
  case (Paar t11 t12)
  then show ?case 
    using subst_paar Un_iff occurs.simps(5) psub_sub_trms
        psub_trms.simps(4) by (metis)
qed(auto)

lemma ext_subst_strong:
  assumes "nabla1  (subst s) (nabla2  nabla3)"
  shows "nabla1  (subst s) nabla2" and "nabla1  (subst s) nabla3"
  using assms
  unfolding ext_subst_def by auto

lemma ext_subst_id:
  shows "nabla  (subst []) nabla"
  unfolding ext_subst_def id_subst by auto


(*<*)
end
(*>*)