Theory Trs_Impl

section‹Implementation of First Order Rewriting›

theory Trs_Impl
  imports
    Trs
    First_Order_Rewriting.Term_Impl
    First_Order_Terms.Matching
    First_Order_Rewriting.Abstract_Rewriting_Impl
    Option_Util
    "Transitive-Closure.RBT_Map_Set_Extension"
begin

subsection ‹Implementation of the Rewrite Relation›
subsubsection‹Generate All Rewrites›

type_synonym ('f, 'v) rules = "('f, 'v) rule list"

context fixes R :: "('f,'v)rules" 
begin

definition rrewrite :: "('f, 'v) term  ('f, 'v) term list"
  where
    "rrewrite s = List.maps (λ (l, r) . case match s l of
      None  []
    | Some σ  [r  σ]) R"

lemma rrewrite_sound: "t  set (rrewrite s)  (s,t)  rrstep (set R)" 
  unfolding rrewrite_def List.maps_def using match_matches[of s]
  by force

lemma rrewrite_complete: assumes "(s,t)  rrstep (set R)"
  shows " u. u  set (rrewrite s)"
proof -
  from assms obtain l r σ where lr: "(l,r)  set R" and s: "s = l  σ" and t: "t = r  σ" 
    by (rule rrstepE)
  from match_complete'[OF s[symmetric]] obtain τ where match: "match s l = Some τ" 
    by auto
  with lr match have "r  τ  set (rrewrite s)" unfolding rrewrite_def List.maps_def by force
  thus ?thesis ..
qed

lemma rrewrite: assumes " l r. (l,r)  set R  vars_term l  vars_term r" 
  shows "set (rrewrite s) = {t. (s,t)  rrstep (set R)}"
proof (standard; clarify)
  fix t
  assume "(s,t)  rrstep (set R)" 
  then obtain l r σ where lr: "(l,r)  set R" and s: "s = l  σ" and t: "t = r  σ" 
    by (rule rrstepE)
  from match_complete'[OF s[symmetric]] obtain τ where match: "match s l = Some τ" 
    and vars: " x. x  vars_term l  σ x = τ x" by auto
  have vars': " x. x  vars_term r  σ x = τ x" using assms[OF lr] vars by auto
  have t: "t = r  τ" unfolding t using vars' by (intro term_subst_eq, auto)
  with lr match show "t  set (rrewrite s)" unfolding rrewrite_def List.maps_def by force
qed (rule rrewrite_sound)

fun rewrite :: "('f, 'v) term  ('f, 'v) term list" where
  "rewrite s = (rrewrite s @ (case s of Var _  [] | Fun f ss  
    concat (map (λ (i, si). map (λ ti. Fun f (ss[i := ti])) (rewrite si))
     (zip [0..< length ss] ss))))"

declare rewrite.simps[simp del]

lemma rewrite_sound: "t  set (rewrite s)  (s,t)  rstep (set R)"
proof (induct s arbitrary: t rule: rewrite.induct)
  case (1 s t)
  note [simp] = rewrite.simps[of s]
  from 1(2) consider (root) "t  set (rrewrite s)" | 
    (arg) f ss ti i where "s = Fun f ss" "i < length ss" "ti  set (rewrite (ss ! i))" "t = Fun f (ss[i := ti])" 
    by (auto simp: set_zip)
  thus ?case
  proof cases
    case root
    with rrewrite_sound[of t s] have "(s,t)  rrstep (set R)" by auto
    thus ?thesis by (rule rrstep_imp_rstep)
  next
    case (arg f ss ti i)
    from arg(2) have mem: "(i, ss ! i)  set (zip [0..<length ss] ss)" by (force simp: set_zip)
    from 1(1)[OF arg(1) mem refl arg(3)] 
    have IH: "(ss ! i, ti)  rstep (set R)" .
    with arg have "(s,t)  nrrstep (set R)" 
      unfolding nrrstep_iff_arg_rstep by blast
    thus ?thesis by (rule nrrstep_imp_rstep)
  qed
qed


lemma rewrite: assumes " l r. (l,r)  set R  vars_term l  vars_term r" 
  shows "set (rewrite s) = {t. (s,t)  rstep (set R)}"
proof (standard; clarify)
  fix t
  assume "(s,t)  rstep (set R)" 
  then obtain C u v where s: "s = Cu" and t: "t = Cv" and step: "(u,v)  rrstep (set R)" 
    by blast
  from rrewrite[OF assms, of u] step have step: "v  set (rrewrite u)" by auto
  show "t  set (rewrite s)" unfolding s t
  proof (induct C)
    case Hole
    then show ?case using step by (auto simp: rewrite.simps[of u])
  next
    case (More f bef C aft)
    show ?case 
      apply (simp add: rewrite.simps[of "Fun f _"] set_zip)
      apply (intro disjI2)
      apply (intro exI[of _ "Cu"] exI)
      apply (intro conjI exI[of _ "length bef"])
      using More by (auto simp: nth_append)
  qed
qed (rule rewrite_sound)

lemma rewrite_complete: assumes "(s,t)  rstep (set R)"
  shows " w. w  set (rewrite s)" 
proof -
  from assms obtain C u v where s: "s = Cu" and t: "t = Cv" and step: "(u,v)  rrstep (set R)" 
    by blast
  from rrewrite_complete[OF step] obtain v where step: "v  set (rrewrite u)" by auto
  have "Cv  set (rewrite s)" unfolding s 
  proof (induct C)
    case Hole
    then show ?case using step by (auto simp: rewrite.simps[of u])
  next
    case (More f bef C aft)
    show ?case 
      apply (simp add: rewrite.simps[of "Fun f _"] set_zip)
      apply (intro disjI2)
      apply (intro exI[of _ "Cu"] exI)
      apply (intro conjI exI[of _ "length bef"])
      using More by (auto simp: nth_append)
  qed
  thus ?thesis by blast
qed
end


lemma rrewrite_mono: "set R  set S  set (rrewrite R s)  set (rrewrite S s)" 
  unfolding rrewrite_def List.maps_def by auto 

lemma Union_image_mono: "( x. x  A  f x  g x)   (f ` A)   (g ` A)"
  by blast

lemma rewrite_mono: assumes "set R  set S"
  shows "set (rewrite R s)  set (rewrite S s)" 
proof -
  note rrewrite = rrewrite_mono[OF assms]
  show ?thesis
  proof (induct s)
    case (Var x)
    thus ?case using rrewrite unfolding rewrite.simps[of _ "Var x"] by auto
  next
    case (Fun f ss)
    show ?case unfolding rewrite.simps[of _ "Fun f ss"]
        set_append term.simps set_concat set_map image_comp set_zip o_def
      apply (intro Un_mono, rule rrewrite)
      by (intro Union_image_mono, insert Fun, force simp: set_conv_nth[of ss])
  qed
qed


definition first_rewrite :: "('f,'v)rules  ('f,'v)term  ('f,'v)term option"
  where "first_rewrite R s  case rewrite R s of Nil  None | Cons t _  Some t"


subsubsection‹Checking a Single Rewrite Step›

definition is_root_step :: "('f, 'v)trs  ('f, 'v) term  ('f, 'v) term  bool"
  where
    "is_root_step R s t = ( (l, r)  R. case match_list Var [(l,s),(r,t)] of
      None  False
    | Some _  True)"

lemma rrstep_code[code_unfold]: "(s,t)  rrstep R  is_root_step R s t"
proof
  show "is_root_step R s t  (s, t)  rrstep R"  
    unfolding is_root_step_def rrstep_def rstep_r_p_s_def'
    by (auto split: option.splits) (force dest: match_list_matches)
  assume "(s, t)  rrstep R"
  then obtain σ l r where lr: "(l,r)  R" and id: "s = l  σ" "t = r  σ" 
    by (metis rrstepE)
  show "is_root_step R s t" unfolding id
    unfolding is_root_step_def 
    by (cases "match_list Var [(l, l  σ), (r, r  σ)]",
        auto intro!: bexI[OF _ lr] dest!: match_list_complete)
qed

lemma is_root_step: "is_root_step R s t  (s, t)  rrstep R"
  unfolding rrstep_code .

fun is_rstep :: "('f,'v)trs  ('f,'v)term  ('f,'v)term  bool" where
  "is_rstep R (Fun f ts) (Fun g ss) = (
     f = g  length ts = length ss  ( i  set [0..<length ss].
        ss = ts[i := ss ! i]  is_rstep R (ts ! i) (ss ! i))
      (Fun f ts, Fun g ss)  rrstep R)" 
| "is_rstep R s t = ((s,t)  rrstep R)" 

lemma is_rstep_sound: "is_rstep R s t  (s,t)  rstep R" 
proof (induct R s t rule: is_rstep.induct)
  case (1 R f ts g ss)
  show ?case
  proof (cases "(Fun f ts, Fun g ss)  rrstep R")
    case True
    thus ?thesis using rrstep_imp_rstep by auto
  next
    case False
    with 1(2) obtain i where
      i: "i < length ss" and
      gf: "g = f" and len: "length ts = length ss" and id: "ss = ts[i := ss ! i]" 
      and rec: "is_rstep R (ts ! i) (ss ! i)"
      by auto
    from 1(1)[OF _ rec] i have "(ts ! i, ss ! i)  rstep R" by auto
    thus ?thesis unfolding gf using id i len
      by (metis nrrstep_iff_arg_rstep nrrstep_imp_rstep)
  qed
qed (insert rrstep_imp_rstep, auto)

lemma is_rstep_complete: assumes "(s,t)  rstep R" 
  shows "is_rstep R s t" 
proof -
  from rstepE[OF assms] obtain C s' t' where 
    id: "s = C s'" "t = Ct'" and step: "(s',t')  rrstep R" 
    using rrstepI by metis
  show ?thesis unfolding id
  proof (induct C)
    case Hole
    then show ?case using step by (cases s'; cases t', auto)
  next
    case (More f bef C aft)
    show ?case unfolding intp_actxt.simps is_rstep.simps
      by (intro disjI1 conjI bexI[of _ "length bef"], insert More, auto)
  qed
qed

lemma is_rstep[simp]: "is_rstep R s t  (s,t)  rstep R" 
  using is_rstep_sound is_rstep_complete by auto

lemma in_rstep_code[code_unfold]: 
  "st  rstep R  (case st of (s,t)  is_rstep R s t)" 
  by (cases st, auto)

subsection‹Computation of a Normal Form›


definition compute_rstep_NF :: "('f,'v)rules  ('f,'v)term  ('f,'v)term option"
  where "compute_rstep_NF R s  compute_NF (first_rewrite R) s"

lemma compute_rstep_NF_sound:
  assumes res: "compute_rstep_NF R s = Some t"
  shows "(s, t)  (rstep (set R))^*" using res[unfolded compute_rstep_NF_def]
proof (rule compute_NF_sound)
  fix s t
  assume "first_rewrite R s = Some t"
  from this[unfolded first_rewrite_def] obtain ts where "rewrite R s = t # ts"
    by (cases "rewrite R s", auto)
  then have t: "t  set (rewrite R s)" by simp
  from rewrite_sound[OF this] show "(s,t)  rstep (set R)" .
qed

lemma compute_rstep_NF_complete: assumes res: "compute_rstep_NF R s = Some t"
  shows "t  NF (rstep (set R))" using res[unfolded compute_rstep_NF_def]
proof (rule compute_NF_complete)
  fix s
  assume "first_rewrite R s = None"
  from this[unfolded first_rewrite_def] have empty: "rewrite R s = []" 
    by (cases "rewrite R s", auto)
  have False if "(s,t)  rstep (set R)" for t 
    using rewrite_complete[OF that] arg_cong[OF empty, of set] by auto
  thus "s  NF (rstep (set R))" by blast
qed

lemma compute_rstep_NF_SN: assumes SN: "SN (rstep (set R))"
  shows " t. compute_rstep_NF R s = Some t"
proof -
  have " t. compute_NF (first_rewrite R) s = Some t"
  proof (rule compute_NF_SN[OF SN])
    fix s t
    assume "first_rewrite R s = Some t"
    from this[unfolded first_rewrite_def] have
      rewrite: "t  set (rewrite R s)" by (auto split: list.splits)
    from rewrite_sound[OF this]
    show "(s,t)  rstep (set R)" .
  qed  
  then show ?thesis unfolding compute_rstep_NF_def .
qed

subsubsection‹Computing Reachable Terms with Limit on Derivation Length›

fun reachable_terms :: 
  "('f, 'v) rules  ('f, 'v) term  nat  ('f, 'v) term list"
  where 
    "reachable_terms R s 0 = [s]"
  | "reachable_terms R s (Suc n) = (
  let ts = (reachable_terms R s n) in
    remdups (ts@(concat (map (λ t. rewrite R t) ts)))
  )"

lemma reachable_terms_nat:
  assumes "t  set (reachable_terms R s i)"
  shows " j. j  i  (s,t)  (rstep (set R))^^j"
  using assms
proof (induct i arbitrary: t)
  case 0 
  then show ?case by auto
next
  case (Suc i) 
  let ?R = "λ j. (rstep (set R))^^j"
  from Suc(2)
  have "t  set (reachable_terms R s i)
     ( u  set (reachable_terms R s i). t  set (rewrite R u))" by (simp add: Let_def)
  then show ?case
  proof
    assume "t  set (reachable_terms R s i)"
    from Suc(1)[OF this] obtain j where "j  i" and "(s,t)  ?R j" by auto 
    then show ?thesis by (intro exI[of _ j], auto)
  next
    assume " u  set (reachable_terms R s i). t  set (rewrite R u)"
    then obtain u where u: "u  set (reachable_terms R s i)"
      and 1: "t  set (rewrite R u)" by auto
    from rewrite_sound[OF 1] have ut: "(u,t)  rstep (set R)" .
    from Suc(1)[OF u] obtain j where j: "j  i" and su: "(s,u)  ?R j" by auto
    from su ut have "(s,t)  ?R (Suc j)" by auto
    with j show ?thesis by (intro exI[of _ "Suc j"], auto)
  qed
qed

lemma reachable_terms:
  assumes "t  set (reachable_terms R s i)"
  shows "(s,t)  (rstep (set R))^*"
  using reachable_terms_nat[OF assms] by (metis relpow_imp_rtrancl)

lemma reachable_terms_one:
  assumes "t  set (reachable_terms R s (Suc 0))"
  shows "(s,t)  (rstep (set R))^="
proof -
  from reachable_terms_nat[OF assms] obtain j where "j  1"
    and "(s,t)  (rstep (set R))^^j" by auto
  then show ?thesis by (cases j, auto)
qed

subsubsection‹Algorithms to Ensure Joinability›

definition
  check_join_NF ::
  "('f :: showl, 'v :: showl) rules  
     ('f, 'v) term  ('f, 'v) term  showsl check"
  where
    "check_join_NF R s t  case (compute_rstep_NF R s, compute_rstep_NF R t) of
      (Some s', Some t')  
     check (s' = t') (
    showsl (STR ''the normal form '')  showsl s'  showsl (STR '' of '')  showsl s 
       showsl (STR '' differs from⏎the normal form '')  showsl t'  showsl (STR '' of '')  showsl t)
       |  _  error (showsl (STR ''strange error in normal form computation''))"

lemma check_join_NF_sound:
  assumes ok: "isOK (check_join_NF R s t)"
  shows "(s, t)  join (rstep (set R))"
proof -
  note ok = ok[unfolded check_join_NF_def]
  from ok obtain s' where s: "compute_rstep_NF R s = Some s'" by force
  note ok = ok[unfolded s]
  from ok obtain t' where t: "compute_rstep_NF R t = Some t'" by force
  from ok[unfolded t] have id: "s' = t'" by simp
  note seq = compute_rstep_NF_sound
  from seq[OF s] seq[OF t]
  show ?thesis unfolding id by auto
qed


function iterative_join_search_main ::
  "('f,'v) rules  ('f,'v) term  ('f,'v) term  nat  nat  bool"
  where
    "iterative_join_search_main R s t i n = (if i  n then
  (((list_inter (reachable_terms R s i) (reachable_terms R t i))  [])  (iterative_join_search_main R s t (Suc i) n)) else False)"
  by pat_completeness auto

termination by (relation "measure ( λ (R,s,t,i,n). Suc n - i)") auto

lemma iterative_join_search_main: 
  "iterative_join_search_main R s t i n  (s,t)  join (rstep (set R))"
proof (induction rule: iterative_join_search_main.induct)
  case (1 R s t i n)
  from 1(2) have i_n: "i  n" by (simp split: if_splits)
  note IH = 1(1)[OF i_n]
  let ?I = "list_inter (reachable_terms R s i) (reachable_terms R t i)"
  from 1(2) i_n have "?I  []  iterative_join_search_main R s t (Suc i) n" by auto
  then show ?case
  proof
    assume a: "?I  []"
    then obtain u us where u: "?I = u # us" by (cases ?I, auto)
    then have d: "u  set ?I" by auto
    from this[simplified] reachable_terms[of u _ _ i] have c: "(s, u)  (rstep (set R))*" by auto
    from d[simplified] reachable_terms[of u _ _ i] have e: "(t,u)  (rstep (set R))^*" by auto
    from c e show ?thesis by auto
  next
    assume b: "iterative_join_search_main R s t (Suc i) n"
    from  IH[OF this] show ?thesis .
  qed
qed

definition iterative_join_search where 
  "iterative_join_search R s t n  iterative_join_search_main R s t 0 n"

lemma iterative_join_search: "iterative_join_search R s t n  (s,t)  join (rstep (set R))"
  by (rule iterative_join_search_main, unfold iterative_join_search_def)

definition
  check_join_BFS_limit ::
  "nat  ('f :: showl, 'v :: showl) rules  
     ('f, 'v) term  ('f, 'v) term  showsl check"
  where
    "check_join_BFS_limit n R s t  check (iterative_join_search R s t n) 
    (showsl (STR ''could not find a joining sequence of length at most '')  
     showsl n  showsl (STR '' for the terms '')  showsl s  
     showsl (STR '' and '')  showsl t  showsl_nl)"

lemma check_join_BFS_limit_sound:
  assumes ok: "isOK (check_join_BFS_limit n R s t)"
  shows "(s, t)  join (rstep (set R))"
  by (rule iterative_join_search, insert ok[unfolded check_join_BFS_limit_def], simp)

definition map_funs_rules :: "('f  'g)  ('f, 'v) rules  ('g, 'v) rules" where
  "map_funs_rules fg R = map (map_funs_rule fg) R"

lemma map_funs_rules_sound[simp]:
  "set (map_funs_rules fg R) = map_funs_trs fg (set R)"
  unfolding map_funs_rules_def map_funs_trs.simps by simp

subsubsection ‹Displaying TRSs as Strings›

fun showsl_rule' :: "('f  showsl)  ('v  showsl)  String.literal  ('f, 'v) rule  showsl"
  where
    "showsl_rule' fun var arr (l, r) =
    showsl_term' fun var l  showsl arr  showsl_term' fun var r"

definition "showsl_rule  showsl_rule' showsl showsl (STR '' -> '')"
definition "showsl_weak_rule  showsl_rule' showsl showsl (STR '' ->= '')"

definition
  showsl_rules' :: "('f  showsl)  ('v  showsl)  String.literal  ('f, 'v) rules  showsl"
  where
    "showsl_rules' fun var arr trs =
    showsl_list_gen (showsl_rule' fun var arr) (STR '''') (STR '''') (STR ''⏎'') (STR '''') trs  showsl_nl"

definition "showsl_rules  showsl_rules' showsl showsl (STR '' -> '')"
definition "showsl_weak_rules  showsl_rules' showsl showsl (STR '' ->= '')"

definition
  showsl_trs' :: "('f  showsl)  ('v  showsl)  String.literal  String.literal  ('f, 'v) rules  showsl"
  where
    "showsl_trs' fun var name arr R = showsl name  showsl (STR ''⏎⏎'')  showsl_rules' fun var arr R"

definition "showsl_trs  showsl_trs' showsl showsl (STR ''rewrite system:'') (STR '' -> '')"


subsubsection‹Computing Syntactic Properties of TRSs›

definition add_vars_rule :: "('f, 'v) rule  'v list  'v list"
  where
    "add_vars_rule r xs = add_vars_term (fst r) (add_vars_term (snd r) xs)"

definition add_funs_rule :: "('f, 'v) rule  'f list  'f list"
  where
    "add_funs_rule r fs = add_funs_term (fst r) (add_funs_term (snd r) fs)"

definition add_funas_rule :: "('f, 'v) rule  ('f × nat) list  ('f × nat) list"
  where
    "add_funas_rule r fs = add_funas_term (fst r) (add_funas_term (snd r) fs)"

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

definition add_funas_args_rule :: "('f, 'v) rule  ('f × nat) list  ('f × nat) list"
  where
    "add_funas_args_rule r fs = add_funas_args_term (fst r) (add_funas_args_term (snd r) fs)"

lemma add_vars_rule_vars_rule_list_conv [simp]:
  "add_vars_rule r xs = vars_rule_list r @ xs"
  by (simp add: add_vars_rule_def vars_rule_list_def)

lemma add_funs_rule_funs_rule_list_conv [simp]:
  "add_funs_rule r fs = funs_rule_list r @ fs"
  by (simp add: add_funs_rule_def funs_rule_list_def)

lemma add_funas_rule_funas_rule_list_conv [simp]:
  "add_funas_rule r fs = funas_rule_list r @ fs"
  by (simp add: add_funas_rule_def funas_rule_list_def)

lemma add_roots_rule_roots_rule_list_conv [simp]:
  "add_roots_rule r fs = roots_rule_list r @ fs"
  by (simp add: add_roots_rule_def roots_rule_list_def)

lemma add_funas_args_rule_funas_args_rule_list_conv [simp]:
  "add_funas_args_rule r fs = funas_args_rule_list r @ fs"
  by (simp add: add_funas_args_rule_def funas_args_rule_list_def)

definition insert_vars_rule :: "('f, 'v) rule  'v list  'v list"
  where
    "insert_vars_rule r xs = insert_vars_term (fst r) (insert_vars_term (snd r) xs)"

definition insert_funs_rule :: "('f, 'v) rule  'f list  'f list"
  where
    "insert_funs_rule r fs = insert_funs_term (fst r) (insert_funs_term (snd r) fs)"

definition insert_funas_rule :: "('f, 'v) rule  ('f × nat) list  ('f × nat) list"
  where
    "insert_funas_rule r fs = insert_funas_term (fst r) (insert_funas_term (snd r) fs)"

definition insert_roots_rule :: "('f, 'v) rule  ('f × nat) list  ('f × nat) list"
  where
    "insert_roots_rule r fs =
    foldr List.insert (option_to_list (root (fst r)) @ option_to_list (root (snd r))) fs"

definition insert_funas_args_rule :: "('f, 'v) rule  ('f × nat) list  ('f × nat) list"
  where
    "insert_funas_args_rule r fs = insert_funas_args_term (fst r) (insert_funas_args_term (snd r) fs)"

lemma set_insert_vars_rule [simp]:
  "set (insert_vars_rule r xs) = vars_term (fst r)  vars_term (snd r)  set xs"
  by (simp add: insert_vars_rule_def ac_simps)

lemma set_insert_funs_rule [simp]:
  "set (insert_funs_rule r xs) = funs_term (fst r)  funs_term (snd r)  set xs"
  by (simp add: insert_funs_rule_def ac_simps)

lemma set_insert_funas_rule [simp]:
  "set (insert_funas_rule r xs) = funas_term (fst r)  funas_term (snd r)  set xs"
  by (simp add: insert_funas_rule_def ac_simps)

lemma set_insert_roots_rule [simp]:
  "set (insert_roots_rule r xs) = root_set (fst r)  root_set (snd r)  set xs"
  by (cases "fst r" "snd r" rule: term.exhaust [case_product term.exhaust])
    (auto simp: insert_roots_rule_def ac_simps)

lemma set_insert_funas_args_rule [simp]:
  "set (insert_funas_args_rule r xs) = funas_args_term (fst r)  funas_args_term (snd r)  set xs"
  by (simp add: insert_funas_args_rule_def ac_simps funas_args_term_def)

abbreviation "vars_rule_impl r  insert_vars_rule r []"
abbreviation "funs_rule_impl r  insert_funs_rule r []"
abbreviation "funas_rule_impl r  insert_funas_rule r []"
abbreviation "roots_rule_impl r  insert_roots_rule r []"
abbreviation "funas_args_rule_impl r  insert_funas_args_rule r []"

lemma set_vars_rule_impl:
  "set (vars_rule_impl r) = vars_rule r"
  by (simp add: vars_rule_def)

lemma xxx_rule_list_code[code]:
  "vars_rule_list r = add_vars_rule r []"
  "funs_rule_list r = add_funs_rule r []"
  "funas_rule_list r = add_funas_rule r []"
  "roots_rule_list r = add_roots_rule r []"
  "funas_args_rule_list r = add_funas_args_rule r []"
  by (simp_all add: vars_rule_list_def funs_rule_list_def funas_rule_list_def
      roots_rule_list_def funas_args_rule_list_def)

lemma xxx_trs_list_code[code]:
  "vars_trs_list trs = foldr add_vars_rule trs []"
  "funs_trs_list trs = foldr add_funs_rule trs []"
  "funas_trs_list trs = foldr add_funas_rule trs []"
  "funas_args_trs_list trs = foldr add_funas_args_rule trs []"
  by (induct trs)
    (simp_all add: vars_trs_list_def funs_trs_list_def funas_trs_list_def
      roots_trs_list_def funas_args_trs_list_def)

definition insert_vars_trs :: "('f, 'v) rule list  'v list  'v list"
  where
    "insert_vars_trs trs = foldr insert_vars_rule trs"

definition insert_funs_trs :: "('f, 'v) rule list  'f list  'f list"
  where
    "insert_funs_trs trs = foldr insert_funs_rule trs"

definition insert_funas_trs :: "('f, 'v) rule list  ('f × nat) list  ('f × nat) list"
  where
    "insert_funas_trs trs = foldr insert_funas_rule trs"

definition insert_roots_trs :: "('f, 'v) rule list  ('f × nat) list  ('f × nat) list"
  where
    "insert_roots_trs trs = foldr insert_roots_rule trs"

definition insert_funas_args_trs :: "('f, 'v) rule list  ('f × nat) list  ('f × nat) list"
  where
    "insert_funas_args_trs trs = foldr insert_funas_args_rule trs"

lemma set_insert_vars_trs [simp]:
  "set (insert_vars_trs trs xs) = (r  set trs. vars_rule r)  set xs"
  by (induct trs arbitrary: xs) (simp_all add: insert_vars_trs_def ac_simps vars_rule_def)

lemma set_insert_funs_trs [simp]:
  "set (insert_funs_trs trs fs) = (r  set trs. funs_rule r)  set fs"
  by (induct trs arbitrary: fs) (simp_all add: insert_funs_trs_def ac_simps funs_rule_def)

lemma set_insert_funas_trs [simp]:
  "set (insert_funas_trs trs fs) = (r  set trs. funas_rule r)  set fs"
  by (induct trs arbitrary: fs) (simp_all add: insert_funas_trs_def ac_simps funas_rule_def)

lemma set_insert_roots_trs [simp]:
  "set (insert_roots_trs trs fs) = (r  set trs. roots_rule r)  set fs"
  by (induct trs arbitrary: fs) (simp_all add: insert_roots_trs_def ac_simps roots_rule_def)

lemma set_insert_funas_args_trs [simp]:
  "set (insert_funas_args_trs trs fs) = (r  set trs. funas_args_rule r)  set fs"
  by (induct trs arbitrary: fs)
    (simp_all add: insert_funas_args_trs_def ac_simps funas_args_rule_def)

abbreviation "vars_trs_impl trs  insert_vars_trs trs []"
abbreviation "funs_trs_impl trs  insert_funs_trs trs []"
abbreviation "funas_trs_impl trs  insert_funas_trs trs []"
abbreviation "roots_trs_impl trs  insert_roots_trs trs []"
abbreviation "funas_args_trs_impl trs  insert_funas_args_trs trs []"

definition defined_list :: "('f, 'v) rule list  ('f × nat) list"
  where
    "defined_list R = [the (root l). (l, r)  R, is_Fun l]"

lemma set_defined_list [simp]:
  "set (defined_list R) = {fn. defined (set R) fn}"
  by (force simp: defined_list_def defined_def elim!: root_Some)

definition check_left_linear_trs :: "('f :: showl, 'v :: showl) rules  showsl check"
  where
    "check_left_linear_trs trs =
     check_all (λr. linear_term (fst r)) trs
       <+? (λ _. showsl_trs trs  showsl (STR ''⏎is not left-linear⏎''))"

lemma check_left_linear_trs [simp]:
  "isOK (check_left_linear_trs R) = left_linear_trs (set R)"
  unfolding check_left_linear_trs_def left_linear_trs_def
  by auto

definition check_varcond_subset :: "(_,_) rules  showsl check"
  where
    "check_varcond_subset R =
    check_allm (λrule. 
      check_subseteq (vars_term_impl (snd rule)) (vars_term_impl (fst rule))
      <+? (λx. showsl (STR ''free variable '')  showsl x
         showsl (STR '' in right-hand side of rule '')  showsl_rule rule  showsl_nl)
    ) R"

lemma check_varcond_subset [simp]:
  "isOK (check_varcond_subset R) = ( (l, r)  set R. vars_term r  vars_term l)"
  unfolding check_varcond_subset_def by force+

definition "check_varcond_no_Var_lhs =
  check_allm (λrule.
    check (is_Fun (fst rule))
      (showsl (STR ''variable left-hand side in rule '')  showsl_rule rule  showsl_nl))"

lemma check_varcond_no_Var_lhs [simp]:
  "isOK (check_varcond_no_Var_lhs R)  ((l, r)  set R. is_Fun l)"
  by (auto simp: check_varcond_no_Var_lhs_def)

definition check_wf_trs :: "(_,_) rules  showsl check"
  where
    "check_wf_trs R = do {
    check_varcond_no_Var_lhs R;
    check_varcond_subset R
  } <+? (λe. showsl (STR ''the TRS is not well-formed⏎'')  e)"

lemma check_wf_trs_conf [simp]:
  "isOK (check_wf_trs R) = wf_trs (set R)"
  by (force simp: check_wf_trs_def wf_trs_def)

definition check_not_wf_trs :: "(_,_) rules  showsl check" where
  "check_not_wf_trs R = check (¬ isOK (check_wf_trs R)) (showsl (STR ''The TRS is well formed⏎''))"

lemma check_not_wf_trs:
  assumes "isOK(check_not_wf_trs R)"
  shows "¬ SN (rstep (set R))"
proof -
  from assms have "¬ wf_trs (set R)" unfolding check_not_wf_trs_def by auto
  with SN_rstep_imp_wf_trs show ?thesis by auto
qed

lemma instance_rule_code[code]:
  "instance_rule lr st  match_list (λ _. fst lr) [(fst st, fst lr), (snd st, snd lr)]  None"
  (is "?l = (match_list ?d ?list  None)")
proof
  assume ?l
  then obtain σ where "fst lr = fst st  σ"
    and "snd lr = snd st  σ" by (auto simp: instance_rule_def)
  then have "l t. (l, t)  set ?list  l  σ = t" by (auto)
  then have "matchers (set ?list)  {}" by (auto simp: matchers_def)
  with match_list_complete
  show "match_list ?d ?list  None" by blast
next
  assume "match_list ?d ?list  None"
  then obtain τ where "match_list ?d ?list = Some τ" by auto
  from match_list_sound [OF this]
  have "fst lr = fst st  τ" and "snd lr = snd st  τ" by auto
  then show ?l by (auto simp: instance_rule_def)
qed

definition
  check_CS_subseteq :: "('f, 'v) rules  ('f, 'v) rules  ('f, 'v) rule check"
  where
    "check_CS_subseteq R S  check_allm (λ (l,r). check (Bex (set S) (instance_rule (l,r))) (l,r)) R"

lemma check_CS_subseteq [simp]:
  "isOK (check_CS_subseteq R S)  subst.closure (set R)  subst.closure (set S)" (is "?l = ?r")
proof
  assume ?l
  show ?r
  proof
    fix x y
    assume "(x,y)  subst.closure (set R)"    
    then show "(x,y)  subst.closure (set S)"
    proof (induct)
      case (subst s t σ)
      with ?l[unfolded check_CS_subseteq_def]
      obtain l r δ where lr: "(l,r)  set S" and s: "s = l  δ" and t: "t = r  δ"
        by (auto simp add: instance_rule_def)
      show ?case unfolding s t
        using subst.closure.intros[OF lr, of "δ s σ"]
        by auto
    qed
  qed
next
  assume ?r
  {
    fix lr
    assume mem: "lr  set R"
    obtain l r where lr: "lr = (l,r)" by (cases lr, auto)
    with mem have "(l,r)  subst.closure (set R)" using subst.subset_closure by auto
    with ?r have "(l,r)  subst.closure (set S)" by auto
    then have "Bex (set S) (instance_rule lr)" unfolding lr
    proof (induct)
      case (subst s t σ)
      then show ?case unfolding instance_rule_def by force
    qed
  }
  thus ?l unfolding check_CS_subseteq_def by auto
qed


definition reverse_rules :: "('f, 'v) rules  ('f, 'v) rules" where
  "reverse_rules rs  map prod.swap rs"

lemma reverse_rules[simp]: "set (reverse_rules R) = (set R)^-1" unfolding reverse_rules_def by force

definition
  map_funs_rules_wa :: "('f × nat  'g)  ('f, 'v) rules  ('g, 'v) rules"
  where
    "map_funs_rules_wa fg R = map (λ(l, r). (map_funs_term_wa fg l, map_funs_term_wa fg r)) R"

lemma map_funs_rules_wa: "set (map_funs_rules_wa fg R) = map_funs_trs_wa fg (set R)"
  unfolding map_funs_rules_wa_def map_funs_trs_wa_def by auto

lemma wf_rule [code]:
  "wf_rule r 
    is_Fun (fst r)  ( x  set (vars_term_impl (snd r)). x  set (vars_term_impl (fst r)))"
  unfolding wf_rule_def by auto

definition wf_rules_impl :: "('f, 'v) rules  ('f, 'v) rules"
  where
    "wf_rules_impl R = filter wf_rule R"

lemma wf_rules_impl [simp]:
  "set (wf_rules_impl R) = wf_rules (set R)"
  unfolding wf_rules_impl_def wf_rules_def by auto

fun check_wf_reltrs :: "(_,_) rules × (_,_) rules  showsl check" where
  "check_wf_reltrs (R, S) = (do {
     check_wf_trs R;
     if R = [] then succeed
     else check_varcond_subset S
   })"

lemma check_wf_reltrs[simp]:
  "isOK (check_wf_reltrs (R, S)) = wf_reltrs (set R) (set S)"
  by (cases R) auto

declare check_wf_reltrs.simps[simp del]

definition check_linear_trs :: "(_,_) rules  showsl check" where
  "check_linear_trs R 
     check_all (λ (l,r). (linear_term l)  (linear_term r)) R
       <+? (λ _. showsl_trs R  showsl (STR ''⏎is not linear⏎''))"

lemma check_linear_trs [simp]:
  "isOK (check_linear_trs R)  linear_trs (set R)"
  unfolding check_linear_trs_def linear_trs_def by auto

definition "non_collapsing_impl R = list_all (is_Fun o snd) R"

lemma non_collapsing_impl[simp]: "non_collapsing_impl R = non_collapsing (set R)"
  unfolding non_collapsing_impl_def non_collapsing_def list_all_iff by auto


type_synonym ('f, 'v) term_map = "'f × nat  ('f, 'v) term list"

definition term_map :: "('f::compare_order, 'v) term list  ('f, 'v) term_map" where
  "term_map ts = fun_of_map (rm.α (elem_list_to_rm (the  root) ts)) []"

definition
  is_NF_main :: "bool  bool  ('f::compare_order, 'v) term_map  ('f, 'v) term  bool"
  where
    "is_NF_main var_cond R_empty m = (if var_cond then (λ_. False) 
     else if R_empty then (λ_. True)
     else (λt. uset (supteq_list t).
       if is_Fun u then
         lset (m (the (root u))). ¬ matches u l
       else True))"

lemma neq_root_no_match:
  assumes "is_Fun l" and "the (root l)  the (root t)"
  shows "¬ matches t l"
  using assms by (cases t) (force iff: matches_iff)+

lemma all_not_conv: "(x  A. ¬ P x) = (¬ (x  A. P x))" by auto

lemma efficient_supteq_list_do_not_match:
  assumes "lset ls. uset (supteq_list t). the (root l)  the (root u)  ¬ matches u l"
  shows
    "(lset ls. uset (supteq_list t). ¬ matches u l) 
     (uset (supteq_list t). lset (term_map ls (the (root u))).
       ¬ matches u l)"
    (is "?lhs  ?rhs" is "_  (uset ?subs. lset (?ls u). ¬ matches u l)")
proof (intro iffI ballI)
  fix u l assume "lset ls. uset ?subs. ¬ matches u l" and "u  set ?subs"
    and "l  set (?ls u)"
  then show "¬ matches u l"
    using elem_list_to_rm.rm_set_lookup[of "the  root" ls "the (root u)"]
    by (auto simp: o_def term_map_def rm_set_lookup_def)
next
  fix l u assume 1: "uset ?subs. lset (?ls u). ¬ matches u l"
    and "l  set ls" and "u  set ?subs"
  with assms have "the (root l)  the (root u)  ¬ matches u l"
    and "lset (?ls u). ¬ matches u l " by simp+
  with elem_list_to_rm.rm_set_lookup[of "the  root" ls "the (root u)"]
    and l  set ls
  show "¬ matches u l" by (auto simp: o_def term_map_def rm_set_lookup_def)
qed

lemma supteq_list_ex:
  "(uset (supteq_list l). σ. t  σ = u)  (σ. l  t  σ)"
  unfolding supteq_list by auto

definition "is_NF_trs R = is_NF_main (rset R. is_Var (fst r)) (R = []) (term_map (map fst R))"
definition "is_NF_terms Q = is_NF_main (qset Q. is_Var q) (Q = []) (term_map Q)"

lemma is_NF_main_NF_trs_conv:
  "is_NF_main (rset R. is_Var (fst r)) (R = []) (term_map (map fst R)) t 
    t  NF_trs (set R)"
  (is "is_NF_main ?var ?R ?map t  _")
proof (intro iffI allI)
  assume is_NF_main: "is_NF_main ?var ?R ?map t"
  show "t  NF_trs (set R)"
  proof (cases "rset R. is_Var (fst r)")
    case True with is_NF_main[unfolded is_NF_main_def] show ?thesis by simp
  next
    case False
    let ?ts = "map fst R"
    from False have allfun: "sset ?ts. is_Fun s" by simp
    with neq_root_no_match
    have no_match: "sset ?ts. uset (supteq_list t). the (root s)  the (root u)
         ¬ matches u s" by blast
    note is_NF_main = is_NF_main[unfolded is_NF_main_def if_not_P[OF False]]
    show ?thesis
    proof (cases "R = []")
      case False
      then have False: "(R = []) = False" by simp
      have "uset (supteq_list t). lset (term_map ?ts (the (root u))). ¬ matches u l"
      proof
        fix u
        assume mem: "u  set (supteq_list t)"
        show "lset (term_map ?ts (the (root u))). ¬ matches u l"
        proof (cases u)
          case (Var x)
          show ?thesis
          proof
            fix l
            assume "l  set (term_map ?ts (the (root u))) "
            with elem_list_to_rm.rm_set_lookup[of "the  root" ?ts "the (root u)"]
            have "l  set ?ts" by (auto simp: o_def term_map_def rm_set_lookup_def)
            then have "is_Fun l" using allfun by auto
            then have "(σ. l  σ  u)" using Var by auto
            then show "¬ matches u l" using matches_iff by blast
          qed
        next
          case (Fun f us)
          with mem is_NF_main[unfolded False] show ?thesis by auto
        qed
      qed
      then show ?thesis
        unfolding efficient_supteq_list_do_not_match[OF no_match, symmetric]
        unfolding all_not_conv matches_iff
        unfolding supteq_list_ex by auto
    qed auto
  qed
next
  assume NF_trs: "t  NF_trs (set R)"
  show "is_NF_main (rset R. is_Var (fst r)) (R = []) (term_map (map fst R)) t"
  proof (cases "rset R. is_Var (fst r)")
    case True
    then obtain l where "l  lhss (set R)" and "is_Var l" by auto
    from lhs_var_not_NF[OF this] and NF_trs show ?thesis by simp
  next
    case False note oFalse = this
    let ?ts = "map fst R"
    from False have "sset ?ts. is_Fun s" by auto
    with neq_root_no_match
    have
      no_match: "sset ?ts. uset (supteq_list t). the (root s)  the (root u)
       ¬ matches u s" by blast
    show ?thesis
    proof (cases "R = []")
      case True then show ?thesis unfolding is_NF_main_def by auto
    next
      case False
      then have False: "(R = []) = False" by simp
      from NF_trs
      show ?thesis
        unfolding is_NF_main_def False if_False if_not_P[OF oFalse]
        using efficient_supteq_list_do_not_match[OF no_match, symmetric]
        unfolding all_not_conv matches_iff
        unfolding supteq_list_ex set_map by fastforce
    qed
  qed
qed

lemma is_NF_trs [simp]:
  "is_NF_trs R = (λ t. t  NF_trs (set R))"
  by (rule ext, unfold is_NF_trs_def is_NF_main_NF_trs_conv, simp)

lemma is_NF_terms [simp]:
  "is_NF_terms Q = (λ t. t  NF_terms (set Q))"
proof (rule ext)
  fix t
  let ?Q = "map (λt. (t, t)) Q"
  have 1: "(tset Q. is_Var t) = (tset ?Q. is_Var (fst t))"
    by (induct Q) (auto simp: o_def)
  have 2: "map fst ?Q = Q" by (induct Q) simp_all
  have 3: "term_map Q = term_map (map fst ?Q)" unfolding 2 ..
  have 4: "set ?Q = Id_on (set Q)" by (induct Q) (auto simp: o_def)
  from is_NF_main_NF_trs_conv[of "?Q" t]
  show "is_NF_terms Q t = (t  NF_terms (set Q))"
    unfolding is_NF_terms_def 1 3 4 unfolding 2 by auto
qed

subsubsection‹Grouping TRS-Rules by Function Symbols›


type_synonym ('f,'v)rule_map = "(('f × nat)  ('f,'v)rules)option"


fun computeRuleMapH :: "('f,'v)rules  (('f × nat) × ('f,'v)rules)list option"
  where "computeRuleMapH [] = Some []"
  | "computeRuleMapH ((Fun f ts,r) # rules) = (let n = length ts in case computeRuleMapH rules of None  None | Some rm  
            (case List.extract (λ (fa,rls). fa = (f,n)) rm of 
                None  Some (((f,n), [(Fun f ts,r)]) # rm)
              | Some (bef,(fa,rls),aft)   Some  ((fa,(Fun f ts,r) # rls) # bef @ aft)))"
  | "computeRuleMapH ((Var _, _) # rules) = None"

definition computeRuleMap :: "('f, 'v) rules  ('f, 'v) rule_map" where
  "computeRuleMap rls 
    (case computeRuleMapH rls of
      None  None
    | Some rm  Some (λf.
      (case map_of rm f of
        None  []
      | Some rls  rls)))"

lemma computeRuleMapHSound2: "(computeRuleMapH R = None) = ( (l, r)  set R. root l = None)"
proof (induct R)
  case (Cons rule rules)
  obtain l r where rule: "rule = (l,r)" by force
  show ?case 
  proof (cases l)
    case (Fun f ts)
    show ?thesis
      using rule Cons
    proof (cases "computeRuleMapH rules")
      case (Some rm) note oSome = this
      let ?e = "List.extract (λ (fa,rls). fa = (f,length ts)) rm"
      from Some Fun rule Cons show ?thesis 
      proof (cases ?e)
        case (Some res)
        then obtain bef aft g rls where "?e = Some (bef, (g,rls), aft)" by (cases res, force) 
        with extract_SomeE[OF this] have rm: "rm = bef @ ((f, length ts),rls) # aft" and e: "?e = Some (bef, ((f,length ts),rls), aft)"
          by auto
        show ?thesis using Cons
          by (simp add: rule Fun Let_def oSome e)
      qed auto
    qed (insert, auto simp: rule Fun)
  qed (auto simp: rule)
qed (auto simp: rule)

lemma computeRuleMapSound2: "(computeRuleMap R = None) = ( (l, r)  set R. root l = None)"
  unfolding computeRuleMap_def
  by (simp only: computeRuleMapHSound2[symmetric], cases "computeRuleMapH R", auto)


lemma computeRuleMapHSound: assumes "computeRuleMapH R = Some rm"
  shows "(λ (f,rls). (f,set rls)) ` set rm = {((f,n),{(l,r) | l r. (l,r)  set R  root l = Some (f, n)}) | f n. {(l,r) | l r. (l,r)  set R  root l = Some (f, n)}  {}}  distinct_eq (λ (f,rls) (g,rls'). f = g) rm"
  using assms
proof (induct R arbitrary: rm)
  case (Cons rule rules)
  let ?setl = "λ rm. (λ (f,rls). (f,set rls)) ` set rm"
  let ?setr = "λ R. {((f,n),{(l,r) | l r. (l,r)  set R  root l = Some (f, n)}) | f n. {(l,r) | l r. (l,r)  set R  root l = Some (f, n)}  {}}"
  obtain l r where Pair: "rule = (l,r)" by force
  show ?case
  proof (cases l)
    case (Var v)
    with Cons Pair show ?thesis by simp
  next
    case (Fun f ts)
    with Cons Pair show ?thesis 
    proof (cases "computeRuleMapH rules")
      case (Some rrm) note oSome = this
      let ?dis = "distinct_eq (λ (f,rls) (g,rls'). f = g)"
      from Cons(1)[OF Some] have drrm: "?dis rrm" and srrm: "?setl rrm = ?setr rules" by auto
      show ?thesis
      proof (cases "List.extract (λ (fa,rls). fa = (f,length ts)) rrm")
        case None
        let ?e = "((f,length ts), [(Fun f ts,r)])"
        let ?e' = "((f,length ts), {(Fun f ts,r)})"
        from None Cons(2) have rm: "rm = ?e # rrm" by (simp add: Fun Pair Some None)
        from None[unfolded extract_None_iff] have rrm: " g n rl. ((g,n),rl)  set rrm  (f,length ts)  (g,n)" by auto
        then have rrm': " g n rl. ((g,n),rl)  ?setr rules  (f,length ts)  (g,n)" by (simp only: srrm[symmetric], auto)
        then have  id: " {(Fun f ts, r)} = {(l, ra). (l = Fun f ts  ra = r  (l, ra)  set rules)  root l = Some (f, length ts)}"  by force
        from rrm have dis: "?dis rm" 
          by (simp add: rm drrm, auto)
        have "?setl rm = insert ?e' (?setl rrm)" by (simp add: rm)
        also have " = insert ?e' (?setr rules)" by (simp add: srrm)
        also have " = ?setr ( (Fun f ts,r) # rules)" 
        proof (rule set_eqI, clarify)
          fix g n rls
          show "(((g,n),rls)  insert ?e' (?setr rules)) = (((g,n),rls)  ?setr ((Fun f ts,r) # rules))"
          proof (cases "(g,n) = (f,length ts)")
            case False
            then have "(((g,n),rls)  insert ?e' (?setr rules)) = (((g,n),rls)  ?setr rules)" by auto
            also have " = (((g,n),rls)  ?setr ((Fun f ts,r) # rules))" using False by auto
            finally show ?thesis .
          next
            case True note oTrue = this
            show ?thesis 
            proof (cases "rls = {(Fun f ts, r)}")
              case True
              with oTrue show ?thesis by (simp add: id, force)
            next
              case False
              show ?thesis using rrm'[of g n rls] True False by (simp add: False True id, auto)
            qed
          qed
        qed
        finally show ?thesis
          by (simp only: dis drrm, simp add: Pair Fun)
      next
        case (Some res)
        obtain bef fg rls aft where "res = (bef,(fg,rls),aft)" by (cases res, force)
        from extract_SomeE[OF Some[simplified this]] Some[simplified this] have rrm: "rrm = bef @ ((f,length ts), rls) # aft" 
          and e: "List.extract (λ (fa, rls). fa = (f,length ts)) rrm = Some (bef, ((f,length ts),rls),aft)" by auto
        let ?e = "((f,length ts), (Fun f ts,r) # rls)"
        let ?e' = "((f,length ts), insert (Fun f ts,r) (set rls))"
        have "((f,length ts),set rls)  ?setl rrm" unfolding rrm by auto
        then have rls: "set rls = {(l, r) |l r. (l, r)  set rules  root l = Some (f, length ts)}" using Cons(1)[OF oSome] by auto
        obtain ba where ba: "ba = bef @ aft" by auto
        from Cons(2) e ba have rm: "rm = ?e # ba" by (simp add: Fun Pair oSome e)
        from drrm[simplified rrm] have dis: "?dis ba"  unfolding distinct_eq_append ba by auto
        from drrm[simplified rrm] have dis: "?dis rm" unfolding rm distinct_eq_append ba by (auto simp: dis[simplified ba])
        from drrm[simplified rrm distinct_eq_append] 
        have diff: "(xset ba. ¬ (λ(g, rls). (f,length ts) = g) x)" by (auto simp: ba)
        have "?setl [((f, length ts),rls)]  ?setl ba = ?setl rrm" using rrm ba by auto
        also have " = ?setr rules" by (rule srrm)
        finally have id: "?setl [((f, length ts),rls)]  ?setl ba = ?setr rules" .          
        have "?setl rm = insert ?e' (?setl ba)" by (simp add: rm)
        also have " = ?setr ((Fun f ts,r) # rules)" 
        proof (rule set_eqI, clarify)
          fix g n rl 
          show "(((g,n),rl)  insert ?e' (?setl ba)) = (((g,n),rl)  ?setr ((Fun f ts,r) # rules))"
          proof (cases "(g,n) = (f,length ts)")
            case False 
            then have "(((g,n),rl)  insert ?e' (?setl ba)) = (((g,n),rl)  ?setl ba)" by auto
            also have " = (((g,n),rl)  ?setr rules)" using False by (simp only: id[symmetric], auto)
            also have " = (((g,n),rl)  ?setr ((Fun f ts,r) # rules))" using False by auto
            finally show ?thesis .
          next
            case True note oTrue = this
            show ?thesis 
            proof (cases "rl = insert (Fun f ts, r) (set rls)")
              case True
              then have "(((g,n),rl)  insert ?e' (?setl ba)) = True" using oTrue by auto
              also have " = (((g,n),rl)  ?setr ((Fun f ts,r) # rules))" unfolding True rls using oTrue by force
              finally show ?thesis .
            next
              case False
              then have "(((g,n),rl)  insert ?e' (?setl ba)) = False" using diff by (simp add: True, auto)
              also have " = (((g,n),rl)  ?setr ((Fun f ts,r) # rules))" 
              proof (rule ccontr)
                assume "¬ ?thesis"
                with True have "((f,length ts),rl)  ?setr ((Fun f ts,r) # rules)" by simp
                then have "rl = {(l, ra) |l ra. (l, ra)  set ((Fun f ts, r) # rules)  root l = Some (f, length ts)}" by simp
                with False rls show False by auto
              qed                              
              finally show ?thesis .
            qed
          qed
        qed
        also have " = ?setr (rule # rules)" by (simp add: Pair Fun)
        finally show ?thesis by (simp add: dis)
      qed
    qed simp
  qed
qed force

lemma computeRuleMapSound:
  assumes "computeRuleMap R = Some rm" 
  shows "(set (rm (f,n))) = {(l,r) | l r. (l,r)  set R  root l = Some (f, n)}"
proof (cases "computeRuleMapH R")
  case None
  then show ?thesis using assms unfolding computeRuleMap_def by auto
next
  case (Some rrm)
  note rrm = computeRuleMapHSound[OF this] 
  note rm = assms[unfolded computeRuleMap_def, simplified Some, simplified, symmetric]
  show ?thesis
  proof (cases "map_of rrm (f, n)")
    case (Some rls)
    from map_of_SomeD[OF this] have "((f,n),set rls)  (λ (f,rls). (f, set rls)) ` set rrm"
      by auto
    then have "set rls = {(l,r) | l r. (l,r)  set R  root l = Some (f, n)}"
      by (simp only: rrm, simp) 
    then show ?thesis by (simp add: rm Some)
  next
    case None
    have id: "{(l, r) |l r. (l, r)  set R  root l = Some (f, n)} = {}" (is "?set = {}")
    proof (rule ccontr)
      assume "¬ ?thesis"
      then obtain l r where "(l, r)  set R  root l = Some (f, n)" by auto
      with rrm have "(((f,n), ?set))  (λ (f,rls). (f, set rls)) ` set rrm" by auto
      with None[unfolded map_of_eq_None_iff] show False by force
    qed
    then show ?thesis by (simp only: rm None id, auto)
  qed
qed



lemma computeRuleMap_left_vars:
  shows "(computeRuleMap R  None) = ( lr  set R.  x. fst lr  Var x)"
proof (cases "computeRuleMap R")
  case None
  from None computeRuleMapSound2 have " (l,r)  set R. root l = None" by auto
  from this obtain l r where "(l,r)  set R  root l = None" by auto
  from this have "(l,r)  set R  ¬ ( x. fst (l,r)  Var x)" by (cases l, auto)
  with None show ?thesis by blast
next
  case (Some rm)
  then have left: "computeRuleMap R  None" by auto
  from Some computeRuleMapSound2 have " (l,r)  set R. root l  None" by force
  then have " lr  set R.  x. fst lr  Var x" by auto
  with left show ?thesis by blast
qed

lemma computeRuleMap_defined: fixes R :: "('f,'v)rules"
  assumes "computeRuleMap R = Some rm"
  shows "(rm (f,n) = []) = (¬ defined (set R) (f,n))"
proof -
  from assms computeRuleMapSound have rm: "(f::'f) n. set (rm (f,n)) = {(l,r) | l r. (l, r)  set R  root l = Some (f, n)}" by force
  show ?thesis
  proof (cases "rm (f,n)")
    case Nil
    with rm have "¬ defined (set R) (f,n)" unfolding defined_def by force
    with Nil show ?thesis by blast
  next
    case (Cons lr RR)
    then have left: "rm (f,n)  []" by auto
    from Cons rm[where f = f and n = n] have "defined (set R) (f,n)" unfolding defined_def by (cases lr, force)
    with left show ?thesis by blast
  qed
qed


lemma computeRuleMap_None_not_SN:
  assumes "computeRuleMap R = None"
  shows "¬ SN_on (rstep (set R)) {t}"
proof -
  from assms computeRuleMap_left_vars[of R] obtain x r where "(Var x,r)  set R" by auto
  from left_var_imp_not_SN[OF this] show ?thesis .
qed

end