Theory Orthogonal_PT

section‹Orthogonal Proof Terms›

theory Orthogonal_PT
imports
  Residual_Join_Deletion
begin

inductive orthogonal::"('f, 'v) pterm  ('f, 'v) pterm  bool" (infixl "p" 50)
  where
  "Var x p Var x"
| "length As = length Bs   i < length As. As!i p Bs!i  Fun f As p Fun f Bs"
| "length As = length Bs  (a,b)  set(zip As Bs). a p b  (Prule α As) p (to_pterm (lhs α))  Bs⟩⇩α"
| "length As = length Bs  (a,b)  set(zip As Bs). a p b  (to_pterm (lhs α))  As⟩⇩α p (Prule α Bs)"
lemmas orthogonal.intros[intro]

lemma orth_symp: "symp (⊥p)"
proof
  {fix A B::"('f, 'v) pterm" assume "A p B"
    then show "B p A" proof(induct)
      case (3 As Bs α)
      then show ?case using orthogonal.intros(4)[where α=α and Bs=As and As=Bs]
        using zip_symm by fastforce
    next
      case (4 As Bs α)
      then show ?case using orthogonal.intros(3)[where α=α and As=Bs and Bs=As]
        using zip_symm by fastforce
    qed (simp_all add:orthogonal.intros)
  }
qed

lemma equal_imp_orthogonal:
  shows "A p A" 
  by(induct A) (simp_all add: orthogonal.intros) 

lemma source_orthogonal:
  assumes "source A = t"
  shows "A p to_pterm t"
  using assms proof(induct A arbitrary:t)
  case (Prule α As)
  then have t:"to_pterm t = (to_pterm (lhs α))  map (to_pterm  source) As⟩⇩α"
    by (metis fun_mk_subst list.map_comp source.simps(3) to_pterm.simps(1) to_pterm_subst)
  from Prule(1) have "(a,b)  set (zip As (map (to_pterm  source) As)). a p b"
    by (metis (mono_tags, lifting) case_prod_beta' comp_def in_set_zip nth_map zip_fst)
  with t show ?case
    using orthogonal.intros(3) by (metis length_map)
qed (simp_all add:orthogonal.intros)

lemma orth_imp_co_initial:
  assumes "A p B"
  shows "co_initial A B"
  using assms proof(induct rule: orthogonal.induct)
  case (2 As Bs f)
  show ?case proof(cases f)
    case (Inr g)
    with 2 show ?thesis unfolding Inr
      by (simp add: nth_map_conv)
  next
    case (Inl α)
    with 2 show ?thesis unfolding Inl
      by (metis nth_map_conv source.simps(3))
  qed
next
  case (3 As Bs α)
  then have l:"length (zip As Bs) = length As"
    by simp
  with 3 have IH:"i < length As. source (As!i) = source (Bs!i)"
    by (metis (mono_tags, lifting) case_prod_conv nth_mem nth_zip)
  have src:"source ((to_pterm (lhs α))  Bs⟩⇩α) = (lhs α)  map source Bs⟩⇩α"
    by (simp add: source_apply_subst)
  from 3(1) l IH show ?case unfolding src source.simps
    by (metis nth_map_conv)
next
  case (4 As Bs α)
  then have l:"length (zip As Bs) = length As"
    by simp
  with 4 have IH:"i < length As. source (As!i) = source (Bs!i)"
    by (metis (mono_tags, lifting) case_prod_conv nth_mem nth_zip)
  have src:"source ((to_pterm (lhs α))  As⟩⇩α) = (lhs α)  map source As⟩⇩α"
    by (simp add: source_apply_subst)
  from 4(1) l IH show ?case unfolding src source.simps
    by (metis nth_map_conv)
qed simp

text‹If two proof terms are orthogonal then residual and join are well-defined.›
lemma orth_imp_residual_defined:
  assumes varcond:"l r. (l, r)  R  is_Fun l" "l r. (l, r)  S  is_Fun l"
    and "A p B"
    and "A  wf_pterm R" and "B  wf_pterm S"
  shows "A re B  None"
  using assms(3-) proof(induct)
  case (2 As Bs f)
  from 2(3) have wellAs:"a  set As. a  wf_pterm R"
    by blast
  from 2(4) have wellBs:"b  set Bs. b  wf_pterm S"
    by blast
  from 2(1,2) wellAs wellBs  have c:"i < length As. (C. As!i re Bs!i = Some C)"
    by auto
  from 2(1) have l:"length As = length (map2 (re) As Bs)"
    by simp
  from 2(1) have "i < length As. As!i re Bs!i = (map2 (re) As Bs)!i"
    by simp
  with c obtain Cs where "i < length As. As!i re Bs!i = Some (Cs!i)" and "length Cs = length As"
    using exists_some_list l by (metis (no_types, lifting))
  with 2 have *:"those (map2 (re) As Bs) = Some Cs"
    by (simp add: those_some)
  show ?case proof(cases f)
    case (Inr g)
    show ?thesis unfolding Inr residual.simps 2(1) * by simp
  next
    case (Inl α)
    show ?thesis unfolding Inl residual.simps 2(1) * by simp
  qed
next
  case (3 As Bs α)
  from 3(3) varcond obtain g ts where g:"lhs α = Fun g ts"
    by (metis Inl_inject is_Fun_Fun_conv sum.simps(4) term.distinct(1) term.sel(2) wf_pterm.cases)
  then have *:"to_pterm (lhs α)  Bs⟩⇩α = Pfun g (map (λt. t  Bs⟩⇩α) (map to_pterm ts))"
    by simp
  from 3(3) have l1:"length As = length (var_rule α)"
    using wf_pterm.simps by fastforce
  from 3(3) have wellAs:"a  set As. a  wf_pterm R"
    by blast
  from 3(1,4) l1 have wellBs:"b  set Bs. b  wf_pterm S"
    by (simp add: lhs_subst_args_wf_pterm)
  from 3(1) have l2:"length (zip As Bs) = length As"
    by simp
  with 3(1,2) wellAs wellBs have "i < length As. As ! i re Bs ! i  None"
    by (metis (mono_tags, lifting) case_prod_conv nth_mem nth_zip)
  then have c:"i < length As. (C. As!i re Bs!i = Some C)"
    by blast
  from 3(1) have "i < length As. As!i re Bs!i = (map2 (re) As Bs)!i"
    by simp
  with c obtain Cs where "i < length As. As!i re Bs!i = Some (Cs!i)" and "length Cs = length As"
    using exists_some_list l2 by (metis (no_types, lifting) length_map)
  with 3 have cs:"those (map2 (re) As Bs) = Some Cs"
    by (simp add: those_some)
  have bs:"match (to_pterm (lhs α)  Bs⟩⇩α) (to_pterm (lhs α)) = Some (Bs⟩⇩α)"
    using lhs_subst_trivial by blast
  then have "(map (Bs⟩⇩α) (var_rule α)) = Bs"
    using 3(1) l1 apply_lhs_subst_var_rule by force
  then show ?case using residual.simps(5) using bs cs g unfolding *
    by simp
next
  case (4 As Bs α)
  from 4(4) varcond obtain g ts where g:"lhs α = Fun g ts"
    by (metis Inl_inject is_Fun_Fun_conv sum.simps(4) term.distinct(1) term.sel(2) wf_pterm.cases)
  then have *:"to_pterm (lhs α)  As⟩⇩α = Pfun g (map (λt. t  As⟩⇩α) (map to_pterm ts))"
    by simp
  from 4(4) have l1:"length Bs = length (var_rule α)"
    using wf_pterm.simps by fastforce
  from 4(1,3) l1 have wellAs:"a  set As. a  wf_pterm R"
    by (simp add: lhs_subst_args_wf_pterm)
  from 4(4)  have wellBs:"b  set Bs. b  wf_pterm S"
    by blast
  from 4(1) have l2:"length (zip As Bs) = length As"
    by simp
  with 4(1,2) wellAs wellBs have "i < length As. As ! i re Bs ! i  None"
    by (metis (mono_tags, lifting) case_prod_conv nth_mem nth_zip)
  then have c:"i < length As. (C. As!i re Bs!i = Some C)"
    by blast
  from 4(1) have "i < length As. As!i re Bs!i = (map2 (re) As Bs)!i"
    by simp
  with c obtain Cs where "i < length As. As!i re Bs!i = Some (Cs!i)" and "length Cs = length As"
    using exists_some_list l2 by (metis (no_types, lifting) length_map)
  with 4 have cs:"those (map2 (re) As Bs) = Some Cs"
    by (simp add: those_some)
  have bs:"match (to_pterm (lhs α)  As⟩⇩α) (to_pterm (lhs α)) = Some (As⟩⇩α)"
    using lhs_subst_trivial by blast
  have "(map (As⟩⇩α) (var_rule α)) = As"
    using 4(1) l1 apply_lhs_subst_var_rule by force
  then show ?case using residual.simps(7) using bs cs g unfolding *
    by simp
qed simp

(*The proof is almost word for word copied from orth_imp_residual_defined. Can this be combined?*)
lemma orth_imp_join_defined:
  assumes varcond:"l r. (l, r)  R  is_Fun l"
    and "A p B"
    and "A  wf_pterm R" and "B  wf_pterm R"
  shows "A  B  None"
  using assms(2-) proof(induct)
  case (2 As Bs f)
  from 2(3) have wellAs:"a  set As. a  wf_pterm R"
    by blast
  from 2(4) have wellBs:"b  set Bs. b  wf_pterm R"
    by blast
  from 2(1,2) wellAs wellBs  have c:"i < length As. (C. As!i  Bs!i = Some C)"
    by auto
  from 2(1) have l:"length As = length (map2 (⊔) As Bs)"
    by simp
  from 2(1) have "i < length As. As!i  Bs!i = (map2 (⊔) As Bs)!i"
    by simp
  with c obtain Cs where "i < length As. As!i  Bs!i = Some (Cs!i)" and "length Cs = length As"
    using exists_some_list l by (metis (no_types, lifting))
  with 2 have *:"those (map2 (⊔) As Bs) = Some Cs"
    by (simp add: those_some)
  show ?case proof(cases f)
    case (Inr g)
    show ?thesis unfolding Inr join.simps 2(1) * by simp
  next
    case (Inl α)
    show ?thesis unfolding Inl join.simps 2(1) * by simp
  qed
next
  case (3 As Bs α)
  from 3(3) varcond obtain g ts where g:"lhs α = Fun g ts"
    by (metis Inl_inject is_Fun_Fun_conv sum.simps(4) term.distinct(1) term.sel(2) wf_pterm.cases)
  then have *:"to_pterm (lhs α)  Bs⟩⇩α = Pfun g (map (λt. t  Bs⟩⇩α) (map to_pterm ts))"
    by simp
  from 3(3) have l1:"length As = length (var_rule α)"
    using wf_pterm.simps by fastforce
  from 3(3) have wellAs:"a  set As. a  wf_pterm R"
    by blast
  from 3(1,4) l1 have wellBs:"b  set Bs. b  wf_pterm R"
    by (simp add: lhs_subst_args_wf_pterm)
  from 3(1) have l2:"length (zip As Bs) = length As"
    by simp
  with 3(1,2) wellAs wellBs have "i < length As. As ! i  Bs ! i  None"
    by (metis (mono_tags, lifting) case_prod_conv nth_mem nth_zip)
  then have c:"i < length As. (C. As!i  Bs!i = Some C)"
    by blast
  from 3(1) have "i < length As. As!i  Bs!i = (map2 (⊔) As Bs)!i"
    by simp
  with c obtain Cs where "i < length As. As!i  Bs!i = Some (Cs!i)" and "length Cs = length As"
    using exists_some_list l2 by (metis (no_types, lifting) length_map)
  with 3 have cs:"those (map2 (⊔) As Bs) = Some Cs"
    by (simp add: those_some)
  have bs:"match (to_pterm (lhs α)  Bs⟩⇩α) (to_pterm (lhs α)) = Some (Bs⟩⇩α)"
    using lhs_subst_trivial by blast
  then have "(map (Bs⟩⇩α) (var_rule α)) = Bs"
    using 3(1) l1 apply_lhs_subst_var_rule by force
  then show ?case using residual.simps(5) using bs cs g unfolding *
    by simp
next
  case (4 As Bs α)
  from 4(4) varcond obtain g ts where g:"lhs α = Fun g ts"
    by (metis Inl_inject is_Fun_Fun_conv sum.simps(4) term.distinct(1) term.sel(2) wf_pterm.cases)
  then have *:"to_pterm (lhs α)  As⟩⇩α = Pfun g (map (λt. t  As⟩⇩α) (map to_pterm ts))"
    by simp
  from 4(4) have l1:"length Bs = length (var_rule α)"
    using wf_pterm.simps by fastforce
  from 4(1,3) l1 have wellAs:"a  set As. a  wf_pterm R"
    by (simp add: lhs_subst_args_wf_pterm)
  from 4(4)  have wellBs:"b  set Bs. b  wf_pterm R"
    by blast
  from 4(1) have l2:"length (zip As Bs) = length As"
    by simp
  with 4(1,2) wellAs wellBs have "i < length As. As ! i  Bs ! i  None"
    by (metis (mono_tags, lifting) case_prod_conv nth_mem nth_zip)
  then have c:"i < length As. (C. As!i  Bs!i = Some C)"
    by blast
  from 4(1) have "i < length As. As!i  Bs!i = (map2 (⊔) As Bs)!i"
    by simp
  with c obtain Cs where "i < length As. As!i  Bs!i = Some (Cs!i)" and "length Cs = length As"
    using exists_some_list l2 by (metis (no_types, lifting) length_map)
  with 4 have cs:"those (map2 (⊔) As Bs) = Some Cs"
    by (simp add: those_some)
  have bs:"match (to_pterm (lhs α)  As⟩⇩α) (to_pterm (lhs α)) = Some (As⟩⇩α)"
    using lhs_subst_trivial by blast
  have "(map (As⟩⇩α) (var_rule α)) = As"
    using 4(1) l1 apply_lhs_subst_var_rule by force
  then show ?case using residual.simps(7) using bs cs g unfolding *
    by simp
qed simp

context no_var_lhs
begin
lemma orth_imp_residual_defined:
  assumes "A p B" and "A  wf_pterm R" and "B  wf_pterm R"
  shows "A re B  None"
  using orth_imp_residual_defined assms no_var_lhs by fastforce 

lemma orth_imp_join_defined:
  assumes "A p B" and "A  wf_pterm R" and "B  wf_pterm R"
  shows "A  B  None"
  using orth_imp_join_defined assms no_var_lhs by fastforce 

lemma orthogonal_ctxt:
  assumes "CA p CB" "C  wf_pterm_ctxt R"
  shows "A p B"
  using assms proof(induct C)
  case (Cfun f ss1 C ss2)
  from Cfun(2) have "i<length (ss1 @ CA # ss2). (ss1 @ CA # ss2) ! i p (ss1 @ CB # ss2) ! i"
    unfolding intp_actxt.simps using orthogonal.simps by (smt (verit) is_Prule.simps(1) is_Prule.simps(3) term.distinct(1) term.sel(4)) 
  then have "CA p CB"
    by (metis append.right_neutral length_append length_greater_0_conv length_nth_simps(1) list.discI nat_add_left_cancel_less nth_append_length) 
  with Cfun(1,3) show ?case by auto
next
  case (Crule α ss1 C ss2)
  from Crule(3) obtain f ts where "lhs α = Fun f ts" 
    using no_var_lhs by (smt (verit, del_insts) Inl_inject Inr_not_Inl case_prodD actxt.distinct(1) actxt.inject term.collapse(2) wf_pterm_ctxt.simps) 
  with Crule(2) have "i<length (ss1 @ CA # ss2). (ss1 @ CA # ss2) ! i p (ss1 @ CB # ss2) ! i"
    unfolding intp_actxt.simps using orthogonal.simps
    by (smt (verit, ccfv_threshold) Inl_inject Inr_not_Inl eval_term.simps(2) term.distinct(1) term.inject(2) to_pterm.simps(2))
  then have "CA p CB"
    by (metis intp_actxt.simps(2) hole_pos.simps(2) hole_pos_poss nth_append_length poss_Cons_poss term.sel(4)) 
  with Crule(1,3) show ?case by auto
qed simp

end

context left_lin_no_var_lhs
begin

lemma orthogonal_subst:
  assumes "A  σ p B  σ" "source A = source B" (*co-initial needed to ensure that A and B share the same variables*)
    and "A  wf_pterm R" "B  wf_pterm R"
  shows "A p B"
  using assms(3,4,1,2) proof(induct A  arbitrary:B rule:subterm_induct)
  case (subterm A)
  show ?case proof(cases A)
    case (Var x)
    with subterm no_var_lhs have "B = Var x"
      by (metis Inl_inject Inr_not_Inl case_prodD co_initial_Var is_VarI term.distinct(1) term.inject(2) wf_pterm.simps) 
    then show ?thesis
      unfolding Var by (simp add: orthogonal.intros(1))
  next
    case (Pfun f As)
    with subterm(5) show ?thesis proof(cases B)
      case (Pfun g Bs)
      from subterm(5) have f:"f = g"
        unfolding A = Pfun f As Pfun by simp
      from subterm(5) have l:"length As = length Bs"
        unfolding A = Pfun f As Pfun using map_eq_imp_length_eq by auto 
      {fix i assume i:"i < length As"
        with subterm(4) have "As!i  σ p Bs!i  σ" 
          unfolding A = Pfun f As Pfun eval_term.simps f
          by (smt (verit) is_Prule.simps(1) is_Prule.simps(3) length_map nth_map orthogonal.simps term.distinct(1) term.sel(4)) 
        moreover from i subterm(5) have "source (As!i) = source (Bs!i)" 
          unfolding A = Pfun f As Pfun eval_term.simps f by (simp add: map_equality_iff) 
        moreover from i l subterm(2,3) have "As!i  wf_pterm R" "Bs!i  wf_pterm R" 
          unfolding A = Pfun f As Pfun by auto
        moreover from i have "As!i  A" 
          unfolding A = Pfun f As by simp
        ultimately have "As!i p Bs!i"
          using subterm(1) by simp
      }      
      with l show ?thesis 
        unfolding f A = Pfun f As Pfun by (simp add: orthogonal.intros(2))
    next
      case (Prule β Bs)
      with subterm(3) have lin:"linear_term (lhs β)"
        using left_lin left_linear_trs_def wf_pterm.cases by fastforce 
      from subterm(3) obtain g ts where lhs:"lhs β = Fun g ts" 
        unfolding Prule using no_var_lhs by (metis Inl_inject case_prodD is_FunE is_Prule.simps(1) is_Prule.simps(3) term.distinct(1) term.inject(2) wf_pterm.simps) 
      with subterm(4) obtain τ1 where "A  σ = to_pterm (lhs β)  τ1"
        unfolding Prule Pfun eval_term.simps using orthogonal.simps by (smt (verit, ccfv_SIG) Inl_inject Inr_not_Inl term.inject(2))
      with subterm(4,5) obtain τ where τ2:"A = to_pterm (lhs β)  τ"
        unfolding Prule Pfun source.simps using simple_pterm_match lin by (metis matches_iff source.simps(2)) 
      let ?As="map τ (var_rule β)" 
      have l:"length Bs = length (var_rule β)"
        using Prule subterm.prems(2) wf_pterm.simps by fastforce 
      from τ2 have A:"A = to_pterm (lhs β)  ?As⟩⇩β"
        by (metis lhs_subst_var_rule set_vars_term_list subsetI vars_to_pterm)  
      {fix i assume i:"i < length Bs"
        have subt:"?As!i  A" 
          using i l by (metis (no_types, lifting) τ2 comp_apply lhs nth_map nth_mem set_remdups set_rev set_vars_term_list subst_image_subterm to_pterm.simps(2) vars_to_pterm)
        have wf:"?As!i  wf_pterm R" 
          using i l by (metis A length_map lhs_subst_args_wf_pterm nth_mem subterm.prems(1))
        have l':"length (var_rule β) = length ?As" 
          by simp
        from subterm(4) A Prule lhs have orth:"?As!i  σ p Bs!i  σ" proof(cases)
          case (4 As' Bs' β')
          then have Bs':"Bs' = map (λs. s  σ) Bs" and β':"β' = β"
            unfolding Prule by simp_all
          have As':"As' = map (λs. s  σ) ?As" proof-
            have l'':"length As' = length ?As" using 4(3) l unfolding Bs' length_map by simp
            {fix j assume j:"j < length As'" and neq:"As'!j  map (λs. s  σ) ?As ! j" 
              let ?x="var_rule β!j" 
              from j have x:"?x  vars_term (lhs β)"
                by (metis comp_apply l' l'' nth_mem set_remdups set_rev set_vars_term_list) 
              then obtain p where p:"p  poss (lhs β)" "lhs β |_p = Var ?x"
                by (meson vars_term_poss_subt_at) 
              from j have 1:"(As'⟩⇩β') ?x = As'!j" 
                using β' l'' lhs_subst_var_i by force
              from j have 2:"(map (λs. s  σ) ?As⟩⇩β) ?x = map (λs. s  σ) ?As ! j" 
                using lhs_subst_var_i by (metis l'' length_map)
              then have False using 4(1) 1 2 p unfolding A eval_lhs_subst[OF l'] β'
                by (smt (verit, del_insts) x neq set_vars_term_list term_subst_eq_rev vars_to_pterm)
            }
            then show ?thesis 
              using l'' by (metis (mono_tags, lifting) map_nth_eq_conv nth_map)
          qed
          have i':"i < length (zip (map (λa. a  σ) (map τ (var_rule β))) (map (λb. b  σ) Bs))"
            using i l by simp 
          from 4(4) have "map (λa. a  σ) (map τ (var_rule β)) ! i p map (λb. b  σ) Bs !i"
            unfolding As' Bs' using i' by (metis case_prodD i l length_map nth_mem nth_zip)
          then show ?thesis
            using i l by auto 
        qed simp_all
        have co_init:"source (?As!i) = source (Bs!i)" proof(rule ccontr)
          assume neq:"source (?As!i)  source (Bs!i)"
          let ?x="var_rule β!i" 
          from i l have x:"?x  vars_term (lhs β)"
            by (metis comp_apply nth_mem set_remdups set_rev set_vars_term_list) 
          then obtain p where p:"p  poss (lhs β)" "lhs β |_p = Var ?x"
            by (meson vars_term_poss_subt_at) 
          from i have 1:"(map source ?As⟩⇩β) ?x = source (?As!i)" 
            using l lhs_subst_var_i by (metis length_map nth_map)
          from i have 2:"(map source Bs⟩⇩β) ?x = source (Bs!i)" 
            using l lhs_subst_var_i by (metis length_map nth_map)
          from subterm(5) show False using neq 1 2 p 
            unfolding Prule A source.simps source_apply_subst[OF to_pterm_wf_pterm[of "lhs β"]] source_to_pterm
            using term_subst_eq_rev x by fastforce
        qed
        from subterm(1) subt wf orth co_init have "?As!i p Bs!i" 
          using i subterm(3) unfolding Prule by (meson fun_well_arg nth_mem) 
      }
      then show ?thesis unfolding A Prule
        by (smt (verit, best) case_prodI2 in_set_idx l length_map length_zip min_less_iff_conj nth_zip orthogonal.intros(4) prod.sel(1) snd_conv)
    qed simp
  next
    case (Prule α As)
    with subterm(2) have lin:"linear_term (lhs α)" 
      using left_lin left_linear_trs_def wf_pterm.cases by fastforce 
    from subterm(2) obtain f ts where lhs:"lhs α = Fun f ts"
      by (metis Inr_not_Inl Prule case_prodD is_FunE no_var_lhs sum.inject(1) term.distinct(1) term.inject(2) wf_pterm.simps) 
    with subterm(5) show ?thesis proof(cases B)
      case (Var x)
      then show ?thesis
        using source_orthogonal subterm.prems(4) by fastforce
    next
      case (Pfun g Bs) (*case is symmetric to above → generalize and simplify*)
      with subterm(4) obtain τ1 where "B  σ = to_pterm (lhs α)  τ1"
        unfolding Prule Pfun eval_term.simps using orthogonal.simps by (smt (verit, ccfv_SIG) Inl_inject Inr_not_Inl term.inject(2))
      with subterm(4,5) obtain τ where τ2:"B = to_pterm (lhs α)  τ"
        unfolding Prule Pfun source.simps using simple_pterm_match lin by (metis matches_iff source.simps(2)) 
      let ?Bs="map τ (var_rule α)" 
      have l:"length As = length (var_rule α)"
        using Prule subterm.prems(1) wf_pterm.simps by fastforce 
      from τ2 have B:"B = to_pterm (lhs α)  ?Bs⟩⇩α"
        by (metis lhs_subst_var_rule set_vars_term_list subsetI vars_to_pterm)  
      have l':"length (var_rule α) = length ?Bs" 
        by simp
      {fix i assume i:"i < length As"
        from subterm(4) B Prule lhs have orth:"As!i  σ p ?Bs!i  σ" proof(cases)
          case (3 As' Bs' α')
          then have As':"As' = map (λs. s  σ) As" and α':"α' = α"
            unfolding Prule by simp_all
          have Bs':"Bs' = map (λs. s  σ) ?Bs" proof-
            have l'':"length Bs' = length ?Bs" using 3(3) l unfolding As' length_map by simp
            {fix j assume j:"j < length Bs'" and neq:"Bs'!j  map (λs. s  σ) ?Bs ! j" 
              let ?x="var_rule α!j" 
              from j have x:"?x  vars_term (lhs α)"
                by (metis comp_apply l'' length_map nth_mem set_remdups set_rev set_vars_term_list)
              then obtain p where p:"p  poss (lhs α)" "lhs α |_p = Var ?x"
                by (meson vars_term_poss_subt_at) 
              from j have 1:"(Bs'⟩⇩α') ?x = Bs'!j" 
                using α' l'' lhs_subst_var_i by force
              from j have 2:"(map (λs. s  σ) ?Bs⟩⇩α) ?x = map (λs. s  σ) ?Bs ! j" 
                using lhs_subst_var_i by (metis l'' length_map)
              then have False using 3(1) 1 2 p unfolding B eval_lhs_subst[OF l'] α'
                by (smt (verit, ccfv_SIG) "3"(2) B α' eval_lhs_subst l' map_eq_conv neq set_vars_term_list term_subst_eq_rev vars_to_pterm x)
            }
            then show ?thesis 
              using l'' by (metis (mono_tags, lifting) map_nth_eq_conv nth_map)
          qed
          have i':"i < length (zip (map (λb. b  σ) As) (map (λa. a  σ) (map τ (var_rule α))))"
            using i l by simp 
          from 3(4) have "map (λb. b  σ) As ! i p map (λa. a  σ) (map τ (var_rule α)) ! i "
            unfolding As' Bs' using i' by (metis case_prodD i l length_map nth_mem nth_zip)
          then show ?thesis
            using i l by auto 
        qed simp_all
        have co_init:"source (As!i) = source (?Bs!i)" proof(rule ccontr)
          assume neq:"source (As!i)  source (?Bs!i)"
          let ?x="var_rule α!i" 
          from i l have x:"?x  vars_term (lhs α)"
            by (metis comp_apply nth_mem set_remdups set_rev set_vars_term_list) 
          then obtain p where p:"p  poss (lhs α)" "lhs α |_p = Var ?x"
            by (meson vars_term_poss_subt_at) 
          from i have 1:"(map source ?Bs⟩⇩α) ?x = source (?Bs!i)" 
            using l lhs_subst_var_i by (metis length_map nth_map)
          from i have 2:"(map source As⟩⇩α) ?x = source (As!i)" 
            using l lhs_subst_var_i by (metis length_map nth_map)
          from subterm(5) show False using neq 1 2 p 
            unfolding Prule B source.simps source_apply_subst[OF to_pterm_wf_pterm[of "lhs α"]] source_to_pterm
            using term_subst_eq_rev x by fastforce
        qed
        from subterm(1,2,3) co_init have "As!i p ?Bs!i" 
          using i l' orth unfolding Prule by (metis B fun_well_arg l lhs_subst_args_wf_pterm nth_mem orth supt.arg)
      }
      then show ?thesis unfolding B Prule
        by (smt (verit, best) case_prodI2 fst_conv in_set_zip l l' orthogonal.intros(3) snd_conv)
    next
      case (Prule β Bs)
      from subterm(4) have α:"α = β"
        unfolding Prule A = Prule α As eval_term.simps using orthogonal.simps
        by (smt (verit) Inl_inject Prule eval_term.simps(2) is_Prule.simps(1) is_Prule.simps(3) lhs no_var_lhs.lhs_is_Fun 
            no_var_lhs_axioms subterm.prems(2) term.collapse(2) term.sel(2) to_pterm.simps(2))
      from subterm(2,3) have l:"length As = length Bs"
        unfolding A = Prule α As Prule using α length_args_well_Prule by blast 
      {fix i assume i:"i < length As"
        with subterm(4) have "As!i  σ p Bs!i  σ" 
          unfolding A = Prule α As Prule eval_term.simps α by (smt (verit, ccfv_threshold) Inl_inject 
          Inr_not_Inl α eval_term.simps(2) length_map lhs nth_map orthogonal.simps term.distinct(1) term.inject(2) to_pterm.simps(2))
        moreover from i subterm(5) have "source (As!i) = source (Bs!i)" 
          using Prule α A = Prule α As co_init_prule subterm.prems(1) subterm.prems(2) by blast
        moreover from i l subterm(2,3) have "As!i  wf_pterm R" "Bs!i  wf_pterm R" 
          unfolding Prule A = Prule α As by auto
        moreover from i have "As!i  A" 
          unfolding A = Prule α As by simp
        ultimately have "As!i p Bs!i"
          using subterm(1) by simp
      }      
      with l show ?thesis 
        unfolding α A = Prule α As Prule by (simp add: orthogonal.intros(2))
    qed
  qed
qed

end

end