Theory FO_Ordered_Resolution

(*  Title:       First-Order Ordered Resolution Calculus with Selection
    Author:      Anders Schlichtkrull <andschl at dtu.dk>, 2016, 2017
    Author:      Jasmin Blanchette <j.c.blanchette at vu.nl>, 2014, 2017
    Author:      Dmitriy Traytel <traytel at inf.ethz.ch>, 2014
    Author:      Sophie Tourret <stourret at mpi-inf.mpg.de>, 2020
    Maintainer:  Anders Schlichtkrull <andschl at dtu.dk>
*)

section ‹First-Order Ordered Resolution Calculus with Selection›

theory FO_Ordered_Resolution
  imports Abstract_Substitution Ordered_Ground_Resolution Standard_Redundancy
begin

text ‹
This material is based on Section 4.3 (``A Simple Resolution Prover for First-Order Clauses'') of
Bachmair and Ganzinger's chapter. Specifically, it formalizes the ordered resolution calculus for
first-order standard clauses presented in Figure 4 and its related lemmas and theorems, including
soundness and Lemma 4.12 (the lifting lemma).

The following corresponds to pages 41--42 of Section 4.3, until Figure 5 and its explanation.
›

locale FO_resolution = mgu subst_atm id_subst comp_subst renamings_apart atm_of_atms mgu
  for
    subst_atm :: "'a :: wellorder  's  'a" and
    id_subst :: "'s" and
    comp_subst :: "'s  's  's" and
    renamings_apart :: "'a literal multiset list  's list" and
    atm_of_atms :: "'a list  'a" and
    mgu :: "'a set set  's option" +
  fixes
    less_atm :: "'a  'a  bool"
  assumes
    less_atm_stable: "less_atm A B  less_atm (A ⋅a σ) (B ⋅a σ)" and
    less_atm_ground: "is_ground_atm A  is_ground_atm B  less_atm A B  A < B"
begin


subsection ‹Library›

lemma Bex_cartesian_product: "(xy  A × B. P xy)  (x  A. y  B. P (x, y))"
  by simp

lemma eql_map_neg_lit_eql_atm:
  assumes "map (λL. L ⋅l η) (map Neg As') = map Neg As"
  shows "As' ⋅al η = As"
  using assms by (induction As' arbitrary: As) auto

lemma instance_list:
  assumes "negs (mset As) = SDA'  η"
  shows "As'. negs (mset As') = SDA'  As' ⋅al η = As"
proof -
  from assms have negL: "L ∈# SDA'. is_neg L"
    using Melem_subst_cls subst_lit_in_negs_is_neg by metis

  from assms have "{#L ⋅l η. L ∈# SDA'#} = mset (map Neg As)"
    using subst_cls_def by auto
  then have "NAs'. map (λL. L ⋅l η) NAs' = map Neg As  mset NAs' = SDA'"
    using image_mset_of_subset_list[of "λL. L ⋅l η" SDA' "map Neg As"] by auto
  then obtain As' where As'_p:
    "map (λL. L ⋅l η) (map Neg As') = map Neg As  mset (map Neg As') = SDA'"
    by (metis (no_types, lifting) Neg_atm_of_iff negL ex_map_conv set_mset_mset)

  have "negs (mset As') = SDA'"
    using As'_p by auto
  moreover have "map (λL. L ⋅l η) (map Neg As') = map Neg As"
    using As'_p by auto
  then have "As' ⋅al η = As"
    using eql_map_neg_lit_eql_atm by auto
  ultimately show ?thesis
    by blast
qed

lemma map2_add_mset_map:
  assumes "length AAs' = n" and "length As' = n"
  shows "map2 add_mset (As' ⋅al η) (AAs' ⋅aml η) = map2 add_mset As' AAs' ⋅aml η"
  using assms
proof (induction n arbitrary: AAs' As')
  case (Suc n)
  then have "map2 add_mset (tl (As' ⋅al η)) (tl (AAs' ⋅aml η)) = map2 add_mset (tl As') (tl AAs') ⋅aml η"
    by simp
  moreover have Succ: "length (As' ⋅al η) = Suc n" "length (AAs' ⋅aml η) = Suc n"
    using Suc(3) Suc(2) by auto
  then have "length (tl (As' ⋅al η)) = n" "length (tl (AAs' ⋅aml η)) = n"
    by auto
  then have "length (map2 add_mset (tl (As' ⋅al η)) (tl (AAs' ⋅aml η))) = n"
    "length (map2 add_mset (tl As') (tl AAs') ⋅aml η) = n"
    using Suc(2,3) by auto
  ultimately have "i < n. tl (map2 add_mset ( (As' ⋅al η)) ((AAs' ⋅aml η))) ! i =
    tl (map2 add_mset (As') (AAs') ⋅aml η) ! i"
    using Suc(2,3) Succ by (simp add: map2_tl map_tl subst_atm_mset_list_def del: subst_atm_list_tl)
  moreover have nn: "length (map2 add_mset ((As' ⋅al η)) ((AAs' ⋅aml η))) = Suc n"
    "length (map2 add_mset (As') (AAs') ⋅aml η) = Suc n"
    using Succ Suc by auto
  ultimately have "i. i < Suc n  i > 0 
    map2 add_mset (As' ⋅al η) (AAs' ⋅aml η) ! i = (map2 add_mset As' AAs' ⋅aml η) ! i"
    by (auto simp: subst_atm_mset_list_def gr0_conv_Suc subst_atm_mset_def)
  moreover have "add_mset (hd As' ⋅a η) (hd AAs' ⋅am η) = add_mset (hd As') (hd AAs') ⋅am η"
    unfolding subst_atm_mset_def by auto
  then have "(map2 add_mset (As' ⋅al η) (AAs' ⋅aml η)) ! 0  = (map2 add_mset (As') (AAs') ⋅aml η) ! 0"
    using Suc by (simp add: Succ(2) subst_atm_mset_def)
  ultimately have "i < Suc n. (map2 add_mset (As' ⋅al η) (AAs' ⋅aml η)) ! i =
    (map2 add_mset (As') (AAs') ⋅aml η) ! i"
    using Suc by auto
  then show ?case
    using nn list_eq_iff_nth_eq by metis
qed auto

context
  fixes S :: "'a clause  'a clause"
begin


subsection ‹Calculus›

text ‹
The following corresponds to Figure 4.
›

definition maximal_wrt :: "'a  'a literal multiset  bool" where
  "maximal_wrt A C  (B  atms_of C. ¬ less_atm A B)"

definition strictly_maximal_wrt :: "'a  'a literal multiset  bool" where
  "strictly_maximal_wrt A C  B  atms_of C. A  B  ¬ less_atm A B"

lemma strictly_maximal_wrt_maximal_wrt: "strictly_maximal_wrt A C  maximal_wrt A C"
  unfolding maximal_wrt_def strictly_maximal_wrt_def by auto

lemma maximal_wrt_subst: "maximal_wrt (A ⋅a σ) (C  σ)  maximal_wrt A C"
  unfolding maximal_wrt_def using in_atms_of_subst less_atm_stable by blast

lemma strictly_maximal_wrt_subst:
  "strictly_maximal_wrt (A ⋅a σ) (C  σ)  strictly_maximal_wrt A C"
  unfolding strictly_maximal_wrt_def using in_atms_of_subst less_atm_stable by blast

inductive eligible :: "'s  'a list  'a clause  bool" where
  eligible:
    "S DA = negs (mset As)  S DA = {#}  length As = 1  maximal_wrt (As ! 0 ⋅a σ) (DA  σ) 
     eligible σ As DA"

inductive
  ord_resolve
  :: "'a clause list  'a clause  'a multiset list  'a list  's  'a clause  bool"
where
  ord_resolve:
    "length CAs = n 
     length Cs = n 
     length AAs = n 
     length As = n 
     n  0 
     (i < n. CAs ! i = Cs ! i + poss (AAs ! i)) 
     (i < n. AAs ! i  {#}) 
     Some σ = mgu (set_mset ` set (map2 add_mset As AAs)) 
     eligible σ As (D + negs (mset As)) 
     (i < n. strictly_maximal_wrt (As ! i ⋅a σ) (Cs ! i  σ)) 
     (i < n. S (CAs ! i) = {#}) 
     ord_resolve CAs (D + negs (mset As)) AAs As σ ((# (mset Cs) + D)  σ)"

inductive
  ord_resolve_rename
  :: "'a clause list  'a clause  'a multiset list  'a list  's  'a clause  bool"
where
  ord_resolve_rename:
    "length CAs = n 
     length AAs = n 
     length As = n 
     (i < n. poss (AAs ! i) ⊆# CAs ! i) 
     negs (mset As) ⊆# DA 
     ρ = hd (renamings_apart (DA # CAs)) 
     ρs = tl (renamings_apart (DA # CAs)) 
     ord_resolve (CAs ⋅⋅cl ρs) (DA  ρ) (AAs ⋅⋅aml ρs) (As ⋅al ρ) σ E 
     ord_resolve_rename CAs DA AAs As σ E"

lemma ord_resolve_empty_main_prem: "¬ ord_resolve Cs {#} AAs As σ E"
  by (simp add: ord_resolve.simps)

lemma ord_resolve_rename_empty_main_prem: "¬ ord_resolve_rename Cs {#} AAs As σ E"
  by (simp add: ord_resolve_empty_main_prem ord_resolve_rename.simps)


subsection ‹Soundness›

text ‹
Soundness is not discussed in the chapter, but it is an important property.
›

lemma ord_resolve_ground_inst_sound:
  assumes
    res_e: "ord_resolve CAs DA AAs As σ E" and
    cc_inst_true: "I ⊨m mset CAs ⋅cm σ ⋅cm η" and
    d_inst_true: "I  DA  σ  η" and
    ground_subst_η: "is_ground_subst η"
  shows "I  E  η"
  using res_e
proof (cases rule: ord_resolve.cases)
  case (ord_resolve n Cs D)
  note da = this(1) and e = this(2) and cas_len = this(3) and cs_len = this(4) and
    aas_len = this(5) and as_len = this(6) and cas = this(8) and mgu = this(10) and
    len = this(1)

  have len: "length CAs = length As"
    using as_len cas_len by auto
  have "is_ground_subst (σ  η)"
    using ground_subst_η by (rule is_ground_comp_subst)
  then have cc_true: "I ⊨m mset CAs ⋅cm σ ⋅cm η" and d_true: "I  DA  σ  η"
    using cc_inst_true d_inst_true by auto

  from mgu have unif: "i < n. A∈#AAs ! i. A ⋅a σ = As ! i ⋅a σ"
    using mgu_unifier as_len aas_len by blast

  show "I  E  η"
  proof (cases "A  set As. A ⋅a σ ⋅a η  I")
    case True
    then have "¬ I  negs (mset As)  σ  η"
      unfolding true_cls_def[of I] by auto
    then have "I  D  σ  η"
      using d_true da by auto
    then show ?thesis
      unfolding e by auto
  next
    case False
    then obtain i where a_in_aa: "i < length CAs" and a_false: "(As ! i) ⋅a σ ⋅a η  I"
      using da len by (metis in_set_conv_nth)
    define C where "C  Cs ! i"
    define BB where "BB  AAs ! i"
    have c_cf': "C ⊆# # (mset CAs)"
      unfolding C_def using a_in_aa cas cas_len
      by (metis less_subset_eq_Union_mset mset_subset_eq_add_left subset_mset.trans)
    have c_in_cc: "C + poss BB ∈# mset CAs"
      using C_def BB_def a_in_aa cas_len in_set_conv_nth cas by fastforce
    {
      fix B
      assume "B ∈# BB"
      then have "B ⋅a σ = (As ! i) ⋅a σ"
        using unif a_in_aa cas_len unfolding BB_def by auto
    }
    then have "¬ I  poss BB  σ  η"
      using a_false by (auto simp: true_cls_def)
    moreover have "I  (C + poss BB)  σ  η"
      using c_in_cc cc_true true_cls_mset_true_cls[of I "mset CAs ⋅cm σ ⋅cm η"] by force
    ultimately have "I  C  σ  η"
      by simp
    then show ?thesis
      unfolding e subst_cls_union using c_cf' C_def a_in_aa cas_len cs_len
      by (metis (no_types, lifting) mset_subset_eq_add_left nth_mem_mset set_mset_mono sum_mset.remove true_cls_mono subst_cls_mono)
  qed
qed

text ‹
The previous lemma is not only used to prove soundness, but also the following lemma which is
used to prove Lemma 4.10.
›

lemma ord_resolve_rename_ground_inst_sound:
  assumes
    "ord_resolve_rename CAs DA AAs As σ E" and
    "ρs = tl (renamings_apart (DA # CAs))" and
    "ρ = hd (renamings_apart (DA # CAs))" and
    "I ⊨m (mset (CAs ⋅⋅cl ρs)) ⋅cm σ ⋅cm η" and
    "I  DA  ρ  σ  η" and
    "is_ground_subst η"
  shows "I  E  η"
  using assms by (cases rule: ord_resolve_rename.cases) (fast intro: ord_resolve_ground_inst_sound)

text ‹
Here follows the soundness theorem for the resolution rule.
›

theorem ord_resolve_sound:
 assumes
   res_e: "ord_resolve CAs DA AAs As σ E" and
   cc_d_true: "σ. is_ground_subst σ  I ⊨m (mset CAs + {#DA#}) ⋅cm σ" and
   ground_subst_η: "is_ground_subst η"
 shows "I  E  η"
proof (use res_e in cases rule: ord_resolve.cases)
  case (ord_resolve n Cs D)
  note da = this(1) and e = this(2) and cas_len = this(3) and cs_len = this(4)
    and aas_len = this(5) and as_len = this(6) and cas = this(8) and mgu = this(10)
  have ground_subst_σ_η: "is_ground_subst (σ  η)"
    using ground_subst_η by (rule is_ground_comp_subst)
  have cas_true: "I ⊨m mset CAs ⋅cm σ ⋅cm η"
    using cc_d_true ground_subst_σ_η by fastforce
  have da_true: "I  DA  σ  η"
    using cc_d_true ground_subst_σ_η by fastforce
  show "I  E  η"
    using ord_resolve_ground_inst_sound[OF res_e cas_true da_true] ground_subst_η by auto
qed

lemma subst_sound:
  assumes
    "σ. is_ground_subst σ  I  C  σ" and
    "is_ground_subst η"
  shows "I  C  ρ  η"
  using assms is_ground_comp_subst subst_cls_comp_subst by metis

lemma subst_sound_scl:
  assumes
    len: "length P = length CAs" and
    true_cas: "σ. is_ground_subst σ  I ⊨m mset CAs ⋅cm σ" and
    ground_subst_η: "is_ground_subst η"
  shows "I ⊨m mset (CAs ⋅⋅cl P) ⋅cm η"
proof -
  from true_cas have "CA. CA∈# mset CAs  (σ. is_ground_subst σ  I  CA  σ)"
    unfolding true_cls_mset_def by force
  then have "i < length CAs. σ. is_ground_subst σ  (I  CAs ! i  σ)"
    using in_set_conv_nth by auto
  then have true_cp: "i < length CAs. σ. is_ground_subst σ  I  CAs ! i  P ! i  σ"
    using subst_sound len by auto

  {
    fix CA
    assume "CA ∈# mset (CAs ⋅⋅cl P)"
    then obtain i where
      i_x: "i < length (CAs ⋅⋅cl P)" "CA = (CAs ⋅⋅cl P) ! i"
      by (metis in_mset_conv_nth)
    then have "σ. is_ground_subst σ  I  CA  σ"
      using true_cp unfolding subst_cls_lists_def by (simp add: len)
  }
  then show ?thesis
    using assms unfolding true_cls_mset_def by auto
qed

text ‹
Here follows the soundness theorem for the resolution rule with renaming.
›

lemma ord_resolve_rename_sound:
  assumes
    res_e: "ord_resolve_rename CAs DA AAs As σ E" and
    cc_d_true: "σ. is_ground_subst σ  I ⊨m ((mset CAs) + {#DA#}) ⋅cm σ" and
    ground_subst_η: "is_ground_subst η"
  shows "I  E  η"
  using res_e
proof (cases rule: ord_resolve_rename.cases)
  case (ord_resolve_rename n ρ ρs)
  note ρs = this(7) and res = this(8)
  have len: "length ρs = length CAs"
    using ρs renamings_apart_length by auto
  have "σ. is_ground_subst σ  I ⊨m (mset (CAs ⋅⋅cl ρs) + {#DA  ρ#}) ⋅cm σ"
    using subst_sound_scl[OF len, of I] subst_sound cc_d_true by auto
  then show "I  E  η"
    using ground_subst_η ord_resolve_sound[OF res] by simp
qed


subsection ‹Other Basic Properties›

lemma ord_resolve_unique:
  assumes
    "ord_resolve CAs DA AAs As σ E" and
    "ord_resolve CAs DA AAs As σ' E'"
  shows "σ = σ'  E = E'"
  using assms
proof (cases rule: ord_resolve.cases[case_product ord_resolve.cases], intro conjI)
  case (ord_resolve_ord_resolve CAs n Cs AAs As σ'' DA CAs' n' Cs' AAs' As' σ''' DA')
  note res = this(1-17) and res' = this(18-34)

  show σ: "σ = σ'"
    using res(3-5,14) res'(3-5,14) by (metis option.inject)

  have "Cs = Cs'"
    using res(1,3,7,8,12) res'(1,3,7,8,12) by (metis add_right_imp_eq nth_equalityI)
  moreover have "DA = DA'"
    using res(2,4) res'(2,4) by fastforce
  ultimately show "E = E'"
    using res(5,6) res'(5,6) σ by blast
qed

lemma ord_resolve_rename_unique:
  assumes
    "ord_resolve_rename CAs DA AAs As σ E" and
    "ord_resolve_rename CAs DA AAs As σ' E'"
  shows "σ = σ'  E = E'"
  using assms unfolding ord_resolve_rename.simps using ord_resolve_unique by meson

lemma ord_resolve_max_side_prems: "ord_resolve CAs DA AAs As σ E  length CAs  size DA"
  by (auto elim!: ord_resolve.cases)

lemma ord_resolve_rename_max_side_prems:
  "ord_resolve_rename CAs DA AAs As σ E  length CAs  size DA"
  by (elim ord_resolve_rename.cases, drule ord_resolve_max_side_prems, simp add: renamings_apart_length)


subsection ‹Inference System›

definition ord_FO_Γ :: "'a inference set" where
  "ord_FO_Γ = {Infer (mset CAs) DA E | CAs DA AAs As σ E. ord_resolve_rename CAs DA AAs As σ E}"

interpretation ord_FO_resolution: inference_system ord_FO_Γ .

lemma finite_ord_FO_resolution_inferences_between:
  assumes fin_cc: "finite CC"
  shows "finite (ord_FO_resolution.inferences_between CC C)"
proof -
  let ?CCC = "CC  {C}"

  define all_AA where "all_AA = (D  ?CCC. atms_of D)"
  define max_ary where "max_ary = Max (size ` ?CCC)"
  define CAS where "CAS = {CAs. CAs  lists ?CCC  length CAs  max_ary}"
  define AS where "AS = {As. As  lists all_AA  length As  max_ary}"
  define AAS where "AAS = {AAs. AAs  lists (mset ` AS)  length AAs  max_ary}"

  note defs = all_AA_def max_ary_def CAS_def AS_def AAS_def

  let ?infer_of =
    "λCAs DA AAs As. Infer (mset CAs) DA (THE E. σ. ord_resolve_rename CAs DA AAs As σ E)"

  let ?Z = "{γ | CAs DA AAs As σ E γ. γ = Infer (mset CAs) DA E
     ord_resolve_rename CAs DA AAs As σ E  infer_from ?CCC γ  C ∈# prems_of γ}"
  let ?Y = "{Infer (mset CAs) DA E | CAs DA AAs As σ E.
    ord_resolve_rename CAs DA AAs As σ E  set CAs  {DA}  ?CCC}"
  let ?X = "{?infer_of CAs DA AAs As | CAs DA AAs As. CAs  CAS  DA  ?CCC  AAs  AAS  As  AS}"
  let ?W = "CAS × ?CCC × AAS × AS"

  have fin_w: "finite ?W"
    unfolding defs using fin_cc by (simp add: finite_lists_length_le lists_eq_set)

  have "?Z  ?Y"
    by (force simp: infer_from_def)
  also have "  ?X"
  proof -
    {
      fix CAs DA AAs As σ E
      assume
        res_e: "ord_resolve_rename CAs DA AAs As σ E" and
        da_in: "DA  ?CCC" and
        cas_sub: "set CAs  ?CCC"

      have "E = (THE E. σ. ord_resolve_rename CAs DA AAs As σ E)
         CAs  CAS  AAs  AAS  As  AS" (is "?e  ?cas  ?aas  ?as")
      proof (intro conjI)
        show ?e
          using res_e ord_resolve_rename_unique by (blast intro: the_equality[symmetric])
      next
        show ?cas
          unfolding CAS_def max_ary_def using cas_sub
            ord_resolve_rename_max_side_prems[OF res_e] da_in fin_cc
          by (auto simp add: Max_ge_iff)
      next
        show ?aas
          using res_e
        proof (cases rule: ord_resolve_rename.cases)
          case (ord_resolve_rename n ρ ρs)
          note len_cas = this(1) and len_aas = this(2) and len_as = this(3) and
            aas_sub = this(4) and as_sub = this(5) and res_e' = this(8)

          show ?thesis
            unfolding AAS_def
          proof (clarify, intro conjI)
            show "AAs  lists (mset ` AS)"
              unfolding AS_def image_def
            proof clarsimp
              fix AA
              assume "AA  set AAs"
              then obtain i where
                i_lt: "i < n" and
                aa: "AA = AAs ! i"
                by (metis in_set_conv_nth len_aas)

              have casi_in: "CAs ! i  ?CCC"
                using i_lt len_cas cas_sub nth_mem by blast

              have pos_aa_sub: "poss AA ⊆# CAs ! i"
                using aa aas_sub i_lt by blast
              then have "set_mset AA  atms_of (CAs ! i)"
                by (metis atms_of_poss lits_subseteq_imp_atms_subseteq set_mset_mono)
              also have aa_sub: "  all_AA"
                unfolding all_AA_def using casi_in by force
              finally have aa_sub: "set_mset AA  all_AA"
                .

              have "size AA = size (poss AA)"
                by simp
              also have "  size (CAs ! i)"
                by (rule size_mset_mono[OF pos_aa_sub])
              also have "  max_ary"
                unfolding max_ary_def using fin_cc casi_in by auto
              finally have sz_aa: "size AA  max_ary"
                .

              let ?As' = "sorted_list_of_multiset AA"

              have "?As'  lists all_AA"
                using aa_sub by auto
              moreover have "length ?As'  max_ary"
                using sz_aa by simp
              moreover have "AA = mset ?As'"
                by simp
              ultimately show "xa. xa  lists all_AA  length xa  max_ary  AA = mset xa"
                by blast
            qed
          next
            have "length AAs = length As"
              unfolding len_aas len_as ..
            also have "  size DA"
              using as_sub size_mset_mono by fastforce
            also have "  max_ary"
              unfolding max_ary_def using fin_cc da_in by auto
            finally show "length AAs  max_ary"
              .
          qed
        qed
      next
        show ?as
          unfolding AS_def
        proof (clarify, intro conjI)
          have "set As  atms_of DA"
            using res_e[simplified ord_resolve_rename.simps]
            by (metis atms_of_negs lits_subseteq_imp_atms_subseteq set_mset_mono set_mset_mset)
          also have "  all_AA"
            unfolding all_AA_def using da_in by blast
          finally show "As  lists all_AA"
            unfolding lists_eq_set by simp
        next
          have "length As  size DA"
            using res_e[simplified ord_resolve_rename.simps]
              ord_resolve_rename_max_side_prems[OF res_e] by auto
          also have "size DA  max_ary"
            unfolding max_ary_def using fin_cc da_in by auto
          finally show "length As  max_ary"
            .
        qed
      qed
    }
    then show ?thesis
      by simp fast
  qed
  also have "  (λ(CAs, DA, AAs, As). ?infer_of CAs DA AAs As) ` ?W"
    unfolding image_def Bex_cartesian_product by fast
  finally show ?thesis
    unfolding inference_system.inferences_between_def ord_FO_Γ_def mem_Collect_eq
    by (fast intro: rev_finite_subset[OF finite_imageI[OF fin_w]])
qed

lemma ord_FO_resolution_inferences_between_empty_empty:
  "ord_FO_resolution.inferences_between {} {#} = {}"
  unfolding ord_FO_resolution.inferences_between_def inference_system.inferences_between_def
    infer_from_def ord_FO_Γ_def
  using ord_resolve_rename_empty_main_prem by auto


subsection ‹Lifting›

text ‹
The following corresponds to the passage between Lemmas 4.11 and 4.12.
›

context
  fixes M :: "'a clause set"
  assumes select: "selection S"
begin

interpretation selection
  by (rule select)

definition S_M :: "'a literal multiset  'a literal multiset" where
  "S_M C =
   (if C  grounding_of_clss M then
      (SOME C'. D σ. D  M  C = D  σ  C' = S D  σ  is_ground_subst σ)
    else
      S C)"

lemma S_M_grounding_of_clss:
  assumes "C  grounding_of_clss M"
  obtains D σ where
    "D  M  C = D  σ  S_M C = S D  σ  is_ground_subst σ"
proof (atomize_elim, unfold S_M_def eqTrueI[OF assms] if_True, rule someI_ex)
  from assms show "C' D σ. D  M  C = D  σ  C' = S D  σ  is_ground_subst σ"
    by (auto simp: grounding_of_clss_def grounding_of_cls_def)
qed

lemma S_M_not_grounding_of_clss: "C  grounding_of_clss M  S_M C = S C"
  unfolding S_M_def by simp

lemma S_M_selects_subseteq: "S_M C ⊆# C"
  by (metis S_M_grounding_of_clss S_M_not_grounding_of_clss S_selects_subseteq subst_cls_mono_mset)

lemma S_M_selects_neg_lits: "L ∈# S_M C  is_neg L"
  by (metis Melem_subst_cls S_M_grounding_of_clss S_M_not_grounding_of_clss S_selects_neg_lits
      subst_lit_is_neg)

end

end

text ‹
The following corresponds to Lemma 4.12:
›

lemma ground_resolvent_subset:
  assumes
    gr_cas: "is_ground_cls_list CAs" and
    gr_da: "is_ground_cls DA" and
    res_e: "ord_resolve S CAs DA AAs As σ E"
  shows "E ⊆# # (mset CAs) + DA"
  using res_e
proof (cases rule: ord_resolve.cases)
  case (ord_resolve n Cs D)
  note da = this(1) and e = this(2) and cas_len = this(3) and cs_len = this(4)
    and aas_len = this(5) and as_len = this(6) and cas = this(8) and mgu = this(10)
  then have cs_sub_cas: "# (mset Cs) ⊆# # (mset CAs)"
    using subseteq_list_Union_mset cas_len cs_len by force
  then have cs_sub_cas: "# (mset Cs) ⊆# # (mset CAs)"
    using subseteq_list_Union_mset cas_len cs_len by force
  then have gr_cs: "is_ground_cls_list Cs"
    using gr_cas by simp
  have d_sub_da: "D ⊆# DA"
    by (simp add: da)
  then have gr_d: "is_ground_cls D"
    using gr_da is_ground_cls_mono by auto

  have "is_ground_cls (# (mset Cs) + D)"
    using gr_cs gr_d by auto
  with e have "E = # (mset Cs) + D"
    by auto
  then show ?thesis
    using cs_sub_cas d_sub_da by (auto simp: subset_mset.add_mono)
qed

lemma ord_resolve_obtain_clauses:
  assumes
    res_e: "ord_resolve (S_M S M) CAs DA AAs As σ E" and
    select: "selection S" and
    grounding: "{DA}  set CAs  grounding_of_clss M" and
    n: "length CAs = n" and
    d: "DA = D + negs (mset As)" and
    c: "(i < n. CAs ! i = Cs ! i + poss (AAs ! i))" "length Cs = n" "length AAs = n"
  obtains DA0 η0 CAs0 ηs0 As0 AAs0 D0 Cs0 where
    "length CAs0 = n"
    "length ηs0 = n"
    "DA0  M"
    "DA0  η0 = DA"
    "S DA0  η0 = S_M S M DA"
    "CA0  set CAs0. CA0  M"
    "CAs0 ⋅⋅cl ηs0 = CAs"
    "map S CAs0 ⋅⋅cl ηs0 = map (S_M S M) CAs"
    "is_ground_subst η0"
    "is_ground_subst_list ηs0"
    "As0  ⋅al η0 = As"
    "AAs0 ⋅⋅aml ηs0 = AAs"
    "length As0 = n"
    "D0  η0 = D"
    "DA0 = D0 + (negs (mset As0))"
    "S_M S M (D + negs (mset As))  {#}  negs (mset As0) = S DA0"
    "length Cs0 = n"
    "Cs0 ⋅⋅cl ηs0 = Cs"
    "i < n. CAs0 ! i = Cs0 ! i + poss (AAs0 ! i)"
    "length AAs0 = n"
  using res_e
proof (cases rule: ord_resolve.cases)
  case (ord_resolve n_twin Cs_twins D_twin)
  note da = this(1) and e = this(2) and cas = this(8) and mgu = this(10) and eligible = this(11)
  from ord_resolve have "n_twin = n" "D_twin = D"
    using n d by auto
  moreover have "Cs_twins = Cs"
    using c cas n calculation(1) length Cs_twins = n_twin by (auto simp add: nth_equalityI)
  ultimately
  have nz: "n  0" and cs_len: "length Cs = n" and aas_len: "length AAs = n" and as_len: "length As = n"
    and da: "DA = D + negs (mset As)" and eligible: "eligible (S_M S M) σ As (D + negs (mset As))"
    and cas: "i<n. CAs ! i = Cs ! i + poss (AAs ! i)"
    using ord_resolve by force+

  note n = n  0 length CAs = n length Cs = n length AAs = n length As = n

  interpret S: selection S by (rule select)

  ― ‹Obtain FO side premises›
  have "CA  set CAs. CA0 ηc0. CA0  M  CA0  ηc0 = CA  S CA0  ηc0 = S_M S M CA  is_ground_subst ηc0"
    using grounding S_M_grounding_of_clss select by (metis (no_types) le_supE subset_iff)
  then have "i < n. CA0 ηc0. CA0  M  CA0  ηc0 = (CAs ! i)  S CA0  ηc0 = S_M S M (CAs ! i)  is_ground_subst ηc0"
    using n by force
  then obtain ηs0f CAs0f where f_p:
    "i < n. CAs0f i  M"
    "i < n. (CAs0f i)  (ηs0f i) = (CAs ! i)"
    "i < n. S (CAs0f i)   (ηs0f i) = S_M S M (CAs ! i)"
    "i < n. is_ground_subst (ηs0f i)"
    using n by (metis (no_types))

  define ηs0 where
    "ηs0 = map ηs0f [0 ..<n]"
  define CAs0 where
    "CAs0 = map CAs0f [0 ..<n]"

  have "length ηs0 = n" "length CAs0 = n"
    unfolding ηs0_def CAs0_def by auto
  note n = length ηs0 = n length CAs0 = n n

  ― ‹The properties we need of the FO side premises›
  have CAs0_in_M: "CA0  set CAs0. CA0  M"
    unfolding CAs0_def using f_p(1) by auto
  have CAs0_to_CAs: "CAs0 ⋅⋅cl ηs0 = CAs"
    unfolding CAs0_def ηs0_def using f_p(2)  by (auto simp: n intro: nth_equalityI)
  have SCAs0_to_SMCAs: "(map S CAs0) ⋅⋅cl ηs0 = map (S_M S M) CAs"
    unfolding CAs0_def ηs0_def using f_p(3) n by (force intro: nth_equalityI)
  have sub_ground: "ηc0  set ηs0. is_ground_subst ηc0"
    unfolding ηs0_def using f_p n by force
  then have "is_ground_subst_list ηs0"
    using n unfolding is_ground_subst_list_def by auto

  ― ‹Split side premises CAs0 into Cs0 and AAs0›
  obtain AAs0 Cs0 where AAs0_Cs0_p:
   "AAs0 ⋅⋅aml ηs0 = AAs" "length Cs0 = n" "Cs0 ⋅⋅cl ηs0 = Cs"
   "i < n. CAs0 ! i = Cs0 ! i + poss (AAs0 ! i)" "length AAs0 = n"
  proof -
    have "i < n. AA0. AA0 ⋅am ηs0 ! i = AAs ! i  poss AA0 ⊆# CAs0 ! i"
    proof (rule, rule)
      fix i
      assume "i < n"
      have "CAs0 ! i  ηs0 ! i = CAs ! i"
        using i < n CAs0 ⋅⋅cl ηs0 = CAs n by force
      moreover have "poss (AAs ! i) ⊆# CAs !i"
        using i < n cas by auto
      ultimately obtain poss_AA0 where
        nn: "poss_AA0  ηs0 ! i = poss (AAs ! i)  poss_AA0 ⊆# CAs0 ! i"
        using cas image_mset_of_subset unfolding subst_cls_def by metis
      then have l: "L ∈# poss_AA0. is_pos L"
        unfolding subst_cls_def by (metis Melem_subst_cls imageE literal.disc(1)
            literal.map_disc_iff set_image_mset subst_cls_def subst_lit_def)

      define AA0 where
        "AA0 = image_mset atm_of poss_AA0"

      have na: "poss AA0 = poss_AA0"
        using l unfolding AA0_def by auto
      then have "AA0 ⋅am ηs0 ! i = AAs ! i"
        using nn by (metis (mono_tags) literal.inject(1) multiset.inj_map_strong subst_cls_poss)
      moreover have "poss AA0 ⊆# CAs0 ! i"
        using na nn by auto
      ultimately show "AA0. AA0 ⋅am ηs0 ! i = AAs ! i  poss AA0 ⊆# CAs0 ! i"
        by blast
    qed
    then obtain AAs0f where
      AAs0f_p: "i < n. AAs0f i ⋅am ηs0 ! i = AAs ! i  (poss (AAs0f i)) ⊆# CAs0 ! i"
      by metis

    define AAs0 where "AAs0 = map AAs0f [0 ..<n]"

    then have "length AAs0 = n"
      by auto
    note n = n length AAs0 = n

    from AAs0_def have "i < n. AAs0 ! i ⋅am ηs0 ! i = AAs ! i"
      using AAs0f_p by auto
    then have AAs0_AAs: "AAs0 ⋅⋅aml ηs0 = AAs"
      using n by (auto intro: nth_equalityI)

    from AAs0_def have AAs0_in_CAs0: "i < n. poss (AAs0 ! i) ⊆# CAs0 ! i"
      using AAs0f_p by auto

    define Cs0 where
      "Cs0 = map2 (-) CAs0 (map poss AAs0)"

    have "length Cs0 = n"
      using Cs0_def n by auto
    note n = n length Cs0 = n

    have "i < n. CAs0 ! i = Cs0 ! i + poss (AAs0 ! i)"
      using AAs0_in_CAs0 Cs0_def n by auto
    then have "Cs0 ⋅⋅cl ηs0 = Cs"
      using CAs0 ⋅⋅cl ηs0 = CAs AAs0_AAs cas n by (auto intro: nth_equalityI)

    show ?thesis
      using that
        AAs0 ⋅⋅aml ηs0 = AAs Cs0 ⋅⋅cl ηs0 = Cs i < n. CAs0 ! i = Cs0 ! i + poss (AAs0 ! i)
        length AAs0 = n length Cs0 = n
      by blast
  qed

  ― ‹Obtain FO main premise›
  have "DA0 η0. DA0  M  DA = DA0  η0  S DA0  η0 = S_M S M DA  is_ground_subst η0"
    using grounding S_M_grounding_of_clss select by (metis le_supE singletonI subsetCE)
  then obtain DA0 η0 where
    DA0_η0_p: "DA0  M  DA = DA0  η0  S DA0  η0 = S_M S M DA  is_ground_subst η0"
    by auto
  ― ‹The properties we need of the FO main premise›
  have DA0_in_M: "DA0  M"
    using DA0_η0_p by auto
  have DA0_to_DA: "DA0  η0 = DA"
    using DA0_η0_p by auto
  have SDA0_to_SMDA: "S DA0  η0 = S_M S M DA"
    using DA0_η0_p by auto
  have "is_ground_subst η0"
    using DA0_η0_p by auto

  ― ‹Split main premise DA0 into D0 and As0›
  obtain D0 As0 where D0As0_p:
     "As0  ⋅al η0 = As" "length As0 = n" "D0  η0 = D" "DA0 = D0 + (negs (mset As0))"
    "S_M S M (D + negs (mset As))  {#}  negs (mset As0) = S DA0"
  proof -
    {
      assume a: "S_M S M (D + negs (mset As)) = {#}  length As = (Suc 0)
         maximal_wrt (As ! 0 ⋅a σ) ((D + negs (mset As))  σ)"
      then have as: "mset As = {#As ! 0#}"
        by (auto intro: nth_equalityI)
      then have "negs (mset As) = {#Neg (As ! 0)#}"
        by (simp add: mset As = {#As ! 0#})
      then have "DA = D + {#Neg (As ! 0)#}"
        using da by auto
      then obtain L where "L ∈# DA0  L ⋅l η0 = Neg (As ! 0)"
        using DA0_to_DA by (metis Melem_subst_cls mset_subset_eq_add_right single_subset_iff)
      then have "Neg (atm_of L) ∈# DA0  Neg (atm_of L) ⋅l η0 = Neg (As ! 0)"
        by (metis Neg_atm_of_iff literal.sel(2) subst_lit_is_pos)
      then have "[atm_of L] ⋅al η0 = As  negs (mset [atm_of L]) ⊆# DA0"
        using as subst_lit_def by auto
      then have "As0. As0 ⋅al η0 = As  negs (mset As0) ⊆# DA0
         (S_M S M (D + negs (mset As))  {#}  negs (mset As0) = S DA0)"
        using a by blast
    }
    moreover
    {
      assume "S_M S M (D + negs (mset As)) = negs (mset As)"
      then have "negs (mset As) = S DA0  η0"
        using da S DA0  η0 = S_M S M DA by auto
      then have "As0. negs (mset As0) = S DA0  As0 ⋅al η0 = As"
        using instance_list[of As "S DA0" η0] S.S_selects_neg_lits by auto
      then have "As0. As0 ⋅al η0 = As  negs (mset As0) ⊆# DA0
         (S_M S M (D + negs (mset As))  {#}  negs (mset As0) = S DA0)"
        using S.S_selects_subseteq by auto
    }
    ultimately have "As0. As0 ⋅al η0 = As  (negs (mset As0)) ⊆# DA0
       (S_M S M (D + negs (mset As))  {#}  negs (mset As0) = S DA0)"
      using eligible unfolding eligible.simps by auto
    then obtain As0 where
      As0_p: "As0 ⋅al η0 = As  negs (mset As0) ⊆# DA0
       (S_M S M (D + negs (mset As))  {#}  negs (mset As0) = S DA0)"
      by blast
    then have "length As0 = n"
      using as_len by auto
    note n = n this

    have "As0 ⋅al η0 = As"
      using As0_p by auto

    define D0 where
      "D0 = DA0 - negs (mset As0)"
    then have "DA0 = D0 + negs (mset As0)"
      using As0_p by auto
    then have "D0  η0 = D"
      using DA0_to_DA da As0_p by auto

    have "S_M S M (D + negs (mset As))  {#}  negs (mset As0) = S DA0"
      using As0_p by blast
    then show ?thesis
      using that As0 ⋅al η0 = As D0  η0= D DA0 = D0 +  (negs (mset As0)) length As0 = n
      by metis
  qed

  show ?thesis
    using that[OF n(2,1) DA0_in_M  DA0_to_DA SDA0_to_SMDA CAs0_in_M CAs0_to_CAs SCAs0_to_SMCAs
        is_ground_subst η0 is_ground_subst_list ηs0 As0  ⋅al η0 = As
        AAs0 ⋅⋅aml ηs0 = AAs
        length As0 = n
        D0  η0 = D
        DA0 = D0 + (negs (mset As0))
        S_M S M (D + negs (mset As))  {#}  negs (mset As0) = S DA0
        length Cs0 = n
        Cs0 ⋅⋅cl ηs0 = Cs
        i < n. CAs0 ! i = Cs0 ! i + poss (AAs0 ! i)
        length AAs0 = n]
    by auto
qed

lemma ord_resolve_rename_lifting:
  assumes
    sel_stable: "ρ C. is_renaming ρ  S (C  ρ) = S C  ρ" and
    res_e: "ord_resolve (S_M S M) CAs DA AAs As σ E" and
    select: "selection S" and
    grounding: "{DA}  set CAs  grounding_of_clss M"
  obtains ηs η η2 CAs0 DA0 AAs0 As0 E0 τ where
    "is_ground_subst η"
    "is_ground_subst_list ηs"
    "is_ground_subst η2"
    "ord_resolve_rename S CAs0 DA0 AAs0 As0 τ E0"
    "CAs0 ⋅⋅cl ηs = CAs" "DA0  η = DA" "E0  η2 = E"
    "{DA0}  set CAs0  M"
    "length CAs0 = length CAs"
    "length ηs = length CAs"
  using res_e
proof (cases rule: ord_resolve.cases)
  case (ord_resolve n Cs D)
  note da = this(1) and e = this(2) and cas_len = this(3) and cs_len = this(4) and
    aas_len = this(5) and as_len = this(6) and nz = this(7) and cas = this(8) and
    aas_not_empt = this(9) and mgu = this(10) and eligible = this(11) and str_max = this(12) and
    sel_empt = this(13)

  have sel_ren_list_inv:
    "ρs Cs. length ρs = length Cs  is_renaming_list ρs  map S (Cs ⋅⋅cl ρs) = map S Cs ⋅⋅cl ρs"
    using sel_stable unfolding is_renaming_list_def by (auto intro: nth_equalityI)

  note n = n  0 length CAs = n length Cs = n length AAs = n length As = n

  interpret S: selection S by (rule select)

  obtain DA0 η0 CAs0 ηs0 As0 AAs0 D0 Cs0 where as0:
    "length CAs0 = n"
    "length ηs0 = n"
    "DA0  M"
    "DA0  η0 = DA"
    "S DA0  η0 = S_M S M DA"
    "CA0  set CAs0. CA0  M"
    "CAs0 ⋅⋅cl ηs0 = CAs"
    "map S CAs0 ⋅⋅cl ηs0 = map (S_M S M) CAs"
    "is_ground_subst η0"
    "is_ground_subst_list ηs0"
    "As0 ⋅al η0 = As"
    "AAs0 ⋅⋅aml ηs0 = AAs"
    "length As0 = n"
    "D0  η0 = D"
    "DA0 = D0 + (negs (mset As0))"
    "S_M S M (D + negs (mset As))  {#}  negs (mset As0) = S DA0"
    "length Cs0 = n"
    "Cs0 ⋅⋅cl ηs0 = Cs"
    "i < n. CAs0 ! i = Cs0 ! i + poss (AAs0 ! i)"
    "length AAs0 = n"
    using ord_resolve_obtain_clauses[of S M CAs DA, OF res_e select grounding n(2) DA = D + negs (mset As)
      i<n. CAs ! i = Cs ! i + poss (AAs ! i) length Cs = n length AAs = n, of thesis] by blast

  note n = length CAs0 = n length ηs0 = n length As0 = n length AAs0 = n length Cs0 = n n

  have "length (renamings_apart (DA0 # CAs0)) = Suc n"
    using n renamings_apart_length by auto

  note n = this n

  define ρ where
    "ρ = hd (renamings_apart (DA0 # CAs0))"
  define ρs where
    "ρs = tl (renamings_apart (DA0 # CAs0))"
  define DA0' where
    "DA0' = DA0  ρ"
  define D0' where
    "D0' = D0  ρ"
  define As0' where
    "As0' = As0 ⋅al ρ"
  define CAs0' where
    "CAs0' = CAs0 ⋅⋅cl ρs"
  define Cs0' where
    "Cs0' = Cs0 ⋅⋅cl ρs"
  define AAs0' where
    "AAs0' = AAs0 ⋅⋅aml ρs"
  define η0' where
    "η0' = inv_renaming ρ  η0"
  define ηs0' where
    "ηs0' = map inv_renaming ρs ⊙s ηs0"

  have renames_DA0: "is_renaming ρ"
    using renamings_apart_length renamings_apart_renaming unfolding ρ_def
    by (metis length_greater_0_conv list.exhaust_sel list.set_intros(1) list.simps(3))

  have renames_CAs0: "is_renaming_list ρs"
    using renamings_apart_length renamings_apart_renaming unfolding ρs_def
    by (metis is_renaming_list_def length_greater_0_conv list.set_sel(2) list.simps(3))

  have "length ρs = n"
    unfolding ρs_def using n by auto
  note n = n length ρs = n
  have "length As0' = n"
    unfolding As0'_def using n by auto
  have "length CAs0' = n"
    using as0(1) n unfolding CAs0'_def by auto
  have "length Cs0' = n"
    unfolding Cs0'_def using n by auto
  have "length AAs0' = n"
    unfolding AAs0'_def using n by auto
  have "length ηs0' = n"
    using as0(2) n unfolding ηs0'_def by auto
  note n = length CAs0' = n length ηs0' = n length As0' = n length AAs0' = n length Cs0' = n n

  have DA0'_DA: "DA0'  η0' = DA"
    using as0(4) unfolding η0'_def DA0'_def using renames_DA0 by simp
  have D0'_D: "D0'  η0' = D"
    using as0(14) unfolding η0'_def D0'_def using renames_DA0 by simp
  have As0'_As: "As0' ⋅al η0' = As"
    using as0(11) unfolding η0'_def As0'_def using renames_DA0 by auto
  have "S DA0'  η0' = S_M S M DA"
    using as0(5) unfolding η0'_def DA0'_def using renames_DA0 sel_stable by auto
  have CAs0'_CAs: "CAs0' ⋅⋅cl ηs0' = CAs"
    using as0(7) unfolding CAs0'_def ηs0'_def using renames_CAs0 n by auto
  have Cs0'_Cs: "Cs0' ⋅⋅cl ηs0' = Cs"
    using as0(18) unfolding Cs0'_def ηs0'_def using renames_CAs0 n by auto
  have AAs0'_AAs: "AAs0' ⋅⋅aml ηs0' = AAs"
    using as0(12) unfolding ηs0'_def AAs0'_def using renames_CAs0 using n by auto
  have "map S CAs0' ⋅⋅cl ηs0' = map (S_M S M) CAs"
    unfolding CAs0'_def ηs0'_def using as0(8) n renames_CAs0 sel_ren_list_inv by auto

  have DA0'_split: "DA0' = D0' + negs (mset As0')"
    using as0(15) DA0'_def D0'_def As0'_def by auto
  then have D0'_subset_DA0': "D0' ⊆# DA0'"
    by auto
  from DA0'_split have negs_As0'_subset_DA0': "negs (mset As0') ⊆# DA0'"
    by auto

  have CAs0'_split: "i<n. CAs0' ! i = Cs0' ! i + poss (AAs0' ! i)"
    using as0(19) CAs0'_def Cs0'_def AAs0'_def n by auto
  then have "i<n. Cs0' ! i ⊆# CAs0' ! i"
    by auto
  from CAs0'_split have poss_AAs0'_subset_CAs0': "i<n. poss (AAs0' ! i) ⊆# CAs0' ! i"
    by auto
  then have AAs0'_in_atms_of_CAs0': "i < n. A∈#AAs0' ! i. A  atms_of (CAs0' ! i)"
    by (auto simp add: atm_iff_pos_or_neg_lit)

  have as0':
    "S_M S M (D + negs (mset As))  {#}  negs (mset As0') = S DA0'"
  proof -
    assume a: "S_M S M (D + negs (mset As))  {#}"
    then have "negs (mset As0)  ρ = S DA0  ρ"
      using as0(16) unfolding ρ_def by metis
    then show "negs (mset As0') = S DA0'"
      using  As0'_def DA0'_def using sel_stable[of ρ DA0] renames_DA0 by auto
  qed

  have vd: "var_disjoint (DA0' # CAs0')"
    unfolding DA0'_def CAs0'_def using renamings_apart_var_disjoint
    unfolding ρ_def ρs_def
    by (metis length_greater_0_conv list.exhaust_sel n(6) subst_cls_lists_Cons zero_less_Suc)

  ― ‹Introduce ground substitution›
  from vd DA0'_DA CAs0'_CAs have "η. i < Suc n. S. S ⊆# (DA0' # CAs0') ! i  S  (η0'#ηs0') ! i = S  η"
    unfolding var_disjoint_def using n by auto
  then obtain η where η_p: "i < Suc n. S. S ⊆# (DA0' # CAs0') ! i  S  (η0'#ηs0') ! i = S  η"
    by auto
  have η_p_lit: "i < Suc n. L. L ∈# (DA0' # CAs0') ! i  L ⋅l (η0'#ηs0') ! i = L ⋅l η"
  proof (rule, rule, rule, rule)
    fix i :: "nat" and L :: "'a literal"
    assume a:
      "i < Suc n"
      "L ∈# (DA0' # CAs0') ! i"
    then have "S. S ⊆# (DA0' # CAs0') ! i  S  (η0' # ηs0') ! i = S  η"
      using η_p by auto
    then have "{# L #}  (η0' # ηs0') ! i = {# L #}  η"
      using a by (meson single_subset_iff)
    then show "L ⋅l (η0' # ηs0') ! i = L ⋅l η" by auto
  qed
  have η_p_atm: "i < Suc n. A. A  atms_of ((DA0' # CAs0') ! i)  A ⋅a (η0'#ηs0') ! i = A ⋅a η"
  proof (rule, rule, rule, rule)
    fix i :: "nat" and A :: "'a"
    assume a:
      "i < Suc n"
      "A  atms_of ((DA0' # CAs0') ! i)"
    then obtain L where L_p: "atm_of L = A  L ∈# (DA0' # CAs0') ! i"
      unfolding atms_of_def by auto
    then have "L ⋅l (η0'#ηs0') ! i = L ⋅l η"
      using η_p_lit a by auto
    then show "A ⋅a (η0' # ηs0') ! i = A ⋅a η"
      using L_p unfolding subst_lit_def by (cases L) auto
  qed

  have DA0'_DA: "DA0'  η = DA"
    using DA0'_DA η_p by auto
  have "D0'  η = D" using η_p D0'_D n D0'_subset_DA0' by auto
  have "As0' ⋅al η = As"
  proof (rule nth_equalityI)
    show "length (As0' ⋅al η) = length As"
      using n by auto
  next
    fix i
    show "i<length (As0' ⋅al η)  (As0' ⋅al η) ! i = As ! i"
    proof -
      assume a: "i < length (As0' ⋅al η)"
      have A_eq: "A. A  atms_of DA0'  A ⋅a η0' = A ⋅a η"
        using η_p_atm n by force
      have "As0' ! i  atms_of DA0'"
        using negs_As0'_subset_DA0' unfolding atms_of_def
        using a n by force
      then have "As0' ! i ⋅a η0' = As0' ! i ⋅a η"
         using A_eq by simp
      then show "(As0' ⋅al η) ! i = As ! i"
        using As0'_As length As0' = n a by auto
    qed
  qed

  interpret selection
    by (rule select)

  have "S DA0'  η = S_M S M DA"
    using S DA0'  η0' = S_M S M DA η_p S.S_selects_subseteq by auto

  from η_p have η_p_CAs0': "i < n. (CAs0' ! i)  (ηs0' ! i) = (CAs0'! i)  η"
    using n by auto
  then have "CAs0' ⋅⋅cl ηs0' = CAs0' ⋅cl η"
    using n by (auto intro: nth_equalityI)
  then have CAs0'_η_fo_CAs: "CAs0' ⋅cl η = CAs"
    using CAs0'_CAs η_p n by auto

  from η_p have "i < n. S (CAs0' ! i)  ηs0' ! i = S (CAs0' ! i)  η"
    using S.S_selects_subseteq n by auto
  then have "map S CAs0' ⋅⋅cl ηs0' = map S CAs0' ⋅cl η"
    using n by (auto intro: nth_equalityI)
  then have SCAs0'_η_fo_SMCAs: "map S CAs0' ⋅cl η = map (S_M S M) CAs"
    using map S CAs0' ⋅⋅cl ηs0' = map (S_M S M) CAs by auto

  have "Cs0' ⋅cl η = Cs"
  proof (rule nth_equalityI)
    show "length (Cs0' ⋅cl η) = length Cs"
      using n by auto
  next
    fix i
    show "i<length (Cs0' ⋅cl η)  (Cs0' ⋅cl η) ! i = Cs ! i"
    proof -
      assume "i < length (Cs0' ⋅cl η)"
      then have a: "i < n"
        using n by force
      have "(Cs0' ⋅⋅cl ηs0') ! i = Cs ! i"
        using Cs0'_Cs a n by force
      moreover
      have η_p_CAs0': "S. S ⊆# CAs0' ! i  S  ηs0' ! i = S  η"
        using η_p a by force
      have "Cs0' ! i  ηs0' ! i = (Cs0' ⋅cl η) ! i"
        using η_p_CAs0' i<n. Cs0' ! i ⊆# CAs0' ! i a n by force
      then have "(Cs0' ⋅⋅cl ηs0') ! i = (Cs0' ⋅cl η) ! i "
        using a n by force
      ultimately show "(Cs0' ⋅cl η) ! i = Cs ! i"
        by auto
    qed
  qed

  have AAs0'_AAs: "AAs0' ⋅aml η = AAs"
  proof (rule nth_equalityI)
    show "length (AAs0' ⋅aml η) = length AAs"
      using n by auto
  next
    fix i
    show "i<length (AAs0' ⋅aml η)  (AAs0' ⋅aml η) ! i = AAs ! i"
    proof -
      assume a: "i < length (AAs0' ⋅aml η)"
      then have "i < n"
        using n by force
      then have "A. A  atms_of ((DA0' # CAs0') ! Suc i)  A ⋅a (η0' # ηs0') ! Suc i = A ⋅a η"
        using η_p_atm n by force
      then have A_eq: "A. A  atms_of (CAs0' ! i)  A ⋅a ηs0' ! i = A ⋅a η"
        by auto
      have AAs_CAs0': "A ∈# AAs0' ! i. A  atms_of (CAs0' ! i)"
        using AAs0'_in_atms_of_CAs0' unfolding atms_of_def
        using a n by force
      then have "AAs0' ! i ⋅am  ηs0' ! i = AAs0' ! i ⋅am η"
        unfolding subst_atm_mset_def using A_eq unfolding subst_atm_mset_def by auto
      then show "(AAs0' ⋅aml η) ! i = AAs ! i"
         using AAs0'_AAs length AAs0' = n length ηs0' = n a by auto
    qed
  qed

  ― ‹Obtain MGU and substitution›
  obtain τ φ where τφ:
    "Some τ = mgu (set_mset ` set (map2 add_mset As0' AAs0'))"
    "τ  φ = η  σ"
  proof -
    have uu: "is_unifiers σ (set_mset ` set (map2 add_mset (As0' ⋅al η) (AAs0' ⋅aml η)))"
      using mgu mgu_sound is_mgu_def unfolding AAs0' ⋅aml η = AAs using As0' ⋅al η = As by auto
    have ησuni: "is_unifiers (η  σ) (set_mset ` set (map2 add_mset As0' AAs0'))"
    proof -
      have "set_mset ` set (map2 add_mset As0' AAs0' ⋅aml η) =
        set_mset ` set (map2 add_mset As0' AAs0') ⋅ass η"
        unfolding subst_atmss_def subst_atm_mset_list_def using subst_atm_mset_def subst_atms_def
        by (simp add: image_image subst_atm_mset_def subst_atms_def)
      then have "is_unifiers σ (set_mset ` set (map2 add_mset As0' AAs0') ⋅ass η)"
        using uu by (auto simp: n map2_add_mset_map)
      then show ?thesis
        using is_unifiers_comp by auto
    qed
    then obtain τ where
      τ_p: "Some τ = mgu (set_mset ` set (map2 add_mset As0' AAs0'))"
      using mgu_complete
      by (metis (mono_tags, opaque_lifting) List.finite_set finite_imageI finite_set_mset image_iff)
    moreover then obtain φ where φ_p: "τ  φ = η  σ"
      by (metis (mono_tags, opaque_lifting) finite_set ησuni finite_imageI finite_set_mset image_iff
          mgu_sound set_mset_mset substitution_ops.is_mgu_def) (* should be simpler *)
    ultimately show thesis
      using that by auto
  qed

  ― ‹Lifting eligibility›
  have eligible0': "eligible S τ As0' (D0' + negs (mset As0'))"
  proof -
    have "S_M S M (D + negs (mset As)) = negs (mset As)  S_M S M (D + negs (mset As)) = {#} 
      length As = 1  maximal_wrt (As ! 0 ⋅a σ) ((D + negs (mset As))  σ)"
      using eligible unfolding eligible.simps by auto
    then show ?thesis
    proof
      assume "S_M S M (D + negs (mset As)) = negs (mset As)"
      then have "S_M S M (D + negs (mset As))  {#}"
        using n by force
      then have "S (D0' + negs (mset As0')) = negs (mset As0')"
        using as0' DA0'_split by auto
      then show ?thesis
        unfolding eligible.simps[simplified]  by auto
    next
      assume asm: "S_M S M (D + negs (mset As)) = {#}  length As = 1 
        maximal_wrt (As ! 0 ⋅a σ) ((D + negs (mset As))  σ)"
      then have "S (D0' + negs (mset As0')) = {#}"
        using D0'  η = D[symmetric] As0' ⋅al η = As[symmetric] S (DA0')  η = S_M S M (DA)
          da DA0'_split subst_cls_empty_iff by metis
      moreover from asm have l: "length As0' = 1"
        using As0' ⋅al η = As by auto
      moreover from asm have "maximal_wrt (As0' ! 0 ⋅a (τ  φ)) ((D0' + negs (mset As0'))  (τ  φ))"
        using As0' ⋅al η = As D0'  η = D using l τφ by auto
      then have "maximal_wrt (As0' ! 0 ⋅a τ ⋅a φ) ((D0' + negs (mset As0'))  τ  φ)"
        by auto
      then have "maximal_wrt (As0' ! 0 ⋅a τ) ((D0' + negs (mset As0'))  τ)"
        using maximal_wrt_subst by blast
      ultimately show ?thesis
        unfolding eligible.simps[simplified] by auto
    qed
  qed

  ― ‹Lifting maximality›
  have maximality: "i < n. strictly_maximal_wrt (As0' ! i ⋅a τ) (Cs0' ! i  τ)"
    (* Reformulate in list notation? *)
  proof -
    from str_max have "i < n. strictly_maximal_wrt ((As0' ⋅al η) ! i ⋅a σ) ((Cs0' ⋅cl η) ! i  σ)"
      using As0' ⋅al η = As  Cs0' ⋅cl η = Cs by simp
    then have "i < n. strictly_maximal_wrt (As0' ! i ⋅a (τ  φ)) (Cs0' ! i  (τ  φ))"
      using n τφ by simp
    then have "i < n. strictly_maximal_wrt (As0' ! i ⋅a τ ⋅a φ) (Cs0' ! i  τ  φ)"
      by auto
    then show "i < n. strictly_maximal_wrt (As0' ! i ⋅a τ) (Cs0' ! i  τ)"
      using strictly_maximal_wrt_subst τφ by blast
  qed

  ― ‹Lifting nothing being selected›
  have nothing_selected: "i < n. S (CAs0' ! i) = {#}"
  proof -
    have "i < n. (map S CAs0' ⋅cl η) ! i = map (S_M S M) CAs ! i"
      by (simp add: map S CAs0' ⋅cl η = map (S_M S M) CAs)
    then have "i < n. S (CAs0' ! i)  η = S_M S M (CAs ! i)"
      using n by auto
    then have "i < n. S (CAs0' ! i)   η = {#}"
      using sel_empt i < n.  S (CAs0' ! i)  η = S_M S M (CAs ! i) by auto
    then show "i < n. S (CAs0' ! i) = {#}"
      using subst_cls_empty_iff by blast
  qed

  ― ‹Lifting AAs0's non-emptiness›
  have "i < n. AAs0' ! i  {#}"
    using n aas_not_empt AAs0' ⋅aml η = AAs by auto

  ― ‹Resolve the lifted clauses›
  define E0' where
    "E0' = ((# (mset Cs0')) + D0')  τ"

  have res_e0': "ord_resolve S CAs0' DA0' AAs0' As0' τ E0'"
    using ord_resolve.intros[of CAs0' n Cs0' AAs0' As0' τ S D0',
      OF _ _ _ _ _ _ i < n. AAs0' ! i  {#} τφ(1) eligible0'
        i < n. strictly_maximal_wrt (As0' ! i ⋅a τ) (Cs0' ! i  τ) i < n. S (CAs0' ! i) = {#}]
    unfolding E0'_def using DA0'_split n i<n. CAs0' ! i = Cs0' ! i + poss (AAs0' ! i) by blast

  ― ‹Prove resolvent instantiates to ground resolvent›
  have e0'φe: "E0'  φ = E"
  proof -
    have "E0'  φ = ((# (mset Cs0')) + D0')  (τ  φ)"
      unfolding E0'_def by auto
    also have " = (# (mset Cs0') + D0')  (η  σ)"
      using τφ by auto
    also have " = (# (mset Cs) + D)  σ"
      using Cs0' ⋅cl η = Cs D0'  η = D by auto
    also have " = E"
      using e by auto
    finally show e0'φe: "E0'  φ = E"
      .
  qed

  ― ‹Replace @{term φ} with a true ground substitution›
  obtain η2 where
    ground_η2: "is_ground_subst η2" "E0'  η2 = E"
  proof -
    have "is_ground_cls_list CAs" "is_ground_cls DA"
      using grounding grounding_ground unfolding is_ground_cls_list_def by auto
    then have "is_ground_cls E"
      using res_e ground_resolvent_subset by (force intro: is_ground_cls_mono)
    then show thesis
      using that e0'φe make_ground_subst by auto
  qed

  have length CAs0 = length CAs
    using n by simp

  have length ηs0 = length CAs
    using n by simp

  ― ‹Wrap up the proof›
  have "ord_resolve S (CAs0 ⋅⋅cl ρs) (DA0  ρ) (AAs0 ⋅⋅aml ρs) (As0 ⋅al ρ) τ E0'"
    using res_e0' As0'_def ρ_def AAs0'_def ρs_def DA0'_def ρ_def CAs0'_def ρs_def by simp
  moreover have "i<n. poss (AAs0 ! i) ⊆# CAs0 ! i"
    using as0(19) by auto
  moreover have "negs (mset As0) ⊆# DA0"
    using local.as0(15) by auto
  ultimately have "ord_resolve_rename S CAs0 DA0 AAs0 As0 τ E0'"
    using ord_resolve_rename[of CAs0 n AAs0 As0 DA0 ρ ρs S τ E0'] ρ_def ρs_def n by auto
  then show thesis
    using that[of η0 ηs0 η2 CAs0 DA0] is_ground_subst η0 is_ground_subst_list ηs0
      is_ground_subst η2 CAs0 ⋅⋅cl ηs0 = CAs DA0  η0 = DA E0'  η2 = E DA0  M
      CA  set CAs0. CA  M length CAs0 = length CAs length ηs0 = length CAs
    by blast
qed

lemma ground_ord_resolve_ground:
  assumes
    select: "selection S" and
    CAs_p: "ground_resolution_with_selection.ord_resolve S CAs DA AAs As E" and
    ground_cas: "is_ground_cls_list CAs" and
    ground_da: "is_ground_cls DA"
  shows "is_ground_cls E"
proof -
  have a1: "atms_of E  (CA  set CAs. atms_of CA)  atms_of DA"
    using ground_resolution_with_selection.ord_resolve_atms_of_concl_subset[OF _ CAs_p]
      ground_resolution_with_selection.intro[OF select] by blast
  {
    fix L :: "'a literal"
    assume "L ∈# E"
    then have "atm_of L  atms_of E"
      by (meson atm_of_lit_in_atms_of)
    then have "is_ground_atm (atm_of L)"
      using a1 ground_cas ground_da is_ground_cls_imp_is_ground_atm is_ground_cls_list_def
      by auto
  }
  then show ?thesis
    unfolding is_ground_cls_def is_ground_lit_def by simp
qed

lemma ground_ord_resolve_imp_ord_resolve:
  assumes
    ground_da: is_ground_cls DA and
    ground_cas: is_ground_cls_list CAs and
    gr: "ground_resolution_with_selection S_G" and
    gr_res: ground_resolution_with_selection.ord_resolve S_G CAs DA AAs As E
  shows σ. ord_resolve S_G CAs DA AAs As σ E
proof (cases rule: ground_resolution_with_selection.ord_resolve.cases[OF gr gr_res])
  case (1 CAs n Cs AAs As D)
  note cas = this(1) and da = this(2) and aas = this(3) and as = this(4) and e = this(5) and
    cas_len = this(6) and cs_len = this(7) and aas_len = this(8) and as_len = this(9) and
    nz = this(10) and casi = this(11) and aas_not_empt = this(12) and as_aas = this(13) and
    eligibility = this(14) and str_max = this(15) and sel_empt = this(16)

  have len_aas_len_as: "length AAs = length As"
    using aas_len as_len by auto

  from as_aas have "i < n. A ∈# add_mset (As ! i) (AAs ! i). A = As ! i"
    by simp
  then have "i < n. card (set_mset (add_mset (As ! i) (AAs ! i)))  Suc 0"
    using all_the_same by metis
  then have "i < length AAs. card (set_mset (add_mset (As ! i) (AAs ! i)))  Suc 0"
    using aas_len by auto
  then have "AA  set (map2 add_mset As AAs). card (set_mset AA)  Suc 0"
    using set_map2_ex[of AAs As add_mset, OF len_aas_len_as] by auto
  then have "is_unifiers id_subst (set_mset ` set (map2 add_mset As AAs))"
    unfolding is_unifiers_def is_unifier_def by auto
  moreover have "finite (set_mset ` set (map2 add_mset As AAs))"
    by auto
  moreover have "AA  set_mset ` set (map2 add_mset As AAs). finite AA"
    by auto
  ultimately obtain σ where
    σ_p: "Some σ = mgu (set_mset ` set (map2 add_mset As AAs))"
    using mgu_complete by metis

  have ground_elig: "ground_resolution_with_selection.eligible S_G As (D + negs (mset As))"
    using eligibility by simp
  have ground_cs: "i < n. is_ground_cls (Cs ! i)"
    using cas cas_len cs_len casi ground_cas nth_mem unfolding is_ground_cls_list_def by force
  have ground_set_as: "is_ground_atms (set As)"
    using da ground_da by (metis atms_of_negs is_ground_cls_is_ground_atms_atms_of
        is_ground_cls_union set_mset_mset)
  then have ground_mset_as: "is_ground_atm_mset (mset As)"
    unfolding is_ground_atm_mset_def is_ground_atms_def by auto
  have ground_as: "is_ground_atm_list As"
    using ground_set_as is_ground_atm_list_def is_ground_atms_def by auto
  have ground_d: "is_ground_cls D"
    using ground_da da by simp

  from as_len nz have atms:
    "atms_of D  set As  {}"
    "finite (atms_of D  set As)"
    by auto
  then have "Max (atms_of D  set As)  atms_of D  set As"
    using Max_in by metis
  then have is_ground_Max: "is_ground_atm (Max (atms_of D  set As))"
    using ground_d ground_mset_as is_ground_cls_imp_is_ground_atm
    unfolding is_ground_atm_mset_def by auto

  have "maximal_wrt (Max (atms_of D  set As)) (D + negs (mset As))"
    unfolding maximal_wrt_def
    by clarsimp (metis atms Max_less_iff UnCI ground_d ground_set_as infinite_growing
        is_ground_Max is_ground_atms_def is_ground_cls_imp_is_ground_atm less_atm_ground)
  moreover have
    "Max (atms_of D  set As) ⋅a σ = Max (atms_of D  set As)" and
    "D  σ + negs (mset As ⋅am σ) = D + negs (mset As)"
    using ground_elig is_ground_Max ground_mset_as ground_d by auto
  ultimately have fo_elig: "eligible S_G σ As (D + negs (mset As))"
    using ground_elig unfolding ground_resolution_with_selection.eligible.simps[OF gr]
      ground_resolution_with_selection.maximal_wrt_def[OF gr] eligible.simps
    by auto

  have "i < n. strictly_maximal_wrt (As ! i) (Cs ! i)"
    using str_max[unfolded ground_resolution_with_selection.strictly_maximal_wrt_def[OF gr]]
      ground_as[unfolded is_ground_atm_list_def] ground_cs as_len less_atm_ground
    unfolding strictly_maximal_wrt_def by clarsimp (fastforce simp: is_ground_cls_as_atms)+
  then have ll: "i < n. strictly_maximal_wrt (As ! i ⋅a σ) (Cs ! i  σ)"
    by (simp add: ground_as ground_cs as_len)

  have ground_e: "is_ground_cls E"
    using ground_d ground_cs cs_len unfolding e is_ground_cls_def
    by simp (metis in_mset_sum_list2 in_set_conv_nth)

  show ?thesis
    using cas da aas as e ground_e ord_resolve.intros[OF cas_len cs_len aas_len as_len nz casi
        aas_not_empt σ_p fo_elig ll sel_empt]
    by auto
qed

end

end