Session Rewrite_Properties_Reduction

Theory Terms_Positions

section ‹Preliminaries›
theory Terms_Positions
  imports Regular_Tree_Relations.Ground_Terms
begin

subsection ‹Additional operations on terms and positions›

subsubsection ‹Linearity›
fun linear_term :: "('f, 'v) term ⇒ bool" where
  "linear_term (Var _) = True" |
  "linear_term (Fun _ ts) = (is_partition (map vars_term ts) ∧ (∀t∈set ts. linear_term t))"
abbreviation "linear_sys ℛ ≡ ∀ (l, r) ∈ ℛ. linear_term l ∧ linear_term r"

subsubsection ‹Positions induced by contexts, by variables and by given subterms›

definition "possc C = {p | p t. p ∈ poss C⟨t⟩}"
definition "varposs s = {p | p. p ∈ poss s ∧ is_Var (s |_ p)}"
definition "poss_of_term u t = {p. p ∈ poss t ∧ t |_ p = u}"


subsubsection ‹Replacing functions symbols that aren't specified in the signature by variables›

definition "funas_rel ℛ = (⋃ (l, r) ∈ ℛ. funas_term l ∪ funas_term r)"

fun term_to_sig where
  "term_to_sig ℱ v (Var x) = Var x"
| "term_to_sig ℱ v (Fun f ts) =
    (if (f, length ts) ∈ ℱ then Fun f (map (term_to_sig ℱ v) ts) else Var v)"

fun ctxt_well_def_hole_path where
  "ctxt_well_def_hole_path ℱ Hole ⟷ True"
| "ctxt_well_def_hole_path ℱ (More f ss C ts) ⟷ (f, Suc (length ss + length ts)) ∈ ℱ ∧ ctxt_well_def_hole_path ℱ C"

fun inv_const_ctxt where
  "inv_const_ctxt ℱ v Hole = Hole"
| "inv_const_ctxt ℱ v ((More f ss C ts)) 
              = (More f (map (term_to_sig ℱ v) ss) (inv_const_ctxt ℱ v C) (map (term_to_sig ℱ v) ts))"

fun inv_const_ctxt' where
  "inv_const_ctxt' ℱ v Hole = Var v"
| "inv_const_ctxt' ℱ v ((More f ss C ts)) 
              = (if (f, Suc (length ss + length ts)) ∈ ℱ then Fun f (map (term_to_sig ℱ v) ss @ inv_const_ctxt' ℱ v C # map (term_to_sig ℱ v) ts) else Var v)"


subsubsection ‹Replace term at a given position in contexts›

fun replace_term_context_at :: "('f, 'v) ctxt ⇒ pos ⇒ ('f, 'v) term ⇒ ('f, 'v) ctxt"
  ("_[_ ← _]C" [1000, 0] 1000) where
  "replace_term_context_at □ p u = □"
| "replace_term_context_at (More f ss C ts) (i # ps) u =
    (if i < length ss then More f (ss[i := (ss ! i)[ps ← u]]) C ts
     else if i = length ss then More f ss (replace_term_context_at C ps u) ts
     else More f ss C (ts[(i - Suc (length ss)) := (ts ! (i - Suc (length ss)))[ps ← u]]))"

abbreviation "constT c ≡ Fun c []"

subsubsection ‹Multihole context closure of a term relation as inductive set›

definition all_ctxt_closed where
  "all_ctxt_closed F r ⟷ (∀f ts ss. (f, length ss) ∈ F ⟶ length ts = length ss ⟶
    (∀i. i < length ts ⟶ (ts ! i, ss ! i) ∈ r) ⟶
    (∀ i. i < length ts ⟶ funas_term (ts ! i) ∪ funas_term (ss ! i) ⊆ F) ⟶ (Fun f ts, Fun f ss) ∈ r) ∧
    (∀ x. (Var x, Var x) ∈ r)"



subsection ‹Destruction and introduction of @{const all_ctxt_closed}›

lemma all_ctxt_closedD: "all_ctxt_closed F r ⟹ (f,length ss) ∈ F ⟹ length ts = length ss
  ⟹ ⟦⋀ i. i < length ts ⟹ (ts ! i, ss ! i) ∈ r ⟧
  ⟹ ⟦⋀ i. i < length ts ⟹ funas_term (ts ! i) ⊆ F ⟧
  ⟹ ⟦⋀ i. i < length ts ⟹ funas_term (ss ! i) ⊆ F ⟧
  ⟹ (Fun f ts, Fun f ss) ∈ r"
  unfolding all_ctxt_closed_def by auto

lemma trans_ctxt_sig_imp_all_ctxt_closed: assumes tran: "trans r"
  and refl: "⋀ t. funas_term t ⊆ F ⟹ (t,t) ∈ r"
  and ctxt: "⋀ C s t. funas_ctxt C ⊆ F ⟹ funas_term s ⊆ F ⟹ funas_term t ⊆ F ⟹ (s,t) ∈ r ⟹ (C ⟨ s ⟩, C ⟨ t ⟩) ∈ r"
  shows "all_ctxt_closed F r" unfolding all_ctxt_closed_def
proof (rule, intro allI impI)
  fix f ts ss
  assume f: "(f,length ss) ∈ F" and
         l: "length ts = length ss" and
         steps: "∀ i < length ts. (ts ! i, ss ! i) ∈ r" and
         sig: "∀ i < length ts. funas_term (ts ! i) ∪  funas_term (ss ! i) ⊆ F"
  from sig have sig_ts: "⋀ t. t ∈ set ts ⟹ funas_term t ⊆ F"  unfolding set_conv_nth by auto
  let ?p = "λ ss. (Fun f ts, Fun f ss) ∈ r ∧ funas_term (Fun f ss) ⊆ F"
  let ?r = "λ xsi ysi. (xsi, ysi) ∈ r ∧ funas_term ysi ⊆ F"
  have init: "?p ts" by (rule conjI[OF refl], insert f sig_ts l, auto)
  have "?p ss"
  proof (rule parallel_list_update[where p = ?p and r = ?r, OF _ HOL.refl init l[symmetric]])
    fix xs i y
    assume len: "length xs = length ts"
       and i: "i < length ts"
       and r: "?r (xs ! i) y"
       and p: "?p xs"
    let ?C = "More f (take i xs) Hole (drop (Suc i) xs)"
    have id1: "Fun f xs = ?C ⟨ xs ! i⟩" using id_take_nth_drop[OF i[folded len]] by simp
    have id2: "Fun f (xs[i := y]) = ?C ⟨ y ⟩" using upd_conv_take_nth_drop[OF i[folded len]] by simp
    from p[unfolded id1] have C: "funas_ctxt ?C ⊆ F" and xi: "funas_term (xs ! i) ⊆ F" by auto
    from r have "funas_term y ⊆ F" "(xs ! i, y) ∈ r" by auto
    with ctxt[OF C xi this] C have r: "(Fun f xs, Fun f (xs[i := y])) ∈ r"
      and f: "funas_term (Fun f (xs[i := y])) ⊆ F" unfolding id1 id2 by auto
    from p r tran have "(Fun f ts, Fun f (xs[i := y])) ∈ r" unfolding trans_def by auto
    with f
    show "?p (xs[i := y])"  by auto
  qed (insert sig steps, auto)
  then show "(Fun f ts, Fun f ss) ∈ r" ..
qed (insert refl, auto)



subsection ‹Lemmas for @{const poss} and ordering of positions›

lemma subst_poss_mono: "poss s ⊆ poss (s ⋅ σ)"
  by (induct s) force+

lemma par_pos_prefix [simp]:
  "(i # p) ⊥ (i # q) ⟹ p ⊥ q"
  by (simp add: par_Cons_iff)

lemma pos_diff_itself [simp]: "p -p p = []"
  by (simp add: pos_diff_def)

lemma pos_les_eq_append_diff [simp]:
  "p ≤p q ⟹ p @ (q -p p) = q"
  by (metis option.sel pos_diff_def position_less_eq_def remove_prefix_append)

lemma pos_diff_append_itself [simp]: "(p @ q) -p p = q"
  by (simp add: pos_diff_def remove_prefix_append)

lemma poss_pos_diffI:
  "p ≤p q ⟹ q ∈ poss s ⟹ q -p p ∈ poss (s |_ p)"
  using poss_append_poss by fastforce

lemma less_eq_poss_append_itself [simp]: "p ≤p (p @ q)"
  using position_less_eq_def by blast

lemma poss_ctxt_apply [simp]:
  "hole_pos C @ p ∈ poss C⟨s⟩ ⟷ p ∈ poss s"
  by (induct C) auto

lemma pos_replace_at_pres:
  "p ∈ poss s ⟹ p ∈ poss s[p ← t]"
proof (induct p arbitrary: s)
  case (Cons i p)
  show ?case using Cons(1)[of "args s ! i"] Cons(2-)
    by (cases s) auto
qed auto

lemma par_pos_replace_pres:
  "p ∈ poss s ⟹ p ⊥ q ⟹ p ∈ poss s[q ← t]"
proof (induct p arbitrary: s q)
  case (Cons i p)
  show ?case using Cons(1)[of "args s ! i" "tl q"] Cons(2-)
    by (cases s; cases q) (auto simp add: nth_list_update par_Cons_iff)
qed auto

lemma poss_of_termE [elim]:
  assumes "p ∈ poss_of_term u s"
    and "p ∈ poss s ⟹ s |_ p = u ⟹ P"
  shows "P" using assms unfolding poss_of_term_def
  by blast

lemma poss_of_term_Cons:
  "i # p ∈ poss_of_term u (Fun f ts) ⟹ p ∈ poss_of_term u (ts ! i)"
  unfolding poss_of_term_def by auto

lemma poss_of_term_const_ctxt_apply:
  assumes "p ∈ poss_of_term (constT c) C⟨s⟩"
  shows "p ⊥ (hole_pos C) ∨ (hole_pos C) ≤p p" using assms
proof (induct p arbitrary: C)
  case Nil then show ?case
    by (cases C) auto
next
  case (Cons i p) then show ?case
    by (cases C) (fastforce simp add: par_Cons_iff dest!: poss_of_term_Cons)+
qed


subsection ‹Lemmas for @{const subt_at} and @{const replace_term_at}›

lemma subt_at_append_dist:
  "p @ q ∈ poss s ⟹ s |_ (p @ q) = (s |_ p) |_ q"
proof (induct p arbitrary: s)
  case (Cons i p) then show ?case
    by (cases s) auto
qed auto

lemma ctxt_apply_term_subt_at_hole_pos [simp]:
  "C⟨s⟩ |_ (hole_pos C @ q) = s |_ q"
  by (induct C) auto

lemma subst_subt_at_dist:
  "p ∈ poss s ⟹ s ⋅ σ |_ p = s |_ p ⋅ σ"
proof (induct p arbitrary: s)
  case (Cons i p) then show ?case
    by (cases s) auto
qed auto

lemma replace_term_at_subt_at_id [simp]: "s[p ← (s |_ p)] = s"
proof (induct p arbitrary: s)
  case (Cons i p) then show ?case
    by (cases s) auto
qed auto


lemma replace_term_at_same_pos [simp]:
  "s[p ← u][p ← t] = s[p ← t]"
  using position_less_refl replace_term_at_above by blast

― ‹Replacement at under substitution›
lemma subt_at_vars_term:
  "p ∈ poss s ⟹ s |_ p = Var x ⟹ x ∈ vars_term s"
  by (metis UnCI ctxt_at_pos_subt_at_id term.set_intros(3) vars_term_ctxt_apply)

lemma linear_term_varposs_subst_replace_term:
  "linear_term s ⟹ p ∈ varposs s ⟹ p ≤p q ⟹
     (s ⋅ σ)[q ← u] = s ⋅ (λ x. if Var x = s |_ p then (σ x)[q -p p ← u] else (σ x))"
proof (induct q arbitrary: s p)
  case (Cons i q)
  show ?case using Cons(1)[of "args s ! i" "tl p"] Cons(2-)
    by (cases s) (auto simp: varposs_def nth_list_update term_subst_eq_conv
      is_partition_alt is_partition_alt_def disjoint_iff subt_at_vars_term intro!: nth_equalityI)
qed (auto simp: varposs_def)

― ‹Replacement at context parallel to the hole position›
lemma par_hole_pos_replace_term_context_at:
  "p ⊥ hole_pos C ⟹ C⟨s⟩[p ← u] = (C[p ← u]C)⟨s⟩"
proof (induct p arbitrary: C)
  case (Cons i p)
  from Cons(2) obtain f ss D ts where [simp]: "C = More f ss D ts" by (cases C) auto 
  show ?case using Cons(1)[of D] Cons(2)
    by (auto simp: list_update_append nth_append_Cons minus_nat.simps(2) split: nat.splits)
qed auto

lemma par_pos_replace_term_at:
  "p ∈ poss s ⟹ p ⊥ q ⟹ s[q ← t] |_ p = s |_ p"
proof (induct p arbitrary: s q)
  case (Cons i p)
  show ?case using Cons(1)[of "args s ! i" "tl q"] Cons(2-)
    by (cases s; cases q) (auto, metis nth_list_update par_Cons_iff)
qed auto


lemma less_eq_subt_at_replace:
  "p ∈ poss s ⟹ p ≤p q ⟹ s[q ← t] |_ p = (s |_ p)[q -p p ← t]"
proof (induct p arbitrary: s q)
  case (Cons i p)
  show ?case using Cons(1)[of "args s ! i" "tl q"] Cons(2-)
    by (cases s; cases q) auto
qed auto


lemma greater_eq_subt_at_replace:
  "p ∈ poss s ⟹ q ≤p p ⟹ s[q ← t] |_ p = t |_ (p -p q)"
proof (induct p arbitrary: s q)
  case (Cons i p)
  show ?case using Cons(1)[of "args s ! i" "tl q"] Cons(2-)
    by (cases s; cases q) auto
qed auto

lemma replace_subterm_at_itself [simp]:
  "s[p ← (s |_ p)[q ← t]] = s[p @ q ← t]"
proof (induct p arbitrary: s)
  case (Cons i p)
  show ?case using Cons(1)[of "args s ! i"]
    by (cases s) auto
qed auto


lemma hole_pos_replace_term_at [simp]:
  "hole_pos C ≤p p ⟹ C⟨s⟩[p ← u] = C⟨s[p -p hole_pos C ← u]⟩"
proof (induct C arbitrary: p)
  case (More f ss C ts) then show ?case
    by (cases p) auto
qed auto

lemma ctxt_of_pos_term_apply_replace_at_ident:
  assumes "p ∈ poss s"
  shows "(ctxt_at_pos s p)⟨t⟩ = s[p ← t]"
  using assms
proof (induct p arbitrary: s)
  case (Cons i p)
  show ?case using Cons(1)[of "args s ! i"] Cons(2-)
    by (cases s) (auto simp: nth_append_Cons intro!: nth_equalityI)
qed auto

lemma ctxt_apply_term_replace_term_hole_pos [simp]:
  "C⟨s⟩[hole_pos C @ q  ← u] = C⟨s[q  ← u]⟩"
  by (simp add: pos_diff_def position_less_eq_def remove_prefix_append)

lemma ctxt_apply_subt_at_hole_pos [simp]: "C⟨s⟩ |_ hole_pos C = s"
  by (induct C) auto

lemma subt_at_imp_supteq':
  assumes "p ∈ poss s" and "s|_p = t" shows "s ⊵ t" using assms
proof (induct p arbitrary: s)
  case (Cons i p)
  from Cons(2-) show ?case using Cons(1)[of "args s ! i"]
    by (cases s) force+
qed auto

lemma subt_at_imp_supteq:
  assumes "p ∈ poss s" shows "s ⊵ s|_p"
proof -
 have "s|_p = s|_p" by auto
 with assms show ?thesis by (rule subt_at_imp_supteq')
qed


subsection ‹@{const term_to_sig} invariants and distributions›

lemma fuans_term_term_to_sig [simp]: "funas_term (term_to_sig ℱ v t) ⊆ ℱ"
  by (induct t) auto

lemma term_to_sig_id [simp]:
  "funas_term t ⊆ ℱ ⟹ term_to_sig ℱ v t = t"
  by (induct t) (auto simp add: UN_subset_iff map_idI)

lemma term_to_sig_subst_sig [simp]:
  "funas_term t ⊆ ℱ ⟹ term_to_sig ℱ v (t ⋅ σ) = t ⋅ (λ x.  term_to_sig ℱ v (σ x))"
  by (induct t) auto

lemma funas_ctxt_ctxt_inv_const_ctxt_ind [simp]:
  "funas_ctxt C ⊆ ℱ ⟹ inv_const_ctxt ℱ v C = C"
  by (induct C) (auto simp add: UN_subset_iff intro!: nth_equalityI)

lemma term_to_sig_ctxt_apply [simp]:
  "ctxt_well_def_hole_path ℱ C ⟹ term_to_sig ℱ v C⟨s⟩ = (inv_const_ctxt ℱ v C)⟨term_to_sig ℱ v s⟩"
  by (induct C) auto

lemma term_to_sig_ctxt_apply' [simp]:
  "¬ ctxt_well_def_hole_path ℱ C ⟹ term_to_sig ℱ v C⟨s⟩ = inv_const_ctxt' ℱ v C"
  by (induct C) auto

lemma funas_ctxt_ctxt_well_def_hole_path:
  "funas_ctxt C ⊆ ℱ ⟹ ctxt_well_def_hole_path ℱ C"
  by (induct C) auto


subsection ‹Misc›

lemma funas_term_subt_at:
  "(f, n) ∈ funas_term t ⟹ (∃ p ts. p ∈ poss t ∧ t |_ p = Fun f ts ∧ length ts = n)"
proof (induct t)
  case (Fun g ts) note IH = this
  show ?case
  proof (cases "g = f ∧ length ts = n")
    case False
    then obtain i where i: "i < length ts" "(f, n) ∈ funas_term (ts ! i)" using IH(2)
      using in_set_idx by force
    from IH(1)[OF nth_mem[OF this(1)] this(2)] show ?thesis using i(1)
      by (metis poss_Cons_poss subt_at.simps(2) term.sel(4))
  qed auto
qed simp

lemma finite_poss: "finite (poss s)"
proof (induct s)
  case (Fun f ts)
  have "poss (Fun f ts) = insert [] (⋃ (set (map2 (λ i p. ((#) i) ` p) [0..< length ts] (map poss ts))))"
    by (auto simp: image_iff set_zip split: prod.splits)
  then show ?case using Fun
    by (auto simp del: poss.simps dest!: set_zip_rightD)
qed simp

lemma finite_varposs: "finite (varposs s)"
  by (intro finite_subset[of "varposs s" "poss s"]) (auto simp: varposs_def finite_poss)

lemma gound_linear [simp]: "ground t ⟹ linear_term t"
  by (induct t) (auto simp: is_partition_alt is_partition_alt_def)

declare ground_substI[intro, simp]
lemma ground_ctxt_substI:
  "(⋀ x. x ∈ vars_ctxt C ⟹ ground (σ x)) ⟹ ground_ctxt (C ⋅c σ)"
  by (induct C) auto


lemma funas_ctxt_subst_apply_ctxt:
  "funas_ctxt (C ⋅c σ) = funas_ctxt C ∪ (⋃ (funas_term ` σ ` vars_ctxt C))"
proof (induct C)
  case (More f ss C ts)
  then show ?case
    by (fastforce simp add: funas_term_subst)
qed simp

lemma varposs_Var[simp]:
  "varposs (Var x) = {[]}"
  by (auto simp: varposs_def)

lemma varposs_Fun[simp]:
  "varposs (Fun f ts) = { i # p| i p. i < length ts ∧ p ∈ varposs (ts ! i)}"
  by (auto simp: varposs_def)

lemma vars_term_varposs_iff:
  "x ∈ vars_term s ⟷ (∃ p ∈ varposs s. s |_ p = Var x)"
proof (induct s)
  case (Fun f ts)
  show ?case using Fun[OF nth_mem]
    by (force simp: in_set_conv_nth Bex_def)
qed auto

lemma vars_term_empty_ground:
  "vars_term s = {} ⟹ ground s"
  by (metis equals0D ground_substI subst_ident)

lemma ground_subst_apply: "ground t ⟹ t ⋅ σ = t"
  by (induct t) (auto intro: nth_equalityI)

lemma varposs_imp_poss:
  "p ∈ varposs s ⟹ p ∈ poss s" by (auto simp: varposs_def)

lemma varposs_empty_gound:
 "varposs s = {} ⟷ ground s"
  by (induct s) (fastforce simp: in_set_conv_nth)+

lemma funas_term_subterm_atI [intro]:
  "p ∈ poss s ⟹ funas_term s ⊆ ℱ ⟹ funas_term (s |_ p) ⊆ ℱ"
  by (metis ctxt_at_pos_subt_at_id funas_ctxt_apply le_sup_iff)

lemma varposs_ground_replace_at:
  "p ∈ varposs s ⟹ ground u ⟹ varposs s[p ← u] = varposs s - {p}"
proof (induct p arbitrary: s)
  case Nil then show ?case
    by (cases s) (auto simp: varposs_empty_gound)
next
  case (Cons i p)
  from Cons(2) obtain f ts where [simp]: "s = Fun f ts" by (cases s) auto
  from Cons(2) have var: "p ∈ varposs (ts ! i)" by auto
  from Cons(1)[OF var Cons(3)] have "j < length ts ⟹ {j # q| q. q ∈ varposs (ts[i := (ts ! i)[p ← u]] ! j)} =
           {j # q |q. q ∈ varposs (ts ! j)} - {i # p}" for j
    by (cases "j = i") (auto simp add: nth_list_update)
  then show ?case by auto blast
qed

lemma funas_term_replace_at_upper:
  "funas_term s[p ← t] ⊆ funas_term s ∪ funas_term t"
proof (induct p arbitrary: s)
  case (Cons i p)
  show ?case using Cons(1)[of "args s ! i"]
    by (cases s) (fastforce simp: in_set_conv_nth nth_list_update split!: if_splits)+
qed simp

lemma funas_term_replace_at_lower:
  "p ∈ poss s ⟹ funas_term t ⊆ funas_term (s[p ← t])"
proof (induct p arbitrary: s)
  case (Cons i p)
  show ?case using Cons(1)[of "args s ! i"] Cons(2-)
    by (cases s) (fastforce simp: in_set_conv_nth nth_list_update split!: if_splits)+
qed simp

lemma poss_of_term_possI [intro!]:
  "p ∈ poss s ⟹ s |_ p = u ⟹ p ∈ poss_of_term u s"
  unfolding poss_of_term_def by blast

lemma poss_of_term_replace_term_at:
  "p ∈ poss s ⟹ p ∈ poss_of_term u s[p ← u]"
proof (induct p arbitrary: s)
  case (Cons i p) then show ?case
    by (cases s) (auto simp: poss_of_term_def)
qed auto

lemma constT_nfunas_term_poss_of_term_empty:
  "(c, 0) ∉ funas_term t ⟷ poss_of_term (constT c) t = {}"
  unfolding poss_of_term_def
  using funas_term_subt_at[of c 0 t]
  using funas_term_subterm_atI[where ?ℱ ="funas_term t" and ?s = t, THEN subsetD]
  by auto

lemma poss_of_term_poss_emptyD:
  assumes "poss_of_term u s = {}"
  shows "p ∈ poss s ⟹ s |_ p ≠ u" using assms
  unfolding poss_of_term_def by blast

lemma possc_subt_at_ctxt_apply:
  "p ∈ possc C ⟹ p ⊥ hole_pos C ⟹ C⟨s⟩ |_ p = C⟨t⟩ |_ p"
proof (induct p arbitrary: C)
  case (Cons i p)
  have [dest]: "length ss # p ∈ possc (More f ss D ts) ⟹ p ∈ possc D" for f ss D ts
    by (auto simp: possc_def)
  show ?case using Cons
    by (cases C) (auto simp: nth_append_Cons)
qed simp

end

Theory Rewriting

section ‹Rewriting›
theory Rewriting
  imports Terms_Positions
begin

subsection ‹Basic rewrite definitions›

subsubsection ‹Rewrite steps with implicit signature declaration (encoded in the type)›

inductive_set rrstep :: "('f, 'v) term rel ⇒ ('f, 'v) term rel" for ℛ where
  [intro]: "(l, r) ∈ ℛ ⟹ (l ⋅ σ, r ⋅ σ) ∈ rrstep ℛ"

inductive_set rstep :: "('f, 'v) term rel ⇒ ('f, 'v) term rel" for ℛ where
  "(s, t) ∈ rrstep ℛ ⟹ (C⟨s⟩, C⟨t⟩) ∈ rstep ℛ"


subsubsection ‹Restrict relations to terms induced by a given signature›

definition "sig_step ℱ ℛ = Restr ℛ (Collect (λ s. funas_term s ⊆ ℱ))"

subsubsection ‹Rewriting under a given signature/restricted to ground terms›

abbreviation "srrstep ℱ ℛ ≡ sig_step ℱ (rrstep ℛ)"
abbreviation "srstep ℱ ℛ ≡ sig_step ℱ (rstep ℛ)"
abbreviation "gsrstep ℱ ℛ ≡ Restr (sig_step ℱ (rstep ℛ)) (Collect ground)"


subsubsection ‹Rewriting sequences involving a root step›

abbreviation (input) relto :: "'a rel ⇒ 'a rel ⇒ 'a rel" where
  "relto R S ≡ S^* O R O S^*"
definition "srsteps_with_root_step ℱ ℛ ≡ relto (sig_step ℱ (rrstep ℛ)) (srstep ℱ ℛ)"


subsection ‹Monotonicity laws›

lemma Restr_mono: "Restr r A ⊆ r" by auto

lemma Restr_trancl_mono_set: "(Restr r A)+ ⊆ A × A"
  by (simp add: trancl_subset_Sigma)

lemma rrstep_rstep_mono: "rrstep ℛ ⊆ rstep ℛ"
  by (auto intro: rstep.intros[where ?C = □, simplified])

lemma sig_step_mono:
  "ℱ ⊆ 𝒢 ⟹ sig_step ℱ ℛ ⊆ sig_step 𝒢 ℛ"
  by (auto simp: sig_step_def)

lemma sig_step_mono2:
  "ℛ ⊆ ℒ ⟹ sig_step ℱ ℛ ⊆ sig_step ℱ ℒ"
  by (auto simp: sig_step_def)

lemma srrstep_monp:
  "ℱ ⊆ 𝒢 ⟹ srrstep ℱ ℛ ⊆ srrstep 𝒢 ℛ"
  by (simp add: sig_step_mono)

lemma srstep_monp:
  "ℱ ⊆ 𝒢 ⟹ srstep ℱ ℛ ⊆ srstep 𝒢 ℛ"
  by (simp add: sig_step_mono)

lemma srsteps_monp:
  "ℱ ⊆ 𝒢 ⟹ (srstep ℱ ℛ)+ ⊆ (srstep 𝒢 ℛ)+"
  by (simp add: sig_step_mono trancl_mono_set)

lemma srsteps_eq_monp:
  "ℱ ⊆ 𝒢 ⟹ (srstep ℱ ℛ)* ⊆ (srstep 𝒢 ℛ)*"
  by (meson rtrancl_mono sig_step_mono subrelI subsetD trancl_into_rtrancl)
  
lemma srsteps_with_root_step_sig_mono:
   "ℱ ⊆ 𝒢 ⟹ srsteps_with_root_step ℱ ℛ ⊆ srsteps_with_root_step 𝒢 ℛ"
  unfolding srsteps_with_root_step_def
  by (simp add: relcomp_mono srrstep_monp srsteps_eq_monp)


subsection ‹Introduction, elimination, and destruction rules for @{const sig_step}, @{const rstep}, @{const rrstep},
   @{const srrstep}, and @{const srstep}›

lemma sig_stepE [elim, consumes 1]:
  "(s, t) ∈ sig_step ℱ ℛ ⟹ ⟦(s, t) ∈ ℛ ⟹ funas_term s ⊆ ℱ ⟹ funas_term t ⊆ ℱ ⟹ P⟧ ⟹ P"
  by (auto simp: sig_step_def)

lemma sig_stepI [intro]:
  "funas_term s ⊆ ℱ ⟹ funas_term t ⊆ ℱ ⟹ (s, t) ∈ ℛ ⟹ (s, t) ∈ sig_step ℱ ℛ"
  by (auto simp: sig_step_def)

lemma rrstep_subst [elim, consumes 1]:
  assumes "(s, t) ∈ rrstep ℛ"
  obtains l r σ where "(l, r) ∈ ℛ" "s = l ⋅ σ" "t = r ⋅ σ" using assms
  by (meson rrstep.simps)
  
lemma rstep_imp_C_s_r:
  assumes "(s, t) ∈ rstep ℛ"
  shows "∃C σ l r. (l,r) ∈ ℛ ∧ s = C⟨l⋅σ⟩ ∧ t = C⟨r⋅σ⟩"using assms
  by (metis rrstep.cases rstep.simps)

  
lemma rstep_imp_C_s_r' [elim, consumes 1]:
  assumes "(s, t) ∈ rstep ℛ"
  obtains C l r σ where "(l,r) ∈ ℛ" "s = C⟨l⋅σ⟩" "t = C⟨r⋅σ⟩" using assms
  using rstep_imp_C_s_r by blast

lemma rrstep_basicI [intro]:
  "(l, r) ∈ ℛ ⟹ (l, r) ∈ rrstep ℛ"
  by (metis rrstepp.intros rrstepp_rrstep_eq subst_apply_term_empty)

lemma rstep_ruleI [intro]:
  "(l, r) ∈ ℛ ⟹ (l, r) ∈ rstep ℛ"
  using rrstep_rstep_mono by blast

lemma rstepI [intro]:
  "(l, r) ∈ ℛ ⟹ s = C⟨l ⋅ σ⟩ ⟹ t = C⟨r ⋅ σ⟩ ⟹ (s, t) ∈ rstep ℛ"
  by (simp add: rrstep.intros rstep.intros)

lemma rstep_substI [intro]:
  "(s, t) ∈ rstep ℛ ⟹ (s ⋅ σ, t ⋅ σ) ∈ rstep ℛ"
  by (auto elim!: rstep_imp_C_s_r' simp flip: subst_subst_compose)

lemma rstep_ctxtI [intro]:
  "(s, t) ∈ rstep ℛ ⟹ (C⟨s⟩, C⟨t⟩) ∈ rstep ℛ"
  by (auto elim!: rstep_imp_C_s_r' simp flip: ctxt_ctxt_compose)

lemma srrstepD:
  "(s, t) ∈ srrstep ℱ ℛ ⟹ (s, t) ∈ rrstep ℛ ∧ funas_term s ⊆ ℱ ∧ funas_term t ⊆ ℱ"
  by (auto simp: sig_step_def)

lemma srstepD:
  "(s, t) ∈ (srstep ℱ ℛ) ⟹ (s, t) ∈ rstep ℛ ∧ funas_term s ⊆ ℱ ∧ funas_term t ⊆ ℱ"
  by (auto simp: sig_step_def)

lemma srstepsD:
  "(s, t) ∈ (srstep ℱ ℛ)+ ⟹ (s, t) ∈ (rstep ℛ)+ ∧ funas_term s ⊆ ℱ ∧ funas_term t ⊆ ℱ"
  unfolding sig_step_def using trancl_mono_set[OF Restr_mono] 
  by (auto simp: sig_step_def dest: subsetD[OF Restr_trancl_mono_set])


subsubsection ‹Transitive and relfexive closure distribution over @{const sig_step}›

lemma funas_rel_converse:
  "funas_rel ℛ ⊆ ℱ ⟹ funas_rel (ℛ¯) ⊆ ℱ" unfolding funas_rel_def
  by auto

lemma rstep_term_to_sig_r:
  assumes "(s, t) ∈ rstep ℛ" and "funas_rel ℛ ⊆ ℱ" and "funas_term s ⊆ ℱ"
  shows "(s, term_to_sig ℱ v t) ∈ rstep ℛ"
proof -
  from assms(1) obtain C l r σ where
    *: "s = C⟨l ⋅ σ⟩" "t = C⟨r ⋅ σ⟩" "(l, r) ∈ ℛ" by auto
  from assms(2, 3) *(3) have "funas_ctxt C ⊆ ℱ" "funas_term l ⊆ ℱ" "funas_term r ⊆ ℱ"
    by (auto simp: *(1) funas_rel_def funas_term_subst subset_eq)
  then have "(term_to_sig ℱ v s, term_to_sig ℱ v t) ∈ rstep ℛ" using *(3)
    by (auto simp: *(1, 2) funas_ctxt_ctxt_well_def_hole_path)
  then show ?thesis using assms(3) by auto
qed

lemma rstep_term_to_sig_l:
  assumes "(s, t) ∈ rstep ℛ" and "funas_rel ℛ ⊆ ℱ" and "funas_term t ⊆ ℱ"
  shows "(term_to_sig ℱ v s, t) ∈ rstep ℛ"
proof -
  from assms(1) obtain C l r σ where
    *: "s = C⟨l ⋅ σ⟩" "t = C⟨r ⋅ σ⟩" "(l, r) ∈ ℛ" by auto
  from assms(2, 3) *(3) have "funas_ctxt C ⊆ ℱ" "funas_term l ⊆ ℱ" "funas_term r ⊆ ℱ"
    by (auto simp: *(2) funas_rel_def funas_term_subst subset_eq)
  then have "(term_to_sig ℱ v s, term_to_sig ℱ v t) ∈ rstep ℛ" using *(3)
    by (auto simp: *(1, 2) funas_ctxt_ctxt_well_def_hole_path)
  then show ?thesis using assms(3) by auto
qed

lemma rstep_trancl_sig_step_r:
  assumes "(s, t) ∈ (rstep ℛ)+" and "funas_rel ℛ ⊆ ℱ" and "funas_term s ⊆ ℱ"
  shows "(s, term_to_sig ℱ v t) ∈ (srstep ℱ ℛ)+" using assms
proof (induct)
  case (base t)
  then show ?case using subsetD[OF fuans_term_term_to_sig, of _ ℱ v]
    by (auto simp: rstep_term_to_sig_r sig_step_def intro!: r_into_trancl)
next
  case (step t u)
  then have st: "(s, term_to_sig ℱ v t) ∈ (srstep ℱ ℛ)+" by auto
  from step(2) obtain  C l r σ where
    *: "t = C⟨l ⋅ σ⟩" "u = C⟨r ⋅ σ⟩" "(l, r) ∈ ℛ" by auto
  show ?case
  proof (cases "ctxt_well_def_hole_path ℱ C")
    case True
    from *(3) step(4) have "funas_term l ⊆ ℱ" "funas_term r ⊆ ℱ" by (auto simp: funas_rel_def)
    then have "(term_to_sig ℱ v t, term_to_sig ℱ v u) ∈ rstep ℛ"
      using True step(2) *(3) unfolding *
      by auto
    then have "(term_to_sig ℱ v t, term_to_sig ℱ v u) ∈ srstep ℱ ℛ"
      by (auto simp:_ sig_step_def)
    then show ?thesis using st by auto
  next
    case False
    then have "term_to_sig ℱ v t = term_to_sig ℱ v u" unfolding * by auto
    then show ?thesis using st by auto
  qed
qed

lemma rstep_trancl_sig_step_l:
  assumes "(s, t) ∈ (rstep ℛ)+" and "funas_rel ℛ ⊆ ℱ" and "funas_term t ⊆ ℱ"
  shows "(term_to_sig ℱ v s, t) ∈ (srstep ℱ ℛ)+" using assms
proof (induct rule: converse_trancl_induct)
  case (base t)
  then show ?case using subsetD[OF fuans_term_term_to_sig, of _ ℱ v]
    by (auto simp: rstep_term_to_sig_l sig_step_def intro!: r_into_trancl)
next
  case (step s u)
  then have st: "(term_to_sig ℱ v u, t) ∈ (srstep ℱ ℛ)+" by auto
  from step(1) obtain C l r σ where
    *: "s = C⟨l ⋅ σ⟩" "u = C⟨r ⋅ σ⟩" "(l, r) ∈ ℛ" by auto
  show ?case
  proof (cases "ctxt_well_def_hole_path ℱ C")
    case True
    from *(3) step(4) have "funas_term l ⊆ ℱ" "funas_term r ⊆ ℱ" by (auto simp: funas_rel_def)
    then have "(term_to_sig ℱ v s, term_to_sig ℱ v u) ∈ rstep ℛ"
      using True step(2) *(3) unfolding *
      by auto
    then have "(term_to_sig ℱ v s, term_to_sig ℱ v u) ∈ srstep ℱ ℛ"
      by (auto simp:_ sig_step_def)
    then show ?thesis using st by auto
  next
    case False
    then have "term_to_sig ℱ v s = term_to_sig ℱ v u" unfolding * by auto
    then show ?thesis using st by auto
  qed
qed

lemma rstep_srstepI [intro]:
  "funas_rel ℛ ⊆ ℱ ⟹ funas_term s ⊆ ℱ ⟹ funas_term t ⊆ ℱ ⟹ (s, t) ∈ rstep ℛ ⟹ (s, t) ∈ srstep ℱ ℛ"
  by blast

lemma rsteps_srstepsI [intro]:
  "funas_rel ℛ ⊆ ℱ ⟹ funas_term s ⊆ ℱ ⟹ funas_term t ⊆ ℱ ⟹ (s, t) ∈ (rstep ℛ)+ ⟹ (s, t) ∈ (srstep ℱ ℛ)+"
  using rstep_trancl_sig_step_r[of s t ℛ ℱ]
  by auto


lemma rsteps_eq_srsteps_eqI [intro]:
  "funas_rel ℛ ⊆ ℱ ⟹ funas_term s ⊆ ℱ ⟹ funas_term t ⊆ ℱ ⟹ (s, t) ∈ (rstep ℛ)* ⟹ (s, t) ∈ (srstep ℱ ℛ)*"
  by (auto simp add: rtrancl_eq_or_trancl)

lemma rsteps_eq_relcomp_srsteps_eq_relcompI [intro]:
  assumes "funas_rel ℛ ⊆ ℱ" "funas_rel 𝒮 ⊆ ℱ"
    and funas: "funas_term s ⊆ ℱ" "funas_term t ⊆ ℱ"
    and steps: "(s, t) ∈ (rstep ℛ)* O (rstep 𝒮)*"
  shows "(s, t) ∈ (srstep ℱ ℛ)* O (srstep ℱ 𝒮)*"
proof -
  from steps obtain u where "(s, u) ∈ (rstep ℛ)*" "(u, t) ∈ (rstep 𝒮)*" by auto
  then have "(s, term_to_sig ℱ v u) ∈ (srstep ℱ ℛ)*" "(term_to_sig ℱ v u, t) ∈ (srstep ℱ 𝒮)*"
    using rstep_trancl_sig_step_l[OF _ assms(2) funas(2), of u v]
    using rstep_trancl_sig_step_r[OF _ assms(1) funas(1), of u v] funas
    by (auto simp: rtrancl_eq_or_trancl)
  then show ?thesis by auto
qed    


subsubsection ‹Distributivity laws›

lemma rstep_smycl_dist:
  "(rstep ℛ)↔ = rstep (ℛ↔)"
  by (auto simp: sig_step_def)

lemma sig_step_symcl_dist:
  "(sig_step ℱ ℛ)↔ = sig_step ℱ (ℛ↔)"
  by (auto simp: sig_step_def)

lemma srstep_symcl_dist:
  "(srstep ℱ ℛ)↔ = srstep ℱ (ℛ↔)"
  by (auto simp: sig_step_def)

lemma Restr_smycl_dist:
  "(Restr ℛ 𝒜)↔ = Restr (ℛ↔) 𝒜"
  by auto

lemmas rew_symcl_inwards = rstep_smycl_dist sig_step_symcl_dist srstep_symcl_dist Restr_smycl_dist
lemmas rew_symcl_outwards = rew_symcl_inwards[symmetric]

lemma rstep_converse_dist:
  "(rstep ℛ)¯ = rstep (ℛ¯)"
  by auto

lemma srrstep_converse_dist:
  "(srrstep ℱ ℛ)¯ = srrstep ℱ (ℛ¯)"
  by (fastforce simp: sig_step_def)

lemma sig_step_converse_rstep:
  "(srstep ℱ ℛ)¯ = sig_step ℱ ((rstep ℛ)¯)"
  by (meson converse.simps set_eq_subset sig_stepE(1) sig_stepE sig_stepI subrelI)

lemma srstep_converse_dist:
  "(srstep ℱ ℛ)¯ = srstep ℱ (ℛ¯)"
  by (auto simp: sig_step_def)

lemma Restr_converse: "(Restr ℛ A)¯ = Restr (ℛ¯) A"
  by auto

lemmas rew_converse_inwards = rstep_converse_dist srrstep_converse_dist sig_step_converse_rstep
   srstep_converse_dist Restr_converse trancl_converse[symmetric] rtrancl_converse[symmetric]
lemmas rew_converse_outwards = rew_converse_inwards[symmetric]

lemma sig_step_rsteps_dist:
  "funas_rel ℛ ⊆ ℱ ⟹ sig_step ℱ ((rstep ℛ)+) = (srstep ℱ ℛ)+"
  by (auto elim!: sig_stepE dest: srstepsD)

lemma sig_step_rsteps_eq_dist:
  "funas_rel ℛ ⊆ ℱ ⟹ sig_step ℱ ((rstep ℛ)+) ∪ Id = (srstep ℱ ℛ)*"
  by (auto simp: rtrancl_eq_or_trancl sig_step_rsteps_dist)

lemma sig_step_conversion_dist:
  "(srstep ℱ ℛ)↔* = (srstep ℱ (ℛ↔))*"
  by (auto simp: rtrancl_eq_or_trancl sig_step_rsteps_dist conversion_def srstep_symcl_dist)

lemma gsrstep_conversion_dist:
  "(gsrstep ℱ ℛ)↔* = (gsrstep ℱ (ℛ↔))*"
  by (auto simp: conversion_def rew_symcl_inwards)
                                                                                         
lemma sig_step_grstep_dist:
  "gsrstep ℱ ℛ = sig_step ℱ (Restr (rstep ℛ) (Collect ground))"
  by (auto simp: sig_step_def)

subsection ‹Substitution closure of @{const srstep}›

lemma srstep_subst_closed:
  assumes "(s, t) ∈ srstep ℱ ℛ" "⋀ x. funas_term (σ x) ⊆ ℱ"
  shows "(s ⋅ σ, t ⋅ σ) ∈ srstep ℱ ℛ" using assms
  by (auto simp: sig_step_def funas_term_subst)

lemma srsteps_subst_closed:
  assumes "(s, t) ∈ (srstep ℱ ℛ)+" "⋀ x. funas_term (σ x) ⊆ ℱ"
  shows "(s ⋅ σ, t ⋅ σ) ∈ (srstep ℱ ℛ)+" using assms(1)
proof (induct rule: trancl.induct)
  case (r_into_trancl s t) show ?case
    using srstep_subst_closed[OF r_into_trancl assms(2)]
    by auto
next
  case (trancl_into_trancl s t u)
  from trancl_into_trancl(2) show ?case
    using srstep_subst_closed[OF trancl_into_trancl(3) assms(2)]
    by (meson rtrancl_into_trancl1 trancl_into_rtrancl)  
qed

lemma srsteps_eq_subst_closed:
  assumes "(s, t) ∈ (srstep ℱ ℛ)*" "⋀ x. funas_term (σ x) ⊆ ℱ"
  shows "(s ⋅ σ, t ⋅ σ) ∈ (srstep ℱ ℛ)*" using assms srsteps_subst_closed
  by (metis rtrancl_eq_or_trancl)

lemma srsteps_eq_subst_relcomp_closed:
  assumes "(s, t) ∈ (srstep ℱ ℛ)* O (srstep ℱ 𝒮)*" "⋀ x. funas_term (σ x) ⊆ ℱ"
  shows "(s ⋅ σ, t ⋅ σ) ∈ (srstep ℱ ℛ)* O (srstep ℱ 𝒮)*"
proof -
  from assms(1) obtain u where "(s, u) ∈ (srstep ℱ ℛ)*" "(u, t) ∈ (srstep ℱ 𝒮)*" by auto
  then have "(s ⋅ σ, u ⋅ σ) ∈ (srstep ℱ ℛ)*" "(u ⋅ σ, t ⋅ σ) ∈ (srstep ℱ 𝒮)*"
    using assms srsteps_eq_subst_closed
    by metis+
  then show ?thesis by auto
qed


subsection ‹Context closure of @{const srstep}›

lemma srstep_ctxt_closed:
  assumes "funas_ctxt C ⊆ ℱ" and "(s, t) ∈ srstep ℱ ℛ"
  shows "(C⟨s⟩, C⟨t⟩) ∈ srstep ℱ ℛ" using assms
  by (intro sig_stepI) (auto dest: srstepD)

lemma srsteps_ctxt_closed:
  assumes "funas_ctxt C ⊆ ℱ" and "(s, t) ∈ (srstep ℱ ℛ)+"
  shows "(C⟨s⟩, C⟨t⟩) ∈ (srstep ℱ ℛ)+" using assms(2) srstep_ctxt_closed[OF assms(1)]
  by (induct) force+

lemma srsteps_eq_ctxt_closed:
  assumes "funas_ctxt C ⊆ ℱ" and "(s, t) ∈ (srstep ℱ ℛ)*"
  shows "(C⟨s⟩, C⟨t⟩) ∈ (srstep ℱ ℛ)*" using srsteps_ctxt_closed[OF assms(1)] assms(2)
  by (metis rtrancl_eq_or_trancl)

lemma sig_steps_join_ctxt_closed:
  assumes "funas_ctxt C ⊆ ℱ" and "(s, t) ∈ (srstep ℱ ℛ)↓"
  shows "(C⟨s⟩, C⟨t⟩) ∈ (srstep ℱ ℛ)↓" using srsteps_eq_ctxt_closed[OF assms(1)] assms(2)
  unfolding join_def rew_converse_inwards
  by auto
                                 

text ‹The following lemma shows that every rewrite sequence either contains a root step or is root stable›

lemma nsrsteps_with_root_step_step_on_args:
  assumes "(s, t) ∈ (srstep ℱ ℛ)+" "(s, t) ∉ srsteps_with_root_step ℱ ℛ"
  shows "∃ f ss ts. s = Fun f ss ∧ t = Fun f ts ∧ length ss = length ts ∧
    (∀ i < length ts. (ss ! i, ts ! i) ∈ (srstep ℱ ℛ)*)" using assms
proof (induct)
  case (base t)
  obtain C l r σ where [simp]: "s = C⟨l ⋅ σ⟩" "t = C⟨r ⋅ σ⟩" and r: "(l, r) ∈ ℛ"
    using base(1) unfolding sig_step_def
    by blast
  then have funas: "funas_ctxt C ⊆ ℱ" "funas_term (l ⋅ σ) ⊆ ℱ" "funas_term (r ⋅ σ) ⊆ ℱ"
    using base(1) by (auto simp: sig_step_def)
  from funas(2-) r have "(l ⋅ σ, r ⋅ σ) ∈ srrstep ℱ ℛ"
    by (auto simp: sig_step_def)
  then have "C = Hole ⟹ False" using base(2) r
    by (auto simp: srsteps_with_root_step_def)
  then obtain f ss D ts where [simp]: "C = More f ss D ts" by (cases C) auto
  have "(D⟨l ⋅ σ⟩, D⟨r ⋅ σ⟩) ∈ (srstep ℱ ℛ)" using base(1) r funas
    by (auto simp: sig_step_def)
  then show ?case using funas by (auto simp: nth_append_Cons)
next
  case (step t u) show ?case
  proof (cases "(s, t) ∈ srsteps_with_root_step ℱ ℛ ∨ (t, u) ∈ sig_step ℱ (rrstep ℛ)")
    case True then show ?thesis using step(1, 2, 4)
      by (auto simp add: relcomp3_I rtrancl.rtrancl_into_rtrancl srsteps_with_root_step_def)
  next
    case False
    obtain C l r σ where *[simp]: "t = C⟨l ⋅ σ⟩" "u = C⟨r ⋅ σ⟩" and r: "(l, r) ∈ ℛ"
      using step(2) unfolding sig_step_def by blast
    then have funas: "funas_ctxt C ⊆ ℱ" "funas_term (l ⋅ σ) ⊆ ℱ" "funas_term (r ⋅ σ) ⊆ ℱ"
      using step(2) by (auto simp: sig_step_def)
    from False have "C ≠ Hole" using funas r by (force simp: sig_step_def)
    then obtain f ss D ts where c[simp]: "C = More f ss D ts" by (cases C) auto
    from step(3, 1) False obtain g sss tss where
      **[simp]: "s = Fun g sss" "t = Fun g tss" and l: "length sss = length tss" and
      inv: "∀ i < length tss. (sss ! i, tss ! i) ∈ (srstep ℱ ℛ)*"
      by auto
    have [simp]: "g = f" and lc: "Suc (length ss + length ts) = length sss"
      using l *(1) unfolding c using **(2) by auto
    then have "∀ i < Suc (length ss + length ts). ((ss @ D⟨l ⋅ σ⟩ # ts) ! i, (ss @ D⟨r ⋅ σ⟩ # ts) ! i) ∈ (srstep ℱ ℛ)*"
      using * funas r by (auto simp: nth_append_Cons r_into_rtrancl rstep.intros rstepI sig_stepI)
    then have "i < length tss ⟹ (sss ! i, (ss @ D⟨r ⋅ σ⟩ # ts) ! i) ∈ (srstep ℱ ℛ)*" for i
      using inv * l lc funas **
      by (auto simp: nth_append_Cons simp del: ** * split!: if_splits)
    then show ?thesis using inv l lc * unfolding c
      by auto
  qed
qed

lemma rstep_to_pos_replace:
  assumes "(s, t) ∈ rstep ℛ"
  shows "∃ p l r σ. p ∈ poss s ∧ (l, r) ∈ ℛ ∧ s |_ p = l ⋅ σ ∧ t = s[p ← r ⋅ σ]"
proof -
  from assms obtain C l r σ where st: "(l, r) ∈ ℛ" "s = C⟨l ⋅ σ⟩" "t = C⟨r ⋅ σ⟩"
    using rstep_imp_C_s_r by fastforce
  from st(2, 3) have *: "t = s[hole_pos C ← r ⋅ σ]" by simp
  from this st show ?thesis unfolding *
    by (intro exI[of _ "hole_pos C"]) auto
qed

lemma pos_replace_to_rstep:
  assumes "p ∈ poss s" "(l, r) ∈ ℛ" 
    and "s |_ p = l ⋅ σ" "t = s[p ← r ⋅ σ]"
  shows "(s, t) ∈ rstep ℛ"
  using assms(1, 3-) replace_term_at_subt_at_id [of s p]
  by (intro rstepI[OF assms(2), of s "ctxt_at_pos s p" σ])
     (auto simp add: ctxt_of_pos_term_apply_replace_at_ident)

end

Theory Replace_Constant

theory Replace_Constant
  imports Rewriting
begin

subsection ‹Removing/Replacing constants in a rewrite sequence that do not appear in the rewrite system›
lemma funas_term_const_subst_conv:
  "(c, 0) ∉ funas_term l ⟷ ¬ (l ⊵ constT c)"
proof (induct l)
  case (Fun f ts) then show ?case
    by auto (metis Fun_supt supteq_supt_conv term.inject(2))+
qed (auto simp add: supteq_var_imp_eq)

lemma fresh_const_single_step_replace:
  assumes lin: "linear_sys ℛ" and fresh: "(c, 0) ∉ funas_rel ℛ"
    and occ: "p ∈ poss_of_term (constT c) s" and step: "(s, t) ∈ rstep ℛ"
  shows "(s[p ← u], t) ∈ rstep ℛ ∨
    (∃ q. q ∈ poss_of_term (constT c) t ∧ (s[p ← u], t[q ← u]) ∈ rstep ℛ)"
proof -
  from occ have const: "p ∈ poss s ∧ s |_ p = constT c" by auto
  from step obtain C l r σ where t [simp]: "s = C⟨l ⋅ σ⟩" "t = C⟨r ⋅ σ⟩"
    and rule: "(l, r) ∈ ℛ" by blast
  from rule lin have lin: "linear_term l" "linear_term r" by fastforce+
  from fresh rule have nt_lhs: "(c, 0) ∉ funas_term l" by (auto simp: funas_rel_def)
  consider (par) "p ⊥ (hole_pos C)" | (below) "hole_pos C ≤p p" using occ
    by (auto dest: poss_of_term_const_ctxt_apply)
  then show ?thesis
  proof cases
    case par
    then have possc: "p ∈ possc C" using const t possc_def by blast 
    then have "p ∈ poss_of_term (constT c) t" "(s[p ← u], t[p ← u]) ∈ rstep ℛ"
      using const par_hole_pos_replace_term_context_at[OF par]
      using possc_subt_at_ctxt_apply[OF possc par, of "r ⋅ σ" "l ⋅ σ"] rule
      by auto (metis par par_pos_replace_pres replace_at_hole_pos) 
    then show ?thesis by blast
  next
    case below
    then obtain q where [simp]:"p = hole_pos C @ q" and poss: "q ∈ poss (l ⋅ σ)"
      using const position_less_eq_def
      by (metis (full_types) ctxt_at_pos_hole_pos ctxt_at_pos_subt_at_pos poss_append_poss t(1))
    have const: "l ⋅ σ |_ q = constT c" using const by auto
    from nt_lhs have "∃ r. r ∈ varposs l ∧ r ≤p q" using const poss
    proof (induct l arbitrary: q)
      case (Var x)
      then show ?case by auto
    next
      case (Fun f ts)
      from Fun(1)[OF nth_mem, of "hd q" "tl q"] Fun(2-) obtain r where
        "r ∈ varposs (ts ! hd q) ∧ r ≤p tl q"
        by (cases q) auto
      then show ?case using Fun(2- 4)
        by (intro exI[of _ "hd q # r"]) auto
    qed
    then obtain x v where varposs: "v ∈ varposs l" "v ≤p q" "l |_ v = Var x"
      unfolding varposs_def by blast
    let ?τ = "λx. if Var x = l |_ v then (σ x)[q -p v ← u] else σ x"
    show ?thesis
    proof (cases "x ∈ vars_term r")
      case True
      then obtain q' where varposs_r: "q' ∈ varposs r" "r |_ q' = Var x"
        by (metis vars_term_varposs_iff)
      have "(s[p ← u], t[(hole_pos C) @ q' @ (q -p v) ← u]) ∈ rstep ℛ"
        using lin varposs rule varposs_r
        by (auto simp: linear_term_varposs_subst_replace_term intro!: rstep_ctxtI)
          (smt (verit, ccfv_SIG) pos_diff_append_itself rrstep.intros rrstep_rstep_mono subset_eq term_subst_eq)
      moreover have "(hole_pos C) @ q' @ q -p v ∈ poss_of_term (constT c) t"
        using varposs_r varposs poss const poss_pos_diffI[OF varposs(2) poss]
        using subt_at_append_dist[of q' "q -p v" "r ⋅ σ"]
        by (auto simp: poss_append_poss varposs_imp_poss[THEN subst_subt_at_dist] varposs_imp_poss[THEN subsetD[OF subst_poss_mono]])
          (metis pos_les_eq_append_diff subst_apply_term.simps(1) subst_subt_at_dist subt_at_append_dist varposs_imp_poss)
      ultimately show ?thesis by auto
    next
      case False
      then have [simp]: "r ⋅ σ = r ⋅ ?τ" using varposs
        by (auto simp add: term_subst_eq_conv)
      have "(s[p ← u], t) ∈ rstep ℛ" using rule varposs lin
        by (auto simp: linear_term_varposs_subst_replace_term)
      then show ?thesis by auto
    qed
  qed
qed

lemma fresh_const_steps_replace:
  assumes lin: "linear_sys ℛ" and fresh: "(c, 0) ∉ funas_rel ℛ"
    and occ: "p ∈ poss_of_term (constT c) s" and steps: "(s, t) ∈ (rstep ℛ)+"
  shows "(s[p ← u], t) ∈ (rstep ℛ)+ ∨
    (∃ q. q ∈ poss_of_term (constT c) t ∧ (s[p ← u], t[q ← u]) ∈ (rstep ℛ)+)"
  using steps occ
proof (induct arbitrary: p rule: converse_trancl_induct)
  case (base s)
  from fresh_const_single_step_replace[OF lin fresh base(2, 1)] show ?case
    by (meson r_into_trancl')
next
  case (step s t)
  from fresh_const_single_step_replace[OF lin fresh step(4, 1)]
  consider (a) "(s[p ← u], t) ∈ rstep ℛ" | (b) "∃q. q ∈ poss_of_term (constT c) t ∧ (s[p ← u], t[q ← u]) ∈ rstep ℛ" by blast
  then show ?case
  proof cases
    case a then show ?thesis using step(2)
      by auto
  next
    case b
    then obtain q where "q ∈ poss_of_term (constT c) t" "(s[p ← u], t[q ← u]) ∈ rstep ℛ" by blast
    from step(3)[OF this(1)] this(2) show ?thesis
      by (metis trancl_into_trancl2)
  qed
qed

lemma remove_const_lhs_steps:
  assumes lin: "linear_sys ℛ" and fresh: "(c, 0) ∉ funas_rel ℛ"
    and const: "(c, 0) ∉ funas_term t"
    and pos: "p ∈ poss_of_term (constT c) s" 
    and steps: "(s, t) ∈ (rstep ℛ)+"
  shows "(s[p ← u], t) ∈ (rstep ℛ)+" using steps pos const fresh_const_steps_replace
  by (metis fresh funas_term_const_subst_conv lin poss_of_termE subt_at_imp_supteq)


text ‹Now we can show that we may remove a constant substitution›

definition const_replace_closed where
  "const_replace_closed c U = (∀ s t u p.
    p ∈ poss_of_term (constT c) s ⟶ (s, t) ∈ U ⟶
    (∃ q. q ∈ poss_of_term (constT c) t ∧ (s[p ← u], t[q ← u]) ∈ U) ∨ (s[p ← u], t) ∈ U)"

lemma const_replace_closedD:
  assumes "const_replace_closed c U" "p ∈ poss_of_term (constT c) s" "(s, t) ∈ U"
  shows "(s[p ← u], t) ∈ U ∨ (∃ q. q ∈ poss_of_term (constT c) t ∧ (s[p ← u], t[q ← u]) ∈ U)" using assms
  unfolding const_replace_closed_def by blast

lemma const_replace_closedI:
  assumes "⋀ s t u p. p ∈ poss_of_term (constT c) s ⟹ (s, t) ∈ U ⟹
       (∃ q. q ∈ poss_of_term (constT c) t ∧ (s[p ← u], t[q ← u]) ∈ U) ∨ (s[p ← u], t) ∈ U"
  shows "const_replace_closed c U" using assms
  unfolding const_replace_closed_def
  by auto

abbreviation const_subst :: "'f ⇒ 'v ⇒ ('f, 'v) Term.term" where
  "const_subst c ≡ (λ x. Fun c [])"

lemma lin_fresh_rstep_const_replace_closed:
  "linear_sys ℛ ⟹ (c, 0) ∉ funas_rel ℛ ⟹ const_replace_closed c (rstep ℛ)"
  using fresh_const_single_step_replace[of ℛ c]
  by (intro const_replace_closedI) (auto simp: constT_nfunas_term_poss_of_term_empty, blast)

lemma const_replace_closed_symcl:
  "const_replace_closed c U ⟹ const_replace_closed c (U=)"
  unfolding const_replace_closed_def
  by (metis Un_iff pair_in_Id_conv)

lemma const_replace_closed_trancl:
  "const_replace_closed c U ⟹ const_replace_closed c (U+)"
proof (intro const_replace_closedI)
  fix s t u p
  assume const: "const_replace_closed c U" and wit: "p ∈ poss_of_term (constT c) s"
    and steps :"(s, t) ∈ U+"
  show "(∃q. q ∈ poss_of_term (constT c) t ∧ (s[p ← u], t[q ← u]) ∈ U+) ∨ (s[p ← u], t) ∈ U+" using steps wit
  proof (induct arbitrary: p rule: converse_trancl_induct)
    case (base s)
    show ?case using const_replace_closedD[OF const base(2, 1)]
      by blast
  next
    case (step s v)
    from const_replace_closedD[OF const step(4, 1)]
    consider (a) "(s[p ← u], v) ∈ U" | (b) "∃ q. q ∈ poss_of_term (constT c) v ∧ (s[p ← u], v[q ← u]) ∈ U" by auto
    then show ?case
    proof cases
      case a then show ?thesis using step(2)
        by (meson trancl_into_trancl2)
    next
      case b
      then show ?thesis using step(3, 4) by (meson trancl_into_trancl2) 
    qed
  qed
qed

lemma const_replace_closed_rtrancl:
  "const_replace_closed c U ⟹ const_replace_closed c (U*)"
proof (intro const_replace_closedI)
  fix s t u p
  assume const: "const_replace_closed c U" and wit: "p ∈ poss_of_term (constT c) s"
    and steps :"(s, t) ∈ U*"
  show "(∃q. q ∈ poss_of_term (constT c) t ∧ (s[p ← u], t[q ← u]) ∈ U*) ∨ (s[p ← u], t) ∈ U*"
    using const_replace_closed_trancl[OF const] wit steps
    by (metis const_replace_closedD rtrancl_eq_or_trancl)
qed

lemma const_replace_closed_relcomp:
  "const_replace_closed c U ⟹ const_replace_closed c V ⟹ const_replace_closed c (U O V)"
proof (intro const_replace_closedI)
  fix s t u p
  assume const: "const_replace_closed c U" "const_replace_closed c V"
   and wit: "p ∈ poss_of_term (constT c) s" and step: "(s, t) ∈ U O V"
  from step obtain w where w: "(s, w) ∈ U" "(w, t) ∈ V" by auto
  from const_replace_closedD[OF const(1) wit this(1)]
  consider (a) "(s[p ← u], w) ∈ U" | (b) "(∃q. q ∈ poss_of_term (constT c) w ∧ (s[p ← u], w[q ← u]) ∈ U)"
    by auto  
  then show "(∃q. q ∈ poss_of_term (constT c) t ∧ (s[p ← u], t[q ← u]) ∈ U O V) ∨ (s[p ← u], t) ∈ U O V"
  proof cases
    case a
    then show ?thesis using w(2) by auto
  next
    case b
    then show ?thesis using const_replace_closedD[OF const(2) _ w(2)]
      by (meson relcomp.simps)
  qed
qed


text ‹@{const const_replace_closed} allow the removal of a fresh constant substitution›
lemma const_replace_closed_remove_subst_lhs:
  assumes repcl: "const_replace_closed c U"
    and const: "(c, 0) ∉ funas_term t"
    and steps: "(s ⋅ const_subst c, t) ∈ U"
  shows "(s, t) ∈ U" using steps
proof (induct "card (varposs s)" arbitrary: s)
  case (Suc n)
  obtain p ps where vl: "varposs s = insert p ps" "p ∉ ps" using Suc(2)
    by (metis card_le_Suc_iff dual_order.refl)
  let ?s = "s[p ← Fun c []]" have vp: "p ∈ varposs s" using vl by auto
  then have [simp]: "?s ⋅ const_subst c = s ⋅ const_subst c"
    by (induct s arbitrary: p) (auto simp: nth_list_update map_update intro!: nth_equalityI)
  have "varposs ?s = ps" using vl varposs_ground_replace_at[of p s "constT c"]
    by auto
  then have "n = card (varposs ?s)" using vl Suc(2) by (auto simp: card_insert_if finite_varposs)
  from Suc(1)[OF this] have IH: "(s[p ← constT c], t) ∈ U" "p ∈ poss_of_term (constT c) s[p ← constT c]"
    using Suc(2, 3) vl poss_of_term_replace_term_at varposs_imp_poss vp
    using ‹s[p ← constT c] ⋅ const_subst c = s ⋅ const_subst c›
    by fastforce+
  show ?case using const_replace_closedD[OF repcl] const IH(2, 1)
    by (metis constT_nfunas_term_poss_of_term_empty empty_iff replace_term_at_same_pos replace_term_at_subt_at_id)
qed (auto simp: ground_subst_apply card_eq_0_iff finite_varposs varposs_empty_gound)


subsubsection ‹Removal lemma applied to various rewrite relations›

lemma remove_const_subst_step_lhs:
  assumes lin: "linear_sys ℛ" and fresh: "(c, 0) ∉ funas_rel ℛ"
    and const: "(c, 0) ∉ funas_term t"
    and step: "(s ⋅ const_subst c, t) ∈ (rstep ℛ)"
  shows "(s, t) ∈ (rstep ℛ)"
  using lin_fresh_rstep_const_replace_closed[OF lin fresh, THEN const_replace_closed_remove_subst_lhs] const step
  by blast

lemma remove_const_subst_steps_lhs:
  assumes lin: "linear_sys ℛ" and fresh: "(c, 0) ∉ funas_rel ℛ"
    and const: "(c, 0) ∉ funas_term t"
    and steps: "(s ⋅ const_subst c, t) ∈ (rstep ℛ)+"
  shows "(s, t) ∈ (rstep ℛ)+"
  using lin_fresh_rstep_const_replace_closed[THEN const_replace_closed_trancl,
    OF lin fresh, THEN const_replace_closed_remove_subst_lhs]
  using const steps
  by blast

lemma remove_const_subst_steps_eq_lhs:
  assumes lin: "linear_sys ℛ" and fresh: "(c, 0) ∉ funas_rel ℛ"
    and const: "(c, 0) ∉ funas_term t"
    and steps: "(s ⋅ const_subst c, t) ∈ (rstep ℛ)*"
  shows "(s, t) ∈ (rstep ℛ)*" using steps const 
  by (cases "s = t") (auto simp: rtrancl_eq_or_trancl funas_term_subst ground_subst_apply vars_term_empty_ground
      dest: remove_const_subst_steps_lhs[OF lin fresh const] split: if_splits)

lemma remove_const_subst_steps_rhs:
  assumes lin: "linear_sys ℛ" and fresh: "(c, 0) ∉ funas_rel ℛ"
    and const: "(c, 0) ∉ funas_term s"
    and steps: "(s, t ⋅ const_subst c) ∈ (rstep ℛ)+"
  shows "(s, t) ∈ (rstep ℛ)+"
proof -
  from steps have revs: "(t ⋅ const_subst c, s) ∈ (rstep (ℛ¯))+"
    unfolding rew_converse_outwards by auto
  have "(t, s) ∈ (rstep (ℛ¯))+" using assms
    by (intro remove_const_subst_steps_lhs[OF _ _ _ revs]) (auto simp: funas_rel_def)
  then show ?thesis unfolding rew_converse_outwards by auto
qed

lemma remove_const_subst_steps_eq_rhs:
  assumes lin: "linear_sys ℛ" and fresh: "(c, 0) ∉ funas_rel ℛ"
    and const: "(c, 0) ∉ funas_term s"
    and steps: "(s, t ⋅ const_subst c) ∈ (rstep ℛ)*"
  shows "(s, t) ∈ (rstep ℛ)*"
  using steps const
  by (cases "s = t") (auto simp: rtrancl_eq_or_trancl funas_term_subst ground_subst_apply vars_term_empty_ground
      dest!: remove_const_subst_steps_rhs[OF lin fresh const] split: if_splits)


text ‹Main lemmas›
lemma const_subst_eq_ground_eq:
  assumes "s ⋅ const_subst c = t ⋅ const_subst d" "c ≠ d"
    and "(c, 0) ∉ funas_term t" "(d, 0) ∉ funas_term s"
  shows "s = t" using assms
proof (induct s arbitrary: t)
  case (Var x) then show ?case by (cases t) auto
next
  case (Fun f ts)
  from Fun(2-) obtain g us where [simp]: "t = Fun g us" by (cases t) auto
  have [simp]: "g = f" and l: "length ts = length us" using Fun(2)
    by (auto intro: map_eq_imp_length_eq)
  have "i < length ts ⟹ ts ! i = us ! i" for i
    using Fun(1)[OF nth_mem, of i "us ! i" for i] Fun(2-) l
    by (auto simp: map_eq_conv')
  then show ?case using l
    by (auto intro: nth_equalityI)
qed


lemma remove_const_subst_steps:
  assumes "linear_sys ℛ" and  "(c, 0) ∉ funas_rel ℛ" and "(d, 0) ∉ funas_rel ℛ"
    and "c ≠ d" "(c, 0) ∉ funas_term t" "(d, 0) ∉ funas_term s"
    and "(s ⋅ const_subst c, t ⋅ const_subst d) ∈ (rstep ℛ)*"
  shows "(s, t) ∈ (rstep ℛ)*"
proof (cases "s ⋅ const_subst c = t ⋅ const_subst d")
  case True
  from const_subst_eq_ground_eq[OF this] assms(4 - 6) show ?thesis by auto
next
  case False
  then have step: "(s ⋅ const_subst c, t ⋅ const_subst d) ∈ (rstep ℛ)+" using assms(7)
    by (auto simp: rtrancl_eq_or_trancl)
  then have "(s, t ⋅ const_subst d) ∈ (rstep ℛ)+" using assms
    by (intro remove_const_subst_steps_lhs[OF _ _ _ step]) (auto simp: funas_term_subst)
  from remove_const_subst_steps_rhs[OF _ _ _ this] show ?thesis using assms
    by auto
qed

lemma remove_const_subst_relcomp_lhs:
  assumes sys: "linear_sys ℛ" "linear_sys 𝒮"
    and fr: "(c, 0) ∉ funas_rel ℛ" and fs:"(c, 0) ∉ funas_rel 𝒮"
    and funas: "(c, 0) ∉ funas_term t"
    and seq: "(s ⋅ const_subst c, t) ∈ (rstep ℛ)* O (rstep 𝒮)*"
  shows "(s, t) ∈ (rstep ℛ)* O (rstep 𝒮)*" using seq
  using lin_fresh_rstep_const_replace_closed[OF sys(1) fr, THEN const_replace_closed_rtrancl]
  using lin_fresh_rstep_const_replace_closed[OF sys(2) fs, THEN const_replace_closed_rtrancl]
  using const_replace_closed_relcomp
  by (intro const_replace_closed_remove_subst_lhs[OF _ funas seq]) force

lemma remove_const_subst_relcomp_rhs:
  assumes sys: "linear_sys ℛ" "linear_sys 𝒮"
    and fr: "(c, 0) ∉ funas_rel ℛ" and fs:"(c, 0) ∉ funas_rel 𝒮"
    and funas: "(c, 0) ∉ funas_term s"
    and seq: "(s, t ⋅ const_subst c) ∈ (rstep ℛ)* O (rstep 𝒮)*"
  shows "(s, t) ∈ (rstep ℛ)* O (rstep 𝒮)*"
proof -
  from seq have "(t ⋅ const_subst c,s) ∈ ((rstep ℛ)* O (rstep 𝒮)*)¯"
    by auto
  then have "(t ⋅ const_subst c,s) ∈ ((rstep 𝒮)*)¯ O ((rstep ℛ)*)¯"
    using converse_relcomp by blast
  note seq = this[unfolded rtrancl_converse[symmetric] rew_converse_inwards]
  from sys fr fs have "linear_sys (𝒮¯)" "linear_sys (ℛ¯)" "(c, 0) ∉ funas_rel (𝒮¯)" "(c, 0) ∉ funas_rel (ℛ¯)"
    by (auto simp: funas_rel_def)
  from remove_const_subst_relcomp_lhs[OF this funas seq]
  have "(t, s) ∈ (rstep (𝒮¯))* O (rstep (ℛ¯))*" by simp
  then show ?thesis
    unfolding rew_converse_outwards converse_relcomp[symmetric]
    by simp
qed


lemma remove_const_subst_relcomp:
  assumes sys: "linear_sys ℛ" "linear_sys 𝒮"
    and fr: "(c, 0) ∉ funas_rel ℛ" "(d, 0) ∉ funas_rel ℛ"
    and fs:"(c, 0) ∉ funas_rel 𝒮" "(d, 0) ∉ funas_rel 𝒮"
    and diff: "c ≠ d" and funas: "(c, 0) ∉ funas_term t" "(d, 0) ∉ funas_term s"
    and seq: "(s ⋅ const_subst c, t ⋅ const_subst d) ∈ (rstep ℛ)* O (rstep 𝒮)*"
  shows "(s, t) ∈ (rstep ℛ)* O (rstep 𝒮)*"
proof -
  from diff funas(1) have *: "(c, 0) ∉ funas_term (t ⋅ const_subst d)"
    by (auto simp: funas_term_subst)
  show ?thesis using remove_const_subst_relcomp_rhs[OF sys fr(2) fs(2) funas(2)
        remove_const_subst_relcomp_lhs[OF sys fr(1) fs(1) * seq]]
    by blast
qed

end
d>

Theory Rewriting_Properties

section ‹Confluence related rewriting properties›
theory Rewriting_Properties
  imports Rewriting
    "Abstract-Rewriting.Abstract_Rewriting"
begin

subsection ‹Confluence related ARS properties›
definition "SCR_on r A ≡ (∀a ∈ A. ∀ b c. (a, b) ∈ r ∧ (a, c) ∈ r ⟶
  (∃ d. (b, d) ∈ r= ∧  (c, d) ∈ r*))"

abbreviation SCR :: "'a rel ⇒ bool" where "SCR r ≡ SCR_on r UNIV"

definition NFP_on :: "'a rel ⇒ 'a set ⇒ bool" where
  "NFP_on r A ⟷ (∀a∈A. ∀b c. (a, b) ∈ r* ∧ (a, c) ∈ r! ⟶ (b, c) ∈ r*)"

abbreviation NFP :: "'a rel ⇒ bool" where "NFP r ≡ NFP_on r UNIV"

definition CE_on :: "'a rel ⇒ 'a rel ⇒ 'a set ⇒ bool" where
  "CE_on r s A ⟷ (∀a∈A. ∀b. (a, b) ∈ r↔* ⟷ (a, b) ∈ s↔*)"

abbreviation CE :: "'a rel ⇒ 'a rel ⇒ bool" where "CE r s ≡ CE_on r s UNIV"

definition NE_on :: "'a rel ⇒ 'a rel ⇒ 'a set ⇒ bool" where
  "NE_on r s A ⟷ (∀a∈A. ∀b. (a, b) ∈ r! ⟷ (a, b) ∈ s!)"

abbreviation NE :: "'a rel ⇒ 'a rel ⇒ bool" where "NE r s ≡ NE_on r s UNIV"

subsection ‹Signature closure of relation to model multihole context closure›

(* AUX lemmas *)

lemma all_ctxt_closed_sig_rsteps [intro]:
  fixes ℛ :: "('f,'v) term rel"
  shows "all_ctxt_closed ℱ ((srstep ℱ ℛ)*)" (is "all_ctxt_closed _ (?R*)")
proof (rule trans_ctxt_sig_imp_all_ctxt_closed)
  fix C :: "('f,'v) ctxt" and s t :: "('f,'v)term"
  assume C: "funas_ctxt C ⊆ ℱ"
  and s: "funas_term s ⊆ ℱ"
  and t: "funas_term t ⊆ ℱ"
  and steps: "(s,t) ∈ ?R*"
  from steps
  show "(C ⟨ s ⟩, C ⟨ t ⟩) ∈ ?R*"
  proof (induct)
    case (step t u)
    from step(2) have tu: "(t,u) ∈ rstep ℛ" and t: "funas_term t ⊆ ℱ" and u: "funas_term u ⊆ ℱ"
      by (auto dest: srstepD)
    have "(C ⟨ t ⟩, C ⟨ u ⟩) ∈ ?R" by (rule sig_stepI[OF _ _ rstep_ctxtI[OF tu]], insert C t u, auto)
    with step(3) show ?case by auto
  qed auto
qed (auto intro: trans_rtrancl)

lemma sigstep_trancl_funas:
  "(s, t) ∈ (srstep ℱ 𝒮)* ⟹ s ≠ t ⟹ funas_term s ⊆ ℱ"
  "(s, t) ∈ (srstep ℱ 𝒮)* ⟹ s ≠ t ⟹ funas_term t ⊆ ℱ"
  by (auto simp: rtrancl_eq_or_trancl dest: srstepsD)

lemma srrstep_to_srestep:
  "(s, t) ∈ srrstep ℱ ℛ ⟹ (s, t) ∈ srstep ℱ ℛ"
  by (meson in_mono rrstep_rstep_mono sig_step_mono2)

lemma srsteps_with_root_step_srstepsD:
  "(s, t) ∈ srsteps_with_root_step ℱ ℛ ⟹ (s, t) ∈ (srstep ℱ ℛ)+"
  by (auto dest: srrstep_to_srestep simp: srsteps_with_root_step_def)

lemma srsteps_with_root_step_sresteps_eqD:
  "(s, t) ∈ srsteps_with_root_step ℱ ℛ ⟹ (s, t) ∈ (srstep ℱ ℛ)*"
  by (auto dest: srrstep_to_srestep simp: srsteps_with_root_step_def)

lemma symcl_srstep_conversion:
  "(s, t) ∈ srstep ℱ (ℛ↔) ⟹ (s, t) ∈ (srstep ℱ ℛ)↔*"
  by (simp add: conversion_def rstep_converse_dist srstep_symcl_dist)

lemma symcl_srsteps_conversion:
  "(s, t) ∈ (srstep ℱ (ℛ↔))* ⟹ (s, t) ∈ (srstep ℱ ℛ)↔*"
  by (simp add: conversion_def rstep_converse_dist srstep_symcl_dist)



lemma NF_srstep_args:
  assumes "Fun f ss ∈ NF (srstep ℱ ℛ)" "funas_term (Fun f ss) ⊆ ℱ" "i < length ss"
  shows "ss ! i ∈ NF (srstep ℱ ℛ)"
proof (rule ccontr)
  assume "ss ! i ∉ NF (srstep ℱ ℛ)"
  then obtain t where step: "(ss ! i, t) ∈ rstep ℛ" "funas_term t ⊆ ℱ"
    by (auto simp: NF_def sig_step_def)
  from assms(3) have [simp]: "Suc (length ss - Suc 0) = length ss" by auto
  from rstep_ctxtI[OF step(1), where ?C = "ctxt_at_pos (Fun f ss)[i]"]  
  have "(Fun f ss, Fun f (ss[i := t])) ∈ srstep ℱ ℛ" using step(2) assms(2, 3)
    by (auto simp: sig_step_def upd_conv_take_nth_drop min_def UN_subset_iff
             dest: in_set_takeD in_set_dropD simp flip: id_take_nth_drop)
  then show False using assms(1)
    by (auto simp: NF_def)
qed

lemma all_ctxt_closed_srstep_conversions [simp]:
  "all_ctxt_closed ℱ ((srstep ℱ ℛ)↔*)"
  by (simp add: all_ctxt_closed_sig_rsteps sig_step_conversion_dist)

(* END AUX *)

lemma NFP_stepD:
  "NFP r ⟹ (a, b) ∈ r* ⟹ (a, c) ∈ r* ⟹ c ∈ NF r ⟹ (b, c) ∈ r*"
  by (auto simp: NFP_on_def)
  
lemma NE_symmetric: "NE r s ⟹ NE s r"
  unfolding NE_on_def by auto

lemma CE_symmetric: "CE r s ⟹ CE s r"
  unfolding CE_on_def by auto

text ‹Reducing the quantification over rewrite sequences for properties @{const CR} ... to
rewrite sequences containing at least one root step›
lemma all_ctxt_closed_sig_reflE:
  "all_ctxt_closed ℱ ℛ ⟹ funas_term t ⊆ ℱ ⟹ (t, t) ∈ ℛ"
proof (induct t)
  case (Fun f ts)
  from Fun(1)[OF nth_mem  Fun(2)] Fun(3)
  have "i < length ts ⟹ funas_term (ts ! i) ⊆ ℱ" "i < length ts ⟹ (ts ! i, ts ! i) ∈ ℛ" for i
    by (auto simp: SUP_le_iff)
  then show ?case using all_ctxt_closedD[OF Fun(2)] Fun(3)
    by simp
qed (simp add: all_ctxt_closed_def)


lemma all_ctxt_closed_relcomp [intro]:
  "(⋀ s t. (s, t) ∈ ℛ ⟹ s ≠ t ⟹ funas_term s ⊆ ℱ ∧ funas_term t ⊆ ℱ) ⟹
   (⋀ s t. (s, t) ∈ 𝒮 ⟹ s ≠ t ⟹ funas_term s ⊆ ℱ ∧ funas_term t ⊆ ℱ) ⟹
   all_ctxt_closed ℱ ℛ ⟹ all_ctxt_closed ℱ 𝒮 ⟹ all_ctxt_closed ℱ (ℛ O 𝒮)"
proof -
  assume funas:"(⋀ s t. (s, t) ∈ ℛ ⟹ s ≠ t ⟹ funas_term s ⊆ ℱ ∧ funas_term t ⊆ ℱ)"
    "(⋀ s t. (s, t) ∈ 𝒮 ⟹ s ≠ t ⟹ funas_term s ⊆ ℱ ∧ funas_term t ⊆ ℱ)"
    and ctxt_cl: "all_ctxt_closed ℱ ℛ" "all_ctxt_closed ℱ 𝒮"
  {fix f ss ts assume ass: "(f, length ss) ∈ ℱ" "length ss = length ts" "⋀ i. i < length ts ⟹ (ss ! i, ts ! i) ∈ (ℛ O 𝒮)"
    "⋀ i . i < length ts ⟹ funas_term (ts ! i) ⊆ ℱ" "⋀i. i < length ts ⟹ funas_term (ss ! i) ⊆ ℱ"
    from ass(2, 3) obtain us where us: "length us = length ts" "⋀ i. i < length ts ⟹ (ss ! i, us ! i) ∈ ℛ"
      "⋀ i. i < length ts ⟹ (us ! i, ts ! i) ∈ 𝒮"
      using Ex_list_of_length_P[of "length ts" "λ x i. (ss ! i, x) ∈ ℛ ∧ (x, ts ! i) ∈ 𝒮"]
      by auto
    from funas have fu: "⋀ i . i < length us ⟹ funas_term (us ! i) ⊆ ℱ" using us ass(4, 5)
      by (auto simp: funas_rel_def) (metis in_mono)
    have "(Fun f ss, Fun f us) ∈ ℛ" using ass(1, 2, 5) us(1, 2) fu
      by (intro all_ctxt_closedD[OF ctxt_cl(1), of f]) auto
    moreover have "(Fun f us, Fun f ts) ∈ 𝒮"  using ass(1, 2, 4) us(1, 3) fu
      by (intro all_ctxt_closedD[OF ctxt_cl(2), of f]) auto
    ultimately have "(Fun f ss, Fun f ts) ∈ ℛ O 𝒮" by auto}
  moreover
  {fix x have "(Var x, Var x) ∈ ℛ" "(Var x, Var x) ∈ 𝒮" using ctxt_cl
      by (auto simp: all_ctxt_closed_def)
    then have "(Var x, Var x) ∈ ℛ O 𝒮" by auto}
  ultimately show ?thesis by (auto simp: all_ctxt_closed_def)
qed


abbreviation "prop_to_rel P ≡ {(s, t)| s t. P s t}"

abbreviation "prop_mctxt_cl ℱ P ≡ all_ctxt_closed ℱ (prop_to_rel P)"

lemma prop_mctxt_cl_Var:
  "prop_mctxt_cl ℱ P ⟹ P (Var x) (Var x)"
  by (simp add: all_ctxt_closed_def)

lemma prop_mctxt_cl_refl_on:
  "prop_mctxt_cl ℱ P ⟹ funas_term t ⊆ ℱ ⟹ P t t"
  using all_ctxt_closed_sig_reflE by blast

lemma prop_mctxt_cl_reflcl_on:
  "prop_mctxt_cl ℱ P ⟹ funas_term s ⊆ ℱ ⟹ P s s"
  using all_ctxt_closed_sig_reflE by blast

lemma reduction_relations_to_root_step:
  assumes "⋀ s t. (s, t) ∈ srsteps_with_root_step ℱ ℛ ⟹ P s t"
    and cl: "prop_mctxt_cl ℱ P"
    and well: "funas_term s ⊆ ℱ" "funas_term t ⊆ ℱ"
    and steps: "(s, t) ∈ (srstep ℱ ℛ)*"
  shows "P s t" using steps well
proof (induct s arbitrary: t)
  case (Var x)
  have "(Var x, t) ∈ (srstep ℱ ℛ)+ ⟹ (Var x, t) ∈ srsteps_with_root_step ℱ ℛ"
    using nsrsteps_with_root_step_step_on_args by blast
  from assms(1)[OF this] show ?case using Var cl
    by (auto simp: rtrancl_eq_or_trancl dest: all_ctxt_closed_sig_reflE)
next
  case (Fun f ss) note IH = this show ?case
  proof (cases "Fun f ss = t")
    case True show ?thesis using IH(2, 4) unfolding True
      by (intro prop_mctxt_cl_reflcl_on[OF cl]) auto      
  next
    case False
    then have step: "(Fun f ss, t) ∈ (srstep ℱ ℛ)+" using IH(2)
      by (auto simp: refl rtrancl_eq_or_trancl)
    show ?thesis
    proof (cases "(Fun f ss, t) ∈ srsteps_with_root_step ℱ ℛ")