Theory Trs

section ‹Term Rewrite Systems›

theory Trs
  imports
    "Abstract-Rewriting.Relation_Closure" 
    First_Order_Terms.Term_More
begin

text ‹
  A rewrite rule is a pair of terms. A term rewrite system (TRS) is a set of rewrite rules.
›
type_synonym ('f, 'v) rule = "('f, 'v) term × ('f, 'v) term"
type_synonym ('f, 'v) trs  = "('f, 'v) rule set"

inductive_set rstep :: "_ ⇒ ('f, 'v) term rel" for R :: "('f, 'v) trs"
  where
    rstep: "⋀C σ l r. (l, r) ∈ R ⟹ s = C⟨l ⋅ σ⟩ ⟹ t = C⟨r ⋅ σ⟩ ⟹ (s, t) ∈ rstep R"

lemma rstep_induct_rule [case_names IH, induct set: rstep]:
  assumes "(s, t) ∈ rstep R"
    and "⋀C σ l r. (l, r) ∈ R ⟹ P (C⟨l ⋅ σ⟩) (C⟨r ⋅ σ⟩)"
  shows "P s t"
  using assms by (induct) simp

text ‹
  An alternative induction scheme that treats the rule-case, the
  substition-case, and the context-case separately.
›
lemma rstep_induct [consumes 1, case_names rule subst ctxt]:
  assumes "(s, t) ∈ rstep R"
    and rule: "⋀l r. (l, r) ∈ R ⟹ P l r"
    and subst: "⋀s t σ. P s t ⟹ P (s ⋅ σ) (t ⋅ σ)"
    and ctxt: "⋀s t C. P s t ⟹ P (C⟨s⟩) (C⟨t⟩)"
  shows "P s t"
  using assms by (induct) auto

lemmas rstepI = rstep.intros [intro]

lemmas rstepE = rstep.cases [elim]

lemma rstep_ctxt [intro]: "(s, t) ∈ rstep R ⟹ (C⟨s⟩, C⟨t⟩) ∈ rstep R"
  by (force simp flip: ctxt_ctxt_compose)

lemma rstep_rule [intro]: "(l, r) ∈ R ⟹ (l, r) ∈ rstep R"
  using rstep.rstep [where C = □ and σ = Var and R = R] by simp

lemma rstep_subst [intro]: "(s, t) ∈ rstep R ⟹ (s ⋅ σ, t ⋅ σ) ∈ rstep R"
  by (force simp flip: subst_subst_compose)

lemma rstep_empty [simp]: "rstep {} = {}"
  by auto

lemma rstep_mono: "R ⊆ S ⟹ rstep R ⊆ rstep S"
  by force

lemma rstep_union: "rstep (R ∪ S) = rstep R ∪ rstep S"
  by auto

lemma rstep_converse [simp]: "rstep (R¯) = (rstep R)¯"
  by auto

interpretation subst: rel_closure "λσ t. t ⋅ σ" Var "λx y. y ∘s x" by (standard) auto
declare subst.closure.induct [consumes 1, case_names subst, induct pred: subst.closure]
declare subst.closure.cases [consumes 1, case_names subst, cases pred: subst.closure]

interpretation ctxt: rel_closure "ctxt_apply_term" □ "(∘c)" by (standard) auto
declare ctxt.closure.induct [consumes 1, case_names ctxt, induct pred: ctxt.closure]
declare ctxt.closure.cases [consumes 1, case_names ctxt, cases pred: ctxt.closure]

lemma rstep_eq_closure: "rstep R = ctxt.closure (subst.closure R)"
  by (force elim: ctxt.closure.cases subst.closure.cases)

lemma ctxt_closed_rstep [intro]: "ctxt.closed (rstep R)"
  by (simp add: rstep_eq_closure ctxt.closed_closure)

lemma ctxt_closed_one:
  "ctxt.closed r ⟹ (s, t) ∈ r ⟹ (Fun f (ss @ s # ts), Fun f (ss @ t # ts)) ∈ r"
  using ctxt.closedD [of r s t "More f ss □ ts"] by auto

subsection‹Well-formed TRSs›

definition
  wf_trs :: "('f, 'v) trs ⇒ bool"
  where
    "wf_trs R = (∀l r. (l,r) ∈ R ⟶ (∃f ts. l = Fun f ts) ∧ vars_term r ⊆ vars_term l)"

lemma wf_trs_imp_lhs_Fun:
  "wf_trs R ⟹ (l,r) ∈ R ⟹ ∃f ts. l = Fun f ts"
  unfolding wf_trs_def by blast

lemma rstep_imp_Fun:
  assumes "wf_trs R"
  shows "(s, t) ∈ rstep R ⟹ ∃f ss. s = Fun f ss"
proof -
  assume "(s, t) ∈ rstep R"
  then obtain C l r σ where lr: "(l,r) ∈ R" and s: "s = C ⟨ l ⋅ σ ⟩" by auto
  with wf_trs_imp_lhs_Fun[OF assms lr] show ?thesis by (cases C, auto)
qed

lemma SN_Var:
  assumes "wf_trs R" shows "SN_on (rstep R) {Var x}"
proof (rule ccontr)
  assume "¬ ?thesis"
  then obtain S where [symmetric]: "S 0 = Var x"
    and chain: "chain (rstep R) S" by auto
  then have "(Var x, S (Suc 0)) ∈ rstep R" by force
  then obtain C l r σ where "(l, r) ∈ R" and "Var x = C⟨l ⋅ σ⟩" by best
  then have "Var x = l ⋅ σ" by (induct C) simp_all
  then obtain y where "l = Var y" by (induct l) simp_all
  with assms and ‹(l, r) ∈ R› show False unfolding wf_trs_def by blast
qed

subsection ‹Function Symbols and Variables of Rules and TRSs›

definition
  vars_rule :: "('f, 'v) rule ⇒ 'v set"
  where
    "vars_rule r = vars_term (fst r) ∪ vars_term (snd r)"

lemma finite_vars_rule:
  "finite (vars_rule r)"
  by (auto simp: vars_rule_def)

definition vars_trs :: "('f, 'v) trs ⇒ 'v set" where
  "vars_trs R = (⋃r∈R. vars_rule r)"

lemma vars_trs_union: "vars_trs (R ∪ S) = vars_trs R ∪ vars_trs S"
  unfolding vars_trs_def by auto

lemma finite_trs_has_finite_vars:
  assumes "finite R" shows "finite (vars_trs R)"
  using assms unfolding vars_trs_def vars_rule_def [abs_def] by simp

lemmas vars_defs = vars_trs_def vars_rule_def

definition funs_rule :: "('f, 'v) rule ⇒ 'f set" where
  "funs_rule r = funs_term (fst r) ∪ funs_term (snd r)"


text ‹The same including arities.›
definition funas_rule :: "('f, 'v) rule ⇒ 'f sig" where
  "funas_rule r = funas_term (fst r) ∪ funas_term (snd r)"

definition funs_trs :: "('f, 'v) trs ⇒ 'f set" where
  "funs_trs R = (⋃r∈R. funs_rule r)"

definition funas_trs :: "('f, 'v) trs ⇒ 'f sig" where
  "funas_trs R = (⋃r∈R. funas_rule r)"

lemma funs_rule_funas_rule: "funs_rule rl = fst ` funas_rule rl"
  using funs_term_funas_term unfolding funs_rule_def funas_rule_def image_Un by metis

lemma funs_trs_funas_trs:"funs_trs R = fst ` funas_trs R"
  unfolding funs_trs_def funas_trs_def image_UN using funs_rule_funas_rule by metis

lemma finite_funas_rule: "finite (funas_rule lr)"
  unfolding funas_rule_def
  using finite_funas_term by auto

lemma finite_funas_trs:
  assumes "finite R"
  shows "finite (funas_trs R)"
  unfolding funas_trs_def
  using assms finite_funas_rule by auto

lemma finite_imp_fresh_sym: 
  assumes "finite R" 
  shows "∃ f n. (f,n) ∉ funas_trs R ∧ n ≥ k" 
proof -
  from assms have "finite (funas_trs R)" unfolding funas_trs_def 
    using finite_funas_rule by blast 
  hence "finite (snd ` funas_trs R)" by blast
  from finite_list[OF this] obtain as where as: "set as = snd ` funas_trs R" by auto
  let ?f = "(undefined, Suc k + (max_list as))" 
  have "Suc k + (max_list as) ∉ set as" 
    using max_list by force
  hence "?f ∉ funas_trs R" unfolding as by force
  thus ?thesis by fastforce
qed


lemma funas_empty[simp]: "funas_trs {} = {}" unfolding funas_trs_def by simp

lemma funas_trs_union[simp]: "funas_trs (R ∪ S) = funas_trs R ∪ funas_trs S"
  unfolding funas_trs_def by blast

definition funas_args_rule :: "('f, 'v) rule ⇒ 'f sig" where
  "funas_args_rule r = funas_args_term (fst r) ∪ funas_args_term (snd r)"

definition funas_args_trs :: "('f, 'v) trs ⇒ 'f sig" where
  "funas_args_trs R = (⋃r∈R. funas_args_rule r)"

lemmas funas_args_defs =
  funas_args_trs_def funas_args_rule_def funas_args_term_def

definition roots_rule :: "('f, 'v) rule ⇒ 'f sig"
  where
    "roots_rule r = set_option (root (fst r)) ∪ set_option (root (snd r))"

definition roots_trs :: "('f, 'v) trs ⇒ 'f sig" where
  "roots_trs R = (⋃r∈R. roots_rule r)"

lemmas roots_defs =
  roots_trs_def roots_rule_def

definition funas_head :: "('f, 'v) trs ⇒ ('f, 'v) trs ⇒ 'f sig" where
  "funas_head P R = funas_trs P - (funas_trs R ∪ funas_args_trs P)"

lemmas funs_defs = funs_trs_def funs_rule_def
lemmas funas_defs =
  funas_trs_def funas_rule_def
  funas_args_defs
  funas_head_def
  roots_defs

text ‹A function symbol is said to be \emph{defined} (w.r.t.\ to a given
TRS) if it occurs as root of some left-hand side.›
definition
  defined :: "('f, 'v) trs ⇒ ('f × nat) ⇒ bool"
  where
    "defined R fn ⟷ (∃l r. (l, r) ∈ R ∧ root l = Some fn)"

lemma defined_funas_trs: assumes d: "defined R fn" shows "fn ∈ funas_trs R"
proof -
  from d [unfolded defined_def] obtain l r
    where "(l, r) ∈ R" and "root l = Some fn" by auto
  then show ?thesis
    unfolding funas_trs_def funas_rule_def [abs_def] by (cases l) force+
qed

fun root_list :: "('f, 'v) term ⇒ ('f × nat) list"
  where
    "root_list (Var x) = []" |
    "root_list (Fun f ts) = [(f, length ts)]"

definition vars_rule_list :: "('f, 'v) rule ⇒ 'v list"
  where
    "vars_rule_list r = vars_term_list (fst r) @ vars_term_list (snd r)"

definition funs_rule_list :: "('f, 'v) rule ⇒ 'f list"
  where
    "funs_rule_list r = funs_term_list (fst r) @ funs_term_list (snd r)"

definition funas_rule_list :: "('f, 'v) rule ⇒ ('f × nat) list"
  where
    "funas_rule_list r = funas_term_list (fst r) @ funas_term_list (snd r)"

definition roots_rule_list :: "('f, 'v) rule ⇒ ('f × nat) list"
  where
    "roots_rule_list r = root_list (fst r) @ root_list (snd r)"

definition funas_args_rule_list :: "('f, 'v) rule ⇒ ('f × nat) list"
  where
    "funas_args_rule_list r = funas_args_term_list (fst r) @ funas_args_term_list (snd r)"

lemma set_vars_rule_list [simp]:
  "set (vars_rule_list r) = vars_rule r"
  by (simp add: vars_rule_list_def vars_rule_def)

lemma set_funs_rule_list [simp]:
  "set (funs_rule_list r) = funs_rule r"
  by (simp add: funs_rule_list_def funs_rule_def)

lemma set_funas_rule_list [simp]:
  "set (funas_rule_list r) = funas_rule r"
  by (simp add: funas_rule_list_def funas_rule_def)

lemma set_roots_rule_list [simp]:
  "set (roots_rule_list r) = roots_rule r"
  by (cases "fst r" "snd r" rule: term.exhaust [case_product term.exhaust])
    (auto simp: roots_rule_list_def roots_rule_def ac_simps)

lemma set_funas_args_rule_list [simp]:
  "set (funas_args_rule_list r) = funas_args_rule r"
  by (simp add: funas_args_rule_list_def funas_args_rule_def)

definition vars_trs_list :: "('f, 'v) rule list ⇒ 'v list"
  where
    "vars_trs_list trs = concat (map vars_rule_list trs)"

definition funs_trs_list :: "('f, 'v) rule list ⇒ 'f list"
  where
    "funs_trs_list trs = concat (map funs_rule_list trs)"

definition funas_trs_list :: "('f, 'v) rule list ⇒ ('f × nat) list"
  where
    "funas_trs_list trs = concat (map funas_rule_list trs)"

definition roots_trs_list :: "('f, 'v) rule list ⇒ ('f × nat) list"
  where
    "roots_trs_list trs = remdups (concat (map roots_rule_list trs))"

definition funas_args_trs_list :: "('f, 'v) rule list ⇒ ('f × nat) list"
  where
    "funas_args_trs_list trs = concat (map funas_args_rule_list trs)"

lemma set_vars_trs_list [simp]:
  "set (vars_trs_list trs) = vars_trs (set trs)"
  by (simp add: vars_trs_def vars_trs_list_def)

lemma set_funs_trs_list [simp]:
  "set (funs_trs_list R) = funs_trs (set R)"
  by (simp add: funs_trs_def funs_trs_list_def)

lemma set_funas_trs_list [simp]:
  "set (funas_trs_list R) = funas_trs (set R)"
  by (simp add: funas_trs_def funas_trs_list_def)

lemma set_roots_trs_list [simp]:
  "set (roots_trs_list R) = roots_trs (set R)"
  by (simp add: roots_trs_def roots_trs_list_def)

lemma set_funas_args_trs_list [simp]:
  "set (funas_args_trs_list R) = funas_args_trs (set R)"
  by (simp add: funas_args_trs_def funas_args_trs_list_def)

lemmas vars_list_defs = vars_trs_list_def vars_rule_list_def
lemmas funs_list_defs = funs_trs_list_def funs_rule_list_def
lemmas funas_list_defs = funas_trs_list_def funas_rule_list_def
lemmas roots_list_defs = roots_trs_list_def roots_rule_list_def
lemmas funas_args_list_defs = funas_args_trs_list_def funas_args_rule_list_def

lemma vars_trs_list_Nil [simp]:
  "vars_trs_list [] = []" unfolding vars_trs_list_def by simp

context
  fixes R :: "('f, 'v) trs"
  assumes "wf_trs R"
begin

lemma funas_term_subst_rhs:
  assumes "funas_trs R ⊆ F" and "(l, r) ∈ R" and "funas_term (l ⋅ σ) ⊆ F"
  shows "funas_term (r ⋅ σ) ⊆ F"
proof -
  have "vars_term r ⊆ vars_term l"  using ‹wf_trs R› and ‹(l, r) ∈ R› by (auto simp: wf_trs_def)
  moreover have "funas_term l ⊆ F" and "funas_term r ⊆ F"
    using ‹funas_trs R ⊆ F› and ‹(l, r) ∈ R› by (auto simp: funas_defs) force+
  ultimately show ?thesis
    using ‹funas_term (l ⋅ σ) ⊆ F› by (force simp: funas_term_subst)
qed

lemma vars_rule_lhs:
  "r ∈ R ⟹ vars_rule r = vars_term (fst r)"
  using ‹wf_trs R› by (cases r) (auto simp: wf_trs_def vars_rule_def)

end

lemma unify_funas_term: assumes "funas_trs (set eqs) ⊆ F" 
  and "⋃ (funas_term ` snd ` set sigma) ⊆ F" 
  and "unify eqs sigma = Some delta" 
shows "⋃ (funas_term ` snd ` set delta) ⊆ F" 
  using assms
proof (induction eqs sigma rule: unify.induct)
  case (2 f ss g ts E bs)
  from 2(4) obtain us where dec: "decompose (Fun f ss) (Fun g ts) = Some us" (is "?e = _")
    by (cases ?e, auto)
  from 2(2) decompose_Some[OF dec] 
  have "funas_trs (set (us @ E)) ⊆ F" 
    unfolding funas_trs_def funas_rule_def by (auto elim!: in_set_zipE, blast+)
  from 2(1)[OF dec this 2(3)] 2(4) dec show ?case by auto
next
  case (3 x t E bs)
  show ?case
  proof (cases "t = Var x")
    case True
    thus ?thesis using 3 by (auto simp: funas_trs_def)
  next
    case False
    with 3 have xt: "x ∉ vars_term t" by auto
    from 3 False xt have "unify (subst_list (subst x t) E) ((x, t) # bs) = Some delta" by auto
    note IH = 3(2)[OF False xt _ _ this]
    from 3(3,4) have bs: "⋃ (funas_term ` snd ` set ((x, t) # bs)) ⊆ F" 
      unfolding funas_trs_def funas_rule_def by auto
    from 3(3) have E: "funas_trs (set (subst_list (subst x t) E)) ⊆ F" 
      unfolding funas_trs_def funas_rule_def 
      by (auto simp: subst_set_def subst_def funas_term_subst split: if_splits)
    from IH[OF E bs]
    show ?thesis .
  qed
next
  case (4 f ts x E bs)
  let ?t = "Fun f ts" 
  define t where "t = ?t" 
  note 4 = 4[folded t_def]
  note [simp] = unify.simps(4)[of f ts x E, folded t_def]
  from 4(4) have xt: "x ∉ vars_term t" by auto
  from 4 xt have "unify (subst_list (subst x t) E) ((x, t) # bs) = Some delta" by auto
  note IH = 4(1)[OF xt _ _ this]
  from 4(2,3) have bs: "⋃ (funas_term ` snd ` set ((x, t) # bs)) ⊆ F" 
    unfolding funas_trs_def funas_rule_def by auto
  from 4(2) have E: "funas_trs (set (subst_list (subst x t) E)) ⊆ F" 
    unfolding funas_trs_def funas_rule_def 
    by (auto simp: subst_set_def subst_def funas_term_subst split: if_splits)
  from IH[OF E bs] show ?case .
qed auto


lemma mgu_list_funas_term: assumes "funas_trs (set eqs) ⊆ F" 
  and "mgu_list eqs = Some σ" 
shows "funas_term (σ x) ⊆ F" 
proof -
  from assms(2)[unfolded mgu_list_def]
  obtain sigma where un: "unify eqs [] = Some sigma" and σ: "σ = subst_of sigma" 
    by (cases "unify eqs []", auto)
  from unify_funas_term[OF assms(1) _ un]
  have "⋃ (funas_term ` snd ` set sigma) ⊆ F" by auto
  thus ?thesis unfolding σ by (meson subst_of_funas_term)
qed

lemma mgu_funas_term: assumes "funas_term s ⊆ F" "funas_term t ⊆ F" 
  and "mgu s t = Some σ" 
shows "funas_term (σ x) ⊆ F" 
proof -
  have "mgu_list [(s,t)] = mgu s t" unfolding mgu_list_def mgu_def by (cases "unify [(s,t)] []", auto)
  also have "… = Some σ" by fact
  finally have "mgu_list [(s, t)] = Some σ" by auto
  from mgu_list_funas_term[OF _ this, of F x] assms
  show ?thesis by (auto simp: funas_trs_def funas_rule_def)
qed

lemma mgu_var_disjoint_generic_funas_term: assumes "funas_term s ⊆ F" "funas_term t ⊆ F"
  and "mgu_var_disjoint_generic vu wu s t = Some (δ,τ)" 
shows "funas_term (δ x) ⊆ F" "funas_term (τ x) ⊆ F" 
proof -
  from assms(3)[unfolded mgu_var_disjoint_generic_def]
  obtain σ where mgu: "mgu (map_vars_term vu s) (map_vars_term wu t) = Some σ" (is "mgu ?s ?t = _")
    and id: "δ = σ o vu" "τ = σ o wu" 
    by (auto split: option.splits)
  from assms have "funas_term ?s ⊆ F" "funas_term ?t ⊆ F" by auto
  from mgu_funas_term[OF this mgu] have "funas_term (σ y) ⊆ F" for y by auto
  thus "funas_term (δ x) ⊆ F" "funas_term (τ x) ⊆ F" unfolding id o_def by auto
qed

lemma mgu_vd_funas_term: assumes "funas_term s ⊆ F" "funas_term t ⊆ F"
  and "mgu_vd ren s t = Some (δ,τ)" 
shows "funas_term (δ x) ⊆ F" "funas_term (τ x) ⊆ F" 
  using mgu_var_disjoint_generic_funas_term[OF assms[unfolded mgu_vd_def]] by blast+


subsection‹Closure Properties›

lemma ctxt_closed_R_imp_supt_R_distr:
  assumes "ctxt.closed R" and "s ⊳ t" and "(t, u) ∈ R" shows "∃t. (s, t) ∈ R ∧ t ⊳ u"
proof -
  from ‹s ⊳ t› obtain C where "C ≠ □" and "C⟨t⟩ = s" by auto
  from ‹ctxt.closed R› and ‹(t,u) ∈ R›
  have RCtCu: "(C⟨t⟩,C⟨u⟩) ∈ R" by (rule ctxt.closedD)
  from ‹C ≠ □› have "C⟨u⟩ ⊳ u" by auto
  from RCtCu have "(s,C⟨u⟩) ∈ R" unfolding ‹C⟨t⟩ = s› .
  from this and ‹C⟨u⟩ ⊳ u› show ?thesis by auto
qed

lemma ctxt_closed_imp_qc_supt: "ctxt.closed R ⟹ {⊳} O R ⊆ R O (R ∪ {⊳})*" by blast

text ‹Let~$R$ be a relation on terms that is closed under contexts. If~$R$
is well-founded then $R \cup \rhd$ is well-founed.›
lemma SN_imp_SN_union_supt:
  assumes "SN R" and "ctxt.closed R"
  shows "SN (R ∪ {⊳})"
proof -
  from ‹ctxt.closed R› have "quasi_commute R {⊳}"
    unfolding quasi_commute_def by (rule ctxt_closed_imp_qc_supt)
  have "SN {⊳}" by (rule SN_supt)
  from ‹SN R› and ‹SN {⊳}› and ‹quasi_commute R {⊳}›
  show ?thesis by (rule quasi_commute_imp_SN)
qed

lemma stable_loop_imp_not_SN:
  assumes stable: "subst.closed r" and steps: "(s, s ⋅ σ) ∈ r+"
  shows "¬ SN_on r {s}"
proof -
  let ?f =  "λ i. s ⋅ (power.power Var (∘s) σ i)"
  have main: "⋀ i. (?f i, ?f (Suc i)) ∈ r+"
  proof -
    fix i
    show "(?f i, ?f (Suc i)) ∈ r+"
    proof (induct i)
      case (Suc i)
      from Suc subst.closed_trancl[OF stable] have step: "(?f i ⋅ σ, ?f (Suc i) ⋅ σ) ∈ r+" by auto
      let ?σg = "power.power Var (∘s) σ i"
      let ?σgs = "power.power Var (∘s) σ (Suc i)"
      have idi: "?σg ∘s σ = σ ∘s ?σg" by (rule subst_monoid_mult.power_commutes)
      have idsi: "?σgs ∘s σ = σ ∘s ?σgs" by (rule subst_monoid_mult.power_commutes)
      have "?f i ⋅ σ = s ⋅ ?σg  ∘s σ" by simp
      also have "… = ?f (Suc i)" unfolding idi by simp
      finally have one: "?f i ⋅ σ = ?f (Suc i)" .
      have "?f (Suc i) ⋅ σ = s ⋅ ?σgs ∘s σ" by simp
      also have "… = ?f (Suc (Suc i))" unfolding idsi by simp
      finally have two: "?f (Suc i) ⋅ σ = ?f (Suc (Suc i))" by simp
      show ?case using one two step by simp
    qed (auto simp: steps)
  qed
  then have "¬ SN_on (r+) {?f 0}" unfolding SN_on_def by best
  then show ?thesis using SN_on_trancl by force
qed

lemma subst_closed_supteq: "subst.closed {⊵}" by blast

lemma subst_closed_supt: "subst.closed {⊳}" by blast

lemma ctxt_closed_supt_subset: "ctxt.closed R ⟹ {⊳} O R ⊆ R O {⊳}" by blast

subsection‹Properties of Rewrite Steps›

lemma rstep_relcomp_idemp1 [simp]:
  "rstep (rstep R O rstep S) = rstep R O rstep S"
proof -
  { fix s t
    assume "(s, t) ∈ rstep (rstep R O rstep S)"
    then have "(s, t) ∈ rstep R O rstep S"
      by (induct) blast+ }
  then show ?thesis by auto
qed

lemma rstep_relcomp_idemp2 [simp]:
  "rstep (rstep R O rstep S O rstep T) = rstep R O rstep S O rstep T"
proof -
  { fix s t
    assume "(s, t) ∈ rstep (rstep R O rstep S O rstep T)"
    then have "(s, t) ∈ rstep R O rstep S O rstep T"
      by (induct) blast+ }
  then show ?thesis by auto
qed

lemma ctxt_closed_rsteps [intro]: "ctxt.closed ((rstep R)*)" by blast

lemma subset_rstep: "R ⊆ rstep R" by auto

lemma subst_closure_rstep_subset: "subst.closure (rstep R) ⊆ rstep R"
  by (auto elim: subst.closure.cases)

lemma subst_closed_rstep [intro]: "subst.closed (rstep R)" by blast

lemma subst_closed_rsteps: "subst.closed ((rstep R)*)" by blast

lemmas supt_rsteps_subset = ctxt_closed_supt_subset [OF ctxt_closed_rsteps]

lemma supteq_rsteps_subset:
  "{⊵} O (rstep R)* ⊆ (rstep R)* O {⊵}" (is "?S ⊆ ?T")
  using supt_rsteps_subset [of R] by (auto simp: supt_supteq_set_conv)

lemma quasi_commute_rsteps_supt:
  "quasi_commute ((rstep R)*) {⊳}"
  unfolding quasi_commute_def using supt_rsteps_subset [of R] by auto

lemma rstep_UN:
  "rstep (⋃i∈A. R i) = (⋃i∈A. rstep (R i))"
  by force

definition
  rstep_r_p_s :: "('f, 'v) trs ⇒ ('f, 'v) rule ⇒ pos ⇒ ('f, 'v) subst ⇒ ('f, 'v) trs"
  where
    "rstep_r_p_s R r p σ = {(s, t).
    let C = ctxt_of_pos_term p s in p ∈ poss s ∧ r ∈ R ∧ (C⟨fst r ⋅ σ⟩ = s) ∧ (C⟨snd r ⋅ σ⟩ = t)}"

lemma rstep_r_p_s_def':
  "rstep_r_p_s R r p σ = {(s, t).
    p ∈ poss s ∧ r ∈ R ∧ s |_ p = fst r ⋅ σ ∧ t = replace_at s p (snd r ⋅ σ)}" (is "?l = ?r")
proof -
  { fix s t
    have "((s,t) ∈ ?l) = ((s,t) ∈ ?r)"
      unfolding rstep_r_p_s_def Let_def
      using ctxt_supt_id [of p s] and subt_at_ctxt_of_pos_term [of p s "fst r ⋅ σ"] by auto }
  then show ?thesis by auto
qed

lemma parallel_steps:
  fixes p1 :: pos
  assumes "(s, t) ∈ rstep_r_p_s R1 (l1, r1) p1 σ1"
    and "(s, u) ∈ rstep_r_p_s R2 (l2, r2) p2 σ2"
    and par: "p1 ⊥ p2"
  shows "(t, (ctxt_of_pos_term p1 u)⟨r1 ⋅ σ1⟩) ∈ rstep_r_p_s R2 (l2, r2) p2 σ2 ∧
         (u, (ctxt_of_pos_term p1 u)⟨r1 ⋅ σ1⟩) ∈ rstep_r_p_s R1 (l1, r1) p1 σ1"
proof -
  have p1: "p1 ∈ poss s" and lr1: "(l1, r1) ∈ R1" and σ1: "s |_ p1 = l1 ⋅ σ1"
    and t: "t = replace_at s p1 (r1 ⋅ σ1)"
    and p2: "p2 ∈ poss s" and lr2: "(l2, r2) ∈ R2" and σ2: "s |_ p2 = l2 ⋅ σ2"
    and u: "u = replace_at s p2 (r2 ⋅ σ2)" using assms by (auto simp: rstep_r_p_s_def')

  have "replace_at t p2 (r2 ⋅ σ2) = replace_at u p1 (r1 ⋅ σ1)"
    using t and u and parallel_replace_at [OF ‹p1 ⊥ p2› p1 p2] by auto
  moreover
  have "(t, (ctxt_of_pos_term p2 t)⟨r2 ⋅ σ2⟩) ∈ rstep_r_p_s R2 (l2, r2) p2 σ2"
  proof -
    have "t |_ p2 = l2 ⋅ σ2" using σ2 and parallel_replace_at_subt_at [OF par p1 p2] and t by auto
    moreover have "p2 ∈ poss t" using parallel_poss_replace_at [OF par p1] and t and p2 by auto
    ultimately show ?thesis using lr2 and ctxt_supt_id [of p2 t] by (simp add: rstep_r_p_s_def)
  qed
  moreover
  have "(u, (ctxt_of_pos_term p1 u)⟨r1 ⋅ σ1⟩) ∈ rstep_r_p_s R1 (l1, r1) p1 σ1"
  proof -
    have par': "p2 ⊥ p1" using parallel_pos_sym [OF par] .
    have "u |_ p1 = l1 ⋅ σ1" using σ1 and parallel_replace_at_subt_at [OF par' p2 p1] and u by auto
    moreover have "p1 ∈ poss u" using parallel_poss_replace_at [OF par' p2] and u and p1 by auto
    ultimately show ?thesis using lr1 and ctxt_supt_id [of p1 u] by (simp add: rstep_r_p_s_def)
  qed
  ultimately show ?thesis by auto
qed

lemma rstep_iff_rstep_r_p_s:
  "(s, t) ∈ rstep R ⟷ (∃l r p σ. (s, t) ∈ rstep_r_p_s R (l, r) p σ)" (is "?lhs = ?rhs")
proof
  assume "(s, t) ∈ rstep R"
  then obtain C σ l r where s: "s = C⟨l ⋅ σ⟩" and t: "t = C⟨r ⋅ σ⟩" and "(l, r) ∈ R" by auto
  let ?p = "hole_pos C"
  let ?C = "ctxt_of_pos_term ?p s"
  have C: "ctxt_of_pos_term ?p s = C" unfolding s by (induct C) simp_all
  have "?p ∈ poss s" unfolding s by simp
  moreover have "(l, r) ∈ R" by fact
  moreover have "?C⟨l ⋅ σ⟩ = s" unfolding C by (simp add: s)
  moreover have "?C⟨r ⋅ σ⟩ = t" unfolding C by (simp add: t)
  ultimately show "?rhs" unfolding rstep_r_p_s_def Let_def by auto
next
  assume "?rhs"
  then obtain l r p σ where "p ∈ poss s"
    and "(l, r) ∈ R"
    and s[symmetric]: "(ctxt_of_pos_term p s)⟨l ⋅ σ⟩ = s"
    and t[symmetric]: "(ctxt_of_pos_term p s)⟨r ⋅ σ⟩ = t"
    unfolding rstep_r_p_s_def Let_def by auto
  then show "?lhs" by auto
qed

lemma rstep_r_p_s_imp_rstep:
  assumes "(s, t) ∈ rstep_r_p_s R r p σ"
  shows "(s, t) ∈ rstep R"
  using assms by (cases r) (auto simp: rstep_iff_rstep_r_p_s)

text ‹Rewriting steps below the root position.›
definition
  nrrstep :: "('f, 'v) trs ⇒ ('f, 'v) trs"
  where
    "nrrstep R = {(s,t). ∃r i ps σ. (s,t) ∈ rstep_r_p_s R r (i#ps) σ}"

text ‹An alternative characterisation of non-root rewrite steps.›
lemma nrrstep_def':
  "nrrstep R = {(s, t). ∃l r C σ. (l, r) ∈ R ∧ C ≠ □ ∧ s = C⟨l⋅σ⟩ ∧ t = C⟨r⋅σ⟩}"
  (is "?lhs = ?rhs")
proof
  show "?lhs ⊆ ?rhs"
  proof (rule subrelI)
    fix s t assume "(s, t) ∈ nrrstep R"
    then obtain l r i ps σ where step: "(s, t) ∈ rstep_r_p_s R (l, r) (i # ps) σ"
      unfolding nrrstep_def by best
    let ?C = "ctxt_of_pos_term (i # ps) s"
    from step have"i # ps ∈ poss s" and "(l, r) ∈ R" and "s = ?C⟨l⋅σ⟩" and "t = ?C⟨r⋅σ⟩"
      unfolding rstep_r_p_s_def Let_def by auto
    moreover from ‹i # ps ∈ poss s› have "?C ≠ □" by (induct s) auto
    ultimately show "(s, t) ∈ ?rhs" by auto
  qed
next
  show "?rhs ⊆ ?lhs"
  proof (rule subrelI)
    fix s t assume "(s, t) ∈ ?rhs"
    then obtain l r C σ where in_R: "(l, r) ∈ R" and "C ≠ □"
      and s: "s = C⟨l⋅σ⟩" and t: "t = C⟨r⋅σ⟩" by auto
    from ‹C ≠ □› obtain i p where ip: "hole_pos C = i # p" by (induct C) auto
    have "i # p ∈ poss s" using hole_pos_poss[of C] unfolding s ip by simp
    then have C: "C = ctxt_of_pos_term (i # p) s"
      unfolding s ip[symmetric] by simp
    from ‹i # p ∈ poss s› in_R s t have "(s, t) ∈ rstep_r_p_s R (l, r) (i # p) σ"
      unfolding rstep_r_p_s_def C by simp
    then show "(s, t) ∈ nrrstep R" unfolding nrrstep_def by best
  qed
qed

lemma nrrstepI: "(l,r) ∈ R ⟹ s = C⟨l⋅σ⟩ ⟹ t = C⟨r ⋅ σ⟩ ⟹ C ≠ □ ⟹ (s,t) ∈ nrrstep R" unfolding nrrstep_def' by auto

lemma nrrstep_union: "nrrstep (R ∪ S) = nrrstep R ∪ nrrstep S"
  unfolding nrrstep_def' by blast

lemma nrrstep_empty[simp]: "nrrstep {} = {}" unfolding nrrstep_def' by blast

text ‹Rewriting step at the root position.›
definition
  rrstep :: "('f, 'v) trs ⇒ ('f, 'v) trs"
  where
    "rrstep R = {(s,t). ∃r σ. (s,t) ∈ rstep_r_p_s R r [] σ}"

text ‹An alternative characterisation of root rewrite steps.›
lemma rrstep_def': "rrstep R = {(s, t). ∃l r σ. (l, r) ∈ R ∧ s = l⋅σ ∧ t = r⋅σ}"
  (is "_ = ?rhs")
  by (auto simp: rrstep_def rstep_r_p_s_def)

lemma rules_subset_rrstep [simp]: "R ⊆ rrstep R"
  by (force simp: rrstep_def' intro: exI [of _ Var])

lemma rrstep_union: "rrstep (R ∪ S) = rrstep R ∪ rrstep S" unfolding rrstep_def' by blast

lemma rrstep_empty[simp]: "rrstep {} = {}"
  unfolding rrstep_def' by auto

lemma subst_closed_rrstep: "subst.closed (rrstep R)"
  unfolding subst.closed_def
proof
  fix ss ts
  assume "(ss,ts) ∈ subst.closure (rrstep R)"
  then show "(ss,ts) ∈ rrstep R"
  proof
    fix s t σ
    assume ss: "ss = s ⋅ σ" and ts: "ts = t ⋅ σ" and step: "(s,t) ∈ rrstep R"
    from step obtain l r δ where lr: "(l,r) ∈ R" and s: "s = l ⋅ δ" and t: "t = r ⋅ δ" unfolding rrstep_def' by auto
    obtain sig where "sig = δ ∘s σ" by auto
    with ss s ts t have "ss = l ⋅ sig" and "ts = r ⋅ sig" by simp+
    with lr show "(ss,ts) ∈ rrstep R" unfolding rrstep_def' by (auto simp: Let_def)
  qed
qed

lemma rstep_iff_rrstep_or_nrrstep: "rstep R = (rrstep R ∪ nrrstep R)"
proof
  show "rstep R ⊆ rrstep R ∪ nrrstep R"
  proof (rule subrelI)
    fix s t assume "(s,t) ∈ rstep R"
    then obtain l r p σ where rstep_rps: "(s,t) ∈ rstep_r_p_s R (l,r) p σ"
      by (auto simp: rstep_iff_rstep_r_p_s)
    then show "(s,t) ∈ rrstep R ∪ nrrstep R" unfolding rrstep_def nrrstep_def by (cases p) auto
  qed
next
  show "rrstep R ∪ nrrstep R ⊆ rstep R"
  proof (rule subrelI)
    fix s t assume "(s,t) ∈ rrstep R ∪ nrrstep R"
    then show "(s,t) ∈ rstep R" by (auto simp: rrstep_def nrrstep_def rstep_iff_rstep_r_p_s)
  qed
qed

lemma rstep_i_pos_imp_rstep_arg_i_pos:
  assumes nrrstep: "(Fun f ss,t) ∈ rstep_r_p_s R (l,r) (i#ps) σ"
  shows "(ss!i,t|_[i]) ∈ rstep_r_p_s R (l,r) ps σ"
proof -
  from nrrstep obtain C where C:"C = ctxt_of_pos_term (i#ps) (Fun f ss)"
    and pos: "(i#ps) ∈ poss (Fun f ss)"
    and Rlr: "(l,r) ∈ R"
    and Fun: "C⟨l⋅σ⟩ = Fun f ss"
    and t: "C⟨r⋅σ⟩ = t" unfolding rstep_r_p_s_def Let_def by auto
  then obtain D where C':"C = More f (take i ss) D (drop (Suc i) ss)" by auto
  then have CFun: "C⟨l⋅σ⟩ = Fun f (take i ss @ (D⟨l⋅σ⟩) # drop (Suc i) ss)" by auto
  from pos have len: "i < length ss" by auto
  from len
  have "(take i ss @ (D⟨l⋅σ⟩) # drop (Suc i) ss)!i = D⟨l⋅σ⟩" by (auto simp: nth_append)
  with C Fun CFun have ssi: "ss!i = D⟨l⋅σ⟩" by auto
  from C' t have t': "t = Fun f (take i ss @ (D⟨r⋅σ⟩) # drop (Suc i) ss)" by auto
  from len
  have "(take i ss @ (D⟨r⋅σ⟩) # drop (Suc i) ss)!i = D⟨r⋅σ⟩" by (auto simp: nth_append)
  with t' have "t|_[i] = (D⟨r⋅σ⟩)|_[]" by auto
  then have subt_at: "t|_[i] = D⟨r⋅σ⟩" by simp
  from C C' have "D = ctxt_of_pos_term ps (ss!i)" by auto
  with pos Rlr ssi[symmetric] subt_at[symmetric]
  show ?thesis unfolding rstep_r_p_s_def Let_def by auto
qed

lemma ctxt_closure_rstep_eq [simp]: "ctxt.closure (rstep R) = rstep R"
  by (rule ctxt.closure_id) blast

lemma subst_closure_rstep_eq [simp]: "subst.closure (rstep R) = rstep R"
  by (rule subst.closure_id) blast

lemma supt_rstep_subset:
  "{⊳} O rstep R ⊆ rstep R O {⊳}"
proof (rule subrelI)
  fix s t assume "(s,t) ∈ {⊳} O rstep R" then show "(s,t) ∈ rstep R O {⊳}"
  proof (induct s)
    case (Var x)
    then have "∃u. Var x ⊳ u ∧ (u,t) ∈ rstep R" by auto
    then obtain u where "Var x ⊳ u" and "(u,t) ∈ rstep R" by auto
    from ‹Var x ⊳ u› show ?case by (cases rule: supt.cases)
  next
    case (Fun f ss)
    then obtain u where "Fun f ss ⊳ u" and "(u,t) ∈ rstep R" by auto
    from ‹Fun f ss ⊳ u› obtain C
      where "C ≠ □" and "C⟨u⟩ = Fun f ss" by auto
    from ‹C ≠ □› have "C⟨t⟩ ⊳ t" by (rule nectxt_imp_supt_ctxt)
    from ‹(u,t) ∈ rstep R› have "(C⟨u⟩,C⟨t⟩) ∈ rstep R" ..
    then have "(Fun f ss,C⟨t⟩) ∈ rstep R" unfolding ‹C⟨u⟩ = Fun f ss› .
    with ‹C⟨t⟩ ⊳ t› show ?case by auto
  qed
qed

lemma ne_rstep_seq_imp_list_of_terms:
  assumes "(s,t) ∈ (rstep R)+"
  shows "∃ts. length ts > 1 ∧ ts!0 = s ∧ ts!(length ts - 1) = t ∧
         (∀i<length ts - 1. (ts!i,ts!(Suc i)) ∈ (rstep R))" (is "∃ts. _ ∧ _ ∧ _ ∧ ?P ts")
  using assms
proof (induct rule: trancl.induct)
  case (r_into_trancl x y)
  let ?ts = "[x,y]"
  have "length ?ts > 1" by simp
  moreover have "?ts!0 = x" by simp
  moreover have "?ts!(length ?ts - 1) = y" by simp
  moreover from r_into_rtrancl r_into_trancl have "?P ?ts" by auto
  ultimately show ?case by fast
next
  case (trancl_into_trancl x y z)
  then obtain ts where "length ts > 1" and "ts!0 = x"
    and last1: "ts!(length ts - 1) = y" and "?P ts" by auto
  let ?ts = "ts@[z]"
  have len: "length ?ts = length ts + 1" by simp
  from ‹length ts > 1› have "length ?ts > 1" by auto
  moreover with ‹ts!0 = x› have "?ts!0 = x" by (induct ts) auto
  moreover have last2: "?ts!(length ?ts - 1) = z" by simp
  moreover have "?P ?ts"
  proof (intro allI impI)
    fix i assume A: "i < length ?ts - 1"
    show "(?ts!i,?ts!(Suc i)) ∈ rstep R"
    proof (cases "i < length ts - 1")
      case True with ‹?P ts› A show ?thesis unfolding len unfolding nth_append by auto
    next
      case False with A have "i = length ts - 1" by simp
      with last1 ‹length ts > 1› have "?ts!i = y" unfolding nth_append by auto
      have "Suc i = length ?ts - 1" using ‹i = length ts - 1› using ‹length ts > 1› by auto
      with last2 have "?ts!(Suc i) = z" by auto
      from ‹(y,z) ∈ rstep R› show ?thesis unfolding ‹?ts!(Suc i) = z› ‹?ts!i = y› .
    qed
  qed
  ultimately show ?case by fast
qed


locale E_compatible =
  fixes R :: "('f,'v)trs" and E :: "('f,'v)trs"
  assumes E: "E O R = R" "Id ⊆ E"
begin

definition restrict_SN_supt_E :: "('f, 'v) trs" where
  "restrict_SN_supt_E = restrict_SN R R ∪ restrict_SN (E O {⊳} O E) R"

lemma ctxt_closed_R_imp_supt_restrict_SN_E_distr:
  assumes "ctxt.closed R"
    and "(s,t) ∈ (restrict_SN (E O {⊳}) R)"
    and "(t,u) ∈ restrict_SN R R"
  shows "(∃t. (s,t) ∈ restrict_SN R R ∧ (t,u) ∈ restrict_SN (E O {⊳}) R)" (is "∃ t. _ ∧ (t,u) ∈ ?snSub")
proof -
  from ‹(s,t) ∈ ?snSub› obtain v where "SN_on R {s}" and ac: "(s,v) ∈ E" and "v ⊳ t" unfolding restrict_SN_def supt_def by auto
  from ‹v ⊳ t› obtain C where "C ≠ Hole" and v: "C⟨t⟩ = v" by best
  from ‹(t,u) ∈ restrict_SN R R› have "(t,u) ∈ R" unfolding restrict_SN_def by auto
  from ‹ctxt.closed R› and this have RCtCu: "(C⟨t⟩,C⟨u⟩) ∈ R" by (rule ctxt.closedD)
  with v ac have "(s,C⟨u⟩) ∈ E O R" by auto
  then have sCu: "(s,C⟨u⟩) ∈ R" using E by simp
  with ‹SN_on R {s}› have one: "SN_on R {C⟨u⟩}"
    using step_preserves_SN_on[of "s" "C⟨u⟩" R] by blast
  from ‹C ≠ □› have "C⟨u⟩ ⊳ u" by auto
  with one E have "(C⟨u⟩,u) ∈ ?snSub" unfolding restrict_SN_def supt_def by auto
  from sCu and ‹SN_on R {s}› and ‹(C⟨u⟩,u) ∈ ?snSub› show ?thesis unfolding restrict_SN_def by auto
qed

lemma ctxt_closed_R_imp_restrict_SN_qc_E_supt:
  assumes ctxt: "ctxt.closed R"
  shows "quasi_commute (restrict_SN R R) (restrict_SN (E O {⊳} O E) R)" (is "quasi_commute ?r ?s")
proof -
  have "?s O ?r ⊆ ?r O (?r ∪ ?s)*"
  proof (rule subrelI)
    fix x y
    assume "(x,y) ∈ ?s O ?r"
    from this obtain z where "(x,z) ∈ ?s" and "(z,y) ∈ ?r" by best
    then obtain v w where ac: "(x,v) ∈ E" and vw: "v ⊳ w" and wz: "(w,z) ∈ E" and zy: "(z,y) ∈ R" and "SN_on R {x}" unfolding restrict_SN_def supt_def
      using E(2) by auto
    from wz zy have "(w,y) ∈ E O R" by auto
    with E have wy: "(w,y) ∈ R" by auto
    from ctxt_closed_R_imp_supt_R_distr[OF ctxt vw wy] obtain w where "(v,w) ∈ R" and "w ⊳ y" using ctxt_closed_R_imp_supt_R_distr[where R = R and s = v and t = z and u = y] by auto
    with ac E have "(x,w) ∈ R" and "w ⊳ y" by auto
    from this and ‹SN_on R {x}› have "SN_on R {w}" using step_preserves_SN_on
      unfolding supt_supteq_conv by auto
    with ‹w ⊳ y› E have "(w,y) ∈ ?s" unfolding restrict_SN_def supt_def by force
    with ‹(x,w) ∈ R› ‹SN_on R {x}› show "(x,y) ∈ ?r O (?r ∪ ?s)*" unfolding restrict_SN_def by auto
  qed
  then show ?thesis unfolding quasi_commute_def .
qed

lemma ctxt_closed_imp_SN_restrict_SN_E_supt:
  assumes "ctxt.closed R"
    and SN: "SN (E O {⊳} O E)"
  shows "SN restrict_SN_supt_E"
proof -
  let ?r = "restrict_SN R R"
  let ?s = "restrict_SN (E O {⊳} O E) R"
  from ‹ctxt.closed R› have "quasi_commute ?r ?s"
    by (rule ctxt_closed_R_imp_restrict_SN_qc_E_supt)
  from SN have "SN ?s" by (rule SN_subset, auto simp: restrict_SN_def)
  have "SN ?r" by (rule SN_restrict_SN_idemp)
  from ‹SN ?r› and ‹SN ?s› and ‹quasi_commute ?r ?s›
  show ?thesis unfolding restrict_SN_supt_E_def by (rule quasi_commute_imp_SN)
qed
end

lemma E_compatible_Id: "E_compatible R Id"
  by standard auto

definition restrict_SN_supt :: "('f, 'v) trs ⇒ ('f, 'v) trs" where
  "restrict_SN_supt R = restrict_SN R R ∪ restrict_SN {⊳} R"

lemma ctxt_closed_SN_on_subt:
  assumes "ctxt.closed R" and "SN_on R {s}" and "s ⊵ t"
  shows "SN_on R {t}"
proof (rule ccontr)
  assume "¬ SN_on R {t}"
  then obtain A where "A 0 = t" and "∀i. (A i,A (Suc i)) ∈ R"
    unfolding SN_on_def by best
  from ‹s ⊵ t› obtain C where "s = C⟨t⟩" by auto
  let ?B = "λi. C⟨A i⟩"
  have "∀i. (?B i,?B(Suc i)) ∈ R"
  proof
    fix i
    from ‹∀i. (A i,A(Suc i)) ∈ R› have "(?B i,?B(Suc i)) ∈ ctxt.closure(R)" by fast
    then show "(?B i,?B(Suc i)) ∈ R" using ‹ctxt.closed R› by auto
  qed
  with ‹A 0 = t› have "?B 0 = s ∧ (∀i. (?B i,?B(Suc i)) ∈ R)" unfolding ‹s = C⟨t⟩› by auto
  then have "¬ SN_on R {s}" unfolding SN_on_def by auto
  with assms show "False" by simp
qed

lemma ctxt_closed_R_imp_supt_restrict_SN_distr:
  assumes R: "ctxt.closed R"
    and st: "(s,t) ∈ (restrict_SN {⊳} R)"
    and tu: "(t,u) ∈ restrict_SN R R"
  shows "(∃t. (s,t) ∈ restrict_SN R R ∧ (t,u) ∈ restrict_SN {⊳} R)" (is "∃ t. _ ∧ (t,u) ∈ ?snSub")
  using E_compatible.ctxt_closed_R_imp_supt_restrict_SN_E_distr[OF E_compatible_Id R _ tu, of s]
    st by auto

lemma ctxt_closed_R_imp_restrict_SN_qc_supt:
  assumes "ctxt.closed R"
  shows "quasi_commute (restrict_SN R R) (restrict_SN supt R)" (is "quasi_commute ?r ?s")
  using E_compatible.ctxt_closed_R_imp_restrict_SN_qc_E_supt[OF E_compatible_Id assms] by auto

lemma ctxt_closed_imp_SN_restrict_SN_supt:
  assumes "ctxt.closed R"
  shows "SN (restrict_SN_supt R)"
  using E_compatible.ctxt_closed_imp_SN_restrict_SN_E_supt[OF E_compatible_Id assms]
  unfolding E_compatible.restrict_SN_supt_E_def[OF E_compatible_Id] restrict_SN_supt_def
  using SN_supt by auto

lemma SN_restrict_SN_supt_rstep:
  shows "SN (restrict_SN_supt (rstep R))"
proof -
  have "ctxt.closed (rstep R)" by (rule ctxt_closed_rstep)
  then show ?thesis by (rule ctxt_closed_imp_SN_restrict_SN_supt)
qed

lemma nrrstep_imp_pos_term:
  "(Fun f ss,t) ∈ nrrstep R ⟹
    ∃i s. t = Fun f (ss[i:=s]) ∧ (ss!i,s) ∈ rstep R ∧ i < length ss"
proof -
  assume "(Fun f ss,t) ∈ nrrstep R"
  then obtain l r i ps σ where rstep_rps:"(Fun f ss,t) ∈ rstep_r_p_s R (l,r) (i#ps) σ"
    unfolding nrrstep_def by auto
  then obtain C
    where "(l,r) ∈ R"
      and pos: "(i#ps) ∈ poss (Fun f ss)"
      and C: "C = ctxt_of_pos_term (i#ps) (Fun f ss)"
      and "C⟨l⋅σ⟩ = Fun f ss"
      and t: "C⟨r⋅σ⟩ = t"
    unfolding rstep_r_p_s_def Let_def by auto
  then obtain D where "C = More f (take i ss) D (drop (Suc i) ss)" by auto
  with t have t': "t = Fun f (take i ss @ (D⟨r⋅σ⟩) # drop (Suc i) ss)" by auto
  from rstep_rps have "(ss!i,t|_[i]) ∈ rstep_r_p_s R (l,r) ps σ"
    by (rule rstep_i_pos_imp_rstep_arg_i_pos)
  then have rstep:"(ss!i,t|_[i]) ∈ rstep R" by (auto simp: rstep_iff_rstep_r_p_s)
  then have "(C⟨ss!i⟩,C⟨t|_[i]⟩) ∈ rstep R" ..
  from pos have len: "i < length ss" by auto
  from len
  have "(take i ss @ (D⟨r⋅σ⟩) # drop (Suc i) ss)!i = D⟨r⋅σ⟩" by (auto simp: nth_append)
  with C t' have "t|_[i] = D⟨r⋅σ⟩" by auto
  with t' have "t = Fun f (take i ss @ (t|_[i]) # drop (Suc i) ss)" by auto
  with len have "t = Fun f (ss[i:=t|_[i]])" by (auto simp: upd_conv_take_nth_drop)
  with rstep len show "∃i s. t = Fun f (ss[i:=s]) ∧ (ss!i,s) ∈ rstep R ∧ i < length ss" by auto
qed


lemma rstep_cases[consumes 1, case_names root nonroot]:
  "⟦(s,t) ∈ rstep R; (s,t) ∈ rrstep R ⟹ P; (s,t) ∈ nrrstep R ⟹ P⟧ ⟹ P"
  by (auto simp: rstep_iff_rrstep_or_nrrstep)

lemma nrrstep_imp_rstep: "(s,t) ∈ nrrstep R ⟹ (s,t) ∈ rstep R"
  by (auto simp: rstep_iff_rrstep_or_nrrstep)

lemma nrrstep_imp_Fun: "(s,t) ∈ nrrstep R ⟹ ∃f ss. s = Fun f ss"
proof -
  assume "(s,t) ∈ nrrstep R"
  then obtain i ps where "i#ps ∈ poss s"
    unfolding nrrstep_def rstep_r_p_s_def Let_def by auto
  then show "∃f ss. s = Fun f ss" by (cases s) auto
qed

lemma nrrstep_imp_subt_rstep:
  assumes "(s,t) ∈ nrrstep R"
  shows "∃i. i < num_args s ∧ num_args s = num_args t ∧ (s|_[i],t|_[i]) ∈ rstep R ∧ (∀j. i ≠ j ⟶ s|_[j] = t|_[j])"
proof -
  from ‹(s,t) ∈ nrrstep R› obtain f ss where "s = Fun f ss" using nrrstep_imp_Fun by blast
  with ‹(s,t) ∈ nrrstep R› have "(Fun f ss,t) ∈ nrrstep R" by simp
  then obtain i u where "t = Fun f (ss[i := u])" and "(ss!i,u) ∈ rstep R" and "i < length ss"
    using nrrstep_imp_pos_term by best
  from ‹s = Fun f ss› and ‹t = Fun f (ss[i := u])› have "num_args s = num_args t" by auto
  from ‹i < length ss› and ‹s = Fun f ss› have "i < num_args s" by auto
  from ‹s = Fun f ss› have "s|_[i] = (ss!i)" by auto
  from ‹t = Fun f (ss[i := u])› and ‹i < length ss› have "t|_[i] = u" by auto
  from ‹s = Fun f ss› and ‹t = Fun f (ss[i := u])›
  have  "∀j. j ≠ i ⟶ s|_[j] = t|_[j]" by auto
  with ‹(ss!i,u) ∈ rstep R›
    and ‹i < num_args s›
    and ‹num_args s = num_args t›
    and ‹s|_[i] = (ss!i)›[symmetric] and ‹t|_[i] = u›[symmetric]
  show ?thesis by (auto)
qed

lemma nrrstep_subt: assumes "(s, t) ∈ nrrstep R" shows "∃u⊲s. ∃v⊲t. (u, v) ∈ rstep R"
proof -
  from assms obtain l r C σ where "(l, r) ∈ R" and "C ≠ □"
    and s: "s = C⟨l⋅σ⟩" and t: "t = C⟨r⋅σ⟩" unfolding nrrstep_def' by best
  from ‹C ≠ □› s have "s ⊳ l⋅σ" by auto
  moreover from ‹C ≠ □› t have "t ⊳ r⋅σ" by auto
  moreover from ‹(l, r) ∈ R› have "(l⋅σ, r⋅σ) ∈ rstep R" by auto
  ultimately show ?thesis by auto
qed

lemma nrrstep_args:
  assumes "(s, t) ∈ nrrstep R"
  shows "∃f ss ts. s = Fun f ss ∧ t = Fun f ts ∧ length ss = length ts
    ∧ (∃j<length ss. (ss!j, ts!j) ∈ rstep R ∧ (∀i<length ss. i ≠ j ⟶ ss!i = ts!i))"
proof -
  from assms obtain l r C σ where "(l, r) ∈ R" and "C ≠ □"
    and s: "s = C⟨l⋅σ⟩" and t: "t = C⟨r⋅σ⟩" unfolding nrrstep_def' by best
  from ‹C ≠ □› obtain f ss1 D ss2 where C: "C = More f ss1 D ss2" by (induct C) auto
  have "s = Fun f (ss1 @ D⟨l⋅σ⟩ # ss2)" (is "_ = Fun f ?ss") by (simp add: s C)
  moreover have "t = Fun f (ss1 @ D⟨r⋅σ⟩ # ss2)" (is "_ = Fun f ?ts") by (simp add: t C)
  moreover have "length ?ss = length ?ts" by simp
  moreover have "∃j<length ?ss.
    (?ss!j, ?ts!j) ∈ rstep R ∧ (∀i<length ?ss. i ≠ j ⟶ ?ss!i = ?ts!i)"
  proof -
    let ?j = "length ss1"
    have "?j < length ?ss" by simp
    moreover have "(?ss!?j, ?ts!?j) ∈ rstep R"
    proof -
      from ‹(l, r) ∈ R› have "(D⟨l⋅σ⟩, D⟨r⋅σ⟩) ∈ rstep R" by auto
      then show ?thesis by auto
    qed
    moreover have "∀i<length ?ss. i ≠ ?j ⟶ ?ss!i = ?ts!i" (is "∀i<length ?ss. _ ⟶ ?P i")
    proof (intro allI impI)
      fix i assume "i < length ?ss" and "i ≠ ?j"
      then have "i < length ss1 ∨ length ss1 < i" by auto
      then show "?P i"
      proof
        assume "i < length ss1" then show "?P i" by (auto simp: nth_append)
      next
        assume "i > length ss1" then show "?P i"
          using ‹i < length ?ss› by (auto simp: nth_Cons' nth_append)
      qed
    qed
    ultimately show ?thesis by best
  qed
  ultimately show ?thesis by auto
qed

lemma nrrstep_iff_arg_rstep:
  "(s,t) ∈ nrrstep R ⟷
   (∃f ss i t'. s = Fun f ss ∧ i < length ss ∧ t = Fun f (ss[i:=t']) ∧ (ss!i,t') ∈ rstep R)"
  (is "?L ⟷ ?R")
proof
  assume L: ?L
  from nrrstep_args[OF this]
  obtain f ss ts where "s = Fun f ss" "t = Fun f ts" by auto
  with nrrstep_imp_pos_term[OF L[unfolded this]]
  show ?R by auto
next assume R: ?R
  then obtain f i ss t'
    where s: "s = Fun f ss" and t: "t = Fun f (ss[i:=t'])"
      and i: "i < length ss" and st': "(ss ! i, t') ∈ rstep R" by auto
  from st' obtain C l r σ where lr: "(l, r) ∈ R" and s': "ss!i = C⟨l ⋅ σ⟩" and t': "t' = C⟨r ⋅ σ⟩" by auto
  let ?D = "More f (take i ss) C (drop (Suc i) ss)"
  have "s = ?D⟨l ⋅ σ⟩" "t = ?D⟨r ⋅ σ⟩" unfolding s t
    using id_take_nth_drop[OF i] upd_conv_take_nth_drop[OF i] s' t' by auto
  with lr show ?L apply(rule nrrstepI) using t' by auto
qed


lemma subterms_NF_imp_SN_on_nrrstep:
  assumes "∀s⊲t. s ∈ NF (rstep R)" shows "SN_on (nrrstep R) {t}"
proof
  fix S assume "S 0 ∈ {t}" and "∀i. (S i, S (Suc i)) ∈ nrrstep R"
  then have "(t, S (Suc 0)) ∈ nrrstep R" by auto
  then obtain l r C σ where "(l, r) ∈ R" and "C ≠ □" and t: "t = C⟨l⋅σ⟩" unfolding nrrstep_def' by auto
  then obtain f ss1 D ss2 where C: "C = More f ss1 D ss2" by (induct C) auto
  have "t ⊳ D⟨l⋅σ⟩" unfolding t C by auto
  moreover have "D⟨l⋅σ⟩ ∉ NF (rstep R)"
  proof -
    from ‹(l, r) ∈ R› have "(D⟨l⋅σ⟩, D⟨r⋅σ⟩) ∈ rstep R" by auto
    then show ?thesis by auto
  qed
  ultimately show False using assms by simp
qed

lemma args_NF_imp_SN_on_nrrstep:
  assumes "∀t∈set ts. t ∈ NF (rstep R)" shows "SN_on (nrrstep R) {Fun f ts}"
proof
  fix S assume "S 0 ∈ {Fun f ts}" and "∀i. (S i, S (Suc i)) ∈ nrrstep R"
  then have "(Fun f ts, S (Suc 0)) ∈ nrrstep R"
    unfolding singletonD[OF ‹S 0 ∈ {Fun f ts}›, symmetric] by simp
  then obtain l r C σ where "(l, r) ∈ R" and "C ≠ □" and "Fun f ts = C⟨l⋅σ⟩"
    unfolding nrrstep_def' by auto
  then obtain ss1 D ss2 where C: "C = More f ss1 D ss2" by (induct C) auto
  with ‹Fun f ts = C⟨l⋅σ⟩› have "D⟨l⋅σ⟩ ∈ set ts" by auto
  moreover have "D⟨l⋅σ⟩ ∉ NF (rstep R)"
  proof -
    from ‹(l, r) ∈ R› have "(D⟨l⋅σ⟩, D⟨r⋅σ⟩) ∈ rstep R" by auto
    then show ?thesis by auto
  qed
  ultimately show False using assms by simp
qed

lemma rrstep_imp_rule_subst:
  assumes "(s,t) ∈ rrstep R"
  shows "∃l r σ. (l,r) ∈ R ∧ (l⋅σ) = s ∧ (r⋅σ) = t"
proof -
  have "ctxt_of_pos_term [] s = Hole" by auto
  obtain l r σ where "(s,t) ∈ rstep_r_p_s R (l,r) [] σ" using assms unfolding rrstep_def by best
  then have "let C = ctxt_of_pos_term [] s in [] ∈ poss s ∧ (l,r) ∈ R ∧ C⟨l⋅σ⟩ = s ∧ C⟨r⋅σ⟩ = t" unfolding rstep_r_p_s_def by simp
  with ‹ctxt_of_pos_term [] s = Hole› have "(l,r) ∈ R" and "l⋅σ = s" and "r⋅σ = t" unfolding Let_def by auto
  then show ?thesis by auto
qed

lemma nrrstep_preserves_root:
  assumes "(Fun f ss,t) ∈ nrrstep R" (is "(?s,t) ∈ nrrstep R") shows "∃ts. t = (Fun f ts)"
  using assms unfolding nrrstep_def rstep_r_p_s_def Let_def by auto

lemma nrrstep_equiv_root: assumes "(s,t) ∈ nrrstep R" shows "∃f ss ts. s = Fun f ss ∧ t = Fun f ts"
proof -
  from assms obtain f ss where "s = Fun f ss" using nrrstep_imp_Fun by best
  with assms obtain ts where "t = Fun f ts" using nrrstep_preserves_root by best
  from ‹s = Fun f ss› and ‹t = Fun f ts› show ?thesis by best
qed

lemma nrrstep_reflects_root:
  assumes "(s,Fun g ts) ∈ nrrstep R" (is "(s,?t) ∈ nrrstep R")
  shows "∃ss. s = (Fun g ss)"
proof -
  from assms obtain f ss ts' where "s = Fun f ss" and "Fun g ts = Fun f ts'" using nrrstep_equiv_root by best
  then have "f = g" by simp
  with ‹s = Fun f ss› have "s = Fun g ss" by simp
  then show ?thesis by auto
qed

lemma nrrsteps_preserve_root:
  assumes "(Fun f ss,t) ∈ (nrrstep R)*"
  shows "∃ts. t = (Fun f ts)"
  using assms by induct (auto simp: nrrstep_preserves_root)

lemma nrrstep_Fun_imp_arg_rsteps:
  assumes "(Fun f ss,Fun f ts) ∈ nrrstep R" (is "(?s,?t) ∈ nrrstep R") and "i < length ss"
  shows "(ss!i,ts!i) ∈ (rstep R)*"
proof -
  from assms have "[i] ∈ poss ?s" using empty_pos_in_poss by simp
  from ‹(?s,?t) ∈ nrrstep R›
  obtain l r j ps σ
    where A: "let C = ctxt_of_pos_term (j#ps) ?s in (j#ps) ∈ poss ?s ∧ (l,r) ∈ R ∧ C⟨l⋅σ⟩ = ?s ∧ C⟨r⋅σ⟩ = ?t" unfolding nrrstep_def rstep_r_p_s_def by force
  let ?C = "ctxt_of_pos_term (j#ps) ?s"
  from A have "(j#ps) ∈ poss ?s" and "(l,r) ∈ R" and "?C⟨l⋅σ⟩ = ?s" and "?C⟨r⋅σ⟩ = ?t" using Let_def by auto
  have C: "?C = More f (take j ss) (ctxt_of_pos_term ps (ss!j)) (drop (Suc j) ss)" (is "?C = More f ?ss1 ?D ?ss2") by auto
  from ‹?C⟨l⋅σ⟩ = ?s› have "?D⟨l⋅σ⟩ = (ss!j)" by (auto simp: take_drop_imp_nth)
  from ‹(l,r) ∈ R› have "(l⋅σ,r⋅σ) ∈ (subst.closure R)" by auto
  then have "(?D⟨l⋅σ⟩,?D⟨r⋅σ⟩) ∈ (ctxt.closure(subst.closure R))"
    and "(?C⟨l⋅σ⟩,?C⟨r⋅σ⟩) ∈ (ctxt.closure(subst.closure R))" by (auto simp only: ctxt.closure.intros)
  then have D_rstep: "(?D⟨l⋅σ⟩,?D⟨r⋅σ⟩) ∈ rstep R" and "(?C⟨l⋅σ⟩,?C⟨r⋅σ⟩) ∈ rstep R"
    unfolding rstep_eq_closure by auto
  from ‹?C⟨r⋅σ⟩ = ?t› and C have "?t = Fun f (take j ss @ ?D⟨r⋅σ⟩ # drop (Suc j) ss)" by auto
  then have ts: "ts = (take j ss @ ?D⟨r⋅σ⟩ # drop (Suc j) ss)" by auto
  have "j = i ∨ j ≠ i" by simp
  from ‹j#ps ∈ poss ?s› have "j < length ss" by simp
  then have "(take j ss @ ?D⟨r⋅σ⟩ # drop (Suc j) ss) ! j = ?D⟨r⋅σ⟩" by (auto simp: nth_append_take)
  with ts have "ts!j = ?D⟨r⋅σ⟩" by auto
  have "j = i ∨ j ≠ i" by simp
  then show "(ss!i,ts!i) ∈ (rstep R)*"
  proof
    assume "j = i"
    with ‹ts!j = ?D⟨r⋅σ⟩› and ‹?D⟨l⋅σ⟩ = ss!j› and D_rstep show ?thesis by auto
  next
    assume "j ≠ i"
    with ‹i < length ss› and ‹j < length ss› have "(take j ss @ ?D⟨r⋅σ⟩ # drop (Suc j) ss) ! i = ss!i" by (auto simp: nth_append_take_drop_is_nth_conv)
    with ts have "ts!i = ss!i" by auto
    then show ?thesis by auto
  qed
qed

lemma nrrstep_imp_arg_rsteps:
  assumes "(s,t) ∈ nrrstep R" and "i < num_args s" shows "(args s!i,args t!i) ∈ (rstep R)*"
proof (cases s)
  fix x assume "s = Var x" then show ?thesis using assms by auto
next
  fix f ss assume "s = Fun f ss"
  then have "(Fun f ss,t) ∈ nrrstep R" using assms by simp
  then obtain ts where "t = Fun f ts" using nrrstep_preserves_root by best
  with ‹(s,t) ∈ nrrstep R› and ‹s = Fun f ss› have "(Fun f ss,Fun f ts) ∈ nrrstep R" by simp
  from  ‹s = Fun f ss› and ‹i < num_args s› have "i < length ss" by simp
  with ‹(Fun f ss,Fun f ts) ∈ nrrstep R›
  have "(ss!i,ts!i) ∈ (rstep R)*" by (rule nrrstep_Fun_imp_arg_rsteps)
  with ‹s = Fun f ss› and ‹t = Fun f ts› show ?thesis by simp
qed

lemma nrrsteps_imp_rsteps: "(s,t) ∈ (nrrstep R)* ⟹ (s,t) ∈ (rstep R)*"
proof (induct rule: rtrancl.induct)
  case (rtrancl_refl a) then show ?case by simp
next
  case (rtrancl_into_rtrancl a b c)
  then have IH: "(a,b) ∈ (rstep R)*" and nrrstep: "(b,c) ∈ nrrstep R" by auto
  from nrrstep have "(b,c) ∈ rstep R" using nrrstep_imp_rstep by auto
  with IH show ?case by auto
qed

lemma nrrstep_Fun_preserves_num_args:
  assumes "(Fun f ss,Fun f ts) ∈ nrrstep R" (is "(?s,?t) ∈ nrrstep R")
  shows "length ss = length ts"
proof -
  from assms obtain l r i ps σ
    where "let C = ctxt_of_pos_term (i#ps) ?s in (i#ps) ∈ poss ?s ∧ (l,r) ∈ R ∧ C⟨l⋅σ⟩ = ?s ∧ C⟨r⋅σ⟩ = ?t" (is "let C = ?C in _")
    unfolding nrrstep_def rstep_r_p_s_def by force
  then have "(l,r) ∈ R" and Cl: "?C⟨l⋅σ⟩ = ?s" and Cr: "?C⟨r⋅σ⟩ = ?t" unfolding Let_def by auto
  have C: "?C = More f (take i ss) (ctxt_of_pos_term ps (ss!i)) (drop (Suc i) ss)" (is "?C = More f ?ss1 ?D ?ss2") by simp
  from C and Cl have s: "?s = Fun f (take i ss @ ?D⟨l⋅σ⟩ # drop (Suc i) ss)" (is "?s = Fun f ?ss") by simp
  from C and Cr have t: "?t = Fun f (take i ss @ ?D⟨r⋅σ⟩ # drop (Suc i) ss)" (is "?t = Fun f ?ts") by simp
  from s and t have ss: "ss = ?ss" and ts: "ts = ?ts" by auto
  have "length ?ss = length ?ts" by auto
  with ss and ts show ?thesis by simp
qed

lemma nrrstep_equiv_num_args:
  assumes "(s,t) ∈ nrrstep R" shows "num_args s = num_args t"
proof -
  from assms obtain f ss ts where s:"s = Fun f ss" and t:"t = Fun f ts" using nrrstep_equiv_root by best
  with assms have "(Fun f ss,Fun f ts) ∈ nrrstep R" by simp
  then have "length ss = length ts" by (rule nrrstep_Fun_preserves_num_args)
  with s and t show ?thesis by auto
qed

lemma nrrsteps_equiv_num_args:
  assumes "(s,t) ∈ (nrrstep R)*" shows "num_args s = num_args t"
  using assms by (induct, auto simp: nrrstep_equiv_num_args)

lemma nrrstep_preserves_num_args:
  assumes "(s,t) ∈ nrrstep R" and "i < num_args s" shows "i < num_args t"
proof (cases s)
  fix x assume "s = Var x" then show ?thesis using assms by auto
next
  fix f ss assume "s = Fun f ss"
  with assms obtain ts where "t = Fun f ts" using nrrstep_preserves_root by best
  from ‹(s,t) ∈ nrrstep R› have "length ss = length ts" unfolding ‹s = Fun f ss› and ‹t = Fun f ts› by (rule nrrstep_Fun_preserves_num_args)
  with assms and ‹s = Fun f ss› and ‹t = Fun f ts› show ?thesis by auto
qed

lemma nrrstep_reflects_num_args:
  assumes "(s,t) ∈ nrrstep R" and "i < num_args t" shows "i < num_args s"
proof (cases t)
  fix x assume "t = Var x" then show ?thesis using assms by auto
next
  fix g ts assume "t = Fun g ts"
  with assms obtain ss where "s = Fun g ss" using nrrstep_reflects_root by best
  from ‹(s,t) ∈ nrrstep R› have "length ss = length ts" unfolding ‹s = Fun g ss› and ‹t = Fun g ts› by (rule nrrstep_Fun_preserves_num_args)
  with assms and ‹s = Fun g ss› and ‹t = Fun g ts› show ?thesis by auto
qed

lemma nrrsteps_imp_arg_rsteps:
  assumes "(s,t) ∈ (nrrstep R)*" and "i < num_args s"
  shows "(args s!i,args t!i) ∈ (rstep R)*"
  using assms
proof (induct rule: rtrancl.induct)
  case (rtrancl_refl a) then show ?case by auto
next
  case (rtrancl_into_rtrancl a b c)
  then have IH: "(args a!i,args b!i) ∈ (rstep R)*" by auto
  from ‹(a,b) ∈ (nrrstep R)*› and ‹i < num_args a› have "i < num_args b" by induct (auto simp: nrrstep_preserves_num_args)
  with ‹(b,c) ∈ nrrstep R›
  have "(args b!i,args c!i) ∈ (rstep R)*" by (rule nrrstep_imp_arg_rsteps)
  with IH show ?case by simp
qed

lemma nrrsteps_imp_eq_root_arg_rsteps:
  assumes steps: "(s,t) ∈ (nrrstep R)*"
  shows "root s = root t ∧ (∀i<num_args s. (s |_ [i], t |_ [i] ) ∈ (rstep R)*)"
proof (cases s)
  case (Var x)
  have "s = t" using steps unfolding Var
  proof (induct)
    case (step y z)
    from nrrstep_imp_Fun[OF step(2)] step(3) have False by auto
    then show ?case ..
  qed simp
  then show ?thesis by auto
next
  case (Fun f ss)
  from nrrsteps_equiv_num_args[OF steps]
    nrrsteps_imp_arg_rsteps[OF steps]
    nrrsteps_preserve_root[OF steps[unfolded Fun]]
  show ?thesis unfolding Fun by auto
qed

lemma SN_on_imp_SN_on_subt:
  assumes "SN_on (rstep R) {t}" shows "∀s⊴t. SN_on (rstep R) {s}"
proof (rule ccontr)
  assume "¬(∀s⊴t. SN_on (rstep R) {s})"
  then obtain s where "t ⊵ s" and "¬ SN_on (rstep R) {s}" by auto
  then obtain S where "S 0 = s" and chain: "chain (rstep R) S" by auto
  from ‹t ⊵ s› obtain C where t: "t = C⟨s⟩" by auto
  let ?S = "λi. C⟨S i⟩"
  from ‹S 0 = s› have "?S 0 = t" by (simp add: t)
  moreover from chain have "chain (rstep R) ?S" by blast
  ultimately have "¬ SN_on (rstep R) {t}" by best
  with assms show False by simp
qed

lemma not_SN_on_subt_imp_not_SN_on:
  assumes "¬ SN_on (rstep R) {t}" and "s ⊵ t"
  shows "¬ SN_on (rstep R) {s}"
  using assms SN_on_imp_SN_on_subt by blast

lemma SN_on_instance_imp_SN_on_var:
  assumes "SN_on (rstep R) {t ⋅ σ}" and "x ∈ vars_term t"
  shows "SN_on (rstep R) {Var x ⋅ σ}"
proof -
  from assms have "t ⊵ Var x" by auto
  then have "t⋅σ ⊵ (Var x)⋅σ" by (rule supteq_subst)
  with SN_on_imp_SN_on_subt and assms show ?thesis by best
qed

lemma var_imp_var_of_arg:
  assumes "x ∈ vars_term (Fun f ss)" (is "x ∈ vars_term ?s")
  shows "∃i < num_args (Fun f ss). x ∈ vars_term (ss!i)"
proof -
  from assms have "x ∈ ⋃(set (map vars_term ss))" by simp
  then have "x ∈ (⋃i<length ss. vars_term(ss!i))" unfolding set_conv_nth by auto
  then have "∃i<length ss. x ∈ vars_term(ss!i)" using UN_iff by best
  then obtain i where "i < length ss" and "x ∈ vars_term(ss!i)" by auto
  then have "i < num_args ?s" by simp
  with ‹x ∈ vars_term(ss!i)› show ?thesis by auto
qed

lemma subt_instance_and_not_subst_imp_subt:
  "s⋅σ ⊵ t ⟹ ∀x ∈ vars_term s. ¬((Var x)⋅σ ⊵ t) ⟹ ∃u. s ⊵ u ∧ t = u⋅σ"
proof (induct s arbitrary: t rule: term.induct)
  case (Var x) then show ?case by auto
next
  case (Fun f ss)
  from ‹Fun f ss⋅σ ⊵ t› have "(Fun f ss⋅σ = t) ∨ (Fun f ss⋅σ ⊳ t)" by auto
  then show ?case
  proof
    assume "Fun f ss⋅σ = t" with Fun show ?thesis by auto
  next
    assume "Fun f ss⋅σ ⊳ t"
    then have "Fun f (map (λt. t⋅σ) ss) ⊳ t" by simp
    then have "∃s ∈ set (map (λt. t⋅σ) ss). s ⊵ t" (is "∃s ∈ set ?ss'. s ⊵ t") by (rule supt_Fun_imp_arg_supteq)
    then obtain s' where "s' ∈ set ?ss'" and "s' ⊵ t" by best
    then have "∃i < length ?ss'. ?ss'!i = s'" using in_set_conv_nth[where ?x = "s'"] by best
    then obtain i where "i < length ?ss'" and "?ss'!i = s'" by best
    then have "?ss'!i = (ss!i)⋅σ" by auto
    from ‹?ss'!i = s'› have "s' = (ss!i)⋅σ" unfolding ‹?ss'!i = (ss!i)⋅σ› by simp
    from ‹s' ⊵ t› have "(ss!i)⋅σ ⊵ t" unfolding ‹s' = (ss!i)⋅σ› by simp
    with ‹i < length ?ss'› have "(ss!i) ∈ set ss" by auto
    with ‹(ss!i)⋅σ ⊵ t› have "∃s ∈ set ss. s⋅σ ⊵ t" by best
    then obtain s where "s ∈ set ss" and "s⋅σ ⊵ t" by best
    with Fun have "∀x ∈ vars_term s. ¬((Var x)⋅σ ⊵ t)" by force
    from Fun
    have IH: "s ∈ set ss ⟶ (∀v. s⋅σ ⊵ v ⟶ (∀x ∈ vars_term s. ¬ Var x⋅σ ⊵ v) ⟶ (∃u. s ⊵ u ∧ v = u⋅σ))"
      by auto
    with ‹s ∈ set ss› have "!!v. s⋅σ ⊵ v ⟹ (∀x ∈ vars_term s. ¬ Var x⋅σ ⊵ v) ⟶ (∃u. s ⊵ u ∧ v = u⋅σ)"
      by simp
    with ‹s⋅σ ⊵ t› have "(∀x ∈ vars_term s. ¬ Var x⋅σ ⊵ t) ⟶ (∃u. s ⊵ u ∧ t = u⋅σ)" by simp
    with ‹∀x ∈ vars_term s. ¬ Var x⋅σ ⊵ t› obtain u where "s ⊵ u" and "t = u⋅σ" by best
    with ‹s ∈ set ss› have "Fun f ss ⊵ u" by auto
    with ‹t = u⋅σ› show ?thesis by best
  qed
qed

lemma SN_imp_SN_subt:
  "SN_on (rstep R) {s} ⟹ s ⊵ t ⟹ SN_on (rstep R) {t}"
  by (rule ctxt_closed_SN_on_subt[OF ctxt_closed_rstep])

lemma subterm_preserves_SN_gen:
  assumes ctxt: "ctxt.closed R"
    and SN: "SN_on R {t}" and supt: "t ⊳ s"
  shows "SN_on R {s}"
proof -
  from supt have "t ⊵ s" by auto
  then show ?thesis using ctxt_closed_SN_on_subt[OF ctxt SN, of s] by simp
qed

context E_compatible
begin

lemma SN_on_step_E_imp_SN_on: assumes "SN_on R {s}"
  and "(s,t) ∈ E"
shows "SN_on R {t}"
  using assms E(1) unfolding SN_on_all_reducts_SN_on_conv[of _ t] SN_on_all_reducts_SN_on_conv[of _ s]
  by blast

lemma SN_on_step_REs_imp_SN_on:
  assumes R: "ctxt.closed R"
    and st: "(s,t) ∈ (R ∪ E O {⊳} O E)"
    and SN: "SN_on R {s}"
  shows "SN_on R {t}"
proof (cases "(s,t) ∈ R")
  case True
  from step_preserves_SN_on[OF this SN] show ?thesis .
next
  case False
  with st obtain u v where su: "(s,u) ∈ E" and uv: "u ⊳ v" and vt: "(v,t) ∈ E" by auto
  have u: "SN_on R {u}" by (rule SN_on_step_E_imp_SN_on[OF SN su])
  with uv R have "SN_on R {v}" by (metis subterm_preserves_SN_gen)
  then show ?thesis by (rule SN_on_step_E_imp_SN_on[OF _ vt])
qed

lemma restrict_SN_supt_E_I:
  "ctxt.closed R ⟹ SN_on R {s} ⟹ (s,t) ∈ R ∪ E O {⊳} O E ⟹ (s,t) ∈ restrict_SN_supt_E"
  unfolding restrict_SN_supt_E_def restrict_SN_def
  using SN_on_step_REs_imp_SN_on[of s t] E(2) by auto

lemma ctxt_closed_imp_SN_on_E_supt:
  assumes R: "ctxt.closed R"
    and SN: "SN (E O {⊳} O E)"
  shows "SN_on (R ∪ E O {⊳} O E) {t. SN_on R {t}}"
proof -
  {
    fix f
    assume f0: "SN_on R {f 0}" and f: "⋀ i. (f i, f (Suc i)) ∈ R ∪ E O {⊳} O E"
    from ctxt_closed_imp_SN_restrict_SN_E_supt[OF assms]
    have SN: "SN restrict_SN_supt_E" .
    {
      fix i
      have "SN_on R {f i}"
        by (induct i, rule f0, rule SN_on_step_REs_imp_SN_on[OF R f])
    } note fi = this
    {
      fix i
      from f[of i] fi[of i]
      have "(f i, f (Suc i)) ∈ restrict_SN_supt_E" by (metis restrict_SN_supt_E_I[OF R])
    }
    with SN have False by auto
  }
  then show ?thesis unfolding SN_on_def by blast
qed
end

lemma subterm_preserves_SN:
  "SN_on (rstep R) {t} ⟹ t ⊳ s ⟹ SN_on (rstep R) {s}"
  by (rule subterm_preserves_SN_gen[OF ctxt_closed_rstep])

lemma SN_on_r_imp_SN_on_supt_union_r:
  assumes ctxt: "ctxt.closed R"
    and "SN_on R T"
  shows "SN_on (supt ∪ R) T" (is "SN_on ?S T")
proof (rule ccontr)
  assume "¬ SN_on ?S T"
  then obtain s where ini: "s 0 : T" and chain: "chain ?S s"
    unfolding SN_on_def by auto
  have SN: "∀i. SN_on R {s i}"
  proof
    fix i show "SN_on R {s i}"
    proof (induct i)
      case 0 show ?case using assms using ‹s 0 ∈ T› and SN_on_subset2[of "{s 0}" T R] by simp
    next
      case (Suc i)
      from chain have "(s i, s (Suc i)) ∈ ?S" by simp
      then show ?case
      proof
        assume "(s i, s (Suc i)) ∈ supt"
        from subterm_preserves_SN_gen[OF ctxt Suc this] show ?thesis .
      next
        assume "(s i, s (Suc i)) ∈ R"
        from step_preserves_SN_on[OF this Suc] show ?thesis .
      qed
    qed
  qed
  have "¬ (∃S. ∀i. (S i, S (Suc i)) ∈ restrict_SN_supt R)"
    using ctxt_closed_imp_SN_restrict_SN_supt[OF ctxt] unfolding SN_defs by auto
  moreover have "∀i. (s i, s (Suc i)) ∈ restrict_SN_supt R"
  proof
    fix i
    from SN have SN: "SN_on R {s i}" by simp
    from chain have "(s i, s (Suc i)) ∈ supt ∪ R" by simp
    then show "(s i, s (Suc i)) ∈ restrict_SN_supt R"
      unfolding restrict_SN_supt_def restrict_SN_def using SN by auto
  qed
  ultimately show False by auto
qed

lemma SN_on_rstep_imp_SN_on_supt_union_rstep:
  "SN_on (rstep R) T ⟹ SN_on (supt ∪ rstep R) T"
  by (rule SN_on_r_imp_SN_on_supt_union_r[OF ctxt_closed_rstep])

lemma SN_supt_r_trancl:
  assumes ctxt: "ctxt.closed R"
    and a: "SN R"
  shows "SN ((supt ∪ R)+)"
proof -
  have "SN (supt ∪ R)"
    using SN_on_r_imp_SN_on_supt_union_r[OF ctxt, of UNIV]
      and a by force
  then show "SN ((supt ∪ R)+)" by (rule SN_imp_SN_trancl)
qed

lemma SN_supt_rstep_trancl:
  "SN (rstep R) ⟹ SN ((supt ∪ rstep R)+)"
  by (rule SN_supt_r_trancl[OF ctxt_closed_rstep])

lemma SN_imp_SN_arg_gen:
  assumes ctxt: "ctxt.closed R"
    and SN: "SN_on R {Fun f ts}" and arg: "t ∈ set ts" shows "SN_on R {t}"
proof -
  from arg have "Fun f ts ⊵ t" by auto
  with SN show ?thesis by (rule ctxt_closed_SN_on_subt[OF ctxt])
qed

lemma SN_imp_SN_arg:
  "SN_on (rstep R) {Fun f ts} ⟹ t ∈ set ts ⟹ SN_on (rstep R) {t}"
  by (rule SN_imp_SN_arg_gen[OF ctxt_closed_rstep])

lemma SNinstance_imp_SN:
  assumes "SN_on (rstep R) {t ⋅ σ}"
  shows "SN_on (rstep R) {t}"
proof
  fix f
  assume prem: "f 0 ∈ {t}" "∀i. (f i, f (Suc i)) ∈ rstep R" 
  let ?g = "λ i. (f i) ⋅ σ"
  from prem have "?g 0 = t ⋅ σ ∧ (∀ i. (?g i, ?g (Suc i)) ∈ rstep R)" using subst_closed_rstep
    by auto
  then have "¬ SN_on (rstep R) {t ⋅ σ}" by auto
  with assms show False by blast
qed

lemma rstep_imp_C_s_r:
  assumes "(s,t) ∈ rstep R"
  shows "∃C σ l r. (l,r) ∈ R ∧ s = C⟨l⋅σ⟩ ∧ t = C⟨r⋅σ⟩"
proof -
  from assms obtain l r p σ where step:"(s,t) ∈ rstep_r_p_s R (l,r) p σ"
    unfolding rstep_iff_rstep_r_p_s by best
  let ?C = "ctxt_of_pos_term p s"
  from step have "p ∈ poss s" and "(l,r) ∈ R" and "?C⟨l⋅σ⟩ = s" and "?C⟨r⋅σ⟩ = t"
    unfolding rstep_r_p_s_def Let_def by auto
  then have "(l,r) ∈ R ∧ s = ?C⟨l⋅σ⟩ ∧ t = ?C⟨r⋅σ⟩" by auto
  then show ?thesis by force
qed

fun map_funs_rule :: "('f ⇒ 'g) ⇒ ('f, 'v) rule ⇒ ('g, 'v) rule"
  where
    "map_funs_rule fg lr = (map_funs_term fg (fst lr), map_funs_term fg (snd lr))"

fun map_funs_trs :: "('f ⇒ 'g) ⇒ ('f, 'v) trs ⇒ ('g, 'v) trs"
  where
    "map_funs_trs fg R = map_funs_rule fg ` R"

lemma map_funs_trs_union: "map_funs_trs fg (R ∪ S) = map_funs_trs fg R ∪ map_funs_trs fg S"
  unfolding map_funs_trs.simps by auto

lemma rstep_map_funs_term: assumes R: "⋀ f. f ∈ funs_trs R ⟹ h f = f" and step: "(s,t) ∈ rstep R"
  shows "(map_funs_term h s, map_funs_term h t) ∈ rstep R"
proof -
  from step obtain C l r σ where s: "s = C⟨l ⋅ σ⟩" and t: "t = C⟨r ⋅ σ⟩" and rule: "(l,r) ∈ R" by auto
  let ?σ = "map_funs_subst h σ"
  let ?h = "map_funs_term h"
  note funs_defs = funs_rule_def[abs_def] funs_trs_def
  from rule have lr: "funs_term l ∪ funs_term r ⊆ funs_trs R" unfolding funs_defs
    by auto
  have hl: "?h l = l"
    by (rule funs_term_map_funs_term_id[OF R], insert lr, auto)
  have hr: "?h r = r"
    by (rule funs_term_map_funs_term_id[OF R], insert lr, auto)
  show ?thesis unfolding s t
    unfolding map_funs_subst_distrib map_funs_term_ctxt_distrib hl hr
    by (rule rstepI[OF rule refl refl])
qed

lemma wf_trs_map_funs_trs[simp]: "wf_trs (map_funs_trs f R) = wf_trs R"
  unfolding wf_trs_def
proof (rule iffI, intro allI impI)
  fix l r
  assume "∀l r. (l, r) ∈ map_funs_trs f R ⟶ (∃f ts. l = Fun f ts) ∧ vars_term r ⊆ vars_term l" and "(l, r) ∈ R"
  then show "(∃f ts. l = Fun f ts) ∧ vars_term r ⊆ vars_term l" by (cases l, force+)
next
  assume ass: " ∀l r. (l, r) ∈ R ⟶ (∃f ts. l = Fun f ts) ∧ vars_term r ⊆ vars_term l"
  show "∀l r. (l, r) ∈ map_funs_trs f R ⟶ (∃f ts. l = Fun f ts) ∧ vars_term r ⊆ vars_term l"
  proof (intro allI impI)
    fix l r
    assume "(l, r) ∈ map_funs_trs f R"
    with ass
    show "(∃f ts. l = Fun f ts) ∧ vars_term r ⊆ vars_term l"
      by (cases l, force+)
  qed
qed

lemma map_funs_trs_comp: "map_funs_trs fg (map_funs_trs gh R) = map_funs_trs (fg o gh) R"
proof -
  have mr: "map_funs_rule (fg o gh) = map_funs_rule fg o map_funs_rule gh"
    by (rule ext, auto simp: map_funs_term_comp)
  then show ?thesis
    by (auto simp: map_funs_term_comp image_comp mr)
qed

lemma map_funs_trs_mono: assumes "R ⊆ R'" shows "map_funs_trs fg R ⊆ map_funs_trs fg R'"
  using assms by auto

lemma map_funs_trs_power_mono:
  fixes R R' :: "('f,'v)trs" and fg :: "'f ⇒ 'f"
  assumes "R ⊆ R'" shows "((map_funs_trs fg)^^n) R ⊆ ((map_funs_trs fg)^^n) R'"
  using assms by (induct n, simp, auto)

declare map_funs_trs.simps[simp del]

lemma rstep_imp_map_rstep:
  assumes "(s, t) ∈ rstep R"
  shows "(map_funs_term fg s, map_funs_term fg t) ∈ rstep (map_funs_trs fg R)"
  using assms
proof (induct)
  case (IH C σ l r)
  then have "(map_funs_term fg l, map_funs_term fg r) ∈ map_funs_trs fg R" (is "(?l, ?r) ∈ ?R")
    unfolding map_funs_trs.simps by force
  then have "(?l, ?r) ∈ rstep ?R" ..
  then have "(?l ⋅ map_funs_subst fg σ, ?r ⋅ map_funs_subst fg σ) ∈ rstep ?R" ..
  then show ?case by auto
qed

lemma rsteps_imp_map_rsteps: assumes "(s,t) ∈ (rstep R)*"
  shows "(map_funs_term fg s, map_funs_term fg t) ∈ (rstep (map_funs_trs fg R))*"
  using assms
proof (induct, clarify)
  case (step y z)
  then have "(map_funs_term fg y, map_funs_term fg z) ∈ rstep (map_funs_trs fg R)" using rstep_imp_map_rstep
    by (auto simp: map_funs_trs.simps)
  with step show ?case by auto
qed

lemma SN_map_imp_SN:
  assumes SN: "SN_on (rstep (map_funs_trs fg R)) {map_funs_term fg t}"
  shows "SN_on (rstep R) {t}"
proof (rule ccontr)
  assume "¬ SN_on (rstep R) {t}"
  from this obtain f where cond: "f 0 = t ∧ (∀ i. (f i, f (Suc i)) ∈ rstep R)"
    unfolding SN_on_def by auto
  obtain g where g: "g = (λ i. map_funs_term fg (f i))" by auto
  with cond have cond2: "g 0 = map_funs_term fg t ∧ (∀ i. (g i, g (Suc i)) ∈ rstep (map_funs_trs fg R))"
    using rstep_imp_map_rstep[where fg = fg] by blast
  from SN
  have "¬ (∃ g. (g 0 = map_funs_term fg t ∧ (∀ i. (g i, g (Suc i)) ∈ rstep (map_funs_trs fg R))))"
    unfolding SN_on_def by auto
  with cond2 show False  by auto
qed

lemma rstep_iff_map_rstep:
  assumes "inj fg"
  shows "(s, t) ∈ rstep R ⟷ (map_funs_term fg s, map_funs_term fg t) ∈ rstep (map_funs_trs fg R)"
proof
  assume "(s,t) ∈ rstep R"
  then show "(map_funs_term fg s, map_funs_term fg t) ∈ rstep(map_funs_trs fg R)"
    by (rule rstep_imp_map_rstep)
next
  assume "(map_funs_term fg s, map_funs_term fg t) ∈ rstep (map_funs_trs fg R)"
  then have "(map_funs_term fg s, map_funs_term fg t) ∈ ctxt.closure(subst.closure(map_funs_trs fg R))"
    by (simp add: rstep_eq_closure)
  then obtain C u v where "(u,v) ∈ subst.closure(map_funs_trs fg R)" and "C⟨u⟩ = map_funs_term fg s"
    and "C⟨v⟩ = map_funs_term fg t"
    by (cases rule: ctxt.closure.cases) force
  then obtain σ w x where "(w,x) ∈ map_funs_trs fg R" and "w⋅σ = u" and "x⋅σ = v"
    by (cases rule: subst.closure.cases) force
  then obtain l r where "w = map_funs_term fg l" and "x = map_funs_term fg r"
    and "(l,r) ∈ R" by (auto simp: map_funs_trs.simps)
  have ps: "C⟨map_funs_term fg l ⋅ σ⟩ = map_funs_term fg s" and pt: "C⟨map_funs_term fg r ⋅ σ⟩ = map_funs_term fg t"
    unfolding ‹w = map_funs_term fg l›[symmetric] ‹x = map_funs_term fg r›[symmetric] ‹w⋅σ = u› ‹x⋅σ = v›
      ‹C⟨u⟩ = map_funs_term fg s› ‹C⟨v⟩ = map_funs_term fg t› by auto
  let ?gf = "the_inv fg"
  let ?C = "map_funs_ctxt ?gf C"
  let ?σ = "map_funs_subst ?gf σ"
  have gffg: "?gf ∘ fg = id" using the_inv_f_f[OF assms] by (intro ext, auto)
  from ps and pt have "s = map_funs_term ?gf (C⟨map_funs_term fg l ⋅ σ⟩)"
    and "t = map_funs_term ?gf (C⟨map_funs_term fg r ⋅ σ⟩)" by (auto simp: map_funs_term_comp gffg)
  then have s: "s = ?C⟨map_funs_term ?gf (map_funs_term fg l ⋅ σ)⟩"
    and t: "t = ?C⟨map_funs_term ?gf (map_funs_term fg r ⋅ σ)⟩" using map_funs_term_ctxt_distrib by auto
  from s have "s = ?C⟨l⋅?σ⟩" by (simp add: map_funs_term_comp gffg)
  from t have "t = ?C⟨r⋅?σ⟩" by (simp add: map_funs_term_comp gffg)
  from ‹(l, r) ∈ R› have "(l⋅?σ, r⋅?σ) ∈ subst.closure R" by blast
  then have "(?C⟨l⋅?σ⟩,?C⟨r⋅?σ⟩) ∈ ctxt.closure(subst.closure R)" by blast
  then show "(s,t) ∈ rstep R" unfolding ‹s = ?C⟨l⋅?σ⟩› ‹t = ?C⟨r⋅?σ⟩› by (simp add: rstep_eq_closure)
qed

lemma rstep_map_funs_trs_power_mono:
  fixes R R' :: "('f,'v)trs" and fg :: "'f ⇒ 'f"
  assumes subset: "R ⊆ R'" shows "rstep (((map_funs_trs fg)^^n) R) ⊆ rstep (((map_funs_trs fg)^^n) R')"
  by (rule rstep_mono, rule map_funs_trs_power_mono, rule subset)

lemma subsetI3: "(⋀x y z. (x, y, z) ∈ A ⟹ (x, y, z) ∈ B) ⟹ A ⊆ B" by auto

lemma aux: "(⋃a∈P. {(x,y,z). x = fst a ∧ y = snd a ∧ Q a z}) = {(x,y,z). (x,y) ∈ P ∧ Q (x,y) z}" (is "?P = ?Q")
proof
  show "?P ⊆ ?Q"
  proof
    fix x assume "x ∈ ?P"
    then obtain a where "a ∈ P" and "x ∈ {(x,y,z). x = fst a ∧ y = snd a ∧ Q a z}" by auto
    then obtain b where "Q (fst x, fst (snd x)) (snd (snd x))" and "(fst x, fst (snd x)) = a" and "snd (snd x) = b" by force
    from ‹a ∈ P› have "(fst a,snd a) ∈ P" unfolding split_def by simp
    from ‹Q (fst x, fst (snd x)) (snd (snd x))› have "Q a b" unfolding ‹(fst x, fst (snd x)) = a› ‹snd (snd x) = b› .
    from ‹(fst a,snd a) ∈ P› and ‹Q a b› show "x ∈ ?Q" unfolding split_def ‹(fst x, fst (snd x)) = a›[symmetric] ‹snd (snd x) = b›[symmetric] by simp
  qed
next
  show "?Q ⊆ ?P"
  proof (rule subsetI3)
    fix x y z assume "(x,y,z) ∈ ?Q"
    then have "(x,y) ∈ P" and "Q (x,y) z" by auto
    then have "x = fst(x,y) ∧ y = snd(x,y) ∧ Q (x,y) z" by auto
    then have "(x,y,z) ∈ {(x,y,z). x = fst(x,y) ∧ y = snd(x,y) ∧ Q (x,y) z}" by auto
    then have "∃p∈P. (x,y,z) ∈ {(x,y,z). x = fst p ∧ y = snd p ∧ Q p z}" using ‹(x,y) ∈ P› by blast
    then show "(x,y,z) ∈ ?P" unfolding UN_iff[symmetric] by simp
  qed
qed

lemma finite_imp_finite_DP_on':
  assumes "finite R"
  shows "finite {(l, r, u).
    ∃h us. u = Fun h us ∧ (l, r) ∈ R ∧ r ⊵ u ∧ (h, length us) ∈ F ∧ ¬ (l ⊳ u)}"
proof -
  have "⋀l r. (l, r) ∈ R ⟹ finite {u. r ⊵ u}"
  proof -
    fix l r
    assume "(l, r) ∈ R"
    show "finite {u. r ⊵ u}" by (rule finite_subterms)
  qed
  with ‹finite R› have "finite(⋃(l, r) ∈ R. {u. r ⊵ u})" by auto
  have "finite(⋃lr∈R. {(l, r, u). l = fst lr ∧ r = snd lr ∧ snd lr ⊵ u})"
  proof (rule finite_UN_I)
    show "finite R" by (rule ‹finite R›)
  next
    fix lr
    assume "lr ∈ R"
    have "finite {u. snd lr ⊵ u}" by (rule finite_subterms)
    then show "finite {(l,r,u). l = fst lr ∧ r = snd lr ∧ snd lr ⊵ u}" by auto
  qed
  then have "finite {(l,r,u). (l,r) ∈ R ∧ r ⊵ u}" unfolding aux by auto
  have "{(l,r,u). (l,r) ∈ R ∧ r ⊵ u} ⊇ {(l,r,u). (∃h us. u = Fun h us ∧ (l,r) ∈ R ∧ r ⊵ u ∧ (h, length us) ∈ F ∧ ¬(l ⊳ u))}" by auto
  with ‹finite {(l,r,u). (l,r) ∈ R ∧ r ⊵ u}› show ?thesis using finite_subset by fast
qed

lemma card_image_le':
  assumes "finite S"
  shows "card (⋃y∈S.{x. x = f y}) ≤ card S"
proof -
  have A:"(⋃y∈S. {x. x = f y}) = f ` S" by auto
  from assms show ?thesis unfolding A using card_image_le by auto
qed

lemma subteq_of_map_imp_map: "map_funs_term g s ⊵ t ⟹ ∃u. t = map_funs_term g u"
proof (induct s arbitrary: t)
  case (Var x)
  then have "map_funs_term g (Var x) ⊳ t ∨ map_funs_term g (Var x) = t" by auto
  then show ?case
  proof
    assume "map_funs_term g (Var x) ⊳ t" then show ?thesis by (cases rule: supt.cases) auto
  next
    assume "map_funs_term g (Var x) = t" then show ?thesis by best
  qed
next
  case (Fun f ss)
  then have "map_funs_term g (Fun f ss) ⊳ t ∨ map_funs_term g (Fun f ss) = t" by auto
  then show ?case
  proof
    assume "map_funs_term g (Fun f ss) ⊳ t"
    then show ?case using Fun by (cases rule: supt.cases) (auto simp: supt_supteq_conv)
  next
    assume "map_funs_term g (Fun f ss) = t" then show ?thesis by best
  qed
qed

lemma map_funs_term_inj:
  assumes "inj (fg :: ('f ⇒ 'g))"
  shows "inj (map_funs_term fg)"
proof -
  {
    fix s t :: "('f,'v)term"
    assume "map_funs_term fg s = map_funs_term fg t"
    then have "s = t"
    proof (induct s arbitrary: t)
      case (Var x) with assms show ?case by (induct t) auto
    next
      case (Fun f ss) then show ?case
      proof (induct t)
        case (Var y) then show ?case by auto
      next
        case (Fun g ts)
        then have A: "map (map_funs_term fg) ss = map (map_funs_term fg) ts" by simp
        then have len_eq:"length ss = length ts" by (rule map_eq_imp_length_eq)
        from A have "!!i. i < length ss ⟹ (map (map_funs_term fg) ss)!i = (map (map_funs_term fg) ts)!i" by auto
        with len_eq have eq: "!!i. i < length ss ⟹ map_funs_term fg  (ss!i) = map_funs_term fg (ts!i)" using nth_map by auto
        have in_set: "!!i. i < length ss ⟹ (ss!i) ∈ set ss" by auto
        from Fun have "∀i < length ss. (ss!i) = (ts!i)" using in_set eq by auto
        with len_eq have "ss = ts" using nth_equalityI[where xs = ss and ys = ts] by simp
        have "f = g" using Fun ‹inj fg› unfolding inj_on_def by auto
        with ‹ss = ts› show ?case by simp
      qed
    qed
  }
  then show ?thesis unfolding inj_on_def by auto
qed

lemma rsteps_closed_ctxt:
  assumes "(s, t) ∈ (rstep R)*"
  shows "(C⟨s⟩, C⟨t⟩) ∈ (rstep R)*"
proof -
  from assms obtain n where "(s,t) ∈ (rstep R)^^n"
    using rtrancl_is_UN_relpow by auto
  then show ?thesis
  proof (induct n arbitrary: s)
    case 0 then show ?case by auto
  next
    case (Suc n)
    from relpow_Suc_D2[OF ‹(s,t) ∈ (rstep R)^^Suc n›] obtain u
      where "(s,u) ∈ (rstep R)" and "(u,t) ∈ (rstep R)^^n" by auto
    from ‹(s,u) ∈ (rstep R)› have "(C⟨s⟩,C⟨u⟩) ∈ (rstep R)" ..
    from Suc and ‹(u,t) ∈ (rstep R)^^n› have "(C⟨u⟩,C⟨t⟩) ∈ (rstep R)*" by simp
    with ‹(C⟨s⟩,C⟨u⟩) ∈ (rstep R)› show ?case by auto
  qed
qed

lemma one_imp_ctxt_closed: assumes one: "⋀ f bef s t aft. (s,t) ∈ r ⟹ (Fun f (bef @ s # aft), Fun f (bef @ t # aft)) ∈ r"
  shows "ctxt.closed r"
proof
  fix s t C
  assume st: "(s,t) ∈ r"
  show "(C⟨s⟩, C⟨t⟩) ∈ r"
  proof (induct C)
    case (More f bef C aft)
    from one[OF More] show ?case by auto
  qed (insert st, auto)
qed

lemma ctxt_closed_nrrstep [intro]: "ctxt.closed (nrrstep R)"
proof (rule one_imp_ctxt_closed)
  fix f bef s t aft
  assume "(s,t) ∈ nrrstep R"
  from this[unfolded nrrstep_def'] obtain l r C σ
    where lr: "(l,r) ∈ R" and C: "C ≠ □"
      and s: "s = C⟨l⋅σ⟩" and t: "t = C⟨r ⋅ σ⟩" by auto
  show "(Fun f (bef @ s # aft), Fun f (bef @ t # aft)) ∈ nrrstep R"
  proof (rule nrrstepI[OF lr])
    show "More f bef C aft ≠ □" by simp
  qed (insert s t, auto)
qed

definition all_ctxt_closed :: "'f sig ⇒ ('f, 'v) trs ⇒ bool" 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)"

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 all_ctxt_closed_sig_reflE: assumes all: "all_ctxt_closed F r"
  shows "funas_term t ⊆ F ⟹ (t,t) ∈ r"
proof (induct t)
  case (Var x)
  from all[unfolded all_ctxt_closed_def] show ?case by auto
next
  case (Fun f ts)
  show ?case
    by (rule all_ctxt_closedD[OF all _ _ Fun(1)], insert Fun(2), force+)
qed

lemma all_ctxt_closed_reflE: assumes all: "all_ctxt_closed UNIV r"
  shows "(t,t) ∈ r"
  by (rule all_ctxt_closed_sig_reflE[OF all], auto)

lemma all_ctxt_closed_relcomp: assumes "all_ctxt_closed UNIV R" "all_ctxt_closed UNIV S"
  shows "all_ctxt_closed UNIV (R O S)"
  unfolding all_ctxt_closed_def
proof (intro allI impI conjI)
  show "(Var x, Var x) ∈ R O S" for x using assms unfolding all_ctxt_closed_def by auto
  fix f ts ss
  assume len: "length ts = length ss" 
    and steps: "∀i<length ts. (ts ! i, ss ! i) ∈ R O S" 
  hence "∀ i. ∃ us. i < length ts ⟶ (ts ! i, us) ∈ R ∧ (us, ss ! i) ∈ S" by blast
  from choice[OF this] obtain us where steps: "⋀ i. i<length ts ⟹ (ts ! i, us i) ∈ R ∧ (us i, ss ! i) ∈ S" 
    by blast
  let ?us = "map us [0..<length ss]" 
  from all_ctxt_closedD[OF assms(2)] steps len have us: "(Fun f ?us, Fun f ss) ∈ S" by auto
  from all_ctxt_closedD[OF assms(1)] steps len have tu: "(Fun f ts, Fun f ?us) ∈ R" by force
  from tu us 
  show "(Fun f ts, Fun f ss) ∈ R O S" by auto
qed

lemma all_ctxt_closed_relpow:
  assumes acc:"all_ctxt_closed UNIV Q"
  shows "all_ctxt_closed UNIV (Q ^^ n)"
proof (induct n)
  case 0
  thus ?case by (auto simp: all_ctxt_closed_def nth_equalityI)
next
  case (Suc n)
  from all_ctxt_closed_relcomp[OF this acc]
  show ?case by simp
qed


lemma all_ctxt_closed_subst_step_sig:
  fixes r :: "('f, 'v) trs" and t :: "('f, 'v) term"
  assumes all: "all_ctxt_closed F r"
    and sig: "funas_term t ⊆ F"
    and steps: "⋀ x. x ∈ vars_term t ⟹ (σ x, τ x) ∈ r"
    and sig_subst: "⋀ x. x ∈ vars_term t ⟹ funas_term (σ x) ∪ funas_term (τ x) ⊆ F"
  shows "(t ⋅ σ, t ⋅ τ) ∈ r"
  using sig steps sig_subst
proof (induct t)
  case (Var x)
  then show ?case by auto
next
  case (Fun f ts)
  {
    fix t
    assume t: "t ∈ set ts"
    with Fun(2-3) have "funas_term t ⊆ F" "⋀ x. x ∈ vars_term t ⟹ (σ x, τ x) ∈ r" by auto
    from Fun(1)[OF t this Fun(4)] t have step: "(t ⋅ σ, t ⋅ τ) ∈ r" by auto
    from Fun(4) t have "⋀ x. x ∈ vars_term t ⟹ funas_term (σ x) ∪ funas_term (τ x) ⊆ F" by auto
    with ‹funas_term t ⊆ F› have "funas_term (t ⋅ σ) ∪ funas_term (t ⋅ τ) ⊆ F" unfolding funas_term_subst by auto
    note step this
  }
  then have steps: "⋀ i. i < length ts ⟹ (ts ! i ⋅ σ, ts ! i ⋅ τ) ∈ r ∧ funas_term (ts ! i ⋅ σ) ∪ funas_term (ts ! i ⋅ τ) ⊆ F" unfolding set_conv_nth by auto
  with all_ctxt_closedD[OF all, of f "map (λ t. t ⋅ τ) ts" "map (λ t. t ⋅ σ) ts"] Fun(2)
  show ?case by auto
qed

lemma all_ctxt_closed_subst_step:
  fixes r :: "('f, 'v) trs" and t :: "('f, 'v) term"
  assumes all: "all_ctxt_closed UNIV r"
    and steps: "⋀ x. x ∈ vars_term t ⟹ (σ x, τ x) ∈ r"
  shows "(t ⋅ σ, t ⋅ τ) ∈ r"
  by (rule all_ctxt_closed_subst_step_sig[OF all _ steps], auto)

lemma all_ctxt_closed_ctxtE: assumes all: "all_ctxt_closed F R"
  and Fs: "funas_term s ⊆ F"
  and Ft: "funas_term t ⊆ F"
  and step: "(s,t) ∈ R"
shows "funas_ctxt C ⊆ F ⟹ (C ⟨ s ⟩, C ⟨ t ⟩) ∈ R"
proof(induct C)
  case Hole
  from step show ?case by auto
next
  case (More f bef C aft)
  let ?n = "length bef"
  let ?m = "Suc (?n + length aft)"
  show ?case unfolding intp_actxt.simps
  proof (rule all_ctxt_closedD[OF all])
    fix i
    let ?t = "λ s. (bef @ C ⟨ s ⟩ # aft) ! i"
    assume "i < length (bef @ C⟨s⟩ # aft)"
    then have i: "i < ?m" by auto
    then have mem: "⋀ s. ?t s ∈ set (bef @ C ⟨ s ⟩ # aft)" unfolding set_conv_nth by auto
    from mem[of s] More Fs show "funas_term (?t s) ⊆ F" by auto
    from mem[of t] More Ft show "funas_term (?t t) ⊆ F" by auto
    from More have step: "(C ⟨ s ⟩, C ⟨ t ⟩) ∈ R" by auto
    {
      fix s
      assume "s ∈ set bef ∪ set aft"
      with More have "funas_term s ⊆ F" by auto
      from all_ctxt_closed_sig_reflE[OF all this] have "(s,s) ∈ R" by auto
    } note steps = this
    show "(?t s, ?t t) ∈ R"
    proof (cases "i = ?n")
      case True
      then show ?thesis using step by auto
    next
      case False
      show ?thesis
      proof (cases "i < ?n")
        case True
        then show ?thesis unfolding append_Cons_nth_left[OF True] using steps by auto
      next
        case False
        with ‹i ≠ ?n› i have "∃ k. k < length aft ∧ i = Suc ?n + k" by presburger
        then obtain k where k: "k < length aft" and i: "i = Suc ?n + k" by auto
        from k show ?thesis using steps unfolding i by (auto simp: nth_append)
      qed
    qed
  qed (insert More, auto)
qed

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 (intro conjI, 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)

lemma trans_ctxt_imp_all_ctxt_closed: assumes tran: "trans r"
  and refl: "refl r"
  and ctxt: "ctxt.closed r"
shows "all_ctxt_closed F r"
  by (rule trans_ctxt_sig_imp_all_ctxt_closed[OF tran _ ctxt.closedD[OF ctxt]], insert refl[unfolded refl_on_def], auto)

lemma all_ctxt_closed_rsteps[intro]: "all_ctxt_closed F ((rstep r)*)"
  by (blast intro: trans_ctxt_imp_all_ctxt_closed trans_rtrancl refl_rtrancl)

lemma subst_rsteps_imp_rsteps:
  fixes σ :: "('f, 'v) subst"
  assumes "⋀ x. x∈vars_term t ⟹ (σ x, τ x) ∈ (rstep R)*"
  shows "(t ⋅ σ, t ⋅ τ) ∈ (rstep R)*"
  by (rule all_ctxt_closed_subst_step)
    (insert assms, auto)

lemma rtrancl_trancl_into_trancl:
  assumes len: "length ts = length ss"
    and steps: "∀ i < length ts. (ts ! i, ss ! i) ∈ R*"
    and i: "i < length ts"
    and step: "(ts ! i, ss ! i) ∈ R+"
    and ctxt: "ctxt.closed R"
  shows "(Fun f ts, Fun f ss) ∈ R+"
proof -
  from ctxt have ctxt_rt: "ctxt.closed (R*)" by blast
  from ctxt have ctxt_t: "ctxt.closed (R+)" by blast
  from id_take_nth_drop[OF i] have ts: "ts = take i ts @ ts ! i # drop (Suc i) ts" (is "_ = ?ts") by auto
  from id_take_nth_drop[OF i[simplified len]] have ss: "ss = take i ss @ ss ! i # drop (Suc i) ss" (is "_ = ?ss") by auto
  let ?mid = "take i ss @ ts ! i # drop (Suc i) ss"
  from trans_ctxt_imp_all_ctxt_closed[OF trans_rtrancl refl_rtrancl ctxt_rt] have all: "all_ctxt_closed UNIV (R*)" .
  from ctxt_closed_one[OF ctxt_t step] have "(Fun f ?mid, Fun f ?ss) ∈ R+" .
  then have part1: "(Fun f ?mid, Fun f ss) ∈ R+" unfolding ss[symmetric] .
  from ts have lents: "length ts =  length ?ts" by simp
  have "(Fun f ts, Fun f ?mid) ∈ R*"
  proof (rule all_ctxt_closedD[OF all])
    fix j
    assume jts: "j < length ts"
    from i len have i: "i < length ss" by auto
    show "(ts ! j, ?mid ! j) ∈ R*"
    proof (cases "j < i")
      case True
      with i have j: "j < length ss" by auto
      with True have id: "?mid ! j = ss ! j" by (simp add: nth_append)
      from steps len j have "(ts ! j, ss ! j) ∈ R*" by auto
      then show ?thesis using id by simp
    next
      case False
      show ?thesis
      proof (cases "j = i")
        case True
        then have "?mid ! j = ts ! j" using i by (simp add: nth_append)
        then show ?thesis by simp
      next
        case False
        from i have min: "min (length ss) i = i" by simp
        from False ‹¬ j < i› have "j > i" by arith
        then obtain k where k: "j - i = Suc k" by (cases "j - i", auto)
        then have j: "j = Suc (i+k)" by auto
        with jts len have ss: "Suc i + k ≤ length ss" and jlen: "j < length ts" by auto
        then have "?mid ! j = ss ! j" using j i by (simp add: nth_append min ‹¬ j < i› nth_drop[OF ss])
        with steps jlen show ?thesis by auto
      qed
    qed
  qed (insert lents[symmetric] len, auto)
  with part1 show ?thesis by auto
qed

lemma SN_ctxt_apply_imp_SN_ctxt_to_term_list_gen:
  assumes ctxt: "ctxt.closed r"
  assumes SN: "SN_on r {C⟨t⟩}"
  shows "SN_on r (set (ctxt_to_term_list C))"
proof -
  {
    fix u
    assume "u ∈ set (ctxt_to_term_list C)"
    from ctxt_to_term_list_supt[OF this, of t] have "C⟨t⟩ ⊵ u"
      by (rule supt_imp_supteq)
    from ctxt_closed_SN_on_subt[OF ctxt, OF SN this]
    have "SN_on r {u}" by auto
  }
  then show ?thesis
    unfolding SN_on_def by auto
qed

lemma rstep_subset: "ctxt.closed R' ⟹ subst.closed R' ⟹ R ⊆ R' ⟹ rstep R ⊆ R'" by fast

lemma trancl_rstep_ctxt:
  "(s,t) ∈ (rstep R)+ ⟹ (C⟨s⟩, C⟨t⟩) ∈ (rstep R)+"
  by (rule ctxt.closedD, blast)

lemma args_steps_imp_steps_gen:
  assumes ctxt: "⋀ bef s t aft. (s, t) ∈ r (length bef) ⟹
    length ts = Suc (length bef + length aft) ⟹
    (Fun f (bef @ (s :: ('f, 'v) term) # aft), Fun f (bef @ t # aft)) ∈ R*"
    and len: "length ss = length ts"
    and args: "⋀ i. i < length ts ⟹ (ss ! i, ts ! i) ∈ (r i)*"
  shows "(Fun f ss, Fun f ts) ∈ R*"
proof -
  let ?tss = "λi. take i ts @ drop i ss"
  {
    fix bef :: "('f,'v)term list" and s t and  aft :: "('f,'v)term list"
    assume "(s,t) ∈ (r (length bef))*" and len: "length ts = Suc (length bef + length aft)"
    then have "(Fun f (bef @ s # aft), Fun f (bef @ t # aft)) ∈ R*"
    proof (induct)
      case (step t u)
      from step(3)[OF len] ctxt[OF step(2) len] show ?case by auto
    qed simp
  }
  note one = this
  have a:"∀i ≤ length ts. (Fun f ss,Fun f (?tss i)) ∈ R*"
  proof (intro allI impI)
    fix i assume "i ≤ length ts" then show "(Fun f ss,Fun f (?tss i)) ∈ R*"
    proof (induct i)
      case 0
      then show ?case by simp
    next
      case (Suc i)
      then have IH: "(Fun f ss,Fun f (?tss i)) ∈ R*"
        and i: "i < length ts" by auto
      have si: "?tss (Suc i) = take i ts @ ts ! i # drop (Suc i) ss"
        unfolding take_Suc_conv_app_nth[OF i] by simp
      have ii: "?tss i = take i ts @ ss ! i # drop (Suc i) ss"
        unfolding Cons_nth_drop_Suc[OF i[unfolded len[symmetric]]] ..
      from i have i': "length (take i ts) < length ts"  and len': "length (take i ts) = i" by auto
      from len i have len'': "length ts = Suc (length (take i ts) + length (drop (Suc i) ss))" by simp
      from one[OF args[OF i'] len''] IH
      show ?case unfolding si ii len' by auto
    qed
  qed
  from this[THEN spec, THEN mp[OF _ le_refl]]
  show ?thesis using len by auto
qed

lemma args_steps_imp_steps:
  assumes ctxt: "ctxt.closed R"
    and len: "length ss = length ts" and args: "∀i<length ss. (ss!i, ts!i) ∈ R*"
  shows "(Fun f ss, Fun f ts) ∈ R*"
proof (rule args_steps_imp_steps_gen[OF _ len])
  fix i
  assume "i < length ts" then show "(ss ! i, ts ! i) ∈ R*" using args len by auto
qed (insert ctxt_closed_one[OF ctxt], auto)

lemmas args_rsteps_imp_rsteps = args_steps_imp_steps [OF ctxt_closed_rstep]

lemma replace_at_subst_steps:
  fixes σ τ :: "('f, 'v) subst"
  assumes acc: "all_ctxt_closed UNIV r"
    and refl: "refl r"
    and *: "⋀x. (σ x, τ x) ∈ r"
    and "p ∈ poss t"
    and "t |_ p = Var x"
  shows "(replace_at (t ⋅ σ) p (τ x), t ⋅ τ) ∈ r"
  using assms(4-)
proof (induction t arbitrary: p)
  case (Var x)
  then show ?case using refl by (simp add: refl_on_def)
next
  case (Fun f ts)
  then obtain i q where [simp]: "p = i # q" and i: "i < length ts"
    and q: "q ∈ poss (ts ! i)" and [simp]: "ts ! i |_ q = Var x" by (cases p) auto
  let ?C = "ctxt_of_pos_term q (ts ! i ⋅ σ)"
  let ?ts = "map (λt. t ⋅ τ) ts"
  let ?ss = "take i (map (λt. t ⋅ σ) ts) @ ?C⟨τ x⟩ # drop (Suc i) (map (λt. t ⋅ σ) ts)"
  have "∀j<length ts. (?ss ! j, ?ts ! j) ∈ r"
  proof (intro allI impI)
    fix j
    assume j: "j < length ts"
    moreover
    { assume [simp]: "j = i"
      have "?ss ! j = ?C⟨τ x⟩" using i by (simp add: nth_append_take)
      with Fun.IH [of "ts ! i" q]
      have "(?ss ! j, ?ts ! j) ∈ r" using q and i by simp }
    moreover
    { assume "j < i"
      with i have "?ss ! j = ts ! j ⋅ σ"
        and "?ts ! j = ts ! j ⋅ τ" by (simp_all add: nth_append_take_is_nth_conv)
      then have "(?ss ! j, ?ts ! j) ∈ r" by (auto simp: * all_ctxt_closed_subst_step [OF acc]) }
    moreover
    { assume "j > i"
      with i and j have "?ss ! j = ts ! j ⋅ σ"
        and "?ts ! j = ts ! j ⋅ τ" by (simp_all add: nth_append_drop_is_nth_conv)
      then have "(?ss ! j, ?ts ! j) ∈ r" by (auto simp: * all_ctxt_closed_subst_step [OF acc]) }
    ultimately show "(?ss ! j, ?ts ! j) ∈ r" by arith
  qed
  moreover have "i < length ts" by fact
  ultimately show ?case
    by (auto intro: all_ctxt_closedD [OF acc])
qed

lemma replace_at_subst_rsteps:
  fixes σ τ :: "('f, 'v) subst"
  assumes *: "⋀x. (σ x, τ x) ∈ (rstep R)*"
    and "p ∈ poss t"
    and "t |_ p = Var x"
  shows "(replace_at (t ⋅ σ) p (τ x), t ⋅ τ) ∈ (rstep R)*"
  by (intro replace_at_subst_steps[OF _ _ assms], auto simp: refl_on_def)

lemma substs_rsteps:
  assumes "⋀x. (σ x, τ x) ∈ (rstep R)*"
  shows "(t ⋅ σ, t ⋅ τ) ∈ (rstep R)*"
proof (induct t)
  case (Var y)
  show ?case using assms by simp_all
next
  case (Fun f ts)
  then have "∀i<length (map (λt. t ⋅ σ) ts).
    (map (λt. t ⋅ σ ) ts ! i, map (λt. t ⋅ τ) ts ! i) ∈ (rstep R)*" by auto
  from args_rsteps_imp_rsteps [OF _ this] show ?case by simp
qed

lemma nrrstep_Fun_imp_arg_rstep:
  fixes ss :: "('f,'v)term list"
  assumes "(Fun f ss,Fun f ts) ∈ nrrstep R" (is "(?s,?t) ∈ nrrstep R")
  shows "∃C i. i < length ss ∧ (ss!i,ts!i) ∈ rstep R ∧ C⟨ss!i⟩ = Fun f ss ∧ C⟨ts!i⟩ = Fun f ts"
proof -
  from ‹(?s,?t) ∈ nrrstep R›
  obtain l r j ps σ where A: "let C = ctxt_of_pos_term (j#ps) ?s in (j#ps) ∈ poss ?s ∧ (l,r) ∈ R ∧ C⟨l⋅σ⟩ = ?s ∧ C⟨r⋅σ⟩ = ?t" unfolding nrrstep_def rstep_r_p_s_def by force
  let ?C = "ctxt_of_pos_term (j#ps) ?s"
  from A have "(j#ps) ∈ poss ?s" and "(l,r) ∈ R" and "?C⟨l⋅σ⟩ = ?s" and "?C⟨r⋅σ⟩ = ?t" using Let_def by auto
  have C: "?C = More f (take j ss) (ctxt_of_pos_term ps (ss!j)) (drop (Suc j) ss)" (is "?C = More f ?ss1 ?D ?ss2") by auto
  from ‹?C⟨l⋅σ⟩ = ?s› have "?D⟨l⋅σ⟩ = (ss!j)" by (auto simp: take_drop_imp_nth)
  from ‹(l,r) ∈ R› have "(l⋅σ,r⋅σ) ∈ (subst.closure R)" by auto
  then have "(?D⟨l⋅σ⟩,?D⟨r⋅σ⟩) ∈ (ctxt.closure(subst.closure R))" and "(?C⟨l⋅σ⟩,?C⟨r⋅σ⟩) ∈ (ctxt.closure(subst.closure R))" by (auto simp only: ctxt.closure.intros)
  then have D_rstep: "(?D⟨l⋅σ⟩,?D⟨r⋅σ⟩) ∈ rstep R" and "(?C⟨l⋅σ⟩,?C⟨r⋅σ⟩) ∈ rstep R"
    by (auto simp: rstep_eq_closure)
  from ‹?C⟨r⋅σ⟩ = ?t› and C have "?t = Fun f (take j ss @ ?D⟨r⋅σ⟩ # drop (Suc j) ss)" by auto
  then have ts: "ts = (take j ss @ ?D⟨r⋅σ⟩ # drop (Suc j) ss)" by auto
  from ‹j#ps ∈ poss ?s› have r0: "j < length ss" by simp
  then have "(take j ss @ ?D⟨r⋅σ⟩ # drop (Suc j) ss) ! j = ?D⟨r⋅σ⟩" by (auto simp: nth_append_take)
  with ts have "ts!j = ?D⟨r⋅σ⟩" by auto
  let ?C' = "More f (take j ss) □ (drop (Suc j) ss)"
  from D_rstep have r1: "(ss!j,ts!j) ∈ rstep R" unfolding ‹ts!j = ?D⟨r⋅σ⟩› ‹?D⟨l⋅σ⟩ = ss!j› by simp
  have "?s = ?C⟨l⋅σ⟩" unfolding ‹?C⟨l⋅σ⟩ = ?s› by simp
  also have "… = ?C'⟨?D⟨l⋅σ⟩⟩" unfolding C by simp
  finally have r2:"?C'⟨ss!j⟩ = ?s" unfolding ‹?D⟨l⋅σ⟩ = ss!j› by simp
  have "?t = ?C⟨r⋅σ⟩" unfolding ‹?C⟨r⋅σ⟩ = ?t› by simp
  also have "… = ?C'⟨?D⟨r⋅σ⟩⟩" unfolding C by simp
  finally have r3:"?C'⟨ts!j⟩ = ?t" unfolding ‹ts!j = ?D⟨r⋅σ⟩› by simp
  from r0 r1 r2 r3 show ?thesis by best
qed

lemma pair_fun_eq[simp]:
  fixes f :: "'a ⇒ 'b" and g :: "'b ⇒ 'a"
  shows "((λ(x,y). (x,f y)) ∘ (λ(x,y). (x,g y))) = (λ(x,y). (x,(f ∘ g) y))" (is "?f = ?g")
proof (rule ext)
  fix ab :: "'c * 'b"
  obtain a b where "ab = (a,b)" by force
  have "((λ(x,y). (x,f y))∘(λ(x,y). (x,g y))) (a,b) = (λ(x,y). (x,(f∘g) y)) (a,b)" by simp
  then show "?f ab = ?g ab" unfolding ‹ab = (a,b)› by simp
qed

lemma restrict_singleton:
  assumes "x ∈ subst_domain σ" shows "∃t. σ |s {x} = (λy. if y = x then t else Var y)"
proof -
  have "σ |s {x} = (λy. if y = x then σ y else Var y)" by (simp add: subst_restrict_def)
  then have "σ |s {x} = (λy. if y = x then σ x else Var y)" by (simp cong: if_cong)
  then show ?thesis by (rule exI[of _ "σ x"])
qed

definition rstep_r_c_s :: "('f,'v)rule ⇒ ('f,'v)ctxt ⇒ ('f,'v)subst ⇒ ('f,'v)term rel"
  where "rstep_r_c_s r C σ = {(s,t) | s t. s = C⟨fst r ⋅ σ⟩ ∧ t = C⟨snd r ⋅ σ⟩}"

lemma rstep_iff_rstep_r_c_s: "((s,t) ∈ rstep R) = (∃ l r C σ. (l,r) ∈ R ∧ (s,t) ∈ rstep_r_c_s (l,r) C σ)" (is "?left = ?right")
proof
  assume ?left
  then obtain l r p σ where step: "(s,t) ∈ rstep_r_p_s R (l,r) p σ"
    unfolding rstep_iff_rstep_r_p_s by blast
  obtain D where D: "D = ctxt_of_pos_term p s" by auto
  with step have Rrule: "(l,r) ∈ R" and s: "s = D⟨l ⋅ σ⟩" and t: "t = D⟨r ⋅ σ⟩"
    unfolding rstep_r_p_s_def by (force simp: Let_def)+
  then show ?right unfolding rstep_r_c_s_def by auto
next
  assume ?right
  from this obtain l r C σ where "(l,r) ∈ R ∧ (s,t) ∈ rstep_r_c_s (l,r) C σ" by auto
  then have rule: "(l,r) ∈ R" and s: "s = C⟨l ⋅ σ⟩" and t: "t = C⟨r ⋅ σ⟩"
    unfolding rstep_r_c_s_def by auto
  show ?left unfolding rstep_eq_closure by (auto simp: s t intro: rule)
qed

lemma rstep_subset_characterization:
  "(rstep R ⊆ rstep S) = (∀ l r. (l,r) ∈ R ⟶ (∃ l' r' C σ . (l',r') ∈ S ∧ l = C⟨l' ⋅ σ⟩ ∧ r = C⟨r' ⋅ σ⟩))" (is "?left = ?right")
proof
  assume ?right
  show ?left
  proof 
    fix s t
    assume "(s,t) ∈ rstep R"
    then obtain l r C σ where step: "(l,r) ∈ R ∧ (s,t) ∈ rstep_r_c_s (l,r) C σ"
      unfolding rstep_iff_rstep_r_c_s by best
    then have Rrule: "(l,r) ∈ R" and s: "s = C⟨l ⋅ σ⟩" and t: "t = C⟨r ⋅ σ⟩"
      unfolding rstep_r_c_s_def by (force)+
    from Rrule ‹?right› obtain l' r' C' σ' where Srule: "(l',r') ∈ S" and l: "l = C'⟨l' ⋅ σ'⟩" and r: "r = C'⟨r' ⋅ σ'⟩"
      by (force simp: Let_def)+
    let ?D = "C ∘c (C' ⋅c σ)"
    let ?sig = "σ' ∘s σ"
    have s2: "s = ?D⟨l' ⋅ ?sig⟩" by (simp add: s l)
    have t2: "t = ?D⟨r' ⋅ ?sig⟩" by (simp add: t r)
    from s2 t2 have sStep: "(s,t) ∈ rstep_r_c_s (l',r') ?D ?sig" unfolding rstep_r_c_s_def by force
    with Srule show "(s,t) ∈ rstep S" by (simp only: rstep_iff_rstep_r_c_s, blast)
  qed
next
  assume ?left
  show ?right
  proof (rule ccontr)
    assume "¬ ?right"
    from this obtain l r where "(l,r) ∈ R" and cond: "∀ l' r' C σ. (l',r') ∈ S ⟶ (l ≠ C⟨l' ⋅ σ⟩ ∨ r ≠ C⟨r' ⋅ σ⟩)" by blast
    then have "(l,r) ∈ rstep R" by blast
    with ‹?left› have "(l,r) ∈ rstep S" by auto
    with cond show False by (simp only: rstep_iff_rstep_r_c_s, unfold rstep_r_c_s_def, force)
  qed
qed

lemma rstep_preserves_funas_terms_var_cond:
  assumes "funas_trs R ⊆ F" and "funas_term s ⊆ F" and "(s,t) ∈ rstep R"
    and wf: "⋀ l r. (l,r) ∈ R ⟹ vars_term r ⊆ vars_term l"
  shows "funas_term t ⊆ F"
proof -
  from ‹(s,t) ∈ rstep R› obtain l r C σ where R: "(l,r) ∈ R"
    and s: "s = C⟨l⋅σ⟩" and t: "t = C⟨r⋅σ⟩" by auto
  from ‹funas_trs R ⊆ F› and R have "funas_term r ⊆ F"
    unfolding funas_defs [abs_def] by force
  with wf[OF R] ‹funas_term s ⊆ F› show ?thesis unfolding s t by (force simp: funas_term_subst)
qed

lemma rstep_preserves_funas_terms:
  assumes "funas_trs R ⊆ F" and "funas_term s ⊆ F" and "(s,t) ∈ rstep R"
    and wf: "wf_trs R"
  shows "funas_term t ⊆ F"
  by (rule rstep_preserves_funas_terms_var_cond[OF assms(1-3)], insert wf[unfolded wf_trs_def], auto)

lemma rsteps_preserve_funas_terms_var_cond:
  assumes F: "funas_trs R ⊆ F" and s: "funas_term s ⊆ F" and steps: "(s,t) ∈ (rstep R)*"
    and wf: "⋀ l r. (l,r) ∈ R ⟹ vars_term r ⊆ vars_term l"
  shows "funas_term t ⊆ F"
  using steps
proof (induct)
  case base then show ?case by (rule s)
next
  case (step t u)
  show ?case by (rule rstep_preserves_funas_terms_var_cond[OF F step(3) step(2) wf])
qed

lemma rsteps_preserve_funas_terms:
  assumes F: "funas_trs R ⊆ F" and s: "funas_term s ⊆ F"
    and steps: "(s,t) ∈ (rstep R)*" and wf: "wf_trs R"
  shows "funas_term t ⊆ F"
  by (rule rsteps_preserve_funas_terms_var_cond[OF assms(1-3)], insert wf[unfolded wf_trs_def], auto)

lemma no_Var_rstep [simp]:
  assumes "wf_trs R" and "(Var x, t) ∈ rstep R" shows "False"
  using rstep_imp_Fun[OF assms] by auto

lemma lhs_wf:
  assumes R: "(l, r) ∈ R" and "funas_trs R ⊆ F"
  shows "funas_term l ⊆  F"
  using assms by (force simp: funas_trs_def funas_rule_def)

lemma rhs_wf:
  assumes R: "(l, r) ∈ R" and "funas_trs R ⊆ F"
  shows "funas_term r ⊆ F"
  using assms by (force simp: funas_trs_def funas_rule_def)

lemma supt_map_funs_term [intro]:
  assumes "t ⊳ s"
  shows "map_funs_term fg t ⊳ map_funs_term fg s"
  using assms
proof (induct)
  case (arg s ss f)
  then have "map_funs_term fg s ∈ set(map (map_funs_term fg) ss)" by simp
  then show ?case unfolding term.map by (rule supt.arg)
next
  case (subt s ss u f)
  then have "map_funs_term fg s ∈ set(map (map_funs_term fg) ss)" by simp
  with ‹map_funs_term fg s ⊳ map_funs_term fg u› show ?case
    unfolding term.map by (metis supt.subt)
qed

lemma nondef_root_imp_arg_step:
  assumes "(Fun f ss, t) ∈ rstep R"
    and wf: "∀(l, r)∈R. is_Fun l"
    and ndef: "¬ defined R (f, length ss)"
  shows "∃i<length ss. (ss ! i, t |_ [i]) ∈ rstep R
    ∧ t = Fun f (take i ss @ (t |_ [i]) # drop (Suc i) ss)"
proof -
  from assms obtain l r p σ
    where rstep_r_p_s: "(Fun f ss, t) ∈ rstep_r_p_s R (l, r) p σ"
    unfolding rstep_iff_rstep_r_p_s by auto
  let ?C = "ctxt_of_pos_term p (Fun f ss)"
  from rstep_r_p_s have "p ∈ poss (Fun f ss)" and "(l, r) ∈ R"
    and "?C⟨l ⋅ σ⟩ = Fun f ss" and "?C⟨r ⋅ σ⟩ = t" unfolding rstep_r_p_s_def Let_def by auto
  have "∃i q. p = i#q"
  proof (cases p)
    case Cons then show ?thesis by auto
  next
    case Nil
    have "?C = □" unfolding Nil by simp
    with ‹?C⟨l⋅σ⟩ = Fun f ss› have "l⋅σ = Fun f ss" by simp
    have "∀(l,r)∈R. ∃f ss. l = Fun f ss"
    proof (intro ballI impI)
      fix lr assume "lr ∈ R"
      with wf have "∀x. fst lr ≠ Var x" by auto
      then have "∃f ss. (fst lr) = Fun f ss" by (cases "fst lr") auto
      then show "(λ(l,r). ∃f ss. l = Fun f ss) lr" by auto
    qed
    with ‹(l,r) ∈ R› obtain g ts where "l = Fun g ts" unfolding wf_trs_def by best
    with ‹l⋅σ = Fun f ss› ‹l = Fun g ts› and ‹(l, r) ∈ R› ndef
    show ?thesis unfolding defined_def by auto
  qed
  then obtain i q where "p = i#q" by auto
  from ‹p ∈ poss(Fun f ss)› have "i < length ss" and "q ∈ poss(ss!i)" unfolding ‹p = i#q› by auto
  let ?D = "ctxt_of_pos_term q (ss!i)"
  have C: "?C = More f (take i ss) ?D (drop (Suc i) ss)" unfolding ‹p = i#q› by auto
  from ‹?C⟨l⋅σ⟩ = Fun f ss› have "take i ss@?D⟨l⋅σ⟩#drop (Suc i) ss = ss" unfolding C by auto
  then have "(take i ss@?D⟨l⋅σ⟩#drop (Suc i) ss)!i = ss!i" by simp
  with ‹i < length ss› have "?D⟨l⋅σ⟩ = ss!i" using nth_append_take[where xs = ss and i = i] by auto
  have t: "t = Fun f (take i ss@?D⟨r⋅σ⟩#drop (Suc i) ss)" unfolding ‹?C⟨r⋅σ⟩ = t›[symmetric] C by simp
  from ‹i < length ss› have "t|_[i] = ?D⟨r⋅σ⟩" unfolding t unfolding subt_at.simps using nth_append_take[where xs = ss and i = i] by auto
  from ‹q ∈ poss(ss!i)› and ‹(l,r) ∈ R›
    and ‹?D⟨l⋅σ⟩ = ss!i› and ‹t|_[i] = ?D⟨r⋅σ⟩›[symmetric]
  have "(ss!i,t|_[i]) ∈ rstep_r_p_s R (l,r) q σ" unfolding rstep_r_p_s_def Let_def by auto
  then have "(ss!i,t|_[i]) ∈ rstep R" unfolding rstep_iff_rstep_r_p_s by auto
  from ‹i < length ss› and this and t show ?thesis unfolding ‹t|_[i] = ?D⟨r⋅σ⟩›[symmetric] by auto
qed

lemma nondef_root_imp_arg_steps:
  assumes "(Fun f ss,t) ∈ (rstep R)*"
    and wf: "∀(l, r)∈R. is_Fun l"
    and "¬ defined R (f,length ss)"
  shows "∃ts. length ts = length ss ∧ t = Fun f ts ∧ (∀i<length ss. (ss!i,ts!i) ∈ (rstep R)*)"
proof -
  from assms obtain n where "(Fun f ss,t) ∈ (rstep R)^^n"
    using rtrancl_imp_relpow by best
  then show ?thesis
  proof (induct n arbitrary: t)
    case 0 then show ?case by auto
  next
    case (Suc n)
    then obtain u where "(Fun f ss,u) ∈ (rstep R)^^n" and "(u,t) ∈ rstep R" by auto
    with Suc obtain ts where IH1: "length ts = length ss" and IH2: "u = Fun f ts" and IH3: "∀i<length ss. (ss!i,ts!i) ∈ (rstep R)*" by auto
    from ‹(u,t) ∈ rstep R› have "(Fun f ts,t) ∈ rstep R" unfolding ‹u = Fun f ts› .
    from nondef_root_imp_arg_step[OF this wf ‹¬ defined R (f,length ss)›[simplified IH1[symmetric]]]
    obtain j where "j < length ts"
      and "(ts!j,t|_[j]) ∈ rstep R"
      and B: "t = Fun f (take j ts@(t|_[j])#drop (Suc j) ts)" (is "t = Fun f ?ts") by auto
    from ‹j < length ts› have "length ?ts = length ts" by auto
    then have A: "length ?ts = length ss" unfolding ‹length ts = length ss› .
    have C: "∀i<length ss. (ss!i,?ts!i) ∈ (rstep R)*"
    proof (intro allI, intro impI)
      fix i assume "i < length ss"
      from ‹i < length ss› and IH3 have "(ss!i,ts!i) ∈ (rstep R)*" by auto
      have "i = j ∨ i ≠ j" by auto
      then show "(ss!i,?ts!i) ∈ (rstep R)*"
      proof
        assume "i = j"
        from ‹j < length ts› have "j ≤ length ts" by simp
        from nth_append_take[OF this] have "?ts!j = t|_[j]" by simp
        from ‹(ts!j,t|_[j]) ∈ rstep R› have "(ts!i,t|_[i]) ∈ rstep R" unfolding ‹i = j› .
        with ‹(ss!i,ts!i) ∈ (rstep R)*› show ?thesis unfolding ‹i = j› unfolding ‹?ts!j = t|_[j]› by auto
      next
        assume "i ≠ j"
        from ‹i < length ss› have "i ≤ length ts" unfolding ‹length ts = length ss› by simp
        from ‹j < length ts› have "j ≤ length ts" by simp
        from nth_append_take_drop_is_nth_conv[OF ‹i ≤ length ts› ‹j ≤ length ts› ‹i ≠ j›]
        have "?ts!i = ts!i" by simp
        with ‹(ss!i,ts!i) ∈ (rstep R)*› show ?thesis by auto
      qed
    qed
    from A and B and C show ?case by blast
  qed
qed

lemma rstep_imp_nrrstep:
  assumes "is_Fun s" and "¬ defined R (the (root s))" and "∀(l,r)∈R. is_Fun l"
    and "(s, t) ∈ rstep R"
  shows "(s, t) ∈ nrrstep R"
proof -
  from ‹is_Fun s› obtain f ss where s: "s = Fun f ss" by (cases s) auto
  with assms have undef: "¬ defined R (f, length ss)" by simp
  from assms have non_var: "∀(l, r)∈R. is_Fun l" by auto
  from nondef_root_imp_arg_step[OF ‹(s, t) ∈ rstep R›[unfolded s] non_var undef]
  obtain i where "i < length ss" and step: "(ss ! i, t |_ [i]) ∈ rstep R"
    and t: "t = Fun f (take i ss @ (t |_ [i]) # drop (Suc i) ss)" by auto
  from step obtain C l r σ where "(l, r) ∈ R" and lhs: "ss ! i = C⟨l ⋅ σ⟩"
    and rhs: "t |_ [i] = C⟨r ⋅ σ⟩" by auto
  let ?C = "More f (take i ss) C (drop (Suc i) ss)"
  have "(l, r) ∈ R" by fact
  moreover have "?C ≠ □" by simp
  moreover have "s = ?C⟨l ⋅ σ⟩"
  proof -
    have "s = Fun f (take i ss @ ss!i # drop (Suc i) ss)"
      using id_take_nth_drop[OF ‹i < length ss›] unfolding s by simp
    also have "… = ?C⟨l ⋅ σ⟩" by (simp add: lhs)
    finally show ?thesis .
  qed
  moreover have "t = ?C⟨r ⋅ σ⟩"
  proof -
    have "t = Fun f (take i ss @ t |_ [i] # drop (Suc i) ss)" by fact
    also have "… = Fun f (take i ss @ C⟨r ⋅ σ⟩ # drop (Suc i) ss)" by (simp add: rhs)
    finally show ?thesis by simp
  qed
  ultimately show "(s, t) ∈ nrrstep R" unfolding nrrstep_def' by blast
qed

lemma rsteps_imp_nrrsteps:
  assumes "is_Fun s" and "¬ defined R (the (root s))"
    and no_vars: "∀(l, r)∈R. is_Fun l"
    and "(s, t) ∈ (rstep R)*"
  shows "(s, t) ∈ (nrrstep R)*"
  using ‹(s, t) ∈ (rstep R)*›
proof (induct)
  case base show ?case by simp
next
  case (step u v)
  from assms obtain f ss where s: "s = Fun f ss" by (induct s) auto
  from nrrsteps_preserve_root[OF ‹(s, u) ∈ (nrrstep R)*›[unfolded s]]
  obtain ts where u: "u = Fun f ts" by auto
  from nrrsteps_equiv_num_args[OF ‹(s, u) ∈ (nrrstep R)*›[unfolded s]]
  have len: "length ss = length ts" unfolding u by simp
  have "is_Fun u" by (simp add: u)
  have undef: "¬ defined R (the (root u))"
    using ‹¬ defined R (the (root s))›
    unfolding s u by (simp add: len)
  have "(u, v) ∈ nrrstep R"
    using rstep_imp_nrrstep[OF ‹is_Fun u› undef no_vars] step
    by simp
  with step show ?case by auto
qed

lemma left_var_imp_not_SN:
  fixes R :: "('f,'v)trs" and t :: "('f, 'v) term"
  assumes "(Var y, r) ∈ R" (is "(?y, _) ∈ _")
  shows "¬ (SN_on (rstep R) {t})"
proof (rule steps_imp_not_SN_on)
  fix t :: "('f,'v)term"
  let ?yt = "subst y t"
  show "(t, r ⋅ ?yt) ∈ rstep R"
    by (rule rstepI[OF assms, where C = □ and σ = ?yt], auto simp: subst_def)
qed

lemma not_SN_subt_imp_not_SN:
  assumes ctxt: "ctxt.closed R" and SN: "¬ SN_on R {t}" and sub: "s ⊵ t"
  shows "¬ SN_on R {s}"
  using ctxt_closed_SN_on_subt[OF ctxt _ sub] SN
  by auto

lemma root_Some:
  assumes "root t = Some fn"
  obtains ss where "length ss = snd fn" and "t = Fun (fst fn) ss"
  using assms by (induct t) auto

lemma map_funs_rule_power:
  fixes f :: "'f ⇒ 'f"
  shows "((map_funs_rule f) ^^ n) = map_funs_rule (f ^^ n)"
proof (rule sym, intro ext, clarify)
  fix  l r :: "('f,'v)term"
  show "map_funs_rule (f ^^ n) (l,r) = (map_funs_rule f ^^ n) (l,r)"
  proof (induct n)
    case 0
    show ?case by (simp add: term.map_ident)
  next
    case (Suc n)
    have "map_funs_rule (f ^^ Suc n) (l,r) = map_funs_rule f (map_funs_rule (f ^^ n) (l,r))"
      by (simp add: map_funs_term_comp)
    also have "… = map_funs_rule f ((map_funs_rule f ^^ n) (l,r))" unfolding Suc ..
    also have "… = (map_funs_rule f ^^ (Suc n)) (l,r)" by simp
    finally show ?case .
  qed
qed

lemma map_funs_trs_power:
  fixes f :: "'f ⇒ 'f"
  shows "map_funs_trs f ^^ n = map_funs_trs (f ^^ n)"
proof
  fix R :: "('f, 'v) trs"
  have "map_funs_rule (f ^^ n) ` R = (map_funs_rule f ^^ n) ` R" unfolding map_funs_rule_power ..
  also have "… = ((λ R. map_funs_trs f R) ^^ n) R" unfolding map_funs_trs.simps
    apply (induct n)
     apply simp
    by (metis comp_apply funpow.simps(2) image_comp)
  finally have "map_funs_rule (f ^^ n) ` R = (map_funs_trs f ^^ n) R" .
  then show "(map_funs_trs f ^^ n) R = map_funs_trs (f ^^ n) R"
    by (simp add: map_funs_trs.simps)
qed

text ‹The set of minimally nonterminating terms with respect to a relation @{term "R"}.›
definition Tinf :: "('f, 'v) trs ⇒ ('f, 'v) terms"
  where
    "Tinf R = {t. ¬ SN_on R {t} ∧ (∀s ⊲ t. SN_on R {s})}"

lemma not_SN_imp_subt_Tinf:
  assumes "¬ SN_on R {s}" shows "∃t⊴s. t ∈ Tinf R"
proof -
  let ?S = "{t | t. s ⊵ t ∧ ¬ SN_on R {t}}"
  from assms have s: "s ∈ ?S" by auto
  from mp[OF spec[OF spec[OF SN_imp_minimal[OF SN_supt]]] s]
  obtain t where st: "s ⊵ t" and nSN: "¬ SN_on R {t}"
    and min: "∀ u. (t,u) ∈ supt ⟶ u ∉ ?S" by auto
  have "t ∈ Tinf R" unfolding Tinf_def
  proof (intro CollectI allI impI conjI nSN)
    fix u
    assume u: "t ⊳ u"
    from u st have "s ⊳ u" using supteq_supt_trans by auto
    with min u show "SN_on R {u}" by auto
  qed
  with st show ?thesis by auto
qed

lemma not_SN_imp_Tinf:
  assumes "¬ SN R" shows "∃t. t ∈ Tinf R"
  using assms not_SN_imp_subt_Tinf unfolding SN_on_def by blast

lemma Tinf_imp_SN_nrrstep: assumes "t ∈ Tinf (rstep R)" 
  shows "SN_on (nrrstep R) {t}" 
proof 
  fix g
  assume "g 0 ∈ {t}" and "∀ i. (g i, g (Suc i)) ∈ nrrstep R" 
  hence steps: "⋀ i. (g i, g (Suc i)) ∈ nrrstep R"
    and t: "t = g 0" by auto
  from steps[of 0] obtain f ts where g0: "g 0 = Fun f ts"
    using nrrstep_imp_Fun by blast
  define n where "n = length ts" 
  have "∃ ts. g i = Fun f ts ∧ length ts = n" for i
  proof (induct i)
    case 0
    show ?case unfolding g0 n_def by auto
  next
    case (Suc i)
    then obtain ts where "g i = Fun f ts" and "length ts = n" by auto
    with steps[of i] show ?case using nrrstep_args by fastforce
  qed
  hence "∀ i. ∃ ts. g i = Fun f ts ∧ length ts = n" by auto
  from choice[OF this] obtain ts where g: "g i = Fun f (ts i)" and len: "length (ts i) = n" for i by blast
  have "∃ j < n. (ts i ! j, ts (Suc i) ! j) ∈ rstep R ∧ (∀ k < n. k ≠ j ⟶ ts (Suc i) ! k = ts i ! k)" for i
    using steps[of i, unfolded g] using len[of i] len[of "Suc i"] 
    using nrrstep_args by force
  hence "∀ i. ∃ j < n. (ts i ! j, ts (Suc i) ! j) ∈ rstep R ∧ (∀ k < n. k ≠ j ⟶ ts (Suc i) ! k = ts i ! k)" 
    by blast
  from choice[OF this] obtain j
    where j: "j i < n" "(ts i ! j i, ts (Suc i) ! j i) ∈ rstep R" 
      "k < n ⟹ k ≠ j i ⟹ ts (Suc i) ! k = ts i ! k" for i k 
    by blast
  hence "range j ⊆ {..<n}" by auto
  hence "finite (range j)"
    using finite_subset by blast
  from pigeonhole_infinite[OF _ this] obtain J
    where inf: "infinite {i. j i = J}" by auto
  define I where "I = {i. j i = J}" 
  obtain i where i: "i ∈ I" unfolding I_def using inf by force
  from this[unfolded I_def] j have J: "J < n" by auto
  define h where "h i = ts i ! J" for i
  {
    fix i
    assume "i ∈ I"
    from this[unfolded I_def] J have "j i = J" by auto
    from j(2)[of i, unfolded this, folded h_def]
    have "(h i, h (Suc i)) ∈ rstep R" .
  } note inI = this
  {
    fix i
    assume "i ∉ I" 
    hence "J ≠ j i" unfolding I_def by auto
    from j(3)[OF J this]
    have "(h i, h (Suc i)) ∈ {}^=" by (auto simp: h_def)
  } note ninI = this
  have chain: "chain (rstep R ∪ {}^=) h"  using inI ninI by auto
  have inf: "INFM j. (h j, h (Suc j)) ∈ rstep R" using inf[folded I_def] inI 
    by (metis (no_types, lifting) INFM_iff_infinite INFM_mono I_def mem_Collect_eq)
  from chain inf   
  have "¬ SN_rel_on_alt (rstep R) ({}^=) {h 0}" 
    unfolding SN_rel_on_alt_def by blast
  hence nSN: "¬ SN_on (rstep R) {h 0}" 
    unfolding SN_rel_on_conv[symmetric]
    unfolding SN_rel_on_Id by auto
  have "t ⊳ h 0" unfolding t g h_def using J[folded len[of 0]] by simp
  with assms[unfolded Tinf_def] have "SN_on (rstep R) {h 0}" by auto
  with nSN show False ..
qed

lemma ctxt_of_pos_term_map_funs_term_conv [iff]:
  assumes "p ∈ poss s"
  shows "map_funs_ctxt fg (ctxt_of_pos_term p s) = (ctxt_of_pos_term p (map_funs_term fg s))"
  using assms
proof (induct s arbitrary: p)
  case (Var x) then show ?case by simp
next
  case (Fun f ss) then show ?case
  proof (cases p)
    case Nil then show ?thesis by simp
  next
    case (Cons i q)
    with ‹p ∈ poss(Fun f ss)› have "i < length ss" and "q ∈ poss(ss!i)" unfolding Cons poss.simps by auto
    then have "ss!i ∈ set ss" by simp
    with Fun and ‹q ∈ poss(ss!i)›
    have IH: "map_funs_ctxt fg(ctxt_of_pos_term q (ss!i)) = ctxt_of_pos_term q (map_funs_term fg (ss!i))" by simp
    have "map_funs_ctxt fg(ctxt_of_pos_term p (Fun f ss)) = map_funs_ctxt fg(ctxt_of_pos_term (i#q) (Fun f ss))" unfolding Cons by simp
    also have "… = map_funs_ctxt fg(More f (take i ss) (ctxt_of_pos_term q (ss!i)) (drop (Suc i) ss))" by simp
    also have "… = More (fg f) (map (map_funs_term fg) (take i ss)) (map_funs_ctxt fg(ctxt_of_pos_term q (ss!i))) (map (map_funs_term fg) (drop (Suc i) ss))" by simp
    also have "… = More (fg f) (map (map_funs_term fg) (take i ss)) (ctxt_of_pos_term q (map_funs_term fg (ss!i))) (map (map_funs_term fg) (drop (Suc i) ss))" unfolding IH by simp
    also have "… = More (fg f) (take i (map (map_funs_term fg) ss)) (ctxt_of_pos_term q (map (map_funs_term fg) ss!i)) (drop (Suc i) (map (map_funs_term fg) ss))" unfolding nth_map[OF ‹i < length ss›,symmetric] take_map drop_map nth_map by simp
    finally show ?thesis unfolding Cons by simp
  qed
qed

lemma var_rewrite_imp_not_SN:
  assumes sn: "SN_on (rstep R) {u}" and step: "(t, s) ∈ rstep R"
  shows "is_Fun t"
  using assms
proof (cases t)
  case (Fun f ts) then show ?thesis by simp
next
  case (Var x)
  from step obtain l r p σ where "(Var x, s) ∈ rstep_r_p_s R (l,r) p σ" unfolding Var rstep_iff_rstep_r_p_s by best
  then have "l ⋅ σ = Var x" and rule: "(l,r) ∈ R" unfolding rstep_r_p_s_def by (auto simp: Let_def)
  from this obtain y where "l = Var y" (is "_ = ?y") by (cases l, auto)
  with rule have "(?y, r) ∈ R" by auto
  then have "¬ (SN_on (rstep R) {u})" by (rule left_var_imp_not_SN)
  with sn show ?thesis by blast
qed

lemma rstep_id: "rstep Id = Id" by auto

lemma map_funs_rule_id [simp]: "map_funs_rule id = id"
  by (intro ext, auto)

lemma map_funs_trs_id [simp]: "map_funs_trs id = id"
  by (intro ext, auto simp: map_funs_trs.simps)

definition sig_step :: "'f sig ⇒ ('f, 'v) trs ⇒ ('f, 'v) trs" where
  "sig_step F R = {(a, b). (a, b) ∈ R ∧ funas_term a ⊆ F ∧ funas_term b ⊆ F}"

lemma sig_step_union: "sig_step F (R ∪ S) = sig_step F R ∪ sig_step F S"
  unfolding sig_step_def by auto

lemma sig_step_UNIV: "sig_step UNIV R = R" unfolding sig_step_def by simp

lemma sig_stepI[intro]: "(a,b) ∈ R ⟹ funas_term a ⊆ F ⟹ funas_term b ⊆ F ⟹ (a,b) ∈ sig_step F R" unfolding sig_step_def by auto

lemma sig_stepE[elim,consumes 1]: "(a,b) ∈ sig_step F R ⟹ ⟦(a,b) ∈ R ⟹ funas_term a ⊆ F ⟹ funas_term b ⊆ F ⟹ P⟧ ⟹ P" unfolding sig_step_def by auto

lemma all_ctxt_closed_sig_rsteps [intro]:
  fixes R :: "('f, 'v) trs"
  shows "all_ctxt_closed F ((sig_step F (rstep R))*)" (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 ⊆ F"
    and s: "funas_term s ⊆ F"
    and t: "funas_term t ⊆ F"
    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 R" and t: "funas_term t ⊆ F" and u: "funas_term u ⊆ F" by auto
    have "(C ⟨ t ⟩, C ⟨ u ⟩) ∈ ?R" by (rule sig_stepI[OF rstep_ctxt[OF tu]], insert C t u, auto)
    with step(3) show ?case by auto
  qed auto
qed (auto intro: trans_rtrancl)

lemma wf_loop_imp_sig_ctxt_rel_not_SN:
  assumes R: "(l,C⟨l⟩) ∈ R" and wf_l: "funas_term l ⊆ F"
    and wf_C: "funas_ctxt C ⊆ F"
    and ctxt: "ctxt.closed R"
  shows "¬ SN_on (sig_step F R) {l}"
proof -
  let ?t = "λ i. (C^i)⟨l⟩"
  have "∀i. funas_term (?t i) ⊆ F"
  proof
    fix i show "funas_term (?t i) ⊆ F" unfolding funas_term_ctxt_apply
      by (rule Un_least[OF _ wf_l], induct i, insert wf_C, auto)
  qed
  moreover have "∀i. (?t i,?t(Suc i)) ∈ R"
  proof
    fix i
    show "(?t i, ?t (Suc i)) ∈ R"
    proof (induct i)
      case 0 with R show ?case by auto
    next
      case (Suc i)
      from ctxt.closedD[OF ctxt Suc, of C]
      show ?case by simp
    qed
  qed
  ultimately have steps: "∀i. (?t i,?t(Suc i)) ∈ sig_step F R" unfolding sig_step_def by blast
  show ?thesis unfolding SN_defs
    by (simp, intro exI[of _ ?t], simp only: steps, simp)
qed

lemma lhs_var_imp_sig_step_not_SN_on:
  assumes x: "(Var x, r) ∈ R" and F: "funas_trs R ⊆ F"
  shows "¬ SN_on (sig_step F (rstep R)) {Var x}"
proof -
  let ?σ = "(λx. r)"
  let ?t = "λi. (?σ ^^ i) x"
  obtain t where t: "t = ?t" by auto
  from rhs_wf[OF x F] have wf_r: "funas_term r ⊆ F" .
  {
    fix i
    have "funas_term (?t i) ⊆ F"
    proof (induct i)
      case 0 show ?case using wf_r by auto
    next
      case (Suc i)
      have "?t (Suc i) = ?t i ⋅ ?σ" unfolding subst_power_Suc subst_compose_def by simp
      also have "funas_term ... ⊆ F" unfolding funas_term_subst[of "?t i"]
        using Suc wf_r by auto
      finally show ?case .
    qed
  } note wf_t = this
  {
    fix i
    have "(t i, t (Suc i)) ∈ (sig_step F (rstep R))" unfolding t
      by (rule sig_stepI[OF rstepI[OF x, of _ □ "?σ ^^ i"] wf_t wf_t], auto simp: subst_compose_def)
  } note steps = this
  have x: "t 0 = Var x" unfolding t by simp
  with steps show ?thesis unfolding SN_defs not_not
    by (intro exI[of _ t], auto)
qed

lemma rhs_free_vars_imp_sig_step_not_SN:
  assumes R: "(l,r) ∈ R" and free: "¬ vars_term r ⊆ vars_term l"
    and F: "funas_trs R ⊆ F"
  shows "¬ SN_on (sig_step F (rstep R)) {l}"
proof -
  from free obtain x where x: "x ∈ vars_term r - vars_term l" by auto
  then have "x ∈ vars_term r" by simp
  from supteq_Var[OF this] have "r ⊵ Var x" .
  then obtain C where r: "C⟨Var x⟩ = r" by auto
  let ?σ = "λy. if y = x then l else Var y"
  let ?t = "λi. ((C ⋅c ?σ)^i)⟨l⟩"
  from rhs_wf[OF R] F have wf_r: "funas_term r ⊆ F" by fast
  from lhs_wf[OF R] F have wf_l: "funas_term l ⊆ F" by fast
  from wf_r[unfolded r[symmetric]]
  have wf_C: "funas_ctxt C ⊆ F" by simp
  from x have neq: "∀y∈vars_term l. y ≠ x" by auto
  have "l⋅?σ = l ⋅ Var"
    by (rule term_subst_eq, insert neq, auto)
  then have l: "l ⋅ ?σ = l" by simp
  have wf_C: "funas_ctxt (C ⋅c ?σ) ⊆ F" using wf_C wf_l
    by simp
  have rsigma: "r⋅?σ = (C ⋅c ?σ)⟨l⟩" unfolding r[symmetric] by simp
  from R have lr: "(l ⋅ ?σ, r ⋅ ?σ) ∈ rstep R" by auto
  then have lr: "(l,(C ⋅c ?σ)⟨l⟩) ∈ rstep R" unfolding l unfolding rsigma .
  show ?thesis
    by (rule wf_loop_imp_sig_ctxt_rel_not_SN[OF lr wf_l wf_C ctxt_closed_rstep])
qed

lemma lhs_var_imp_rstep_not_SN: assumes "(Var x,r) ∈ R" shows "¬ SN(rstep R)"
  using lhs_var_imp_sig_step_not_SN_on[OF assms subset_refl] unfolding sig_step_def SN_defs by blast

lemma rhs_free_vars_imp_rstep_not_SN:
  assumes "(l,r) ∈ R" and "¬ vars_term r ⊆ vars_term l"
  shows "¬ SN_on (rstep R) {l}"
  using rhs_free_vars_imp_sig_step_not_SN[OF assms subset_refl] unfolding sig_step_def SN_defs by blast

lemma free_right_rewrite_imp_not_SN:
  assumes step: "(t,s) ∈ rstep_r_p_s R (l,r) p σ"
    and vars: "¬ vars_term l ⊇ vars_term r"
  shows "¬ SN_on (rstep R) {t}"
proof
  assume SN: "SN_on (rstep R) {t}"
  let ?C = "ctxt_of_pos_term p t"
  from step have left: "?C⟨l ⋅ σ⟩ = t" (is "?t = t") and right: "?C⟨r ⋅ σ⟩ = s" and pos: "p ∈ poss t"
    and rule: "(l,r) ∈ R"
    unfolding rstep_r_p_s_def by (auto simp: Let_def)
  from rhs_free_vars_imp_rstep_not_SN[OF rule vars] have nSN:"¬ SN_on (rstep R) {l}" by simp
  from SN_imp_SN_subt[OF SN ctxt_imp_supteq[of ?C "l ⋅ σ", simplified left]]
  have SN: "SN_on (rstep R) {l ⋅ σ}" .
  from SNinstance_imp_SN[OF SN] nSN show False by simp
qed

lemma not_SN_on_rstep_subst_apply_term[intro]:
  assumes "¬ SN_on (rstep R) {t}" shows "¬ SN_on (rstep R) {t ⋅ σ}"
  using assms unfolding SN_on_def by best

lemma SN_rstep_imp_wf_trs: assumes "SN (rstep R)" shows "wf_trs R"
proof (rule ccontr)
  assume "¬ wf_trs R"
  then obtain l r where R: "(l,r) ∈ R"
    and not_wf: "(∀f ts. l ≠ Fun f ts) ∨ ¬(vars_term r ⊆ vars_term l)" unfolding wf_trs_def
    by auto
  from not_wf have "¬ SN (rstep R)"
  proof
    assume free: "¬ vars_term r ⊆ vars_term l"
    from rhs_free_vars_imp_rstep_not_SN[OF R free] show ?thesis unfolding SN_defs by auto
  next
    assume "∀f ts. l ≠ Fun f ts"
    then obtain x where l:"l = Var x" by (cases l) auto
    with R have "(Var x,r) ∈ R" unfolding l by simp
    from lhs_var_imp_rstep_not_SN[OF this] show ?thesis by simp
  qed
  with assms show False by blast
qed

lemma SN_sig_step_imp_wf_trs: assumes SN: "SN (sig_step F (rstep R))" and F: "funas_trs R ⊆ F" shows "wf_trs R"
proof (rule ccontr)
  assume "¬ wf_trs R"
  then obtain l r where R: "(l,r) ∈ R"
    and not_wf: "(∀f ts. l ≠ Fun f ts) ∨ ¬(vars_term r ⊆ vars_term l)" unfolding wf_trs_def
    by auto
  from not_wf have "¬ SN (sig_step F (rstep R))"
  proof
    assume free: "¬ vars_term r ⊆ vars_term l"
    from rhs_free_vars_imp_sig_step_not_SN[OF R free F] show ?thesis unfolding SN_on_def by auto
  next
    assume "∀f ts. l ≠ Fun f ts"
    then obtain x where l:"l = Var x" by (cases l) auto
    with R have "(Var x,r) ∈ R" unfolding l by simp
    from lhs_var_imp_sig_step_not_SN_on[OF this F] show ?thesis
      unfolding SN_on_def by auto
  qed
  with assms show False by blast
qed

lemma rhs_free_vars_imp_rstep_not_SN':
  assumes "(l, r) ∈ R" and "¬ vars_term r ⊆ vars_term l"
  shows "¬ SN (rstep R)"
  using rhs_free_vars_imp_rstep_not_SN [OF assms] by (auto simp: SN_defs)

lemma SN_imp_variable_condition:
  assumes "SN (rstep R)"
  shows "∀(l, r) ∈ R. vars_term r ⊆ vars_term l"
  using assms and rhs_free_vars_imp_rstep_not_SN' [of _ _ R] by blast

lemma rstep_cases'[consumes 1, case_names root nonroot]:
  assumes rstep: "(s, t) ∈ rstep R"
    and root: "⋀l r σ. (l, r) ∈ R ⟹ l ⋅ σ = s ⟹ r ⋅ σ = t ⟹ P"
    and nonroot: "⋀f ss1 u ss2 v. s = Fun f (ss1 @ u # ss2) ⟹ t = Fun f (ss1 @ v # ss2) ⟹ (u, v) ∈ rstep R ⟹ P"
  shows "P"
proof -
  from rstep_imp_C_s_r[OF rstep] obtain C σ l r
    where R: "(l,r) ∈ R" and s: "C⟨l⋅σ⟩ = s" and t: "C⟨r⋅σ⟩ = t" by fast
  show ?thesis proof (cases C)
    case Hole
    from s t have "l⋅σ = s" and "r⋅σ = t" by (auto simp: Hole)
    with R show ?thesis by (rule root)
  next
    case (More f ss1 D ss2)
    let ?u = "D⟨l⋅σ⟩"
    let ?v  = "D⟨r⋅σ⟩"
    have "s = Fun f (ss1 @ ?u # ss2)" by (simp add: More s[symmetric])
    moreover have "t = Fun f (ss1 @ ?v # ss2)" by (simp add: More t[symmetric])
    moreover have "(?u,?v) ∈ rstep R" using R by auto
    ultimately show ?thesis by (rule nonroot)
  qed
qed

lemma NF_Var: assumes wf: "wf_trs R" shows "(Var x, t) ∉ rstep R"
proof
  assume "(Var x, t) ∈ rstep R"
  from rstep_imp_C_s_r[OF this] obtain C l r σ
    where R: "(l,r) ∈ R" and lhs: "Var x = C⟨l⋅σ⟩" by fast
  from lhs have "Var x = l⋅σ" by (induct C) auto
  then obtain y where l: "l = Var y" by (induct l) auto
  from wf R obtain f ss where "l = Fun f ss" unfolding wf_trs_def by best
  with l show False by simp
qed

lemma rstep_cases_Fun'[consumes 2, case_names root nonroot]:
  assumes wf: "wf_trs R"
    and rstep: "(Fun f ss,t) ∈ rstep R"
    and root': "⋀ls r σ. (Fun f ls,r) ∈ R ⟹ map (λt. t⋅σ) ls = ss ⟹ r⋅σ = t ⟹ P"
    and nonroot': "⋀i u. i < length ss ⟹ t = Fun f (take i ss@u#drop (Suc i) ss) ⟹ (ss!i,u) ∈ rstep R ⟹ P"
  shows "P"
  using rstep proof (cases rule: rstep_cases')
  case (root l r σ)
  with wf obtain g ls where l: "l = Fun g ls" unfolding wf_trs_def by best
  from root have [simp]: "g = f" unfolding l by simp
  from root have "(Fun f ls,r) ∈ R" and "map (λt. t⋅σ) ls = ss" and "r⋅σ = t" unfolding l by auto
  then show ?thesis by (rule root')
next
  case (nonroot g ss1 u ss2 v)
  then have [simp]: "g = f" and args: "ss = ss1 @ u # ss2" by auto
  let ?i = "length ss1"
  from args have ss1: "take ?i ss = ss1" by simp
  from args have "drop ?i ss = u # ss2" by simp
  then have "drop (Suc 0) (drop ?i ss) = ss2" by simp
  then have ss2: "drop (Suc ?i) ss = ss2" by simp
  from args have len: "?i < length ss" by simp
  from id_take_nth_drop[OF len] have "ss = take ?i ss @ ss!?i # drop (Suc ?i) ss" by simp
  then have u: "ss!?i = u" unfolding args unfolding ss1[unfolded args] ss2[unfolded args] by simp
  from nonroot have "t = Fun f (take ?i ss@v#drop (Suc ?i) ss)" unfolding ss1 ss2 by simp
  moreover from nonroot have "(ss!?i,v) ∈ rstep R" unfolding u by simp
  ultimately show ?thesis by (rule nonroot'[OF len])
qed

lemma rstep_preserves_undefined_root:
  assumes "wf_trs R" and "¬ defined R (f, length ss)" and "(Fun f ss, t) ∈ rstep R"
  shows "∃ts. length ts = length ss ∧ t = Fun f ts"
proof -
  from ‹wf_trs R› and ‹(Fun f ss, t) ∈ rstep R› show ?thesis
  proof (cases rule: rstep_cases_Fun')
    case (root ls r σ)
    then have "defined R (f, length ss)" by (auto simp: defined_def)
    with ‹¬ defined R (f, length ss)› show ?thesis by simp
  next
    case (nonroot i u) then show ?thesis by simp
  qed
qed

lemma rstep_ctxt_imp_nrrstep: assumes step: "(s,t) ∈ rstep R" and C: "C ≠ □" shows "(C⟨s⟩,C⟨t⟩) ∈ nrrstep R"
proof -
  from step obtain l r D σ where "(l,r) ∈ R" "s = D⟨l ⋅ σ⟩" "t = D⟨r ⋅ σ⟩" by auto
  thus ?thesis unfolding nrrstep_def' using C
    by (intro CollectI, unfold split, intro exI[of _ "C ∘c D"] exI conjI, auto) (cases C, auto)
qed

lemma rsteps_ctxt_imp_nrrsteps: assumes steps: "(s,t) ∈ (rstep R)*" and C: "C ≠ □" shows "(C⟨s⟩,C⟨t⟩) ∈ (nrrstep R)*"
  using steps 
proof (induct)
  case (step t u)
  from rstep_ctxt_imp_nrrstep[OF step(2) C] step(3) show ?case by simp
qed simp

lemma nrrstep_mono:
  assumes "R ⊆ R'"
  shows "nrrstep R ⊆ nrrstep R'"
  using assms by (force simp: nrrstep_def rstep_r_p_s_def Let_def)

lemma rrstepE:
  assumes "(s, t) ∈ rrstep R"
  obtains l and r and σ where "(l, r) ∈ R" and "s = l ⋅ σ" and "t = r ⋅ σ"
  using assms by (auto simp: rrstep_def rstep_r_p_s_def)

lemma nrrstepE:
  assumes "(s, t) ∈ nrrstep R"
  obtains C and l and r and σ where "C ≠ □" and "(l, r) ∈ R"
    and "s = C⟨l ⋅ σ⟩" and "t = C⟨r ⋅ σ⟩"
  using assms by (auto simp: nrrstep_def rstep_r_p_s_def Let_def)
    (metis ctxt.cop_nil list.discI poss_Cons_poss replace_at_subt_at subt_at_id_imp_eps)


lemma singleton_subst_restrict [simp]:
  "subst x s |s {x} = subst x s"
  unfolding subst_def subst_restrict_def by (rule ext) simp

lemma singleton_subst_map [simp]:
  "f ∘ subst x s = (f ∘ Var)(x := f s)" by (intro ext, auto simp: subst_def)

lemma subst_restrict_vars [simp]:
  "(λz. if z ∈ V then f z else g z) |s V = f |s V"
  unfolding subst_restrict_def
proof (intro ext)
  fix x
  show "(if x ∈ V then if x ∈ V then f x else g x else Var x)
    = (if x ∈ V then f x else Var x)" by simp
qed

lemma subst_restrict_restrict [simp]:
  assumes "V ∩ W = {}"
  shows "((λz. if z ∈ V then f z else g z) |s W) = g |s W"
  unfolding subst_restrict_def
proof (intro ext)
  fix x
  show "(if x ∈ W then if x ∈ V then f x else g x else Var x)
    = (if x ∈ W then g x else Var x)" using assms by auto
qed

lemma rstep_rstep: "rstep (rstep R) = rstep R"
proof -
  have "ctxt.closure (subst.closure (rstep R)) = rstep R" by (simp only: subst_closure_rstep_eq ctxt_closure_rstep_eq)
  then show ?thesis unfolding rstep_eq_closure .
qed

lemma rstep_trancl_distrib: "rstep (R+) ⊆ (rstep R)+"
proof
  fix s t
  assume "(s,t) ∈ rstep (R+)"
  then show "(s,t) ∈ (rstep R)+"
  proof
    fix l r C σ
    presume lr: "(l,r) ∈ R+" and s: "s = C⟨l ⋅ σ⟩" and t: "t = C⟨r ⋅ σ⟩"
    from lr have "(C⟨l ⋅ σ⟩, C⟨r ⋅ σ⟩) ∈ (rstep R)+"
    proof(induct)
      case (base r)
      then show ?case by auto
    next
      case (step r rr)
      from step(2) have "(C⟨r ⋅ σ⟩, C⟨rr ⋅ σ⟩) ∈ (rstep R)" by auto
      with step(3) show ?case by auto
    qed
    then show "(s,t) ∈ (rstep R)+" unfolding s t .
  qed auto
qed

lemma rsteps_closed_subst:
  assumes "(s, t) ∈ (rstep R)*"
  shows "(s ⋅ σ, t ⋅ σ) ∈ (rstep R)*"
  using assms and subst.closed_rtrancl [OF subst_closed_rstep] by (auto simp: subst.closed_def)

lemma join_subst:
  "subst.closed r ⟹ (s, t) ∈ r↓ ⟹ (s ⋅ σ, t ⋅ σ) ∈ r↓"
  by (simp add: join_def subst.closedD subst.closed_comp subst.closed_converse subst.closed_rtrancl)


lemma join_subst_rstep [intro]:
  "(s, t) ∈ (rstep R)↓ ⟹ (s ⋅ σ, t ⋅ σ) ∈ (rstep R)↓"
  by (intro join_subst, auto)

lemma join_ctxt [intro]:
  assumes "(s, t) ∈ (rstep R)↓"
  shows "(C⟨s⟩, C⟨t⟩) ∈ (rstep R)↓"
proof -
  from assms obtain u where "(s, u) ∈ (rstep R)*" and "(t, u) ∈ (rstep R)*" by auto
  then have "(C⟨s⟩, C⟨u⟩) ∈ (rstep R)*" and "(C⟨t⟩, C⟨u⟩) ∈ (rstep R)*" by (auto intro: rsteps_closed_ctxt)
  then show ?thesis by blast
qed

lemma rstep_simps:
  "rstep (R=) = (rstep R)="
  "rstep (rstep R) = rstep R"
  "rstep (R ∪ S) = rstep R ∪ rstep S"
  "rstep Id = Id"
  "rstep (R↔) = (rstep R)↔"
  by auto

lemma rstep_rtrancl_idemp [simp]:
  "rstep ((rstep R)*) = (rstep R)*"
proof -
  { fix s t
    assume "(s, t) ∈ rstep ((rstep R)*)"
    then have "(s, t) ∈ (rstep R)*"
      by (induct) (metis rsteps_closed_ctxt rsteps_closed_subst) }
  then show ?thesis by auto
qed

lemma all_ctxt_closed_rstep_conversion: 
  "all_ctxt_closed UNIV ((rstep R)↔*)" 
  unfolding conversion_def rstep_simps(5)[symmetric] by blast

lemma arg_rstep_imp_rstep: assumes "(ss ! i, ti) ∈ rstep R" and "i < length ss" 
  shows "(Fun f ss, Fun f (ss[i := ti])) ∈ rstep R" 
  using assms by (metis nrrstep_iff_arg_rstep nrrstep_imp_rstep)

lemma arg_rstep_opt_imp_rstep_opt: assumes "(ss ! i, ti) ∈ (rstep R)=" and "i < length ss"
  shows "(Fun f ss, Fun f (ss[i := ti])) ∈ (rstep R)=" 
  using assms by (metis arg_rstep_imp_rstep rstep_simps(1))

lemma arg_rsteps_imp_rsteps: assumes "(ss ! i, ti) ∈ (rstep R)*" and "i < length ss"
  shows "(Fun f ss, Fun f (ss[i := ti])) ∈ (rstep R)*" 
  using assms
  by (metis arg_rstep_imp_rstep rstep_rtrancl_idemp)


definition instance_rule :: "('f, 'v) rule ⇒ ('f, 'w) rule ⇒ bool" where
  "instance_rule lr st ⟷ (∃ σ. fst lr = fst st ⋅ σ ∧ snd lr = snd st ⋅ σ)"
  (* instance rule has implementation in Substitution.thy *)

definition eq_rule_mod_vars :: "('f, 'v) rule ⇒ ('f, 'v) rule ⇒ bool" where
  "eq_rule_mod_vars lr st ⟷ instance_rule lr st ∧ instance_rule st lr"

notation eq_rule_mod_vars ("(_/ =v _)" [51,51] 50)

lemma instance_rule_var_cond: assumes eq: "instance_rule (s,t) (l,r)"
  and vars: "vars_term r ⊆ vars_term l"
shows "vars_term t ⊆ vars_term s"
proof -
  from eq[unfolded instance_rule_def]
  obtain τ where s: "s = l ⋅ τ" and t: "t = r ⋅ τ" by auto
  show ?thesis
  proof
    fix x
    assume "x ∈ vars_term t"
    from this[unfolded t] have "x ∈ vars_term (l ⋅ τ)" using vars unfolding vars_term_subst by auto
    then show "x ∈ vars_term s" unfolding s by auto
  qed
qed

lemma instance_rule_rstep: assumes step: "(s,t) ∈ rstep {lr}"
  and bex: "Bex R (instance_rule lr)"
shows "(s,t) ∈ rstep R"
proof -
  from bex obtain lr' where inst: "instance_rule lr lr'" and R: "lr' ∈ R" by auto
  obtain l r where lr: "lr = (l,r)" by force
  obtain l' r' where lr': "lr' = (l',r')" by force
  note inst = inst[unfolded lr lr']
  note R = R[unfolded lr']
  from inst[unfolded instance_rule_def] obtain σ where l: "l = l' ⋅ σ" and r: "r = r' ⋅ σ" by auto
  from step[unfolded lr] obtain C τ where "s = C ⟨l ⋅ τ⟩" "t = C ⟨r ⋅ τ⟩" by auto
  with l r have s: "s = C⟨l' ⋅ (σ ∘s τ)⟩" and t: "t = C⟨r' ⋅ (σ ∘s τ)⟩" by auto
  from rstepI[OF R s t] show ?thesis .
qed

lemma eq_rule_mod_vars_var_cond: assumes eq: "(l,r) =v (s,t)"
  and vars: "vars_term r ⊆ vars_term l"
shows "vars_term t ⊆ vars_term s"
  by (rule instance_rule_var_cond[OF _ vars], insert eq[unfolded eq_rule_mod_vars_def], auto)

lemma eq_rule_mod_varsE[elim]: fixes l :: "('f,'v)term" 
  assumes "(l,r) =v (s,t)"
  shows "∃ σ τ. l = s ⋅ σ ∧ r = t ⋅ σ ∧ s = l ⋅ τ ∧ t = r ⋅ τ ∧ range σ ⊆ range Var ∧ range τ ⊆ range Var"
proof -
  from assms[unfolded eq_rule_mod_vars_def instance_rule_def fst_conv snd_conv]
  obtain σ τ where l: "l = s ⋅ σ" and r: "r = t ⋅ σ" and s: "s = l ⋅ τ" and t: "t = r ⋅ τ" by blast+
  obtain f :: 'f where True by auto
  let ?vst = "vars_term (Fun f [s,t])"
  let ?vlr = "vars_term (Fun f [l,r])"
  define σ' where "σ' ≡ λ x. if x ∈ ?vst then σ x else Var x"
  define τ' where "τ' ≡ λ x. if x ∈ ?vlr then τ x else Var x"
  show ?thesis
  proof (intro exI conjI)
    show l: "l = s ⋅ σ'" unfolding l σ'_def
      by (rule term_subst_eq, auto)
    show r: "r = t ⋅ σ'" unfolding r σ'_def
      by (rule term_subst_eq, auto)
    show s: "s = l ⋅ τ'" unfolding s τ'_def
      by (rule term_subst_eq, auto)
    show t: "t = r ⋅ τ'" unfolding t τ'_def
      by (rule term_subst_eq, auto)
    have "Fun f [s,t] ⋅ Var = Fun f [l, r] ⋅ τ'" unfolding s t by simp
    also have "… = Fun f [s,t] ⋅ (σ' ∘s τ')" unfolding l r by simp
    finally have "Fun f [s,t] ⋅ (σ' ∘s τ') = Fun f [s,t] ⋅ Var" by simp
    from term_subst_eq_rev[OF this] have vst: "⋀ x. x ∈ ?vst ⟹ σ' x ⋅ τ' = Var x" unfolding subst_compose_def by auto
    have "Fun f [l,r] ⋅ Var = Fun f [s, t] ⋅ σ'" unfolding l r by simp
    also have "… = Fun f [l,r] ⋅ (τ' ∘s σ')" unfolding s t by simp
    finally have "Fun f [l,r] ⋅ (τ' ∘s σ') = Fun f [l,r] ⋅ Var" by simp
    from term_subst_eq_rev[OF this] have vlr: "⋀ x. x ∈ ?vlr ⟹ τ' x ⋅ σ' = Var x" unfolding subst_compose_def by auto
    {
      fix x
      have "σ' x ∈ range Var"
      proof (cases "x ∈ ?vst")
        case True
        from vst[OF this] show ?thesis by (cases "σ' x", auto)
      next
        case False
        then show ?thesis unfolding σ'_def by auto
      qed
    }
    then show "range σ' ⊆ range Var" by auto
    {
      fix x
      have "τ' x ∈ range Var"
      proof (cases "x ∈ ?vlr")
        case True
        from vlr[OF this] show ?thesis by (cases "τ' x", auto)
      next
        case False
        then show ?thesis unfolding τ'_def by auto
      qed
    }
    then show "range τ' ⊆ range Var" by auto
  qed
qed

subsection‹Linear and Left-Linear TRSs›

definition
  linear_trs :: "('f, 'v) trs ⇒ bool"
  where
    "linear_trs R ≡ ∀(l, r)∈R. linear_term l ∧ linear_term r"

lemma linear_trsE[elim,consumes 1]: "linear_trs R ⟹ (l,r) ∈ R ⟹ linear_term l ∧ linear_term r"
  unfolding linear_trs_def by auto

lemma linear_trsI[intro]: "⟦ ⋀ l r. (l,r) ∈ R ⟹ linear_term l ∧ linear_term r⟧ ⟹ linear_trs R"
  unfolding linear_trs_def by auto

definition
  left_linear_trs :: "('f, 'v) trs ⇒ bool"
  where
    "left_linear_trs R ⟷ (∀(l, r)∈R. linear_term l)"

lemma left_linear_trs_union: "left_linear_trs (R ∪ S) = (left_linear_trs R ∧ left_linear_trs S)"
  unfolding left_linear_trs_def by auto

lemma left_linear_mono: assumes "left_linear_trs S" and "R ⊆ S" shows "left_linear_trs R"
  using assms unfolding left_linear_trs_def by auto

lemma left_linear_map_funs_trs[simp]:  "left_linear_trs (map_funs_trs f R) = left_linear_trs R"
  unfolding left_linear_trs_def by (auto simp: map_funs_trs.simps)

lemma left_linear_weak_match_rstep:
  assumes rstep: "(u, v) ∈ rstep R"
    and weak_match: "weak_match s u"
    and ll: "left_linear_trs R"
  shows "∃t. (s, t) ∈ rstep R ∧ weak_match t v"
  using weak_match
proof (induct rule: rstep_induct_rule [OF rstep])
  case (1 C sig l r)
  from 1(2) show ?case
  proof (induct C arbitrary: s)
    case (More f bef C aft s)
    let ?n = "Suc (length bef + length aft)"
    let ?m = "length bef"
    from More(2) obtain ss where s: "s = Fun f ss" and lss: "?n = length ss" and wm: "(∀i<length ss. weak_match (ss ! i) ((bef @ C⟨l ⋅ sig⟩ # aft) ! i))"  by (cases s, auto)
    from lss wm[THEN spec, of ?m] have "weak_match (ss ! ?m) C⟨l ⋅ sig⟩" by auto
    from More(1)[OF this] obtain t where wmt:  "weak_match t C⟨r ⋅ sig⟩" and step: "(ss ! ?m,t) ∈ rstep R" by auto
    from lss have mss: "?m < length ss" by simp
    let ?tsi = "λ t. take ?m ss @ t # drop (Suc ?m) ss"
    let ?ts = "?tsi t"
    let ?ss = "?tsi (ss ! ?m)"
    from id_take_nth_drop[OF mss]
    have lts: "length ?ts = ?n" using lss by auto
    show ?case
    proof (rule exI[of _ "Fun f ?ts"], intro conjI)
      have "weak_match (Fun f ?ts) (More f bef C aft)⟨r ⋅ sig⟩ =
        weak_match (Fun f ?ts) (Fun f (bef @ C⟨r ⋅ sig⟩ # aft))" by simp
      also have "…" proof (unfold weak_match.simps lts, intro conjI refl allI impI)
        fix i
        assume i: "i < ?n"
        show "weak_match (?ts ! i) ((bef @ C⟨r ⋅ sig⟩ # aft) ! i)"
        proof (cases "i = ?m")
          case True
          have "weak_match (?ts ! i) ((bef @ C⟨r ⋅ sig⟩ # aft) ! i) = weak_match t C⟨r ⋅ sig⟩"
            using True mss by (simp add: nth_append)
          then show ?thesis using wmt by simp
        next
          case False
          have eq: "?ts ! i = ss ! i ∧ (bef @ C⟨r ⋅ sig⟩ # aft) ! i = (bef @ C⟨l ⋅ sig⟩ # aft) ! i"
          proof (cases "i < ?m")
            case True
            then show ?thesis by (simp add: nth_append lss[symmetric])
          next
            case False
            with ‹i ≠ ?m› i have "∃ j. i = Suc (?m + j) ∧ j < length aft" by presburger
            then obtain j where i: "i = Suc (?m + j)" and j: "j < length aft" by auto
            then have id: " (Suc (length bef + j) - min (Suc (length bef + length aft)) (length bef)) = Suc j" by simp
            from j show ?thesis by (simp add: nth_append i id lss[symmetric])
          qed
          then show ?thesis using wm[THEN spec, of i] i[unfolded lss] by (simp)
        qed
      qed simp
      finally show "weak_match (Fun f ?ts) (More f bef C aft)⟨r ⋅ sig⟩" by simp
    next
      have "s = Fun f ?ss" unfolding s using id_take_nth_drop[OF mss, symmetric] by simp
      also have "… = (More f (take ?m ss) □ (drop (Suc ?m) ss))⟨(ss ! ?m)⟩" (is "_ = ?C⟨_⟩") by simp
      finally have s: "s = ?C⟨ss ! ?m⟩" .
      have t: "Fun f ?ts = ?C⟨t⟩" by simp
      from rstep_ctxt[OF step]
      show "(s, Fun f ?ts) ∈ rstep R"
        unfolding s t .
    qed
  next
    case (Hole s)
    from ll 1(1) have "linear_term l" unfolding left_linear_trs_def by auto
    from linear_weak_match[OF this Hole[simplified] refl] obtain τ where
      "s = l ⋅ τ" and "(∀ x ∈ vars_term l . weak_match (Var x ⋅ τ) (Var x ⋅ sig))"
      by auto
    then obtain tau where s: "s = l ⋅ tau" and wm: "(∀ x ∈ vars_term l . weak_match (tau x) (Var x ⋅ sig))"
      by (auto)
    let ?delta = "(λ x. if x ∈ vars_term l then tau x else Var x ⋅ sig)"
    show ?case
    proof (rule exI[of _ "r ⋅ ?delta"], rule conjI)
      have "s = l ⋅ (tau |s (vars_term l))" unfolding s by (rule coincidence_lemma)
      also have "… = l ⋅ (?delta  |s (vars_term l))" by simp
      also have "… = l ⋅ ?delta" by (rule coincidence_lemma[symmetric])
      finally have s: "s = l ⋅ ?delta" .
      from 1(1) have step: "(l ⋅ ?delta, r ⋅ ?delta) ∈ rstep R" by auto
      then show "(s, r ⋅ ?delta) ∈ rstep R" unfolding s .
    next
      have "weak_match (r ⋅ ?delta) (r ⋅ sig)"
      proof (induct r)
        case (Fun f ss)
        from this[unfolded set_conv_nth]
        show ?case by (force)
      next
        case (Var x)
        show ?case
        proof (cases "x ∈ vars_term l")
          case True
          with wm Var show ?thesis by simp
        next
          case False
          show ?thesis by (simp add: Var False weak_match_refl)
        qed
      qed
      then show "weak_match (r ⋅ ?delta) (□ ⟨(r ⋅ sig)⟩)" by simp
    qed
  qed
qed

context
begin

private fun S where
  "S R s t 0 = s"
| "S R s t (Suc i) = (SOME u. (S R s t i,u) ∈ rstep R ∧ weak_match u (t(Suc i)))"

lemma weak_match_SN:
  assumes wm: "weak_match s t"
    and ll: "left_linear_trs R"
    and SN: "SN_on (rstep R) {s}"
  shows "SN_on (rstep R) {t}"
proof
  fix f
  assume t0: "f 0 ∈ {t}" and chain: "chain (rstep R) f"
  let ?s = "S R s f"
  let ?P = "λi u. (?s i, u) ∈ rstep R ∧ weak_match u (f (Suc i))"
  have "∀i. (?s i, ?s (Suc i)) ∈ rstep R ∧ weak_match (?s (Suc i)) (f (Suc i))"
  proof
    fix i show "(?s i, ?s (Suc i)) ∈ rstep R ∧ weak_match (?s (Suc i)) (f (Suc i))"
    proof (induct i)
      case 0
      from chain have ini: "(f 0, f (Suc 0)) ∈ rstep R" by simp
      then have "(t, f (Suc 0)) ∈ rstep R" unfolding singletonD[OF t0, symmetric] .
      from someI_ex[OF left_linear_weak_match_rstep[OF this wm ll]]
      show ?case by simp
    next
      case (Suc i)
      then have IH1: "(?s i, ?s (Suc i)) ∈ rstep R"
        and IH2: "weak_match (?s (Suc i)) (f (Suc i))" by auto
      from chain have nxt: "(f (Suc i), f (Suc (Suc i))) ∈ rstep R" by simp
      from someI_ex[OF left_linear_weak_match_rstep[OF this IH2 ll]]
      have "∃u. ?P (Suc i) u" by auto
      from someI_ex[OF this]
      show ?case by simp
    qed
  qed
  moreover have "?s 0 = s" by simp
  ultimately have "¬ SN_on (rstep R) {s}" by best
  with SN show False by simp
qed
end

lemma lhs_notin_NF_rstep: "(l, r) ∈ R ⟹ l ∉ NF (rstep R)" by auto

lemma NF_instance:
  assumes "(t ⋅ σ) ∈ NF (rstep R)" shows "t ∈ NF (rstep R)"
  using assms by auto

lemma NF_subterm:
  assumes "t ∈ NF (rstep R)" and "t ⊵ s"
  shows "s ∈ NF (rstep R)"
proof (rule ccontr)
  assume "¬ ?thesis"
  then obtain u where "(s, u) ∈ rstep R" by auto
  from ‹t ⊵ s› obtain C where "t = C⟨s⟩" by auto
  with ‹(s, u) ∈ rstep R› have "(t, C⟨u⟩) ∈ rstep R" by auto
  then have "t ∉ NF (rstep R)" by auto
  with assms show False by simp
qed

abbreviation
  lhss :: "('f, 'v) trs ⇒ ('f, 'v) terms"
  where
    "lhss R ≡ fst ` R"

abbreviation
  rhss :: "('f, 'v) trs ⇒ ('f, 'v) terms"
  where
    "rhss R ≡ snd ` R"


definition map_funs_trs_wa :: "('f × nat ⇒ 'g) ⇒ ('f, 'v) trs ⇒ ('g, 'v) trs" where
  "map_funs_trs_wa fg R = (λ(l, r). (map_funs_term_wa fg l, map_funs_term_wa fg r)) ` R"

lemma map_funs_trs_wa_union: "map_funs_trs_wa fg (R ∪ S) = map_funs_trs_wa fg R ∪ map_funs_trs_wa fg S"
  unfolding map_funs_trs_wa_def by auto

lemma map_funs_term_wa_compose: "map_funs_term_wa gh (map_funs_term_wa fg t) = map_funs_term_wa (λ (f,n). gh (fg (f,n), n)) t"
  by (induct t, auto)

lemma map_funs_trs_wa_compose: "map_funs_trs_wa gh (map_funs_trs_wa fg R) = map_funs_trs_wa (λ (f,n). gh (fg (f,n), n)) R" (is "?L = map_funs_trs_wa ?fgh R")
proof -
  have "map_funs_trs_wa ?fgh R = {(map_funs_term_wa ?fgh l, map_funs_term_wa ?fgh r)| l r. (l,r) ∈ R}" unfolding map_funs_trs_wa_def by auto
  also have "… = {(map_funs_term_wa gh (map_funs_term_wa fg l), map_funs_term_wa gh (map_funs_term_wa fg r)) | l r. (l,r) ∈ R}" unfolding map_funs_term_wa_compose ..
  finally show ?thesis unfolding map_funs_trs_wa_def by force
qed

lemma map_funs_trs_wa_funas_trs_id: assumes R: "funas_trs R ⊆ F"
  and id: "⋀ g n. (g,n) ∈ F ⟹ f (g,n) = g"
shows "map_funs_trs_wa f R = R"
proof -
  {
    fix l r
    assume "(l,r) ∈ R"
    with R have l: "funas_term l ⊆ F" and r: "funas_term r ⊆ F" unfolding funas_trs_def
      by (force simp: funas_rule_def)+
    from map_funs_term_wa_funas_term_id[OF l id] map_funs_term_wa_funas_term_id[OF r id]
    have "map_funs_term_wa f l = l" "map_funs_term_wa f r = r" by auto
  } note main = this
  have "map_funs_trs_wa f R = {(map_funs_term_wa f l, map_funs_term_wa f r) | l r. (l,r) ∈ R}"
    unfolding map_funs_trs_wa_def by force
  also have "… = R" using main by force
  finally show ?thesis .
qed

lemma map_funs_trs_wa_rstep: assumes step:"(s,t) ∈ rstep R"
  shows "(map_funs_term_wa fg s,map_funs_term_wa fg t) ∈ rstep (map_funs_trs_wa fg R)"
  using step
proof (induct)
  case (IH C σ l r)
  show ?case unfolding map_funs_trs_wa_def
    by (rule rstepI[where l = "map_funs_term_wa fg l" and r = "map_funs_term_wa fg r" and C = "map_funs_ctxt_wa fg C"], auto simp: IH)
qed

lemma map_funs_trs_wa_rsteps: assumes step:"(s,t) ∈ (rstep R)*"
  shows "(map_funs_term_wa fg s,map_funs_term_wa fg t) ∈ (rstep (map_funs_trs_wa fg R))*"
  using step
proof (induct)
  case (step a b)
  from map_funs_trs_wa_rstep[OF step(2), of fg] step(3) show ?case by auto
qed auto

lemma rstep_ground:
  assumes wf_trs: "⋀l r. (l, r) ∈ R ⟹ vars_term r ⊆ vars_term l"
    and ground: "ground s"
    and step: "(s, t) ∈ rstep R"
  shows "ground t"
  using step ground
proof (induct)
  case (IH C σ l r)
  from wf_trs[OF IH(1)] IH(2)
  show ?case by auto
qed

lemma rsteps_ground:
  assumes wf_trs: "⋀l r. (l, r) ∈ R ⟹ vars_term r ⊆ vars_term l"
    and ground: "ground s"
    and steps: "(s, t) ∈ (rstep R)*"
  shows "ground t"
  using steps ground
  by (induct, insert rstep_ground[OF wf_trs], auto)

definition locally_terminating :: "('f,'v)trs ⇒ bool"
  where "locally_terminating R ≡ ∀ F. finite F ⟶ SN (sig_step F (rstep R))"

definition "non_collapsing R ⟷ (∀ lr ∈ R. is_Fun (snd lr))"

lemma supt_rstep_stable:
  assumes "(s, t) ∈ {⊳} ∪ rstep R"
  shows "(s ⋅ σ, t ⋅ σ) ∈ {⊳} ∪ rstep R"
  using assms proof
  assume "s ⊳ t" show ?thesis
  proof (rule UnI1)
    from ‹s ⊳ t› show "s ⋅ σ ⊳ t ⋅ σ" by (rule supt_subst)
  qed
next
  assume "(s, t) ∈ rstep R" show ?thesis
  proof (rule UnI2)
    from ‹(s, t) ∈ rstep R› show "(s ⋅ σ, t ⋅ σ) ∈ rstep R" ..
  qed
qed

lemma supt_rstep_trancl_stable:
  assumes "(s, t) ∈ ({⊳} ∪ rstep R)+"
  shows "(s ⋅ σ, t ⋅ σ) ∈ ({⊳} ∪ rstep R)+"
  using assms proof (induct)
  case (base u)
  then have "(s ⋅ σ, u ⋅ σ) ∈ {⊳} ∪ rstep R" by (rule supt_rstep_stable)
  then show ?case ..
next
  case (step u v)
  from ‹(s ⋅ σ, u ⋅ σ) ∈ ({⊳} ∪ rstep R)+›
    and supt_rstep_stable[OF ‹(u, v) ∈ {⊳} ∪ rstep R›, of "σ"]
  show ?case ..
qed

lemma supt_rsteps_stable:
  assumes "(s, t) ∈ ({⊳} ∪ rstep R)*"
  shows "(s ⋅ σ, t ⋅ σ) ∈ ({⊳} ∪ rstep R)*"
  using assms
proof (induct)
  case base then show ?case ..
next
  case (step u v)
  from ‹(s, u) ∈ ({⊳} ∪ rstep R)*› and ‹(u, v) ∈ {⊳} ∪ rstep R›
  have "(s, v) ∈ ({⊳} ∪ rstep R)+" by (rule rtrancl_into_trancl1)
  from trancl_into_rtrancl[OF supt_rstep_trancl_stable[OF this]]
  show ?case .
qed

lemma eq_rule_mod_vars_refl[simp]: "r =v r"
proof (cases r)
  case (Pair l r)
  {
    have "fst (l, r) = fst (l, r) ⋅ Var ∧ snd (l, r) = snd (l, r) ⋅ Var" by auto
  }
  then show ?thesis unfolding Pair eq_rule_mod_vars_def instance_rule_def by best
qed

lemma instance_rule_refl[simp]: "instance_rule r r"
  using eq_rule_mod_vars_refl[of r] unfolding eq_rule_mod_vars_def by simp

lemma is_Fun_Fun_conv: "is_Fun t = (∃f ts. t = Fun f ts)" by auto

lemma wf_trs_def':
  "wf_trs R = (∀(l, r)∈R. is_Fun l ∧ vars_term r ⊆ vars_term l)"
  by (rule iffI) (auto simp: wf_trs_def is_Fun_Fun_conv)

definition wf_rule :: "('f, 'v) rule ⇒ bool" where
  "wf_rule r ⟷ is_Fun (fst r) ∧ vars_term (snd r) ⊆ vars_term (fst r)"

definition wf_rules :: "('f, 'v) trs ⇒ ('f, 'v) trs" where
  "wf_rules R = {r. r ∈ R ∧ wf_rule r}"

lemma wf_trs_wf_rules[simp]: "wf_trs (wf_rules R)"
  unfolding wf_trs_def' wf_rules_def wf_rule_def split_def by simp

lemma wf_rules_subset[simp]: "wf_rules R ⊆ R"
  unfolding wf_rules_def by auto

fun wf_reltrs :: "('f, 'v) trs ⇒ ('f, 'v) trs  ⇒ bool" where
  "wf_reltrs R S = (
    wf_trs R ∧ (R ≠ {} ⟶ (∀l r. (l, r) ∈ S ⟶ vars_term r ⊆ vars_term l)))"

lemma SN_rel_imp_wf_reltrs:
  assumes SN_rel: "SN_rel (rstep R) (rstep S)"
  shows "wf_reltrs R S"
proof (rule ccontr)
  assume "¬ ?thesis"
  then obtain l r where "¬ wf_trs R ∨ R ≠ {} ∧ (l,r) ∈ S ∧ ¬ vars_term r ⊆ vars_term l" (is "_ ∨ ?two") by auto
  then show False
  proof
    assume "¬ wf_trs R"
    with SN_rstep_imp_wf_trs[OF SN_rel_imp_SN[OF assms]]
    show False by simp
  next
    assume ?two
    then obtain ll rr x where lr: "(l,r) ∈ S" and llrr: "(ll,rr) ∈ R" and x: "x ∈ vars_term r" and nx: "x ∉ vars_term l" by auto
    obtain f and σ
      where sigma: "σ = (λy. if x = y then Fun f [ll,l] else Var y)" by auto
    have id: "σ |s (vars_term l) = Var" unfolding sigma
      by (simp add: subst_restrict_def, rule ext, auto simp: nx)
    have l: "l = l ⋅ σ"  by (simp add: coincidence_lemma[of l σ] id)
    have "(l ⋅ σ, r ⋅ σ) ∈ rstep S" using lr by auto
    with l have sstep: "(l, r ⋅ σ) ∈ rstep S" by simp
    from supteq_subst[OF supteq_Var[OF x], of σ] have
      "r ⋅ σ ⊵ Fun f [ll,l]" unfolding sigma by auto
    then obtain C where "C⟨Fun f [ll, l]⟩ = r ⋅ σ" by auto
    with sstep have sstep: "(l,C⟨Fun f [ll, l]⟩) ∈ rstep S" by simp
    obtain r where r: "r = relto (rstep R) (rstep S) ∪ {⊳}" by auto
    have "(C⟨Fun f [ll,l]⟩, C⟨Fun f [rr,l]⟩) ∈ rstep R"
      by (intro rstepI[OF llrr, of _ "C ∘c More f [] □ [l]" Var], auto)
    with sstep have relto: "(l,C⟨Fun f [rr,l]⟩) ∈ r" unfolding  r by auto
    have "C⟨Fun f [rr,l]⟩ ⊵ Fun f [rr,l]" using ctxt_imp_supteq by auto
    also have "Fun f [rr,l] ⊳ l" by auto
    finally have supt: "C⟨Fun f [rr,l]⟩ ⊳ l" unfolding supt_def by simp
    then have "(C⟨Fun f [rr,l]⟩, l) ∈ r" unfolding r by auto
    with relto have loop: "(l, l) ∈ r+" by auto
    have "SN r" unfolding r
      by (rule SN_imp_SN_union_supt[OF SN_rel[unfolded SN_rel_defs]], blast)
    then have "SN (r+)" by (rule SN_imp_SN_trancl)
    with loop show False unfolding SN_on_def by auto
  qed
qed

lemmas rstep_wf_rules_subset = rstep_mono[OF wf_rules_subset]

definition map_vars_trs :: "('v ⇒ 'w) ⇒ ('f, 'v) trs ⇒ ('f, 'w) trs" where
  "map_vars_trs f R = (λ (l, r). (map_vars_term f l, map_vars_term f r)) ` R"

lemma map_vars_trs_rstep:
  assumes "(s, t) ∈ rstep (map_vars_trs f R)" (is "_ ∈ rstep ?R")
  shows "(s ⋅ τ, t ⋅ τ) ∈ rstep R"
  using assms
proof
  fix ml mr C σ
  presume mem: "(ml,mr) ∈ ?R" and s: "s = C⟨ml ⋅ σ⟩" and t: "t = C⟨mr ⋅ σ⟩"
  let ?m = "map_vars_term f"
  from mem obtain l r where mem: "(l,r) ∈ R" and id: "ml = ?m l" "mr = ?m r"
    unfolding map_vars_trs_def by auto
  have id: "s ⋅ τ = (C ⋅c τ)⟨?m l ⋅ σ ∘s τ⟩" "t ⋅ τ = (C ⋅c τ)⟨?m r ⋅ σ ∘s τ⟩" by (auto simp: s t id)
  then show "(s ⋅ τ, t ⋅ τ) ∈ rstep R"
    unfolding id apply_subst_map_vars_term
    using mem by auto
qed auto

lemma map_vars_rsteps:
  assumes "(s,t) ∈ (rstep (map_vars_trs f R))*" (is "_ ∈ (rstep ?R)*")
  shows "(s ⋅ τ, t ⋅ τ) ∈ (rstep R)*"
  using assms
proof (induct)
  case base then show ?case by simp
next
  case (step t u)
  from map_vars_trs_rstep[OF step(2), of τ] step(3) show ?case by auto
qed

lemma rsteps_subst_closed: "(s,t) ∈ (rstep R)+ ⟹ (s ⋅ σ, t ⋅ σ) ∈ (rstep R)+"
proof -
  let ?R = "rstep R"
  assume steps: "(s,t) ∈ ?R+"
  have subst: "subst.closed (?R+)" by (rule subst.closed_trancl[OF subst_closed_rstep])
  from this[unfolded subst.closed_def] steps show ?thesis by auto
qed

lemma supteq_rtrancl_supt:
  "(R+ O {⊵}) ⊆ ({⊳} ∪ R)+" (is "?l ⊆ ?r")
proof
  fix x z
  assume "(x,z) ∈ ?l"
  then obtain y where xy: "(x,y) ∈ R+" and yz: "y ⊵ z" by auto
  from xy have xy: "(x,y) ∈ ?r" by (rule trancl_mono, simp)
  show "(x,z) ∈ ?r"
  proof (cases "y = z")
    case True
    with xy show ?thesis by simp
  next
    case False
    with yz have yz: "(y,z) ∈ {⊳} ∪ R" by auto
    with xy have xz: "(x,z) ∈ ?r O ({⊳} ∪ R)" by auto
    then show ?thesis by (metis UnCI trancl_unfold)
  qed
qed

lemma rrstepI[intro]: "(l, r) ∈ R ⟹ s = l ⋅ σ ⟹ t = r ⋅ σ ⟹ (s, t) ∈ rrstep R"
  unfolding rrstep_def' by auto

lemma CS_rrstep_conv: "subst.closure = rrstep"
  apply (intro ext)
  apply (unfold rrstep_def')
  apply (intro subset_antisym)
  by (insert subst.closure.cases, blast, auto)

text ‹Rewrite steps at a fixed position›

inductive_set rstep_pos :: "('f, 'v) trs ⇒ pos ⇒ ('f, 'v) term rel" for R and p
  where
    rule [intro]:"(l, r) ∈ R ⟹ p ∈ poss s ⟹ s |_ p = l ⋅ σ ⟹
    (s, replace_at s p (r ⋅ σ)) ∈ rstep_pos R p"

lemma rstep_pos_subst:
  assumes "(s, t) ∈ rstep_pos R p"
  shows "(s ⋅ σ, t ⋅ σ) ∈ rstep_pos R p"
  using assms
proof (cases)
  case (rule l r σ')
  with rstep_pos.intros [OF this(2), of p "s ⋅ σ" "σ' ∘s σ"]
  show ?thesis by (auto simp: ctxt_of_pos_term_subst)
qed

lemma rstep_pos_rule:
  assumes "(l, r) ∈ R"
  shows "(l, r) ∈ rstep_pos R []"
  using rstep_pos.intros [OF assms, of "[]" l Var] by simp

lemma rstep_pos_rstep_r_p_s_conv:
  "rstep_pos R p = {(s, t) | s t r σ. (s, t) ∈ rstep_r_p_s R r p σ}"
  by (auto simp: rstep_r_p_s_def Let_def subt_at_ctxt_of_pos_term
      intro: replace_at_ident
      elim!: rstep_pos.cases)

lemma rstep_rstep_pos_conv:
  "rstep R = {(s, t) | s t p. (s, t) ∈ rstep_pos R p}"
  by (force simp: rstep_pos_rstep_r_p_s_conv rstep_iff_rstep_r_p_s)

lemma rstep_pos_supt:
  assumes "(s, t) ∈ rstep_pos R p"
    and q: "q ∈ poss u" and u: "u |_ q = s"
  shows "(u, (ctxt_of_pos_term q u)⟨t⟩) ∈ rstep_pos R (q @ p)"
  using assms
proof (cases)
  case (rule l r σ)
  with q and u have "(q @ p) ∈ poss u" and "u |_ (q @ p) = l ⋅ σ" by auto
  with rstep_pos.rule [OF rule(2) this] show ?thesis
    unfolding rule by (auto simp: ctxt_of_pos_term_append u)
qed

lemma rrstep_rstep_pos_conv:
  "rrstep R = rstep_pos R []"
  by (auto simp: rrstep_def rstep_pos_rstep_r_p_s_conv)

lemma rrstep_imp_rstep:
  assumes "(s, t) ∈ rrstep R"
  shows "(s, t) ∈ rstep R"
  using assms by (auto simp: rrstep_def rstep_iff_rstep_r_p_s)

lemma not_NF_rstep_imp_subteq_not_NF_rrstep:
  assumes "s ∉ NF (rstep R)"
  shows "∃t ⊴ s. t ∉ NF (rrstep R)"
proof -
  from assms obtain u where "(s, u) ∈ rstep R" by auto
  then obtain l r C σ where "(l, r) ∈ R" and s: "s = C⟨l ⋅ σ⟩" and u: "u = C⟨r ⋅ σ⟩" by auto
  then have "(l ⋅ σ, r ⋅ σ) ∈ rrstep R" and "l ⋅ σ ⊴ s" by auto
  then show ?thesis by blast
qed

lemma all_subt_NF_rrstep_iff_all_subt_NF_rstep:
  "(∀s ⊲ t. s ∈ NF (rrstep R)) ⟷ (∀s ⊲ t. s ∈ NF (rstep R))"
  by (auto dest: rrstep_imp_rstep supt_supteq_trans not_NF_rstep_imp_subteq_not_NF_rrstep)

lemma not_in_poss_imp_NF_rstep_pos [simp]:
  assumes "p ∉ poss s"
  shows "s ∈ NF (rstep_pos R p)"
  using assms by (auto simp: NF_def elim: rstep_pos.cases)

lemma Var_rstep_imp_rstep_pos_Empty:
  assumes "(Var x, t) ∈ rstep R"
  shows "(Var x, t) ∈ rstep_pos R []"
  using assms by (metis Var_supt nrrstep_subt rrstep_rstep_pos_conv rstep_cases)

lemma rstep_args_NF_imp_rrstep:
  assumes "(s, t) ∈ rstep R"
    and "∀u ⊲ s. u ∈ NF (rstep R)"
  shows "(s, t) ∈ rrstep R"
  using assms by (metis NF_iff_no_step nrrstep_subt rstep_cases)

lemma rstep_pos_imp_rstep_pos_Empty:
  assumes "(s, t) ∈ rstep_pos R p"
  shows "(s |_ p, t |_ p) ∈ rstep_pos R []"
  using assms by (cases) (auto simp: replace_at_subt_at intro: rstep_pos_rule rstep_pos_subst)

lemma rstep_pos_arg:
  assumes "(s, t) ∈ rstep_pos R p"
    and "i < length ss" and "ss ! i = s"
  shows "(Fun f ss, (ctxt_of_pos_term [i] (Fun f ss))⟨t⟩) ∈ rstep_pos R (i # p)"
  using assms
  by cases (auto simp: rstep_pos.simps)

lemma rstep_imp_max_pos:
  assumes "(s, t) ∈ rstep R"
  shows "∃u. ∃p∈poss s. (s, u) ∈ rstep_pos R p ∧ (∀v ⊲ s |_ p. v ∈ NF (rstep R))"
  using assms
proof (induction s arbitrary: t)
  case (Var x)
  from Var_rstep_imp_rstep_pos_Empty [OF this] show ?case by auto
next
  case (Fun f ss)
  show ?case
  proof (cases "∀v ⊲ Fun f ss |_ []. v ∈ NF (rstep R)")
    case True
    moreover with Fun.prems
    have "(Fun f ss, t) ∈ rstep_pos R []"
      by (auto dest: rstep_args_NF_imp_rrstep simp: rrstep_rstep_pos_conv)
    ultimately show ?thesis by auto
  next
    case False
    then obtain v where "v ⊲ Fun f ss" and "v ∉ NF (rstep R)" by auto
    then obtain s and w where "s ∈ set ss" and "s ⊵ v" and "(s, w) ∈ rstep R"
      by (auto simp: NF_def) (metis NF_iff_no_step NF_subterm supt_Fun_imp_arg_supteq)
    from Fun.IH [OF this(1, 3)] obtain u and p
      where "p ∈ poss s" and *: "(s, u) ∈ rstep_pos R p"
        and **: "∀v ⊲ s |_ p. v ∈ NF (rstep R)" by blast
    from ‹s ∈ set ss› obtain i
      where "i < length ss" and [simp]:"ss ! i = s" by (auto simp: in_set_conv_nth)
    with ‹p ∈ poss s› have "i # p ∈ poss (Fun f ss)" by auto
    moreover with ** have "∀v ⊲ Fun f ss |_ (i # p). v ∈ NF (rstep R)" by auto
    moreover from rstep_pos_arg [OF * ‹i < length ss› ‹ss ! i = s›]
    have "(Fun f ss, (ctxt_of_pos_term [i] (Fun f ss))⟨u⟩) ∈ rstep_pos R (i # p)" .
    ultimately show ?thesis by blast
  qed
qed

subsection‹Normal Forms›

abbreviation NF_trs :: "('f, 'v) trs ⇒ ('f, 'v) terms" where
  "NF_trs R ≡ NF (rstep R)"

lemma NF_trs_mono: "r ⊆ s ⟹ NF_trs s ⊆ NF_trs r"
  by (rule NF_anti_mono[OF rstep_mono])

lemma NF_trs_union: "NF_trs (R ∪ S) = NF_trs R ∩ NF_trs S"
  unfolding rstep_union using NF_anti_mono[of _ "rstep R ∪ rstep S"] by auto

abbreviation NF_terms :: "('f, 'v) terms ⇒ ('f, 'v) terms" where
  "NF_terms Q ≡ NF (rstep (Id_on Q))"

lemma NF_terms_anti_mono:
  "Q ⊆ Q' ⟹ NF_terms Q' ⊆ NF_terms Q"
  by (rule NF_trs_mono, auto)

lemma lhs_var_not_NF:
  assumes "l ∈ T" and "is_Var l" shows "t ∉ NF_terms T"
proof -
  from assms obtain x where l: "l = Var x" by (cases l, auto)
  let ?σ = "subst x t"
  from assms have "l ∉ NF_terms T" by auto
  with NF_instance[of l "?σ" "Id_on T"]
  have "l ⋅ ?σ ∉ NF_terms T" by auto
  then show ?thesis by (simp add: l subst_def)
qed

lemma not_NF_termsE[elim]:
  assumes "s ∉ NF_terms Q"
  obtains l C σ where "l ∈ Q" and "s = C⟨l ⋅ σ⟩"
proof -
  from assms obtain t where "(s, t) ∈ rstep (Id_on Q)" by auto
  with ‹⋀l C σ. ⟦l ∈ Q; s = C⟨l ⋅ σ⟩⟧ ⟹ thesis› show ?thesis by auto
qed

lemma notin_NF_E [elim]:
  fixes R :: "('f, 'v) trs"
  assumes "t ∉ NF_trs R"
  obtains C l and σ :: "('f, 'v) subst" where "l ∈ lhss R" and "t = C⟨l ⋅ σ⟩"
proof -
  assume 1: "⋀l C (σ::('f, 'v) subst). l ∈ lhss R ⟹ t = C⟨l ⋅ σ⟩ ⟹ thesis"
  from assms obtain u where "(t, u) ∈ rstep R" by (auto simp: NF_def)
  then obtain C σ l r where "(l, r) ∈ R" and "t = C⟨l ⋅ σ⟩" by blast
  with 1 show ?thesis by force
qed

lemma NF_ctxt_subst: "NF_terms Q = {t. ¬ (∃ C q σ. t = C⟨q⋅σ⟩ ∧ q ∈ Q)}" (is "_ = ?R")
proof -
  {
    fix t
    assume "t ∉ ?R"
    then obtain C q σ where t: "t = C⟨q⋅σ⟩" and q: "q ∈ Q" by auto
    have "(t,t) ∈ rstep (Id_on Q)"
      unfolding t using q by auto
    then have "t ∉ NF_terms Q" by auto
  }
  moreover
  {
    fix t
    assume "t ∉ NF_terms Q"
    then obtain C q σ where t: "t = C⟨q⋅σ⟩" and q: "q ∈ Q" by auto
    then have "t ∉ ?R" by auto
  }
  ultimately show ?thesis by auto
qed

lemma some_NF_imp_no_Var:
  assumes "t ∈ NF_terms Q"
  shows "Var x ∉ Q"
proof
  assume "Var x ∈ Q"
  with assms[unfolded NF_ctxt_subst] have "⋀ σ C. t ≠ C ⟨ σ x ⟩" by force
  from this[of Hole "λ _. t"] show False by simp
qed

lemma NF_map_vars_term_inj:
  assumes inj: "⋀ x. n (m x) = x" and NF: "t ∈ NF_terms Q"
  shows "(map_vars_term m t) ∈ NF_terms (map_vars_term m ` Q)"
proof (rule ccontr)
  assume "¬ ?thesis"
  then obtain u where "(map_vars_term m t, u) ∈ rstep (Id_on (map_vars_term m ` Q))" by blast
  then obtain ml mr C σ where in_mR: "(ml, mr) ∈ Id_on (map_vars_term m ` Q)"
    and mt: "map_vars_term m t = C⟨ml ⋅ σ⟩" by best
  let ?m = n
  from in_mR obtain l r where "(l, r) ∈ Id_on Q" and ml: "ml = map_vars_term m l" by auto
  have "t = map_vars_term ?m (map_vars_term m t)" by (simp add: map_vars_term_inj_compose[of n m, OF inj])
  also have "… = map_vars_term ?m (C⟨ml ⋅ σ⟩)" by (simp add: mt)
  also have "… = (map_vars_ctxt ?m C)⟨map_vars_term ?m (map_vars_term m l ⋅ σ)⟩"
    by (simp add: map_vars_term_ctxt_commute ml)
  also have "… = (map_vars_ctxt ?m C)⟨l ⋅ (map_vars_subst_ran ?m (σ ∘ m))⟩"
    by (simp add: apply_subst_map_vars_term map_vars_subst_ran)
  finally show False using NF and ‹(l, r) ∈ Id_on Q› by auto
qed

lemma notin_NF_terms: "t ∈ Q ⟹ t ∉ NF_terms Q"
  using lhs_notin_NF_rstep[of t t "Id_on Q"] by (simp add: Id_on_iff)

lemma NF_termsI [intro]:
  assumes NF: "⋀ C l σ. t = C ⟨l ⋅ σ⟩ ⟹ l ∈ Q ⟹ False"
  shows "t ∈ NF_terms Q"
  by (rule ccontr, rule not_NF_termsE [OF _ NF])

lemma NF_args_imp_NF:
  assumes ss: "⋀ s. s ∈ set ss ⟹ s ∈ NF_terms Q"
    and someNF: "t ∈ NF_terms Q"
    and root: "Some (f,length ss) ∉ root ` Q"
  shows "(Fun f ss) ∈ NF_terms Q"
proof
  fix C l σ
  assume id: "Fun f ss = C ⟨ l ⋅ σ ⟩" and l: "l ∈ Q"
  show False
  proof (cases C)
    case Hole
    with id have id: "Fun f ss = l ⋅ σ" by simp
    show False
    proof (cases l)
      case (Fun g ls)
      with id have fg: "f = g" and ss: "ss = map (λ s. s ⋅ σ) ls" by auto
      from arg_cong[OF ss, of length] have len: "length ss = length ls" by simp
      from l[unfolded Fun] root[unfolded fg len] show False by force
    next
      case (Var x)
      from some_NF_imp_no_Var[OF someNF] Var l show False by auto
    qed
  next
    case (More g bef D aft)
    note id = id[unfolded More]
    from id have NF: "ss ! length bef = D ⟨l ⋅ σ⟩" by auto
    from id have mem: "ss ! length bef ∈ set ss" by auto
    from ss[OF mem, unfolded NF_ctxt_subst NF] l show False by auto
  qed
qed

lemma NF_Var_is_Fun:
  assumes Q: "Ball Q is_Fun"
  shows "Var x ∈ NF_terms Q"
proof
  fix C l σ
  assume x: "Var x = C ⟨ l ⋅ σ ⟩" and l: "l ∈ Q"
  from l Q obtain f ls where l: "l = Fun f ls" by (cases l, auto)
  then show False using x by (cases C, auto)
qed

lemma NF_terms_lhss [simp]: "NF_terms (lhss R) = NF (rstep R)"
proof
  show "NF (rstep R) ⊆ NF_terms (lhss R)" by force
next
  show "NF_terms (lhss R) ⊆ NF (rstep R)"
  proof
    fix s assume NF: "s ∈ NF_terms (lhss R)"
    show "s ∈ NF (rstep R)"
    proof (rule ccontr)
      assume "s ∉ NF (rstep R)"
      then obtain t where "(s, t) ∈ rstep R" by auto
      then obtain l r C σ where "(l, r) ∈ R" and s: "s = C⟨l ⋅ σ⟩" by auto
      then have "(l, l) ∈ Id_on (lhss R)" by force
      then have "(s, s) ∈ rstep (Id_on (lhss R))" unfolding s by auto
      with NF show False by auto
    qed
  qed
qed

subsection‹Relative Rewrite Steps›

abbreviation "relstep R E ≡ relto (rstep R) (rstep E)"

lemma args_SN_on_relstep_nrrstep_imp_args_SN_on:
  assumes SN: "⋀ u. s ⊳ u ⟹ SN_on (relstep R E) {u}"
    and st: "(s,t) ∈ nrrstep (R ∪ E)"
    and supt: "t ⊳ u"
  shows "SN_on (relstep R E) {u}"
proof -
  from nrrstepE[OF st] obtain C l r σ where "C ≠ □" and lr: "(l,r) ∈ R ∪ E"
    and s: "s = C⟨l ⋅ σ⟩" and t: "t = C⟨r ⋅ σ⟩" by blast
  then obtain f bef C aft where s: "s = Fun f (bef @ C⟨l ⋅ σ⟩ # aft)" and t: "t = Fun f (bef @ C⟨r ⋅ σ⟩ # aft)"
    by (cases C, auto)
  let ?ts = "bef @ C⟨r ⋅ σ⟩ # aft"
  let ?ss = "bef @ C⟨l ⋅ σ⟩ # aft"
  from supt obtain D where "t = D⟨u⟩" and "D ≠ □" by auto
  then obtain bef' aft' D where t': "t = Fun f (bef' @ D⟨u⟩ # aft')" unfolding t by (cases D, auto)
  have "D⟨u⟩ ⊵ u" by auto
  then have supt: "⋀ s. s ⊳ D⟨u⟩ ⟹ s ⊳ u" by (metis supt_supteq_trans)
  show "SN_on (relstep R E) {u}"
  proof (cases "D⟨u⟩ ∈ set ?ss")
    case True
    then have "s ⊳ D⟨u⟩" unfolding s by auto
    then have "s ⊳ u" by (rule supt)
    with SN show ?thesis by auto
  next
    case False
    have "D⟨u⟩ ∈ set ?ts" using arg_cong[OF t'[unfolded t], of args] by auto
    with False have Du: "D⟨u⟩ = C⟨r ⋅ σ⟩" by auto
    have "s ⊳ C⟨l ⋅ σ⟩" unfolding s by auto
    with SN have "SN_on (relstep R E) {C⟨l ⋅ σ⟩}" by auto
    from step_preserves_SN_on_relto[OF _ this, of "C⟨r ⋅ σ⟩"] lr
    have SN: "SN_on (relstep R E) {D⟨u⟩}" using Du by auto
    show ?thesis
      by (rule ctxt_closed_SN_on_subt[OF ctxt.closed_relto SN], auto)
  qed
qed

lemma Tinf_nrrstep:
  assumes tinf: "s ∈ Tinf (relstep R E)" and st: "(s,t) ∈ nrrstep (R ∪ E)"
    and t: "¬ SN_on (relstep R E) {t}"
  shows "t ∈ Tinf (relstep R E)"
  unfolding Tinf_def
  by (intro CollectI conjI[OF t] allI impI)
    (rule args_SN_on_relstep_nrrstep_imp_args_SN_on[OF _ st],
      insert tinf[unfolded Tinf_def], auto)

lemma Tinf_rstep_imp_first_root_step: assumes "s ∈ Tinf (rstep R)" 
  shows "∃ t u. (s,t) ∈ (nrrstep R)^* ∧ (t,u) ∈ rrstep R ∧ t ∈ Tinf (rstep R) ∧ ¬ SN_on (rstep R) {u}"
proof -
  from assms have "¬ SN_on (rstep R) {s}" unfolding Tinf_def by auto
  then obtain f where f0: "f 0 = s" and steps: "⋀ i. (f i, f (Suc i)) ∈ rstep R" by auto
  show ?thesis
  proof (cases "∃ i. (f i, f (Suc i)) ∈ rrstep R")
    case True
    define i where "i = (LEAST i. (f i, f (Suc i)) ∈ rrstep R)" 
    from LeastI_ex[OF True, folded i_def]
    have rrstep: "(f i, f (Suc i)) ∈ rrstep R" .
    have nSN: "¬ SN_on (rstep R) {f j}" for j using steps 
      by (simp add: chain_imp_not_SN_on steps)
    have nrr: "(f j, f (Suc j)) ∈ nrrstep R" if "j < i" for j
      using not_less_Least[OF that[unfolded i_def]] steps[of j]
      using rstep_cases by blast
    hence steps: "(s, f i) ∈ (nrrstep R)^*" unfolding f0[symmetric]
      by (metis rtrancl_fun_conv)
    have "f j ∈ Tinf (rstep R)" if "j ≤ i" for j using that
    proof (induct j)
      case 0
      show ?case using assms f0 by auto
    next
      case (Suc j)
      hence "j < i" and "f j ∈ Tinf (rstep R)" by auto
      with Tinf_nrrstep[where E = "{}" and R = R, simplified] nrr[OF this(1)] nSN
      show ?case by auto
    qed
    with rrstep nSN steps show ?thesis by auto
  next
    case False
    with steps have nrr: "⋀ i. (f i, f (Suc i)) ∈ nrrstep R"
      by (meson rstep_cases)
    hence "¬ SN_on (nrrstep R) {s}" using f0 by auto
    with Tinf_imp_SN_nrrstep[OF assms] 
    have False by auto
    thus ?thesis ..
  qed
qed


lemma subterm_preserves_SN_on_relstep:
  "SN_on (relstep R E) {s} ⟹ s ⊵ t ⟹ SN_on (relstep R E) {t}"
  using SN_imp_SN_subt [of "rstep (rstep ((rstep E)*) O rstep R O rstep ((rstep E)*))"]
  by (simp only: rstep_relcomp_idemp2) (simp only: rstep_rtrancl_idemp)

inductive_set rstep_rule :: "('f, 'v) rule ⇒ ('f, 'v) term rel" for ρ
  where
    rule: "s = C⟨fst ρ ⋅ σ⟩ ⟹ t = C⟨snd ρ ⋅ σ⟩ ⟹ (s, t) ∈ rstep_rule ρ"

lemma rstep_ruleI [intro]:
  "s = C⟨l ⋅ σ⟩ ⟹ t = C⟨r ⋅ σ⟩ ⟹ (s, t) ∈ rstep_rule (l, r)"
  by (auto simp: rstep_rule.simps)

lemma rstep_rule_ctxt:
  "(s, t) ∈ rstep_rule ρ ⟹ (C⟨s⟩, C⟨t⟩) ∈ rstep_rule ρ"
  using rstep_rule.rule [of "C⟨s⟩" "C ∘c D" ρ _ "C⟨t⟩" for D]
  by (auto elim: rstep_rule.cases simp: ctxt_of_pos_term_append)

lemma rstep_rule_subst:
  assumes "(s, t) ∈ rstep_rule ρ"
  shows "(s ⋅ σ, t ⋅ σ) ∈ rstep_rule ρ"
  using assms
proof (cases)
  case (rule C τ)
  then show ?thesis
    using rstep_rule.rule [of "s ⋅ σ" _ "ρ" "τ ∘s σ"]
    by (auto elim!: rstep_rule.cases simp: ctxt_of_pos_term_subst)
qed

lemma rstep_rule_imp_rstep:
  "ρ ∈ R ⟹ (s, t) ∈ rstep_rule ρ ⟹ (s, t) ∈ rstep R"
  by (force elim: rstep_rule.cases)

lemma rstep_imp_rstep_rule:
  assumes "(s, t) ∈ rstep R"
  obtains l r where "(l, r) ∈ R" and "(s, t) ∈ rstep_rule (l, r)"
  using assms by blast

lemma term_subst_rstep:
  assumes "⋀x. x ∈ vars_term t ⟹ (σ x, τ x) ∈ rstep R"
  shows "(t ⋅ σ, t ⋅ τ) ∈ (rstep R)*"
  using assms
proof (induct t)
  case (Fun f ts)
  { fix ti
    assume ti: "ti ∈ set ts"
    with Fun(2) have "⋀x. x ∈ vars_term ti ⟹ (σ x, τ x) ∈ rstep R" by auto
    from Fun(1) [OF ti this] have "(ti ⋅ σ, ti ⋅ τ) ∈ (rstep R)*" by blast
  }
  then show ?case by (simp add: args_rsteps_imp_rsteps)
qed auto

lemma term_subst_rsteps:
  assumes "⋀x. x ∈ vars_term t ⟹ (σ x, τ x) ∈ (rstep R)*"
  shows "(t ⋅ σ, t ⋅ τ) ∈ (rstep R)*"
  by (metis assms rstep_rtrancl_idemp rtrancl_idemp term_subst_rstep)

lemma term_subst_rsteps_nrrsteps:
  assumes "⋀x. x ∈ vars_term t ⟹ (σ x, τ x) ∈ (rstep R)*"
    and "is_Fun t" 
  shows "(t ⋅ σ, t ⋅ τ) ∈ (nrrstep R)*"
proof -
  from assms obtain f ts where t: "t = Fun f ts" by auto
  show ?thesis unfolding t eval_term.simps 
  proof (rule args_steps_imp_steps_gen[where r = "λ _. rstep R"], goal_cases)
    case (1 bef s t aft)
    then obtain C l r σ where "(l,r) ∈ R" and "s = C ⟨l ⋅ σ ⟩" 
      and "t = C ⟨ r ⋅ σ ⟩" by auto
    hence "(Fun f (bef @ s # aft), Fun f (bef @ t # aft)) ∈ nrrstep R"
      using nrrstepI[of l r R _ "More f bef C aft"] by auto
    thus ?case by auto
  next
    case (3 i)
    hence mem: "ts ! i ∈ set ts" by auto
    hence vars: "vars_term (ts ! i) ⊆ vars_term t" unfolding t by auto
    have "(ts ! i ⋅ σ, ts ! i ⋅ τ) ∈ (rstep R)^*"
      by (rule term_subst_rsteps, insert vars assms, auto)
    thus ?case using 3 by auto
  qed auto
qed

lemma term_subst_rsteps_join:
  assumes "⋀y. y ∈ vars_term u ⟹ (σ1 y, σ2 y) ∈ (rstep R)↓"
  shows "(u ⋅ σ1, u ⋅ σ2) ∈ (rstep R)↓"
  using assms
proof -
  { fix x
    assume "x ∈ vars_term u"
    from assms [OF this] have "∃σ. (σ1 x, σ x) ∈ (rstep R)* ∧ (σ2 x, σ x) ∈ (rstep R)*" by auto
  }
  then have "∀x ∈ vars_term u. ∃σ. (σ1 x, σ x) ∈ (rstep R)* ∧ (σ2 x, σ x) ∈ (rstep R)*" by blast
  then obtain s where "∀x ∈ vars_term u. (σ1 x, (s x) x) ∈ (rstep R)* ∧ (σ2 x, (s x) x) ∈ (rstep R)*" by metis
  then obtain σ where "∀x ∈ vars_term u. (σ1 x, σ x) ∈ (rstep R)* ∧ (σ2 x, σ x) ∈ (rstep R)*" by fast
  then have "(u ⋅ σ1, u ⋅ σ) ∈ (rstep R)* ∧ (u ⋅ σ2, u ⋅ σ) ∈ (rstep R)*" using term_subst_rsteps by metis
  then show ?thesis by blast
qed

lemma funas_trs_converse [simp]: "funas_trs (R¯) = funas_trs R"
  by (auto simp: funas_defs)

lemma rstep_rev: assumes "(s, t) ∈ rstep_pos {(l,r)} p" shows "((t, s) ∈ rstep_pos {(r,l)} p)"
proof-
  from assms obtain σ where step:"t = (ctxt_of_pos_term p s)⟨r ⋅ σ⟩" "p ∈ poss s" "s |_ p = l ⋅ σ"
    unfolding rstep_pos.simps by auto
  with replace_at_below_poss[of p s p] have pt:"p ∈ poss t" by auto
  with step ctxt_supt_id[OF step(2)] have "s = (ctxt_of_pos_term p t)⟨l ⋅ σ⟩"
    by (simp add: ctxt_of_pos_term_replace_at_below)
  with step ctxt_supt_id[OF pt] show ?thesis unfolding rstep_pos.simps
    by (metis pt replace_at_subt_at singletonI)
qed

lemma conversion_ctxt_closed: "(s, t) ∈ (rstep R)↔* ⟹ (C⟨s⟩, C⟨t⟩) ∈ (rstep R)↔*"
  using rsteps_closed_ctxt unfolding conversion_def
  by (simp only: rstep_simps(5)[symmetric])

lemma conversion_subst_closed:
  "(s, t) ∈ (rstep R)↔* ⟹ (s ⋅ σ,  t ⋅ σ) ∈ (rstep R)↔*"
  using rsteps_closed_subst unfolding conversion_def
  by (simp only: rstep_simps(5)[symmetric])

lemma rstep_simulate_conv:
  assumes "⋀ l r. (l, r) ∈ S ⟹ (l, r) ∈ (rstep R)↔*"
  shows "(rstep S) ⊆ (rstep R)↔*"
proof
  fix s t
  assume "(s, t) ∈ rstep S"
  then obtain l r C σ where s: "s = C⟨l ⋅ σ⟩" and t:"t = C⟨r ⋅ σ⟩" and lr: "(l, r) ∈ S"
    unfolding rstep_iff_rstep_r_c_s rstep_r_c_s_def by auto
  with assms have "(l, r) ∈ (rstep R)↔*" by auto
  then show "(s, t) ∈ (rstep R)↔*" using conversion_ctxt_closed conversion_subst_closed s t by metis
qed

lemma symcl_simulate_conv:
  assumes "⋀ l r. (l, r) ∈ S ⟹ (l, r) ∈ (rstep R)↔*"
  shows "(rstep S)↔ ⊆ (rstep R)↔*"
  using rstep_simulate_conv[OF assms]
  by auto (metis conversion_inv subset_iff)

lemma conv_union_simulate:
  assumes "⋀ l r. (l, r) ∈ S ⟹ (l, r) ∈ (rstep R)↔*"
  shows "(rstep (R ∪ S))↔* = (rstep R)↔*"
proof
  show "(rstep (R ∪ S))↔* ⊆ (rstep R)↔*"
    unfolding conversion_def
  proof
    fix s t
    assume "(s, t) ∈ ((rstep (R ∪ S))↔)*"
    then show "(s, t) ∈ ((rstep R)↔)*"
    proof (induct rule: rtrancl_induct)
      case (step u t)
      then have "(u, t) ∈ (rstep R)↔ ∨ (u, t) ∈ (rstep S)↔" by auto
      then show ?case
      proof
        assume "(u, t) ∈ (rstep R)↔"
        with step show ?thesis using rtrancl_into_rtrancl by metis
      next
        assume "(u, t) ∈ (rstep S)↔"
        with symcl_simulate_conv[OF assms] have "(u, t) ∈ (rstep R)↔*" by auto
        with step show ?thesis by auto
      qed
    qed simp
  qed
next
  show "(rstep R)↔* ⊆ (rstep (R ∪ S))↔*"
    unfolding conversion_def
    using rstep_union rtrancl_mono sup.cobounded1 symcl_Un
    by metis
qed

lemma args_NF_rstep_imp_NF_nrrstep: assumes "set (args t) ⊆ NF (rstep R)" 
  shows "t ∈ NF (nrrstep R)" 
  using assms by (smt (verit) NF_E NF_I UnCI nrrstep_args nth_mem sup.order_iff term.sel(4))

lemma SN_nrrstep_imp_args_SN_rstep: assumes "SN_on (nrrstep R) {t}" 
  shows "SN_on (rstep R) (set (args t))" 
proof
  fix g  
  assume "g 0 ∈ set (args t)" and steps: "∀n. (g n, g (Suc n)) ∈ rstep R" 
  from this(1) obtain f ts i where t: "t = Fun f ts" and i: "i < length ts" and g0: "g 0 = ts ! i" 
    by (cases t, auto simp: set_conv_nth)
  define h where "h n = Fun f (ts [i := g n])" for n 
  have "(h n, h (Suc n)) ∈ nrrstep R" for n using steps[rule_format, of n] i unfolding h_def 
    unfolding nrrstep_iff_arg_rstep by fastforce
  with assms have "h 0 ≠ t" by blast
  with g0 i show False unfolding t h_def by auto
qed

lemma arg_rsteps_into_nrrsteps: 
  assumes "(t, u) ∈ (rstep R)*" 
  and "i < length ss" 
shows "(Fun f (ss[i := t]), Fun f (ss[i := u])) ∈ (nrrstep R)*" 
  using assms(1)
proof induct
  case (step u v)
  from assms(2) step(2) 
  have "(Fun f (ss[i := u]), Fun f (ss[i := v])) ∈ nrrstep R" 
    unfolding nrrstep_iff_arg_rstep by force
  with step(3) show ?case by auto
qed auto


lemma rstep_r_p_s_subst: "(s,t) ∈ rstep_r_p_s R r p σ ⟹ (s ⋅ δ, t ⋅ δ) ∈ rstep_r_p_s R r p (σ ∘s δ)" 
  unfolding rstep_r_p_s_def Let_def by simp
  (metis ctxt_of_pos_term_subst subst_apply_term_ctxt_apply_distrib)

lemma nrrstep_Fun_imp_opt_arg_rstep:
  assumes "(Fun f ss,Fun f ts) ∈ nrrstep R" (is "(?s,?t) ∈ nrrstep R") and "i < length ss"
  shows "(ss!i,ts!i) ∈ (rstep R)=" 
  using assms(1,2) nrrstep_args by force


lemma nrrstep_imp_arg_opt_rstep:
  assumes "(s,t) ∈ nrrstep R" and "i < num_args s" shows "(args s!i,args t!i) ∈ (rstep R)="
  by (metis assms(1,2) nrrstep_Fun_imp_opt_arg_rstep nrrstep_equiv_root term.sel(4))

lemma nrrsteps_imp_arg_rsteps_count:
  assumes "(s,t) ∈ (nrrstep R)^^n" and i: "i < num_args s"
  shows "∃ m. m ≤ n ∧ (args s!i,args t!i) ∈ (rstep R)^^m"
  using assms
proof (induct n arbitrary: s)
  case (Suc n s)
  from Suc(2) obtain u where su: "(s,u) ∈ nrrstep R" and ut: "(u,t) ∈ (nrrstep R)^^n"
    by (meson relpow_Suc_D2)
  from su have "num_args s = num_args u" by (rule nrrstep_equiv_num_args)
  with Suc have "i < num_args u" by auto
  from Suc(1)[OF ut this] obtain m where IH: "m ≤ n" "(args u ! i, args t ! i) ∈ (rstep R)^^m" by auto
  from nrrstep_imp_arg_opt_rstep[OF su Suc(3)] 
  have "args s ! i = args u ! i ∨ (args s ! i, args u ! i) ∈ rstep R" 
    by auto
  thus ?case
  proof
    assume "args s ! i = args u ! i" 
    with IH show ?thesis by (auto intro: exI[of _ m])
  next
    assume "(args s ! i, args u ! i) ∈ rstep R" 
    with IH show ?thesis by (intro exI[of _ "Suc m"]) 
      (meson Suc_le_mono relpow_Suc_I2)
  qed
qed auto

lemma rstep_vars_term: assumes "⋀ lr. lr ∈ R ⟹ vars_term (fst lr) ⊇ vars_term (snd lr)"
  shows "(s,t) ∈ rstep R ⟹ vars_term s ⊇ vars_term t" 
  using assms
  by (force elim!: rstepE simp: vars_term_ctxt_apply vars_term_subst)



definition "suptrel R = (relto {⊳} (rstep R))+"
end