Theory TA_moves

theory TA_moves
imports Tree_Automata_Utils Basic_Utils
theory TA_moves
imports "$ISAFOR/Tree_Automata/Tree_Automata" Tree_Automata_Utils Basic_Utils
begin

inductive move :: " ('q,'f) ta ⇒ ('f,'q) term ⇒ ('f,'q) term ⇒ bool" for TA where
  eps [intro]: "(q, q') ∈ ta_eps TA ⟹ move TA (Var q) (Var q')"
| rule [intro]: "∀q'∈set qs. is_Var q' ⟹ f (map the_Var qs) → q ∈ ta_rules TA ⟹
                 move TA (Fun f qs) (Var q)"
| ctxt [intro]: "f = g ⟹ length ts = length ss ⟹ (*`length ts = length ss` not needed anymore?*)
    (∃i < length ts. ss = take i ts @ ss ! i # drop (Suc i) ts ∧ move TA (ts ! i) (ss ! i)) ⟹
    move TA (Fun f ts) (Fun g ss)"

"move' TA ≡ {(s,t). move TA s t}"">abbreviation "move' TA ≡ {(s,t). move TA s t}"

lemma move_Var_Fun_neg:
  "¬ move TA (Var q) (Fun f ts)"
  using  move.cases by fast

lemma move_ctxt_closed:
  "move TA s t ⟹ move TA C⟨s⟩ C⟨t⟩"
proof (induction C)
  case (More f ss1 C ss2)
  let ?ts = "ss1 @ C⟨s⟩ # ss2" and ?ss = "ss1 @ C⟨t⟩ # ss2" and ?i = "length ss1"
  have "length ?ts = length ?ss" by simp
  moreover have "?i < length ?ts ∧ ?ss = take ?i ?ts @ ?ss ! ?i # drop (Suc ?i) ?ts ∧
        move TA (?ts ! length ss1) (?ss ! length ss1)"
    using More by force
  ultimately show ?case unfolding ctxt_apply_term.simps by (intro move.intros) blast+
qed simp

lemma move_star_ctxt_closed:
  assumes "(s, t) ∈ (move' TA)*"
  shows "(C⟨s⟩, C⟨t⟩) ∈ (move' TA)*"
  using assms
proof (induction rule: rtrancl_induct)
  case (step y z)
  thus ?case using move_ctxt_closed[of TA y z C]
    by (auto intro: rtrancl_into_rtrancl)
qed simp

lemma ta_res'_vars:
  "t ∈ ta_res' TA (Var q) ⟹ is_Var t"
  by (auto elim!: ta_res'.elims)

lemma move'_vars:
  "(Var q, t) ∈ move' TA ⟹ is_Var t"
  by (auto elim!: move.cases)

lemma move'_vars_star:
  assumes "(Var q, t) ∈ (move' TA)*"
  shows "is_Var t"
  using assms
proof (induction arbitrary: q rule: rtrancl_induct)
  case (step y z)
  thus ?case using move'_vars by fast
qed simp

lemma move'_ta_states1:
  assumes "(Var q, t) ∈ move' TA"
  shows "q ∈ ta_states TA"
proof -
  obtain q' where "t = Var q'" using move'_vars[OF assms] by fast
  thus ?thesis using assms ta_eps_states by (auto elim: move.cases)
qed

lemma move'_ta_states2:
  assumes "(t, Var q) ∈ move' TA"
  shows "q ∈ ta_states TA"
proof (cases t)
  case (Var x)
  hence "(x, q) ∈ ta_eps TA" using assms by (auto elim: move.cases)
  then show ?thesis using ta_eps_states by blast
next
  case (Fun f ts)
  show ?thesis using assms r_rhs_states[of f "map the_Var ts" q TA]
    unfolding Fun by (auto elim: move.cases)
qed

lemma move'_ta_states3:
  assumes "(t, Var q) ∈ (move' TA)*"
 and "t ≠ Var q"
shows "q ∈ ta_states TA"
proof -
  obtain s where "(t, s) ∈ (move' TA)*" "(s, Var q) ∈ (move' TA)"
    using rtranclE assms by metis
  then show ?thesis using move'_ta_states2[of s q TA] by argo
qed

lemma is_Var_map:
  "∀i < length qs. is_Var ((map Var qs) ! i)"
  by auto

lemma transition_chain:
  assumes "∀i < length zs. zs ! i ∈ R*"
          "∀i < length zs - 1. snd (zs ! i) = fst (zs ! (Suc i))"
  shows "zs ≠ [] ⟶ (fst (zs ! 0), snd (zs ! (length zs - 1))) ∈ R*"
  using assms
proof (induction zs)
  case (Cons a zs)
  have "∀i<length zs. zs ! i ∈ R*" using Cons(2) by force
  moreover have "∀i. Suc i < length zs ⟶ snd (zs ! i) = fst (zs ! Suc i)" using Cons(3) by force
  ultimately have "zs ≠ [] ⟶ (fst (zs ! 0), snd (zs ! (length zs - 1))) ∈ R*"
    using Cons(1) by (cases zs) auto
  moreover have "a ∈ R*" using Cons(2) by force
  moreover have "zs ≠ [] ⟶ snd a = fst (zs ! 0)" using Cons(3) by force
  ultimately show ?case
    by simp (metis One_nat_def length_0_conv nth_Cons' prod.collapse rtrancl_trans)
qed simp

fun create_list :: "(nat ⇒ 'a) ⇒ nat ⇒ 'a list" where
  "create_list f 0 = []"
| "create_list f (Suc n) = f n # create_list f n"

lemma create_list_length [simp]:
  "length (create_list f n) = n"
  by (induction n) auto

lemma create_list_ith:
  "i < n ⟶ (rev (create_list f n)) ! i = f i"
  by (induction n) (simp, metis create_list.simps(2) create_list_length diff_Suc_Suc length_Cons
      length_upt less_SucE list.size(3) nth_Cons_0 nth_Cons_Suc rev_nth upt_rec)

lemma transition_chain':
  assumes "∀i < length xs. (f xs ys i, g xs ys i) ∈ R*"
          "∀i < length xs - 1. g xs ys i = f xs ys (Suc i)"
          "length xs = length ys" "xs ≠ []"
  shows "(f xs ys 0, g xs ys (length xs - 1)) ∈ R*"
proof -
  define ith zs where "ith = (λi. (f xs ys i, g xs ys i))" and
                      "zs = rev (create_list ith (length xs))"
  have zs_i: "∀i<length zs. zs ! i ∈ R*" using assms(1,3) create_list_ith[of _ "length xs" ith]
    unfolding zs_def ith_def length_rev create_list_length by presburger
  have chain: "∀i<length zs - 1. snd (zs ! i) = fst (zs ! Suc i)"
    using assms(2-4) create_list_ith[of _ "length xs" ith]
    unfolding zs_def ith_def length_rev create_list_length by fastforce
  show ?thesis using transition_chain[of zs R, OF zs_i chain] assms(3,4)
    unfolding zs_def ith_def
    by (smt Suc_diff_Suc create_list_ith create_list_length diff_Suc_eq_diff_pred fst_conv
        length_greater_0_conv length_rev lessI minus_nat.diff_0 snd_conv)
qed

lemma move_ta_res:
  assumes "move TA s q" "is_Var q"
  shows "the_Var q ∈ ta_res TA s"
  using assms
proof (induction s q rule: move.induct)
  case (rule qs f q)
  hence "f (map the_Var qs) → q ∈ ta_rules TA ∧ (q, q) ∈ (ta_eps TA)* ∧
       length (map the_Var qs) = length qs"
    by auto
  moreover { fix i
    assume asm: "i < length qs"
    hence "is_Var (qs ! i)" using rule(1) by simp
    hence "(map the_Var qs) ! i ∈ ta_res TA (qs ! i)" using asm by force
  }
  ultimately show ?case by force
qed simp+

lemma move_ta_res':
  assumes "move TA s q"
  shows "q ∈ ta_res' TA s"
  using assms
proof (induction s q rule: move.induct)
  case (rule qs f q)
  hence "f (map the_Var qs) → q ∈ ta_rules TA ∧ (q, q) ∈ (ta_eps TA)* ∧
       length (map the_Var qs) = length qs"
    by auto
  moreover { fix i
    assume asm: "i < length qs"
    hence "is_Var (qs ! i)" using rule(1) by simp
    hence "(map the_Var qs) ! i ∈ ta_res TA (qs ! i)" using asm by force
  }
  ultimately show ?case by force
next
  case (ctxt f g ts ss)
  then obtain i where "i < length ts" "ss = take i ts @ ss ! i # drop (Suc i) ts"
                      "ss ! i ∈ ta_res' TA (ts ! i)"
    by blast
  hence "j < length ts ⟶ ss ! j ∈ ta_res' TA (ts ! j)" for j
    using ta_res'_refl[of "ts ! _" TA]
    by (metis less_imp_le_nat nth_append_take_drop_is_nth_conv)
  thus ?case using ctxt(1,2) by fastforce
qed force

lemma ta_res'_ta_res:
  assumes "t ∈ ta_res' TA s" "p ∈ ta_res TA t"
  shows "p ∈ ta_res TA s"
  using assms
proof (induction arbitrary: p t rule: ta_res'.induct)
  case (2 TA f ts) show ?case using 2(2-)
  proof (induction t)
    case (Var q)
    show ?thesis using ta_res_ctxt[of q TA "Fun f ts" p ] Var by simp
  next
    case (Fun g ss)
    have ss_props: "g = f" "length ss = length ts" "∀i < length ts. ss ! i ∈ ta_res' TA (ts ! i)"
      using Fun(2) by (auto elim!: ta_res'.cases)
    obtain qs p' where qs_props: "(g qs → p') ∈ ta_rules TA ∧
          (p',p) ∈ (ta_eps TA)* ∧ length qs = length ss ∧
          (∀i < length ss. qs ! i ∈ (map (ta_res TA) ss) ! i)"
      using Fun(3) by auto
    { fix i
      assume asm: "i < length ts"
      hence ss_i_ts_i: "ss ! i ∈ ta_res' TA (ts ! i)" using ss_props by blast
      have "qs ! i ∈ ta_res TA (ts ! i)"
        using Fun(3) 2(1)[OF asm ss_i_ts_i, of "qs ! i"] asm ss_props(2) qs_props by force
    } note inner = this
    hence "∀i<length ts. qs ! i ∈ ta_res TA (ts ! i)"
      using ss_props(1,2) construct_exI'[of "length ts" "λx i. x ∈ ta_res TA (ts ! i)"] by blast
    thus ?thesis using qs_props unfolding ss_props by auto
  qed
qed force

lemma move_preserves_ta_res:
  assumes "move TA s t" "q ∈ ta_res TA t" shows "q ∈ ta_res TA s"
  using assms
  by (meson move_ta_res' ta_res'_ta_res)

lemma move_ta_res_star:
  assumes "(s, q) ∈ (move' TA)*" "is_Var q"
  shows "the_Var q ∈ ta_res TA s"
  using assms
proof (induction rule: converse_rtrancl_induct)
  case (step y z)
  hence "the_Var q ∈ ta_res TA z" by argo
  moreover have "z ∈ ta_res' TA y" using step(1) move_ta_res'[of TA y z] by auto
  ultimately show ?case using ta_res'_ta_res by fast
qed auto

lemma ta_res_move_star:
  assumes "q ∈ ta_res TA s"
  shows "(s, Var q) ∈ (move' TA)*"
  using assms
proof (induction TA s arbitrary: q rule: ta_res.induct)
  case (1 TA p)
  hence "(p, q) ∈ (ta_eps TA)*"
    using ta_res'_vars by (auto elim!: ta_res'.elims)
  thus ?case by (induction rule: rtrancl_induct)
    (simp, metis case_prodI mem_Collect_eq move.intros(1) rtrancl.simps)
next
  case (2 TA f ts)
  then obtain q' qs where seq:
    "(f qs → q') ∈ ta_rules TA" "(q',q) ∈ ((ta_eps TA)^*)" "length qs = length ts"
     "∀i < length ts. qs ! i ∈ (map (ta_res TA) ts) ! i" by auto
  let ?f = "λts qs i. Fun f ((map Var (take i qs)) @ ts ! i # drop (Suc i) ts)" and
      ?g = "λts qs i. Fun f ((map Var (take i qs)) @ Var (qs ! i) # drop (Suc i) ts)"
  have "∀i < length ts. (ts ! i, Var (qs ! i)) ∈ (move' TA)*"
    using 2(1)[of _ "ts ! _"] 2(2) seq by (auto elim!: ta_res.cases)
  hence move_in_ctxt: "i < length ts ⟶ (Fun f ((map Var (take i qs)) @ ts ! i # drop (Suc i) ts),
                            Fun f ((map Var (take i qs)) @ Var (qs ! i) # drop (Suc i) ts))
                            ∈ (move' TA)*" for i
    using move_star_ctxt_closed[of _ _ TA "More f _ □ _"] by simp
  moreover { fix i
    assume asm: "i < length ts - 1"
    hence "map Var (take i qs) @ [Var (qs ! i)] = map Var (take (Suc i) qs)" using seq(3)
      by (simp add: take_Suc_conv_app_nth)
    moreover have "drop (Suc i) ts = ts ! Suc i # drop (Suc (Suc i)) ts" using asm
      by (metis Cons_nth_drop_Suc Suc_eq_plus1 less_diff_conv)
    ultimately have "?g ts qs i = ?f ts qs (Suc i)" using seq(3) by auto
  }
  ultimately have first_part: "(Fun f ts, Fun f (map Var qs)) ∈ (move' TA)*"
    using transition_chain'[of ts "?f" qs ?g "move' TA"] seq(3)
    by (cases ts) (fastforce, simp, metis (no_types, lifting) Cons_nth_drop_Suc
          append_take_drop_id diff_self_eq_0 length_0_conv length_drop lessI
          list.map_disc_iff list.simps(9) map_append)
  have qs_simp: "map (the_Var ∘ Var) qs = qs" using map_nth_eq_conv[of qs qs "the_Var ∘ Var"] by simp
  have "move TA (Fun f (map Var qs)) (Var q')"
    using seq(1) by (intro move.intros(2)) (auto elim!: move.cases simp: qs_simp)
  moreover have "(Var q', Var q) ∈ (move' TA)*"
    using seq(2) by (induction rule: rtrancl_induct)
      (simp, metis (no_types) case_prodI mem_Collect_eq move.intros(1) rtrancl.simps)
  ultimately show ?case using first_part
    by (metis case_prodI mem_Collect_eq rtrancl.rtrancl_into_rtrancl rtrancl_trans)
qed

lemma ta_res'_move_star:
  assumes "t ∈ ta_res' TA s"
  shows "(s, t) ∈ (move' TA)*"
  using assms
proof (induction TA s arbitrary: t rule: ta_res'.induct)
  case (1 TA q)
  then obtain q' where "(q, q') ∈ (ta_eps TA)*" "t = Var q'"
    using ta_res'_vars by (auto elim!: ta_res'.elims)
  thus ?case
  proof (induction arbitrary: t rule: rtrancl_induct)
    case (step y z)
    show ?case using step(1-3) unfolding step(4)
      by (simp, metis (no_types) case_prodI mem_Collect_eq move.intros(1) rtrancl.simps)
  qed blast
next
  case (2 TA f ts)
  consider (Var) "t ∈ {q. ∃q'. q = Var q' ∧ q' ∈ ta_res TA (Fun f ts)}" |
           (Fun) "t ∈ {t. ∃ss. t = Fun f ss ∧ length ss = length ts ∧
                 (∀ i < length ts. ss ! i ∈ ta_res' TA (ts ! i))}"
    using 2(2) by (metis (mono_tags, lifting) Un_iff ta_res'.simps(2))
  thus ?case
  proof cases
    case Var
    then obtain q where t_props: "t = Var q" "q ∈ ta_res TA (Fun f ts)" by blast
    show ?thesis using ta_res_move_star[OF t_props(2)] unfolding t_props(1) term.sel .
  next
    case Fun
    let ?f = "λts ss i. Fun f (take i ss @ ts ! i # drop (Suc i) ts)" and
      ?g = "λts ss i. Fun f (take i ss @ ss ! i # drop (Suc i) ts)"
    obtain ss where t_props: "t = Fun f ss" "length ss = length ts"
        "∀ i < length ts. ss ! i ∈ ta_res' TA (ts ! i)"
      using 2(2) Fun by blast
    hence "i < length ts ⟶ (ts ! i, ss ! i) ∈ (move' TA)*" for i
      using 2(1)[of i "ss ! i"] 2(2) unfolding Fun by blast

    hence move_in_ctxt: "i < length ts ⟶ (Fun f (take i ss @ ts ! i # drop (Suc i) ts),
                            Fun f (take i ss @ ss ! i # drop (Suc i) ts)) ∈ (move' TA)*" for i
      using move_star_ctxt_closed[of _ _ TA "More f _ □ _"] by simp
    moreover { fix i
      assume asm: "i < length ts - 1"
      hence "take i ss @ [ss ! i] = take (Suc i) ss" using t_props(2)
        by (simp add: take_Suc_conv_app_nth)
      moreover have "drop (Suc i) ts = ts ! Suc i # drop (Suc (Suc i)) ts" using asm
        by (metis Cons_nth_drop_Suc Suc_eq_plus1 less_diff_conv)
      ultimately have "?g ts ss i = ?f ts ss (Suc i)" using t_props(2) by auto
    }
    ultimately show ?thesis
      using transition_chain'[of ts "?f" ss ?g "move' TA"] t_props(2) unfolding t_props(1)
        by (cases ts) (force, simp, metis Cons_nth_drop_Suc lessI less_or_eq_imp_le
            list.sel(1) take_all take_hd_drop)
  qed
qed

lemma move_Fun_single:
  assumes "(s,t) ∈ (move' TA)*"
  shows "(Fun f (ss@(s#ts)), Fun f (ss@(t#ts))) ∈ (move' TA)*"
  using assms
  by (simp add: ctxt.closedI ctxt_closed_one move_star_ctxt_closed)

lemma move_Fun:
  assumes "∀i < length ts. (ts!i, ss!i) ∈ (move' TA)*"
  and "length ts = length ss"
  and "ts ≠ []"
  shows "(Fun f ts, Fun f ss) ∈ (move' TA)*"
proof -
  let ?h = "λ ts ss i. (Fun f ((take i ss)@(ts!i)#(drop (Suc i) ts)))"
  let ?g = "λ ts ss i. (Fun f ((take i ss)@(ss!i)#(drop (Suc i) ts)))"
  have "∀i< length ts - 1. ?g ts ss i = ?h ts ss (Suc i)"
    by (simp add: Cons_nth_drop_Suc assms(2) list.size(3) take_Suc_conv_app_nth)
  moreover have "∀i < length ts. (?h ts ss i, ?g ts ss i) ∈ (move' TA)*"
    using assms by (simp add: move_Fun_single)
  moreover have "?h ts ss  0 = Fun f ts" "?g ts ss  (length ts - 1) = Fun f ss"
   using assms(2,3) nth_drop_0
   by (auto)[1](metis Cons_nth_drop_Suc One_nat_def Suc_diff_Suc
                append_take_drop_id assms(2) assms(3) diff_less diff_zero drop_eq_Nil
                length_greater_0_conv order_refl zero_less_Suc)
  ultimately show ?thesis using transition_chain'[of "ts" "?h" "ss" "?g" "(move' TA)"]
    assms(2,3) by argo
qed


lemma move_ctxt_closure:
  assumes "length ss = length ts" "num_holes C = length ss"
    "∀i < length ts. (ss!i, ts!i) ∈ (move' TA)*"
  shows "(fill_holes C ss, fill_holes C ts) ∈ (move' TA)*" using assms
proof (induction C arbitrary: ss ts)
  case (MVar x)
  then show ?case  by simp
next
  case MHole
  hence "∃q q'. ss = [q] ∧ ts = [q']" using MHole
    by (metis eq_fill.intros eqf_MHoleE)
  thus ?case using assms MHole.prems(3) by force
next
  case (MFun f Cs)
  let ?sss = "(partition_holes ss Cs)"
  let ?tss = "(partition_holes ts Cs)"
  obtain Css Cts  where  Css_Cts:"fill_holes (MFun f Cs) ss = Fun f Css"
                        "fill_holes (MFun f Cs) ts = Fun f Cts"
    by simp
  {fix i
   assume loc_asm:"i < length Cs"
   hence "length (?sss!i) = length (?tss!i)" using assms(1) MFun by simp
   moreover have "num_holes (Cs!i) = length (?sss!i)" using assms(2) loc_asm MFun by force
   moreover have "∀j < length (?tss!i). ((?sss ! i)!j , (?tss ! i)!j)∈ (move' TA)*"
      using loc_asm MFun assms(3) by (metis calculation(1) calculation(2) length_map nth_map
                  num_holes.simps(3) partition_by_nth_nth(1) partition_by_nth_nth(2))
   ultimately have "(fill_holes (Cs!i) (?sss!i), fill_holes (Cs!i) (?tss!i)) ∈ (move' TA)*"
     using MFun(1) loc_asm by force}
  hence "∀i < length Cs. (fill_holes (Cs!i) (?sss!i), fill_holes (Cs!i) (?tss!i)) ∈ (move' TA)*"
    by blast
  hence "∀i < length Cts. (Css!i, Cts!i) ∈ (move' TA)*" using MFun Css_Cts by force
  moreover have "length Css = length Cts" using Css_Cts by force
  ultimately show ?case using MFun move_Fun Css_Cts
    by (metis list.simps(8) list.size(3) map_nth rtrancl.rtrancl_refl upt_0)
qed

end