Theory Parallel_Rewriting

subsection ‹The Parallel Rewrite Relation›

theory Parallel_Rewriting
  imports
    Trs
    Multihole_Context
begin

text ‹The parallel rewrite relation as inductive definition›
inductive_set par_rstep :: "('f,'v)trs  ('f,'v)trs" for R :: "('f,'v)trs"
  where root_step[intro]: "(s,t)  R  (s  σ,t  σ)  par_rstep R"
  |  par_step_fun[intro]: " i. i < length ts  (ss ! i,ts ! i)  par_rstep R  length ss = length ts
              (Fun f ss, Fun f ts)  par_rstep R"
  |  par_step_var[intro]: "(Var x, Var x)  par_rstep R"

lemma par_rstep_refl[intro]: "(t,t)  par_rstep R"
  by (induct t, auto)

lemma all_ctxt_closed_par_rstep[intro]: "all_ctxt_closed F (par_rstep R)"
  unfolding all_ctxt_closed_def                  
  by auto

lemma args_par_rstep_pow_imp_par_rstep_pow:
  "length xs = length ys  i<length xs. (xs ! i, ys ! i)  par_rstep R ^^ n 
  (Fun f xs, Fun f ys)  par_rstep R ^^ n"
proof(induct n arbitrary:ys)
  case 0
  then have "i<length xs. (xs ! i = ys ! i)" by simp
  with 0 show ?case using relpow_0_I list_eq_iff_nth_eq by metis
next
  case (Suc n)
  let ?c = "λ z i. (xs ! i, z)  par_rstep R ^^ n  (z, ys ! i)  par_rstep R"
  { fix i assume "i < length xs"
    from relpow_Suc_E[OF Suc(3)[rule_format, OF this]]
    have " z. (?c z i)" by metis
  }
  with choice have " zf.  i < length xs. (?c (zf i) i)" by meson
  then obtain zf where a:" i < length xs. (?c (zf i) i)" by auto
  let ?zs = "map zf [0..<length xs]"
  have len:"length xs = length ?zs" by simp
  from a map_nth have  "i<length xs.  (xs ! i, ?zs ! i)  par_rstep R ^^ n" by auto
  from Suc(1)[OF len this] have n:"(Fun f xs, Fun f ?zs)  par_rstep R ^^ n" by auto
  from a map_nth have  "i<length xs. (?zs ! i, ys ! i)  par_rstep R" by auto
  with par_step_fun len Suc(2) have "(Fun f ?zs, Fun f ys)  par_rstep R" by auto
  with n show ?case by auto
qed

lemma ctxt_closed_par_rstep[intro]: "ctxt.closed (par_rstep R)"
proof (rule one_imp_ctxt_closed)
  fix f bef s t aft
  assume st: "(s,t)  par_rstep R"
  let ?ss = "bef @ s # aft"
  let ?ts = "bef @ t # aft"
  show "(Fun f ?ss, Fun f ?ts)  par_rstep R"
  proof (rule par_step_fun)
    fix i
    assume "i < length ?ts"
    show "(?ss ! i, ?ts ! i)  par_rstep R"
      using par_rstep_refl[of "?ts ! i" R] st by (cases "i = length bef", auto simp: nth_append)
  qed simp
qed

lemma subst_closed_par_rstep: "(s,t)  par_rstep R  (s  σ, t  σ)  par_rstep R"
proof (induct rule: par_rstep.induct)
  case (root_step s t τ)
  show ?case
    using par_rstep.root_step[OF root_step, of "τ s σ"] by auto
next
  case (par_step_var x)
  show ?case by auto
next
  case (par_step_fun ss ts f)
  show ?case unfolding eval_term.simps
    by (rule par_rstep.par_step_fun, insert par_step_fun(2-3), auto)
qed

lemma R_par_rstep: "R  par_rstep R"
  using root_step[of _ _ R Var] by auto

lemma par_rstep_rsteps: "par_rstep R  (rstep R)*"
proof
  fix s t
  assume "(s,t)  par_rstep R"
  then show "(s,t)  (rstep R)*"
  proof (induct rule: par_rstep.induct)
    case (root_step s t sigma)
    then show ?case by auto
  next
    case (par_step_var x)
    then show ?case by auto
  next
    case (par_step_fun ts ss f)
    from all_ctxt_closedD[of UNIV, OF all_ctxt_closed_rsteps _ par_step_fun(3) par_step_fun(2)]
    show ?case unfolding par_step_fun(3) by simp
  qed
qed

lemma rstep_par_rstep: "rstep R  par_rstep R"
  by (rule rstep_subset[OF ctxt_closed_par_rstep subst.closedI R_par_rstep],
      insert subst_closed_par_rstep, auto)

lemma par_rsteps_rsteps: "(par_rstep R)* = (rstep R)*" (is "?P = ?R")
proof
  from rtrancl_mono[OF par_rstep_rsteps[of R]] show "?P  ?R" by simp
  from rtrancl_mono[OF rstep_par_rstep] show "?R  ?P" .
qed

lemma par_rsteps_union: "(par_rstep A  par_rstep B)* =
    (rstep (A  B))*" 
proof
  show "(par_rstep A  par_rstep B)*  (rstep (A  B))*"
    by (metis par_rsteps_rsteps rstep_union rtrancl_Un_rtrancl set_eq_subset)
  show "(rstep (A  B))*  (par_rstep A  par_rstep B)*" unfolding rstep_union
    by (meson rstep_par_rstep rtrancl_mono sup_mono)
qed

lemma par_rstep_inverse: "par_rstep (R^-1) = (par_rstep R)^-1" 
proof -
  {
    fix s t :: "('a,'b)term" and R
    assume "(s,t)  par_rstep (R^-1)" 
    hence "(t,s)  par_rstep R" 
      by (induct s t, auto)
  }
  from this[of _ _ R] this[of _ _ "R^-1"]
  show ?thesis by auto
qed

lemma par_rstep_conversion: "(rstep R)* = (par_rstep R)*" 
  unfolding conversion_def 
  by (metis par_rsteps_rsteps rtrancl_Un_rtrancl rtrancl_converse)

lemma par_rstep_mono: assumes "R  S"
  shows "par_rstep R  par_rstep S" 
proof 
  fix s t
  show "(s, t)  par_rstep R  (s, t)  par_rstep S" 
    by (induct s t rule: par_rstep.induct, insert assms, auto)
qed

lemma wf_trs_par_rstep: assumes wf: " l r. (l,r)  R  is_Fun l"
  and step: "(Var x, t)  par_rstep R"
shows "t = Var x"
  using step
proof (cases rule: par_rstep.cases)
  case (root_step l r σ)
  from root_step(1) wf[OF root_step(3)] show ?thesis by (cases l, auto)
qed auto

text ‹main lemma which tells us, that either a parallel rewrite step of l ⋅ σ› is inside l›, or
  we can do the step completely inside σ›
lemma par_rstep_linear_subst: assumes lin: "linear_term l"
  and step: "(l  σ, t)  par_rstep R"
shows "( τ. t = l  τ  ( x  vars_term l. (σ x, τ x)  par_rstep R) 
               ( C l'' l' r'. l = Cl''  is_Fun l''  (l',r')  R  (l''  σ = l'  τ)  ((C c σ)  r'  τ , t)  par_rstep R))"
  using lin step
proof (induction l arbitrary: t)
  case (Var x t)
  let ?tau = "λ y. t"
  show ?case
    by (rule exI[of _ ?tau], rule disjI1, insert Var(2), auto)
next
  case (Fun f ss)
  let ?ss = "map (λ s. s  σ) ss"
  let ?R = "par_rstep R"
  from Fun(3)
  show ?case
  proof (cases rule: par_rstep.cases)
    case (root_step l r τ)
    show ?thesis
    proof (rule exI, rule disjI2, intro exI conjI)
      show "(l,r)  R" by (rule root_step(3))
      show "Fun f ss = Fun f ss" by simp
      show "(Fun f ss)  σ = l  τ" by (rule root_step(1))
      show "(( c σ) r  τ , t)  ?R" unfolding root_step(2) using par_rstep_refl by simp
    qed simp
  next
    case (par_step_var x)
    then show ?thesis by simp
  next
    case (par_step_fun ts ss1 g)
    then have id: "ss1 = ?ss" "g = f" and len: "length ts = length ss" by auto
    let ?p1 = "λ τ i. ts ! i = ss ! i  τ  ( x  vars_term (ss ! i). (σ x, τ x)  ?R)"
    let ?p2 = "λ τ i. ( C l'' l' r'. ss ! i = C l''  is_Fun l''  (l',r')  R  l''  σ = l'  τ  ((C c σ) r'  τ , (ts ! i))  ?R)"
    let ?p = "λ τ i. ?p1 τ i  ?p2 τ i"
    {
      fix i
      assume i: "i < length ss"
      with par_step_fun(4) id have i2: "i < length ts" by auto
      from par_step_fun(3)[OF i2] have step: "(ss ! i  σ, ts ! i)  par_rstep R" unfolding id nth_map[OF i] .
      from i have mem: "ss ! i  set ss" by auto
      from Fun.prems(1) mem have "linear_term (ss ! i)" by auto
      from Fun.IH[OF mem this step] have " τ. ?p τ i" .
    }
    then have " i.  tau. i < length ss  ?p tau i" by blast
    from choice[OF this] obtain taus where taus: " i. i < length ss  ?p (taus i) i" by blast
    show ?thesis
    proof (cases " i. i < length ss  ?p2 (taus i) i")
      case True
      then obtain i where i: "i < length ss" and p2: "?p2 (taus i) i" by blast+
      from par_step_fun(2)[unfolded id] have t: "t = Fun f ts" .
      from i have i': "i < length ts" unfolding len .
      from p2 obtain C l'' l' r' where ssi: "ss ! i = C l''" and "is_Fun l''" "(l',r')  R" "l''  σ = l'  taus i"
        and tsi: "((C c σ)  r'  taus i , ts ! i)  ?R" by blast
      from id_take_nth_drop[OF i, unfolded ssi] obtain bef aft where ss: "ss = bef @ C  l''  # aft"
        and bef: "bef = take i ss"
        and aft: "aft = drop (Suc i) ss" by blast
      let ?C = "More f bef C aft"
      let ?r = "(C c σ)  r'  taus i "
      let ?sig = "map (λ s. s  σ)"
      let ?bra = "?sig bef @ ?r # ?sig aft"
      have C: "(?C c σ)  r'  taus i  = Fun f ?bra" by simp
      show ?thesis unfolding ss
      proof (rule exI[of _ "taus i"], rule disjI2, rule exI[of _ ?C], intro exI conjI)
        show "is_Fun l''" by fact
        show "(l',r')  R" by fact
        show "l''  σ = l'  taus i" by fact
        show "((?C c σ)  r'  taus i , t)  ?R" unfolding C t
        proof  (rule par_rstep.par_step_fun)
          show "length ?bra = length ts"
            unfolding len unfolding ss by simp
        next
          fix j
          assume j: "j < length ts"
          show "(?bra ! j, ts ! j)  ?R"
          proof (cases "j = i")
            case True
            then have "?bra ! j = ?r" using bef i by (simp add: nth_append)
            then show ?thesis using tsi True by simp
          next
            case False
            from bef i have "min (length ss) i = i" by simp
            then have "?bra ! j = (?sig bef @ (C  l''   σ) # ?sig aft) ! j" using False bef i by (simp add: nth_append)
            also have "... = ?sig ss ! j" unfolding ss by simp
            also have "... = ss1 ! j" unfolding id ..
            finally show ?thesis
              using par_step_fun(3)[OF j] by auto
          qed
        qed
      qed simp
    next
      case False
      with taus have taus: " i. i < length ss  ?p1 (taus i) i" by blast
      from Fun(2) have "is_partition (map vars_term ss)" by simp
      from subst_merge[OF this, of taus] obtain τ where tau: " i x. i < length ss  x  vars_term (ss ! i)  τ x = taus i x" by auto
      let ?tau = τ
      {
        fix i
        assume i: "i < length ss"
        then have mem: "ss ! i  set ss" by auto
        from taus[OF i] have p1: "?p1 (taus i) i" .
        have id: "ss ! i  (taus i) = ss ! i  τ"
          by (rule term_subst_eq, rule tau[OF i, symmetric])
        have "?p1 ?tau i"
        proof (rule conjI[OF _ ballI])
          fix x
          assume x: "x  vars_term (ss ! i)"
          with p1 have step: "(σ x, taus i x)  par_rstep R" by auto
          with tau[OF i x]
          show "(σ x, ?tau x)  par_rstep R" by simp
        qed (insert p1[unfolded id], auto)
      } note p1 = this
      have p1: " i. i < length ss  ?p1 τ i" by (rule p1)
      let ?ss = "map (λ s. s  τ) ss"
      show ?thesis unfolding par_step_fun(2) id
      proof (rule exI[of _ τ], rule disjI1, rule conjI[OF _ ballI])
        have "ts = map (λ i. ts ! i) [0 ..< (length ts)]" by (rule map_nth[symmetric])
        also have "...  = map (λ i. ?ss ! i) [0 ..< length ?ss]" unfolding len using p1 by auto
        also have "... = ?ss" by (rule map_nth)
        finally have ts: "ts = ?ss" .
        show "Fun f ts = Fun f ss  τ" unfolding ts by auto
      next
        fix x
        assume "x  vars_term (Fun f ss)"
        then obtain s where s: "s  set ss" and x: "x  vars_term s" by auto
        from s[unfolded set_conv_nth] obtain i where i: "i < length ss" and s: "s = ss ! i" by auto
        from p1[OF i] x[unfolded s]
        show "(σ x, τ x)  par_rstep R" by blast
      qed
    qed
  qed
qed

lemma par_rstep_id:
  "(s, t)  R  (s, t)  par_rstep R"
  using par_rstep.root_step [of s t R Var] by simp

subsection ‹Parallel Rewriting using Multihole Contexts›

datatype ('f,'v)par_info = Par_Info 
  (par_left: "('f,'v)term") 
  (par_right: "('f,'v)term")
  (par_rule: "('f,'v)rule")

abbreviation par_lefts where "par_lefts  map par_left" 
abbreviation par_rights where "par_rights  map par_right" 
abbreviation par_rules where "par_rules  (λ info. par_rule ` set info)" 

definition par_cond :: "('f,'v)trs  ('f,'v)par_info  bool" where
  "par_cond R info = (par_rule info  R  (par_left info, par_right info)  rrstep {par_rule info})" 

abbreviation par_conds where "par_conds R  λ infos. Ball (set infos) (par_cond R)"

lemma par_cond_imp_rrstep: assumes "par_cond R info"
  shows "(par_left info, par_right info)  rrstep R" 
  using assms unfolding par_cond_def 
  by (metis rrstepE rrstepI singletonD)

lemma par_conds_imp_rrstep: assumes "par_conds R infos"
  and "s = par_lefts infos ! i" "t = par_rights infos ! i"
  and "i < length infos" 
shows "(s, t)  rrstep R"
proof -
  from assms have eq: "s = par_left (infos ! i)" "t = par_right (infos ! i)" and pc: "par_cond R (infos ! i)" 
    by auto
  show ?thesis unfolding eq using par_cond_imp_rrstep[OF pc] .
qed

definition par_rstep_mctxt where 
  "par_rstep_mctxt R C infos = {(s, t). s =f (C, par_lefts infos)  t =f (C, par_rights infos)  par_conds R infos}"

lemma par_rstep_mctxtI: assumes "s =f (C, par_lefts infos)" "t =f (C, par_rights infos)" "par_conds R infos" 
  shows "(s,t)  par_rstep_mctxt R C infos" 
  unfolding par_rstep_mctxt_def using assms by auto

lemma par_rstep_mctxt_reflI: "(s,s)  par_rstep_mctxt R (mctxt_of_term s) []" 
  by (intro par_rstep_mctxtI, auto)

lemma par_rstep_mctxt_varI: "(Var x, Var x)  par_rstep_mctxt R (MVar x) []" 
  by (intro par_rstep_mctxtI, auto)

lemma par_rstep_mctxt_MHoleI: "(l,r)  R  s = l  σ  t = r  σ  infos = [Par_Info s t (l,r)] 
   (s,t)  par_rstep_mctxt R MHole infos" 
  by (intro par_rstep_mctxtI, auto simp: par_cond_def)

lemma par_rstep_mctxt_funI: 
  assumes rec: " i. i < length ts  (ss ! i, ts ! i)  par_rstep_mctxt R (Cs ! i) (infos ! i)" 
    and len: "length ss = length ts" "length Cs = length ts" "length infos = length ts" 
  shows "(Fun f ss, Fun f ts)  par_rstep_mctxt R (MFun f Cs) (concat infos)"
  unfolding par_rstep_mctxt_def
proof (standard, unfold split, intro conjI)
  {
    fix i
    assume "i < length ts" 
    from rec[OF this, unfolded par_rstep_mctxt_def]
    have "ss ! i =f (Cs ! i, par_lefts (infos ! i))" "ts ! i =f (Cs ! i, par_rights (infos ! i))" 
      "par_conds R (infos ! i)" by auto
  } note * = this
  from *(3)[folded len(3)] show "par_conds R (concat infos)"
    by (metis in_set_conv_nth nth_concat_split)
  show "Fun f ss =f (MFun f Cs, par_lefts (concat infos))" unfolding map_concat
    by (intro eqf_MFunI, insert *(1) len, auto)
  show "Fun f ts =f (MFun f Cs, par_rights (concat infos))" unfolding map_concat
    by (intro eqf_MFunI, insert *(2) len, auto)
qed

lemma par_rstep_mctxt_funI_ex: 
  assumes " i. i < length ts   C infos. (ss ! i, ts ! i)  par_rstep_mctxt R C infos" 
    and "length ss = length ts" 
  shows " C infos. (Fun f ss, Fun f ts)  par_rstep_mctxt R C infos  C  MHole" 
proof -
  let ?n = "length ts" 
  from assms(1) have " i.  C infos. i < ?n  (ss ! i, ts ! i)  par_rstep_mctxt R C infos"  by auto
  from choice[OF this] obtain C where " i.  infos. i < ?n  (ss ! i, ts ! i)  par_rstep_mctxt R (C i) infos" by auto
  from choice[OF this] obtain infos where steps: " i. i < ?n  (ss ! i, ts ! i)  par_rstep_mctxt R (C i) (infos i)" by auto
  let ?Cs = "map C [0 ..< ?n]" 
  let ?Is = "map infos [0 ..< ?n]" 
  show ?thesis
  proof (intro exI conjI, rule par_rstep_mctxt_funI)
    show "length ?Cs = ?n" by simp
    show "length ?Is = ?n" by simp
  qed (insert assms(2) steps, auto)
qed

text ‹Parallel rewriting is closed under multihole-contexts.›
lemma par_rstep_mctxt:
  assumes "s =f (C, ss)" and "t =f (C, ts)"
    and "i<length ss. (ss ! i, ts ! i)  par_rstep R"
  shows "(s, t)  par_rstep R"
proof -
  have [simp]: "length ss = length ts" using assms by (auto dest!: eqfE)
  have [simp]: "t = fill_holes C ts" using assms by (auto dest: eqfE)
  have "(s, fill_holes C ts)  par_rstep R"
    using assms by (intro eqf_all_ctxt_closed_step [of UNIV _ s C ss, THEN conjunct1]) auto
  then show ?thesis by simp
qed

lemma par_rstep_mctxt_rrstepI :
  assumes "s =f (C, ss)" and "t =f (C, ts)"
    and "i<length ss. (ss ! i, ts ! i)  rrstep R"
  shows "(s, t)  par_rstep R"
  by (meson assms contra_subsetD par_rstep_mctxt rrstep_imp_rstep rstep_par_rstep)


lemma par_rstep_mctxtD:
  assumes "(s, t)  par_rstep R"
  shows "C ss ts. s =f (C, ss)  t =f (C, ts)  (i<length ss. (ss ! i, ts ! i)  rrstep R)"
    (is "C ss ts. ?P s t C ss ts")
  using assms
proof (induct)
  case (root_step s t σ)
  then have "(s  σ, t  σ)  rrstep R" by auto
  moreover have "s  σ =f (MHole, [s  σ])" and "t  σ =f (MHole, [t  σ])" by auto
  ultimately show ?case by force
next
  case (par_step_var x)
  have "Var x =f (MVar x, [])" by auto
  then show ?case by force
next
  case (par_step_fun ts ss f)
  then have "i<length ts. x. ?P (ss ! i) (ts ! i) (fst x) (fst (snd x)) (snd (snd x))" by force
  then obtain g where "i<length ts. ?P (ss ! i) (ts ! i) (fst (g i)) (fst (snd (g i))) (snd (snd (g i)))"
    unfolding choice_iff' by blast
  moreover
  define Cs us vs where "Cs = map (λi. fst (g i)) [0 ..< length ts]"
    and "us = map (λi. fst (snd (g i))) [0 ..< length ts]"
    and "vs = map (λi. snd (snd (g i))) [0 ..< length ts]"
  ultimately have [simp]: "length Cs = length ts"
    "length us = length ts" "length vs = length ts"
    and *: "i<length us. ss ! i =f (Cs ! i, us ! i)  ts ! i =f (Cs ! i, vs ! i) 
      (j<length (us ! i). (us ! i ! j, vs ! i ! j)  rrstep R)"
    by simp_all
  define C where "C = MFun f Cs"
  have "Fun f ss =f (C, concat us)" and "Fun f ts =f (C, concat vs)"
    using * by (auto simp: C_def length ss = length ts intro: eqf_MFunI)
  moreover have "i<length (concat us). (concat us ! i, concat vs ! i)  rrstep R"
    using * by (intro concat_all_nth) (auto dest!: eqfE)
  ultimately show ?case by blast
qed

lemma par_rstep_mctxt_mono: assumes "R  S"
  shows "par_rstep_mctxt R C infos  par_rstep_mctxt S C infos" 
  using assms unfolding par_rstep_mctxt_def par_cond_def by auto


lemma par_rstep_mctxtE:
  assumes "(s, t)  par_rstep R"
  obtains C infos where "s =f (C, par_lefts infos)" and "t =f (C, par_rights infos)"
    and "par_conds R infos"
proof -
  have " C infos. s =f (C, par_lefts infos)  t =f (C, par_rights infos)  par_conds R infos" (is "C infos. ?P s t C infos")
    using assms
  proof (induct)
    case (root_step s t σ)
    thus ?case by (intro exI[of _ MHole] exI[of _ "[Par_Info (s  σ) (t  σ) (s,t)]"], auto simp: par_cond_def)
  next
    case (par_step_var x)
    show ?case by (intro exI[of _ "MVar x"] exI[of _ Nil], auto)
  next
    case (par_step_fun ts ss f)
    have "C infos. (Fun f ss, Fun f ts)  par_rstep_mctxt R C infos  C  MHole" 
      by (intro par_rstep_mctxt_funI_ex, insert par_step_fun, auto simp: par_rstep_mctxt_def)
    then obtain C infos where "(Fun f ss, Fun f ts)  par_rstep_mctxt R C infos" by auto
    hence "?P (Fun f ss) (Fun f ts) C infos" 
      by (auto simp: par_rstep_mctxt_def)
    thus ?case by blast
  qed
  with that show ?thesis by blast
qed

lemma par_rstep_par_rstep_mctxt_conv:
  "(s, t)  par_rstep R  (C infos. (s, t)  par_rstep_mctxt R C infos)"
proof
  assume "(s, t)  par_rstep R"
  from par_rstep_mctxtE[OF this] obtain C infos
    where "s =f (C, par_lefts infos)" and "t =f (C, par_rights infos)" and "par_conds R infos" 
    by metis
  then show "C infos. (s, t)  par_rstep_mctxt R C infos" by (auto simp: par_rstep_mctxt_def)
next
  assume "C infos. (s, t)  par_rstep_mctxt R C infos"
  then show "(s, t)  par_rstep R"
    by (force simp: par_rstep_mctxt_def par_cond_def rrstep_def' set_conv_nth intro!: par_rstep_mctxt_rrstepI)
qed

fun subst_apply_par_info :: "('f,'v)par_info  ('f,'v)subst  ('f,'v)par_info" (infixl "⋅pi" 67) where
  "Par_Info s t r ⋅pi σ = Par_Info (s  σ) (t  σ) r" 

lemma subst_apply_par_info_simps[simp]: 
  "par_left (info ⋅pi σ) = par_left info  σ"
  "par_right (info ⋅pi σ) = par_right info  σ"
  "par_rule (info ⋅pi σ) = par_rule info"
  "par_cond R info  par_cond R (info ⋅pi σ)"
  unfolding par_cond_def
  by (cases info; force simp: subst.closedD subst_closed_rrstep)+

lemma par_rstep_mctxt_subst: assumes "(s,t)  par_rstep_mctxt R C infos" 
  shows "(s  σ, t  σ)  par_rstep_mctxt R (C ⋅mc σ) (map (λ i. i ⋅pi σ) infos)" 
  using assms unfolding par_rstep_mctxt_def by (auto simp: o_def dest!: subst_apply_mctxt_sound[of _ C _ σ])

lemma par_rstep_mctxt_MVarE: 
  assumes "(s,t)  par_rstep_mctxt R (MVar x) infos" 
  shows "s = Var x" "t = Var x" "infos = []" 
  using assms[unfolded par_rstep_mctxt_def]
  by (auto dest: eqf_MVarE)

lemma par_rstep_mctxt_MHoleE: 
  assumes "(s,t)  par_rstep_mctxt R MHole infos" 
  obtains info where 
    "par_left info = s" 
    "par_right info = t" 
    "infos = [info]" 
    "(s, t)  rrstep R" 
    "par_cond R info" 
proof -
  from assms[unfolded par_rstep_mctxt_def, simplified]
  have "s =f (MHole, par_lefts infos)" "t =f (MHole, par_rights infos)" and "par_conds R infos" by auto
  from eqf_MHoleE[OF this(1)] eqf_MHoleE[OF this(2)] this(3)
  obtain info where *: "infos = [info]" "s = par_left info" "t = par_right info" "par_cond R info"  
    by (cases infos, auto)
  from par_cond_imp_rrstep[OF *(4)] *
  have "(s,t)  rrstep R" by auto
  with * have " info. par_left info = s  par_right info = t  infos = [info]  (s, t)  rrstep R  
    par_cond R info" by auto
  thus "(info.
        par_left info = s 
        par_right info = t 
        infos = [info] 
        (s, t)  rrstep R  par_cond R info  thesis) 
    thesis" by blast
qed

lemma par_rstep_mctxt_MFunD: 
  assumes "(s,t)  par_rstep_mctxt R (MFun f Cs) infos" 
  shows " ss ts Infos. 
    s = Fun f ss 
    t = Fun f ts 
    length ss = length Cs 
    length ts = length Cs 
    length Infos = length Cs  
    infos = concat Infos 
    ( i < length Cs. (ss ! i, ts ! i)  par_rstep_mctxt R (Cs ! i) (Infos ! i))"
proof -
  from assms[unfolded par_rstep_mctxt_def]
  have eq: "s =f (MFun f Cs, par_lefts infos)" "t =f (MFun f Cs, par_rights infos)" 
    and pc: "par_conds R infos" 
    by auto
  define Infos where "Infos = partition_holes infos Cs" 
  let ?sss = "map par_lefts Infos" 
  let ?tss = "map par_rights Infos" 
  let ?n = "length Cs" 
  let ?is = "[0..<?n]"
  from eqfE[OF eq(1)]
  have s: "s = Fun f (map (λi. fill_holes (Cs ! i) (?sss ! i)) ?is)" 
    and num: "num_holes (MFun f Cs) = length infos" 
    and len: "length Infos = ?n"
    and infos: "infos = concat Infos"
    and lens: " i. i < ?n  num_holes (Cs ! i) = length (Infos ! i)" 
    by (auto simp: Infos_def)
  note pc = pc[unfolded infos set_concat]
  from eqfE[OF eq(2)] num
  have t: "t = Fun f (map (λi. fill_holes (Cs ! i) (?tss ! i)) ?is)" 
    by (auto simp: Infos_def)
  show ?thesis
    apply (intro exI[of _ Infos] exI conjI infos len allI impI)
        apply (rule s)
       apply (rule t)
      apply force
     apply force
    apply (intro par_rstep_mctxtI, insert lens len pc, auto)
    done
qed


subsection‹Variable Restricted Parallel Rewriting›
  (* a parallel rewrite relation that restricts instantiation of variables,
   relevant for Toyama's refinement on joining parallel critical pairs *)

(* it is assumed that the context-positions are within the term *)
fun vars_below_hole :: "('f,'v)term  ('f,'v)mctxt  'v set" where
  "vars_below_hole t MHole = vars_term t" 
| "vars_below_hole t (MVar y) = {}" 
| "vars_below_hole (Fun _ ts) (MFun _ Cs) = 
      (set (map (λ (t,C). vars_below_hole t C) (zip ts Cs)))" 
| "vars_below_hole (Var _) (MFun _ _) = Code.abort (STR ''assumption in vars_below_hole violated'') (λ _. {})" 

lemma vars_below_hole_no_hole: "hole_poss C = {}  vars_below_hole t C = {}" 
  by (induct t C rule: vars_below_hole.induct, auto simp: set_zip, blast)

lemma vars_below_hole_mctxt_of_term[simp]: "vars_below_hole t (mctxt_of_term u) = {}" 
  by (rule vars_below_hole_no_hole, auto)

lemma vars_below_hole_vars_term: "vars_below_hole t C  vars_term t" 
  by (induct t C rule: vars_below_hole.induct; force simp: set_zip set_conv_nth)

lemma vars_below_hole_subst[simp]: "vars_below_hole t (C ⋅mc σ) = vars_below_hole t C" 
  by (induct t C rule: vars_below_hole.induct; fastforce simp: set_zip)

lemma vars_below_hole_Fun: assumes "length ls = length Cs" 
  shows "vars_below_hole (Fun f ls) (MFun f Cs) =  {vars_below_hole (ls ! i) (Cs ! i) | i. i < length Cs}" 
  using assms by (auto simp: set_zip)  

lemma vars_below_hole_term_subst: 
  "hole_poss D  poss t  vars_below_hole (t  σ) D =  (vars_term ` σ ` vars_below_hole t D)"
proof (induct t D rule: vars_below_hole.induct)
  case (1 t)
  then show ?case by (auto simp: vars_term_subst)
next
  case (3 f ts g Cs)
  then show ?case by (fastforce simp: set_zip)
next
  case (4 x f Cs)
  hence hp: "hole_poss (MFun f Cs) = {}" by auto
  show ?case unfolding vars_below_hole_no_hole[OF hp] by auto
qed auto


lemma vars_below_hole_eqf: assumes "t =f (C, ts)"
  shows "vars_below_hole t C =  (vars_term ` set ts)" 
  using assms
proof (induct C arbitrary: t ts)
  case (MVar x)
  from eqf_MVarE[OF MVar(1)]  
  show ?case by auto
next
  case MHole
  from eqf_MHoleE[OF MHole(1)]
  show ?case by auto
next
  case (MFun f Cs t ss)
  from eqf_MFunE[OF MFun(2)] obtain ts sss where
    *: "t = Fun f ts" "length ts = length Cs" "length sss = length Cs" 
    " i. i < length Cs  ts ! i =f (Cs ! i, sss ! i)"
    "ss = concat sss" by blast
  {
    fix i
    assume i: "i < length Cs" 
    hence mem: "Cs ! i  set Cs" by auto
    from MFun(1)[OF mem *(4)[OF i]]
    have "vars_below_hole (ts ! i) (Cs ! i) =  (vars_term ` set (sss ! i))" .
  } note IH = this
  show ?case unfolding *(1) *(5) set_concat set_conv_nth[of sss] using IH *(2,3)
    by (auto simp: set_zip)
qed

(* The variable restricted parallel rewrite relation *)

definition "par_rstep_var_restr R V = {(s,t) | s t C infos. 
  (s, t)  par_rstep_mctxt R C infos  vars_below_hole t C  V = {}}" 

lemma par_rstep_var_restr_mono: assumes "R  S" "W  V" 
  shows "par_rstep_var_restr R V  par_rstep_var_restr S W" 
  unfolding par_rstep_var_restr_def using par_rstep_mctxt_mono[OF assms(1)] assms(2)
  by blast

lemma par_rstep_var_restr_refl[simp]: "(t, t)  par_rstep_var_restr R V" 
  unfolding par_rstep_var_restr_def
  by (intro CollectI exI conjI refl, force, rule par_rstep_mctxt_reflI, auto)

text ‹the most important property: a substitution step and a parallel step 
  can be merged into a single parallel step›
lemma merge_par_rstep_var_restr: 
  assumes subst_R: " x. (δ x, γ x)  par_rstep R" 
    and st: "(s, t)  par_rstep_var_restr R V" 
    and subst_eq: " x. x  V  δ x = γ x"
  shows "(s  δ, t  γ)  par_rstep R"
proof -
  from st[unfolded par_rstep_var_restr_def] subst_eq
  obtain C infos where st: "(s, t)  par_rstep_mctxt R C infos" 
    and subst_eq: " x. x  vars_below_hole t C  δ x = γ x"
    by auto
  thus ?thesis  
  proof (induct C arbitrary: s t infos)
    case (MVar x)
    from par_rstep_mctxt_MVarE[OF this(1)]
    show ?case using subst_R by auto
  next
    case (MHole s t)
    have "(s,t)  par_rstep R" 
      using MHole.prems(1) par_rstep_par_rstep_mctxt_conv by blast
    hence step: "(s  δ, t  δ)  par_rstep R" 
      by (rule subst_closed_par_rstep)
    have "vars_below_hole t MHole = vars_term t" by simp
    with MHole(2) have t: "t  δ = t  γ" by (auto intro: term_subst_eq)
    thus ?case using step by auto
  next
    case (MFun f Cs s t infos)
    let ?n = "length Cs" 
    let ?is = "[0..<?n]" 

    from par_rstep_mctxt_MFunD[OF MFun(2)]
    obtain ss ts Infos
      where s: "s = Fun f ss" 
        and t: "t = Fun f ts" 
        and len: "length ss = length Cs" 
        "length ts = length Cs"
        "length Infos = length Cs" 
        and infos: "infos = concat Infos" 
        and steps: " i. i<length Cs  (ss ! i, ts ! i)  par_rstep_mctxt R (Cs ! i) (Infos ! i)" 
      by blast
    {
      fix i
      assume i: "i < ?n"
      hence mem: "Cs ! i  set Cs" by auto
      have IH: "(ss ! i  δ, ts ! i  γ)  par_rstep R" 
      proof (rule MFun(1)[OF mem steps[OF i]])
        fix x
        assume "x  vars_below_hole (ts ! i) (Cs ! i)" 
        hence "x  vars_below_hole t (MFun f Cs)" unfolding t using i len(2)
          by (auto simp: set_zip)
        from MFun(3)[OF this] show "δ x = γ x" .
      qed
    }
    thus ?case unfolding s t using len(1-2) MFun(1-2) by auto
  qed
qed

text ‹the variable restricted parallel rewrite relation is closed under variable renamings, 
  provided that the set of forbidden variables is also renamed (in the inverse way)›
lemma par_rstep_var_restr_subst: 
  assumes "(s,t)  par_rstep_var_restr R (γ ` V)" 
    and " x. σ x  (Var o γ) = Var x" 
  shows "(s  σ, t  σ)  par_rstep_var_restr R V"
proof -
  from assms(1)[unfolded par_rstep_var_restr_def, simplified]
  obtain C infos where step: "(s, t)  par_rstep_mctxt R C infos" and vars: "vars_below_hole t C  γ ` V = {}"
    by auto
  from step[unfolded par_rstep_mctxt_def, simplified] 
  have "t =f (C, par_rights infos)" by auto
  hence "hole_poss C  poss t" by (metis hole_poss_subset_poss)
  hence hp: "hole_poss (C ⋅mc σ)  poss t" 
    using hole_poss_subst by auto
  from par_rstep_mctxt_subst[OF step, of σ]
  have step: "(s  σ, t  σ)  par_rstep_mctxt R (C ⋅mc σ) (map (λi. i ⋅pi σ) infos)" .
  show "(s  σ, t  σ)  par_rstep_var_restr R V" 
    unfolding par_rstep_var_restr_def
  proof (standard, intro exI conjI, rule refl, rule step)
    show "vars_below_hole (t  σ) (C ⋅mc σ)  V = {}" 
      unfolding vars_below_hole_term_subst[OF hp] 
      unfolding vars_below_hole_subst
    proof (intro equals0I, elim IntE)
      fix x
      assume "x   (vars_term ` σ ` vars_below_hole t C)" 
      then obtain y where y: "y  vars_below_hole t C" and x: "x  vars_term (σ y)" by auto
      from y vars have y: "y  γ ` V" by auto
      assume "x  V"
      with assms(2)[of y] y x show False unfolding o_def by (cases "σ y", auto)
    qed
  qed
qed

end