Theory NU_Termination

(*<*)
theory NU_Termination
imports NU_Mgu
begin
(*>*)

section ‹Termination›

text ‹
  Defines a lexicographic termination measure and proves that all the unification
  reductions decrease this measure.  
›


lemma apply_subst_equivalence: 
  shows "apply_subst s P = (apply_subst_eprobs s (fst P), apply_subst_fprobs s (snd P))"
  unfolding apply_subst_def apply_subst_eprobs_def apply_subst_fprobs_def by simp


fun size_trm :: "trm  nat"
  where
  "size_trm (Unit)      = 1" |
  "size_trm (Atom a)    = 1" |
  "size_trm (Susp pi X) = 1" |
  "size_trm (Abst a t)  = 1 + size_trm t" |
  "size_trm (Func F t)  = 1 + size_trm t" |
  "size_trm (Paar t t') = 1 + (size_trm t) + (size_trm t')"

fun size_fprobs :: "fprobs  nat"
  where 
    "size_fprobs [] = 0" |
    "size_fprobs (x#xs) = (size_trm (snd x))+(size_fprobs xs)"

fun size_eprobs :: "eprobs  nat"
  where
 "size_eprobs [] = 0" | 
  "size_eprobs (x#xs) = (size_trm (fst x))+(size_trm (snd x))+(size_eprobs xs)"


lemma size_swap [simp]: "size_trm (swap pi t) = size_trm t"
  by (induct t) auto

definition rank_r
  where
  "rank_r = measures [λ(eprobs, fprobs). card (vars_eprobs eprobs),
                      λ(eprobs, fprobs). size_eprobs eprobs, 
                      λ(eprobs, fprobs). size_fprobs fprobs]"


lemma vars_term_finite [simp]: "finite (vars_trm t)"
  by (induct t) auto


lemma vars_eprobs_finite [simp]: "finite (vars_eprobs P)"
  by (induct P) auto


lemma not_occurs_trm: "¬occurs X t  X vars_trm t"
  by (induct t) auto

lemma not_occurs_subst: "¬occurs X t1 X vars_trm (subst [(X,swap pi2 t1)] t2)" 
  using subst_susp not_occurs_trm by (induct t2) (auto simp add: vars_swap)

lemma not_occurs_list: "¬ occurs X t 
  X  vars_eprobs (apply_subst_eprobs [(X, swap pi t)] xs)"
  using not_occurs_subst apply_subst_eprobs_def by (induct xs) auto


lemma vars_equ: 
  assumes "¬occurs X t1" and "occurs X t2"
  shows "vars_trm (subst [(X, swap pi t1)] t2) = (vars_trm t1  vars_trm t2)-{X}"
  using assms
proof(induct t2)
  case (Susp pi' Y)
  hence eq: "X=Y" 
    unfolding occurs.simps(3) by argo
  have subst_i: "subst [(X, swap pi t1)] (Susp pi' Y) = swap pi'(look_up X [(X, swap pi t1)])"
    using eq subst_susp by simp
  also have "... = swap pi'(swap pi t1)" by simp
  hence "vars_trm (subst [(X, swap pi t1)] (Susp pi' Y)) =  vars_trm t1"
    using subst_i swap_append vars_swap by simp
  thus
    "vars_trm (subst [(X, swap pi t1)] (Susp pi' Y)) = 
    vars_trm t1  vars_trm (Susp pi' Y) - {X}"
    using eq assms(1) not_occurs_subst[of X t1 pi Susp pi' Y] by auto
next
  case (Paar t21 t22)
  hence "occurs X t21  occurs X t22"
    unfolding occurs.simps(5) by argo
  then show ?case
  proof
    assume "occurs X t21" 
    hence "vars_trm (subst [(X, swap pi t1)] t21) = vars_trm t1  vars_trm t21 - {X}"
      using assms(1) Paar by auto 
    hence "vars_trm (subst [(X, swap pi t1)] (Paar t21 t22)) =
    (vars_trm t1  vars_trm t21 - {X})  (vars_trm t1  vars_trm t22 - {X})"
      using Paar.hyps(2) assms(1) subst_not_occurs[of X t22 swap pi t1] not_occurs_trm
      by (cases "occurs X t22") auto
    thus "vars_trm (subst [(X, swap pi t1)] (Paar t21 t22)) =
    vars_trm t1  vars_trm (Paar t21 t22) - {X}" by auto
  next
    assume "occurs X t22"
     hence "vars_trm (subst [(X, swap pi t1)] t22) = vars_trm t1  vars_trm t22 - {X}"
       using assms(1) Paar by auto
     hence "vars_trm (subst [(X, swap pi t1)] (Paar t21 t22)) =
    (vars_trm t1  vars_trm t21 - {X})  (vars_trm t1  vars_trm t22 - {X})"
      using Paar.hyps(1) assms(1) subst_not_occurs[of X t21 swap pi t1] not_occurs_trm
      by (cases "occurs X t21") auto
    thus "vars_trm (subst [(X, swap pi t1)] (Paar t21 t22)) =
    vars_trm t1  vars_trm (Paar t21 t22) - {X}" by auto
  qed
qed (simp_all)


lemma vars_subseteq:
  assumes "¬occurs X t "
  shows "vars_eprobs (apply_subst_eprobs [(X, swap pi t)] xs)  (vars_trm t  vars_eprobs xs)"
  using assms
proof(induct xs)
  case Nil
  have "apply_subst_eprobs [(X, swap pi t)] [] = []"
    unfolding apply_subst_eprobs_def by simp
  hence "vars_eprobs (apply_subst_eprobs [(X, swap pi t)] []) = {}"
    by simp
  thus "vars_eprobs (apply_subst_eprobs [(X, swap pi t)] [])  vars_trm t  vars_eprobs []"
    by simp
next
  case (Cons a xs)
  have "apply_subst_eprobs [(X, swap pi t)] (a # xs) = 
  (subst [(X, swap pi t)] (fst a), subst [(X, swap pi t)] (snd a)) # (apply_subst_eprobs[(X, swap pi t)] xs)"
    unfolding apply_subst_eprobs_def case_prod_beta by simp
  hence A: "vars_eprobs (apply_subst_eprobs [(X, swap pi t)] (a # xs)) = 
    (vars_trm (subst [(X, swap pi t)] (snd a)))(vars_trm (subst [(X, swap pi t)] (fst a)))
    (vars_eprobs (apply_subst_eprobs[(X, swap pi t)] xs))"
    by auto
  then show "vars_eprobs (apply_subst_eprobs [(X, swap pi t)] (a # xs))
     vars_trm t  vars_eprobs (a # xs)"
  proof(cases "occurs X (fst a)")
    case True
    have X_in_fst: 
      "occurs X (fst a)" by fact
    hence vars_fst:
      "vars_trm (subst [(X, swap pi t)] (fst a)) = (vars_trm t  vars_trm (fst a))-{X}"
      using vars_equ[OF assms X_in_fst] by simp
    then show "vars_eprobs (apply_subst_eprobs [(X, swap pi t)] (a # xs))
     vars_trm t  vars_eprobs (a # xs)"
    proof(cases "occurs X (snd a)")
      case True
      have X_in_snd: "occurs X (snd a)" by fact
      hence vars_snd:
        "vars_trm (subst [(X, swap pi t)] (snd a)) = (vars_trm t  vars_trm (snd a))-{X}"
        using vars_equ[OF assms X_in_snd] by simp
      with vars_fst
      have "vars_trm (subst [(X, swap pi t)] (snd a))  vars_trm (subst [(X, swap pi t)] (fst a))  = 
      vars_trm t  vars_trm (snd a)  vars_trm (fst a) - {X}"
        by auto
      hence "vars_trm (subst [(X, swap pi t)] (snd a))  vars_trm (subst [(X, swap pi t)] (fst a))  
      vars_trm t  vars_eprobs (a # xs)" by auto
      thus ?thesis using A Cons by auto
    next
      case False
      hence vars_snd: "vars_trm (subst [(X, swap pi t)] (snd a)) = vars_trm (snd a)"
        using subst_not_occurs by auto
      with vars_fst
      have "vars_trm (subst [(X, swap pi t)] (snd a))  vars_trm (subst [(X, swap pi t)] (fst a))  = 
      vars_trm t  vars_trm (snd a)  vars_trm (fst a) - {X}"
        using False not_occurs_trm by auto
      hence "vars_trm (subst [(X, swap pi t)] (snd a))  vars_trm (subst [(X, swap pi t)] (fst a))  
      vars_trm t  vars_eprobs (a # xs)" by auto
      thus ?thesis using A Cons by auto
    qed
  next
    case False
    hence vars_fst:
      "vars_trm (subst [(X, swap pi t)] (fst a)) = vars_trm (fst a)"
      using subst_not_occurs by simp
    then show "vars_eprobs (apply_subst_eprobs [(X, swap pi t)] (a # xs))
     vars_trm t  vars_eprobs (a # xs)"
    proof(cases "occurs X (snd a)")
      case True
      have X_in_snd: "occurs X (snd a)" by fact
      hence vars_snd:
        "vars_trm (subst [(X, swap pi t)] (snd a)) = (vars_trm t  vars_trm (snd a))-{X}"
        using vars_equ[OF assms X_in_snd] by simp
       with vars_fst
      have "vars_trm (subst [(X, swap pi t)] (snd a))  vars_trm (subst [(X, swap pi t)] (fst a))  = 
      vars_trm t  vars_trm (snd a)  vars_trm (fst a) - {X}"
        using False not_occurs_trm by auto
      hence "vars_trm (subst [(X, swap pi t)] (snd a))  vars_trm (subst [(X, swap pi t)] (fst a))  
      vars_trm t  vars_eprobs (a # xs)" by auto
      thus ?thesis using A Cons by auto
    next
      case False
      hence vars_snd: "vars_trm (subst [(X, swap pi t)] (snd a)) = vars_trm (snd a)"
        using subst_not_occurs by auto
      with vars_fst
      have "vars_trm (subst [(X, swap pi t)] (snd a))  vars_trm (subst [(X, swap pi t)] (fst a))  = 
       vars_trm (snd a)  vars_trm (fst a)"
        by simp
      hence "vars_trm (subst [(X, swap pi t)] (snd a))  vars_trm (subst [(X, swap pi t)] (fst a))  
      vars_trm t  vars_eprobs (a # xs)" by auto
      thus ?thesis using A Cons by auto
    qed
  qed
qed


lemma vars_decrease: 
  assumes "¬occurs X t"
  shows "card (vars_eprobs (apply_subst_eprobs [(X, swap pi t)] xs))
                 < card (insert X (vars_trm t  vars_eprobs xs))"
  using assms
proof(cases "X  (vars_trm t  vars_eprobs xs)")
  case True
  hence "insert X (vars_trm t  vars_eprobs xs) = vars_trm t  vars_eprobs xs"
    using  insert_absorb by auto
  moreover have subset:
    "vars_eprobs (apply_subst_eprobs [(X, swap pi t)] xs)  vars_trm t  vars_eprobs xs"
    using assms vars_subseteq by simp
  hence
    "vars_eprobs (apply_subst_eprobs [(X, swap pi t)] xs)  vars_trm t  vars_eprobs xs - {X}"
    using not_occurs_list assms subset_Diff_insert by auto
  ultimately have 
  "card (vars_eprobs (apply_subst_eprobs [(X, swap pi t)] xs))
                  card (vars_trm t  vars_eprobs xs - {X})"    
    using Finite_Set.card_mono
    by (metis finite_Diff finite_Un vars_eprobs_finite vars_term_finite)
  thus "card (vars_eprobs (apply_subst_eprobs [(X, swap pi t)] xs))
                 < card (insert X (vars_trm t  vars_eprobs xs))"
    by (simp add: card.insert_remove)
next
  case False
  hence "card (vars_trm t  vars_eprobs xs) < card (insert X (vars_trm t  vars_eprobs xs))"
    by auto
  moreover have subset:
    "vars_eprobs (apply_subst_eprobs [(X, swap pi t)] xs)  vars_trm t  vars_eprobs xs"
    using assms vars_subseteq by simp
  hence "card (vars_eprobs (apply_subst_eprobs [(X, swap pi t)] xs))
                  card (vars_trm t  vars_eprobs xs)"
    using Finite_Set.card_mono
    by (metis finite_Un vars_eprobs_finite vars_term_finite)
  ultimately show 
    "card (vars_eprobs (apply_subst_eprobs [(X, swap pi t)] xs))
    < card (insert X (vars_trm t  vars_eprobs xs))"
    by simp
qed


lemma rank_r_cred: 
  assumes "P1(nabla)P2" 
  shows "(P2, P1)  rank_r"
  unfolding rank_r_def by (cases rule: c_red.cases[OF P1  nabla  P2], simp_all)

lemma rank_r_sred:
  assumes "P1   s P2"
  shows "(P2,P1)  rank_r"
proof(cases rule: s_red.cases[OF P1 s P2])
  case (2 t1 t2 s1 s2 xs ys)
   case (2 t1 t2 s1 s2 xs ys)
  let ?union = "vars_trm s1  vars_trm s2  vars_trm t1  vars_trm t2  vars_eprobs xs"
    and ?size = "size_trm t1 + size_trm t2 + size_trm s1 + size_trm s2 + size_eprobs xs"
  from 2 have "vars_eprobs ((Paar t1 t2, Paar s1 s2) # xs) = ?union"
    unfolding vars_eprobs.simps vars_trm.simps by auto
  moreover from 2 have
    "size_eprobs ((Paar t1 t2, Paar s1 s2) # xs) = 2 + ?size"
    unfolding size_eprobs.simps using size_trm.simps(6) by auto
  from 2 have
  "vars_eprobs ((t1, s1) # (t2, s2) # xs) = ?union"
    unfolding vars_eprobs.simps by auto
  moreover from 2 have 
    "size_eprobs ((t1, s1) # (t2, s2) # xs) = ?size"
    unfolding size_eprobs.simps by simp
  ultimately have 
    "size_eprobs ((t1, s1) # (t2, s2) # xs) < size_eprobs ((Paar t1 t2, Paar s1 s2) # xs)"
    "card (vars_eprobs ((t1, s1) # (t2, s2) # xs)) = card (vars_eprobs ((Paar t1 t2, Paar s1 s2) # xs))"
    by simp+
  with 2 show "(P2, P1)  rank_r" 
    unfolding rank_r_def by simp
next
  case (7 pi1 X pi2 xs ys)
  let ?mapds = "map (λa. (a, Susp [] X)) (ds_list pi1 pi2) @ ys"
  let ?union = "{X}  vars_eprobs xs"
  from 7 have 
  vars: "vars_eprobs ((Susp pi1 X, Susp pi2 X) # xs) = ?union" and
  size: "size_eprobs ((Susp pi1 X, Susp pi2 X) # xs) = 2 + size_eprobs xs"
    unfolding vars_eprobs.simps size_eprobs.simps by simp+
  then show "(P2, P1)  rank_r"
     proof(cases "X  vars_eprobs xs")
    case True
   hence "card ?union = card (vars_eprobs xs)"
     by (simp add: insert_absorb)
   with 7 show "(P2, P1)  rank_r" 
      unfolding rank_r_def by simp
  next
    case False
    hence "card ?union = 1 + card (vars_eprobs xs)"
      by auto
    with 7 show "(P2, P1)  rank_r" 
      unfolding rank_r_def by simp
  qed
next
  case (8 X t pi xs ys)
   let ?union = "insert X (vars_trm t  vars_eprobs xs)"
    and ?size = "size_trm t + size_eprobs xs"
   from 8 have 
     vars: "vars_eprobs ((Susp pi X, t) # xs) = ?union" and
     size: "size_eprobs ((Susp pi X, t) # xs) = 1 + ?size"
    unfolding vars_eprobs.simps size_eprobs.simps by simp+
   moreover from 8 have
    "P2 = (apply_subst_eprobs [(X, swap (rev pi) t)] xs, 
    apply_subst_fprobs [(X, swap (rev pi) t)] ys)"
     using apply_subst_equivalence by auto
   ultimately show ?thesis  
    using 8 vars_decrease[OF 8(4)] unfolding rank_r_def by simp
next
  case (9 X t pi xs ys)
   let ?union = "insert X (vars_trm t  vars_eprobs xs)"
    and ?size = "size_trm t + size_eprobs xs"
  from 9 have 
     vars: "vars_eprobs ((t, Susp pi X) # xs) = ?union" and
     size: "size_eprobs ((t, Susp pi X) # xs) = 1 + ?size"
    unfolding vars_eprobs.simps size_eprobs.simps by simp+
  moreover from 9 have
    "P2 = (apply_subst_eprobs [(X, swap (rev pi) t)] xs, 
    apply_subst_fprobs [(X, swap (rev pi) t)] ys)"
     using apply_subst_equivalence by auto
   ultimately show ?thesis  
    using 9 vars_decrease[OF 9(4)] unfolding rank_r_def by simp
qed (unfold rank_r_def, auto simp add: vars_swap)

lemma rank_r_trans: "(P1,P2)  rank_r; (P2,P3)  rank_r (P1,P3) rank_r"
  unfolding rank_r_def by auto

lemma rank_r_red_plus: 
  assumes "P1 (s,nabla)P2" 
  shows "(P2, P1)  rank_r"
  using assms 
by(induct rule: red_plus.induct)(auto dest: rank_r_sred rank_r_cred rank_r_trans)

lemma wf_rank_r: 
  shows "wf (rank_r)"
  unfolding rank_r_def by simp

(*<*)
end
(*>*)