Theory Ordered_Resolution_Completeness

theory Ordered_Resolution_Completeness
  imports
    Grounded_Ordered_Resolution
    Ground_Ordered_Resolution_Completeness
begin

section ‹Completeness›

context grounded_ordered_resolution_calculus
begin

subsection ‹Liftings›

lemma factoring_lifting:
  fixes
    DG CG :: "'tG clause" and
    D C :: "'t clause" and
    γ :: 'subst
  defines
    [simp]: "DG  clause.to_ground (D  γ)" and
    [simp]: "CG  clause.to_ground (C  γ)"
  assumes
    ground_factoring: "ground.factoring DG CG" and
    D_grounding: "clause.is_ground (D  γ)" and
    C_grounding: "clause.is_ground (C  γ)" and
    select: "clause.from_ground (selectG DG) = (select D)  γ" and
    type_preserving_γ: "type_preserving_on (clause.vars D) 𝒱 γ" and
    𝒱: "infinite_variables_per_type 𝒱"
  obtains C'
  where
    "factoring (𝒱, D) (𝒱, C')"
    "Infer [DG] CG  inference_ground_instances (Infer [(𝒱, D)] (𝒱, C'))"
    "C'  γ = C  γ"
  using ground_factoring
proof(cases DG CG rule: ground.factoring.cases)
  case ground_factoringI: (factoringI lG DG' tG)

  have "D  {#}"
    using ground_factoringI(3)
    by auto

  then obtain l1 where
    l1_is_maximal: "is_maximal l1 D" and
    l1_γ_is_maximal: "is_maximal (l1 ⋅l γ) (D  γ)"
    using that obtain_maximal_literal D_grounding
    by blast

  obtain t1 where
    l1: "l1 = (Pos t1)" and
    l1: "l1 ⋅l γ = (Pos (term.from_ground tG))" and
    t1: "t1 ⋅t γ = term.from_ground tG"
  proof-
    have "is_maximal (literal.from_ground lG) (D  γ)"
      using D_grounding ground_factoringI(2)
      by auto

    then have "l1 ⋅l γ = (Pos (term.from_ground tG))"
      unfolding ground_factoringI(4)
      using unique_maximal_in_ground_clause[OF D_grounding l1_γ_is_maximal]
      by simp

    then show ?thesis
      using that
      by (metis Neg_atm_of_iff clause_safe_unfolds(9) literal.collapse(1) literal.sel(1)
          subst_polarity_stable(2))
  qed

  obtain l2 D' where
    l2: "l2 ⋅l γ = Pos (term.from_ground tG)" and
    D: "D = add_mset l1 (add_mset l2 D')"
  proof-

    obtain D'' where D: "D = add_mset l1 D''"
      using maximal_in_clause[OF l1_is_maximal]
      by (meson multi_member_split)

    moreover have "D  γ = clause.from_ground (add_mset lG ( add_mset lG DG'))"
      using ground_factoringI(3) CG_def
      by (metis DG_def D_grounding clause.to_ground_inverse)

    ultimately have "D''  γ = add_mset (literal.from_ground lG) (clause.from_ground DG')"
      using l1
      by (simp add: ground_factoringI(4))

    then obtain l2 where "l2 ⋅l γ = Pos (term.from_ground tG)" "l2 ∈# D''"
      unfolding clause.subst_def ground_factoringI
      using msed_map_invR
      by force

    then show ?thesis
      using that
      unfolding D
      by (metis mset_add)
  qed

  then obtain t2 where
    l2: "l2 = (Pos t2)" and
    t2: "t2 ⋅t γ = term.from_ground tG"
    unfolding ground_factoringI(2)
    by (metis clause_safe_unfolds(9) is_pos_def literal.sel(1) subst_polarity_stable(2))

  have D'_γ: "D'  γ = clause.from_ground DG'"
    using D D_grounding ground_factoringI l1 l2
    by force

  obtain μ where
    type_preserving_μ: "type_preserving_on (clause.vars D) 𝒱 μ" and
    imgu: "term.is_imgu μ {{t1, t2}}"
  proof (rule obtain_type_preserving_on_imgu[OF _ that], intro conjI)

    show "t1 ⋅t γ = t2 ⋅t γ"
      using t1 t2 
      by argo
  next

    show "type_preserving_on (term.vars t1  term.vars t2) 𝒱 γ"
      using type_preserving_γ
      unfolding D l1 l2
      by auto
  qed

  obtain σ where γ: "γ = μ  σ"
    using term.obtain_imgu_absorption[of γ, OF _ imgu] t1 t2
    by auto

  let ?C'' = "add_mset l1 D'"
  let ?C' = "?C''  μ"

  show ?thesis
  proof(rule that)

    show factoring: "factoring (𝒱, D) (𝒱, ?C')"
    proof (rule factoringI; (rule D imgu type_preserving_μ refl 𝒱)?)

      show "select D = {#}"
        using ground_factoringI(1) select
        by simp
    next

      have "l1 ⋅l μ ∈# D  μ"
        using l1_is_maximal clause.subst_in_to_set_subst maximal_in_clause
        by blast

      then show "is_maximal (l1 ⋅l μ) (D  μ)"
        using is_maximal_if_grounding_is_maximal D_grounding l1_γ_is_maximal
        unfolding γ
        by auto       
    next

      show "D = add_mset l1 (add_mset (Pos t2) D')"
        unfolding D l2 ..
    next
      show "l1 = Pos t1"
        using l1 .
    qed

    show C'_γ: "?C'  γ = C  γ"
    proof-
      have "term.is_idem μ"
        using imgu
        unfolding term.is_imgu_iff_is_idem_and_is_mgu
        by blast

      then have μ_γ: "μ  γ = γ"
        unfolding γ term.is_idem_def term.assoc[symmetric]
        by argo

      have "C  γ = clause.from_ground (add_mset (Pos tG) DG')"
        using ground_factoringI(5) clause.to_ground_eq[OF C_grounding clause.ground_is_ground]
        unfolding CG_def
        by (metis clause.from_ground_inverse ground_factoringI(4))

      also have "... = ?C''  γ"
        using t1 D'_γ l1
        by auto

      also have "... = ?C'  γ"
        unfolding clause.subst_comp_subst[symmetric] μ_γ ..

      finally show ?thesis ..
    qed

    show "Infer [DG] CG  inference_ground_instances (Infer [(𝒱, D)] (𝒱, ?C'))"
    proof (rule is_inference_ground_instance_one_premise)
      show "is_inference_ground_instance_one_premise (𝒱, D) (𝒱, ?C') (Infer [DG] CG) γ"
      proof(unfold split, intro conjI; (rule refl 𝒱)?)

        show "inference.is_ground (Infer [D] ?C' ⋅ι γ)"
          using C_grounding D_grounding C'_γ
          by auto
      next

        show "Infer [DG] CG = inference.to_ground (Infer [D] ?C' ⋅ι γ)"
          using C'_γ
          by simp
      next

        have "clause.vars ?C'  clause.vars D"
          using clause.variables_in_base_imgu[OF imgu, of ?C'']
          unfolding D l1 l2
          by auto

        then show "type_preserving_on (clause.vars ?C') 𝒱 γ"
          using type_preserving_γ 
          by blast
      qed

      show "Infer [DG] CG  ground.G_Inf"
        unfolding ground.G_Inf_def
        using ground_factoring
        by blast
    qed
  qed
qed

lemma resolution_lifting:
  fixes 
    EG DG CG :: "'tG clause" and
    E D C :: "'t clause" and
    γ ρ1 ρ2 :: 'subst and
    𝒱1 𝒱2 :: "('v, 'ty) var_types"
  defines
    [simp]: "EG  clause.to_ground (E  ρ1  γ)" and
    [simp]: "DG  clause.to_ground (D  ρ2  γ)" and
    [simp]: "CG  clause.to_ground (C  γ)" and
    [simp]: "NG  ground_instances 𝒱1 E  ground_instances 𝒱2 D" and
    [simp]: "ιG  Infer [DG, EG] CG"
  assumes
    ground_resolution: "ground.resolution DG EG CG" and
    ρ1: "term.is_renaming ρ1" and
    ρ2: "term.is_renaming ρ2" and
    rename_apart: "clause.vars (E  ρ1)  clause.vars (D  ρ2) = {}" and
    E_grounding: "clause.is_ground (E  ρ1  γ)" and
    D_grounding: "clause.is_ground (D  ρ2  γ)" and
    C_grounding: "clause.is_ground (C  γ)" and
    select_from_E: "clause.from_ground (selectG EG) = (select E)  ρ1  γ" and
    select_from_D: "clause.from_ground (selectG DG) = (select D)  ρ2  γ" and
    type_preserving_ρ1: "type_preserving_on (clause.vars E) 𝒱1 (ρ1  γ)" and
    type_preserving_ρ2: "type_preserving_on (clause.vars D) 𝒱2 (ρ2  γ)" and
    type_preserving_ρ1: "type_preserving_on (clause.vars E) 𝒱1 ρ1" and
    type_preserving_ρ2: "type_preserving_on (clause.vars D) 𝒱2 ρ2" and
    𝒱1: "infinite_variables_per_type 𝒱1" and
    𝒱2: "infinite_variables_per_type 𝒱2"
  obtains C' 𝒱3
  where
    "resolution (𝒱2, D) (𝒱1, E) (𝒱3, C')"
    "ιG  inference_ground_instances (Infer [(𝒱2, D), (𝒱1, E)] (𝒱3, C'))"
    "C'  γ = C  γ"
  using ground_resolution
proof(cases DG EG CG rule: ground.resolution.cases)
  case ground_resolutionI: (resolutionI lG1 lG2 EG' DG' tG)

  have E_γ: "E  ρ1  γ = clause.from_ground (add_mset lG1 EG')"
    using ground_resolutionI(5)
    unfolding EG_def
    by (metis E_grounding clause.to_ground_inverse)

  have D_γ: "D  ρ2  γ = clause.from_ground (add_mset lG2 DG')"
    using ground_resolutionI(6) DG_def
    by (metis D_grounding clause.to_ground_inverse)

  let ?selectG_empty = "selectG (clause.to_ground (E  ρ1  γ)) = {#}"
  let ?selectG_not_empty = "selectG (clause.to_ground (E  ρ1  γ))  {#}"

  obtain l1 where
    l1: "l1 ⋅l ρ1  γ = literal.from_ground lG1" and
    l1_is_maximal: "?selectG_empty  is_maximal l1 E" and
    l1_γ_is_maximal: "?selectG_empty  is_maximal (l1 ⋅l ρ1  γ) (E  ρ1  γ)" and
    l1_selected: "?selectG_not_empty  is_maximal l1 (select E)" and
    l1_γ_selected: "?selectG_not_empty is_maximal (l1 ⋅l ρ1  γ) (select E  ρ1  γ)" and   
    l1_in_E: "l1 ∈# E"
  proof -
    have E_not_empty: "E  {#}"
      using ground_resolutionI(5)
      by auto

    then obtain max_l where
      "is_maximal max_l E" and
      is_max_in_E_γ: "is_maximal (max_l ⋅l ρ1  γ) (E  ρ1  γ)"
      using that E_grounding obtain_maximal_literal E_not_empty
      by blast

    moreover then have "max_l ∈# E" 
      unfolding is_maximal_def
      by blast

    moreover have "max_l ⋅l ρ1  γ = literal.from_ground lG1" if ?selectG_empty
    proof -
      have "ground_is_maximal lG1 EG"
        using ground_resolutionI(2) that
        unfolding is_maximal_def
        by simp

      then show ?thesis
        using unique_maximal_in_ground_clause[OF E_grounding is_max_in_E_γ] E_grounding
        unfolding ground_resolutionI(3)
        by simp
    qed

    moreover then obtain selected_l where
      "is_maximal selected_l (select E)"
      "is_maximal (selected_l ⋅l ρ1  γ) ((select E)  ρ1  γ)"
      "selected_l ⋅l ρ1  γ = literal.from_ground lG1"
    if ?selectG_not_empty
    proof -

      have "is_maximal (literal.from_ground lG1) (select E  ρ1  γ)"
        if ?selectG_not_empty
        using ground_resolutionI(2) that
        unfolding ground_resolutionI(3)
        by (metis EG_def select_from_E)

      then show ?thesis
        using
          that
          obtain_maximal_literal[OF _ select_ground_subst[OF E_grounding]]
          unique_maximal_in_ground_clause[OF select_ground_subst[OF E_grounding]]
        by (metis (no_types, lifting) clause.magma_subst_empty(1) is_maximal_not_empty)
    qed

    moreover then have "selected_l ∈# E" if ?selectG_not_empty
      using that maximal_in_clause mset_subset_eqD select_subset
      by meson

    ultimately show ?thesis
      using that ground_resolutionI
      by blast
  qed

  obtain E' where E: "E = add_mset l1 E'"
    by (meson l1_in_E multi_member_split)

  then have E'_γ: "E'  ρ1  γ = clause.from_ground EG'"
    using l1 E_γ
    by auto

  obtain t1 where 
    l1: "l1 = Neg t1" and
    t1: "t1 ⋅t ρ1  γ = term.from_ground tG"
    using l1 
    by (metis Neg_atm_of_iff literal_from_ground_atom_from_ground(1) clause_safe_unfolds(9)
        ground_resolutionI(7) literal.sel(2) subst_polarity_stable(2))

  obtain l2 where
    l2: "l2 ⋅l ρ2  γ = literal.from_ground lG2" and
    l2_is_strictly_maximal: "is_strictly_maximal l2 D"
  proof-
    have "is_strictly_maximal (literal.from_ground lG2) (D  ρ2  γ)"
      using ground_resolutionI(4) D_grounding
      by simp

    then show ?thesis
      using obtain_strictly_maximal_literal[OF D_grounding] that
      by force
  qed

  then have l2_in_D: "l2 ∈# D"
    using strictly_maximal_in_clause
    by blast

  from l2 have l2: "l2 ⋅l ρ2  γ = (Pos (term.from_ground tG))"
    unfolding ground_resolutionI
    by simp

  then obtain t2 where
    l2: "l2 = Pos t2" and
    t2: "t2 ⋅t ρ2  γ = term.from_ground tG"
    by (metis clause_safe_unfolds(9) literal.collapse(1) literal.disc(1) literal.sel(1) 
        subst_polarity_stable(2))

  obtain D' where D: "D = add_mset l2 D'"
    by (meson l2_in_D multi_member_split)

  then have D'_γ: "D'  ρ2  γ = clause.from_ground DG'"
    using D_γ l2
    unfolding ground_resolutionI
    by auto

  obtain 𝒱3 where
    𝒱3: "infinite_variables_per_type 𝒱3" and
    𝒱1_𝒱3: "xclause.vars E. 𝒱1 x = 𝒱3 (term.rename ρ1 x)" and
    𝒱2_𝒱3: "xclause.vars D. 𝒱2 x = 𝒱3 (term.rename ρ2 x)"
    using clause.obtain_merged_𝒱[OF ρ1 ρ2 rename_apart clause.finite_vars clause.finite_vars 
        infinite_UNIV] .

  have type_preserving_γ: "type_preserving_on (clause.vars (E  ρ1)  clause.vars (D  ρ2)) 𝒱3 γ"
  proof(unfold Set.ball_Un, intro conjI)

    show "type_preserving_on (clause.vars (E  ρ1)) 𝒱3 γ"
      using clause.renaming_grounding[OF ρ1 type_preserving_ρ1 E_grounding 𝒱1_𝒱3] .
  next

    show "type_preserving_on (clause.vars (D  ρ2)) 𝒱3 γ"
      using clause.renaming_grounding[OF ρ2 type_preserving_ρ2 D_grounding 𝒱2_𝒱3] .
  qed

  obtain μ where
    type_preserving_μ: "type_preserving_on (clause.vars (E  ρ1)  clause.vars (D  ρ2)) 𝒱3  μ" and
    imgu: "term.is_imgu μ {{t1 ⋅t ρ1, t2 ⋅t ρ2}}"
  proof (rule obtain_type_preserving_on_imgu[OF _ that], intro conjI)

    show "t1 ⋅t ρ1 ⋅t γ = t2 ⋅t ρ2 ⋅t γ"
      using t1 t2
      by simp
  next

    show "type_preserving_on (term.vars (t1 ⋅t ρ1)  term.vars (t2 ⋅t ρ2)) 𝒱3 γ"
      using type_preserving_γ
      unfolding E D l1 l2
      by auto
  qed

  obtain σ where γ: "γ = μ  σ"
    using term.obtain_imgu_absorption[of γ, OF _ imgu] t1 t2
    by auto

  define C' where
    C': "C' = (E'  ρ1 + D'  ρ2)  μ"

  show ?thesis
  proof(rule that)

    show resolution: "resolution (𝒱2, D) (𝒱1, E) (𝒱3, C')"
    proof (rule resolutionI; ((rule ρ1 ρ2 E D l1 l2 imgu type_preserving_μ rename_apart 
            type_preserving_ρ1 type_preserving_ρ2 𝒱1 𝒱2 C' 𝒱1_𝒱3 𝒱2_𝒱3)+)?)

      show "¬ E  ρ1  μ c D  ρ2  μ"
      proof(rule clause.order.ground_less_not_less_eq)

        show "clause.vars (D  ρ2  μ  σ) = {}"
          using D_grounding
          unfolding γ
          by simp

        show "clause.vars (E  ρ1  μ  σ) = {}"
          using E_grounding
          unfolding γ
          by simp

        show "D  ρ2  μ  σ c E  ρ1  μ  σ"
          using ground_resolutionI(1) D_grounding E_grounding
          unfolding EG_def DG_def clause.order.lessG_def γ
          by simp
      qed
    next
      assume "select E = {#}"

      moreover then have ?selectG_empty
        using is_maximal_not_empty l1_selected 
        by blast

      moreover have "l1 ⋅l ρ1  μ ∈# E  ρ1  μ"
        using l1_in_E
        by blast

      ultimately show "is_maximal (l1 ⋅l ρ1  μ) (E  ρ1  μ)"
        using l1_γ_is_maximal is_maximal_if_grounding_is_maximal E_grounding 
        unfolding γ
        by force
    next
      assume "select E  {#}"

      then have "¬?selectG_empty"
        using is_maximal_not_empty l1_selected select_from_E 
        by auto

      moreover have "l1 ⋅l ρ1  μ ∈# select E  ρ1  μ"
        using l1_selected maximal_in_clause calculation 
        by blast

      ultimately show "is_maximal (l1 ⋅l ρ1  μ) (select E  ρ1  μ)"
        using select_ground_subst[OF E_grounding] is_maximal_if_grounding_is_maximal l1_γ_selected
        unfolding γ
        by fastforce
    next

      show "select D = {#}"
        using ground_resolutionI(3) select_from_D 
        by fastforce
    next

      show "is_strictly_maximal (l2 ⋅l ρ2  μ) (D  ρ2  μ)"
      proof(rule is_strictly_maximal_if_grounding_is_strictly_maximal)

        show "l2 ⋅l ρ2  μ ∈# D  ρ2  μ"
          using l2_in_D
          by blast

        show "clause.is_ground (D  ρ2  μ  σ)"
          using D_grounding[unfolded γ]
          by simp

        show "is_strictly_maximal (l2 ⋅l ρ2  μ ⋅l σ) (D  ρ2  μ  σ)"
          using l2 D_γ ground_resolutionI(4)
          unfolding γ ground_resolutionI
          by fastforce
      qed
    qed

    show C'_γ: "C'  γ = C  γ"
    proof-

      have "term.is_idem μ"
        using imgu term.is_imgu_iff_is_idem_and_is_mgu
        by blast

      then have μ_γ: "μ  γ = γ"
        unfolding γ term.is_idem_def
        by (metis term.assoc)

      have "C  γ = (clause.from_ground EG' + clause.from_ground DG')"
        using ground_resolutionI(8, 9) clause.to_ground_inverse[OF C_grounding]
        by auto

      then show ?thesis
        unfolding
          C'
          E'_γ[symmetric]
          D'_γ[symmetric]
          clause.subst_comp_subst[symmetric]
          μ_γ
        by simp
    qed

    show "ιG  inference_ground_instances (Infer [(𝒱2, D), (𝒱1, E)] (𝒱3, C'))"
    proof (rule is_inference_ground_instance_two_premises)

      show "is_inference_ground_instance_two_premises (𝒱2, D) (𝒱1, E) (𝒱3, C') ιG γ ρ1 ρ2"
      proof(unfold split, intro conjI;
          (rule ρ1 ρ2 rename_apart refl 𝒱1 𝒱2 𝒱3)?)

        show "inference.is_ground (Infer [D  ρ2, E  ρ1] C' ⋅ι γ)"
          using D_grounding E_grounding C_grounding C'_γ
          by auto
      next

        show "ιG = inference.to_ground (Infer [D  ρ2, E  ρ1] C' ⋅ι γ)"
          using C'_γ
          by simp
      next

        show "type_preserving_on (clause.vars C') 𝒱3 γ"
        proof(rule type_preserving_on_subset[OF type_preserving_γ])

          show "clause.vars C'  clause.vars (E  ρ1)  clause.vars (D  ρ2)"
          proof (unfold subset_eq, intro ballI)
            fix x

            have is_imgu: "term.is_imgu μ {{t1 ⋅t ρ1, t2 ⋅t ρ2}}"
              using imgu
              by blast

            assume "x  clause.vars C'"

            then consider
              (E') "x  clause.vars (E'  ρ1  μ)" |
              (D') "x  clause.vars (D'  ρ2  μ)"
              unfolding C'
              by auto

            then show "x  clause.vars (E  ρ1)  clause.vars (D  ρ2)"
            proof cases
              case E'

              then show ?thesis
                using clause.variables_in_base_imgu[OF is_imgu]
                unfolding E l1 D l2
                by auto
            next
              case D'

              then show ?thesis
                using clause.variables_in_base_imgu[OF is_imgu]
                unfolding E l1 D l2
                by auto
            qed
          qed
        qed
      qed
      show "ιG  ground.G_Inf"
        unfolding ground.G_Inf_def
        using ground_resolution
        by simp
    qed
  qed
qed

subsection ‹Ground instances›

context
  fixes ιG N
  assumes
    subst_stability: "subst_stability_on N" and
    ιG_Inf_from: "ιG  ground.Inf_from_q selectG ((uncurried_ground_instances ` N))"
begin

lemma factoring_ground_instance:
  assumes ground_factoring: "ιG  ground.factoring_inferences"
  obtains ι where
    "ι  Inf_from N"
    "ιG  inference_ground_instances ι"
proof -

  obtain DG CG where
    ιG: "ιG = Infer [DG] CG" and
    ground_inference: "ground.factoring DG CG"
    using ground_factoring
    by blast

  have DG_in_groundings: "DG  (uncurried_ground_instances ` N)"
    using ιG_Inf_from
    unfolding ιG ground.Inf_from_q_def ground.Inf_from_def
    by simp

  obtain D γ 𝒱 where
    D_grounding: "clause.is_ground (D  γ)" and
    type_preserving_γ: "type_preserving_on (clause.vars D) 𝒱 γ" and
    𝒱: "infinite_variables_per_type 𝒱" and
    D_in_N: "(𝒱, D)  N" and
    "selectG DG = clause.to_ground (select D  γ)"
    "D  γ = clause.from_ground DG"
    using subst_stability[rule_format, OF DG_in_groundings]
    by blast

  then have
    DG: "DG = clause.to_ground (D  γ)" and
    select: "clause.from_ground (selectG DG) = select D  γ"
    by (simp_all add: select_ground_subst)

  obtain C where
    CG: "CG = clause.to_ground (C  γ)" and
    C_grounding: "clause.is_ground (C  γ)"
    by (metis clause.all_subst_ident_iff_ground clause.from_ground_inverse
        clause.ground_is_ground)

  obtain C' where
    factoring: "factoring (𝒱, D) (𝒱, C')" and
    inference_ground_instances: "ιG  inference_ground_instances (Infer [(𝒱, D)] (𝒱, C'))" and
    C'_C: "C'  γ = C  γ"
    using
      factoring_lifting[OF
        ground_inference[unfolded DG CG]
        D_grounding
        C_grounding
        select[unfolded DG]
        type_preserving_γ
        𝒱]
    unfolding DG CG ιG .

  let  = "Infer [(𝒱, D)] (𝒱, C')"

  show ?thesis
  proof(rule that[OF _ inference_ground_instances])

    show "  Inf_from N"
      using D_in_N factoring
      unfolding Inf_from_def inferences_def inference_system.Inf_from_def
      by auto
  qed
qed


lemma resolution_ground_instance:
  assumes ground_resolution: "ιG  ground.resolution_inferences"
  obtains ι where
    "ι  Inf_from N"
    "ιG  inference_ground_instances ι"
proof-
  obtain EG DG CG where
    ιG : "ιG = Infer [DG, EG] CG" and
    ground_resolution: "ground.resolution DG EG CG"
    using assms(1)
    by blast

  have
    EG_in_groundings: "EG   (uncurried_ground_instances ` N)" and
    DG_in_groundings: "DG   (uncurried_ground_instances ` N)"
    using ιG_Inf_from
    unfolding ιG ground.Inf_from_q_def ground.Inf_from_def
    by simp_all

  obtain E 𝒱1 γ1 where
    E_grounding: "clause.is_ground (E  γ1)" and
    type_preserving_γ1: "type_preserving_on (clause.vars E) 𝒱1 γ1" and
    𝒱1: "infinite_variables_per_type 𝒱1" and
    E_in_N: "(𝒱1, E)  N" and
    "selectG EG = clause.to_ground (select E  γ1)"
    "E  γ1 = clause.from_ground EG"
    using subst_stability[rule_format, OF EG_in_groundings]
    by blast

  then have
    EG: "EG = clause.to_ground (E  γ1)" and
    select_from_E: "clause.from_ground (selectG EG) = select E  γ1"
    by (simp_all add: select_ground_subst)

  obtain D 𝒱2 γ2 where
    D_grounding: "clause.is_ground (D  γ2)" and
    type_preserving_γ2: "type_preserving_on (clause.vars D) 𝒱2 γ2" and
    𝒱2: "infinite_variables_per_type 𝒱2" and
    D_in_N: "(𝒱2, D)  N" and
    "selectG DG = clause.to_ground (select D  γ2)"
    "D  γ2 = clause.from_ground DG"
    using subst_stability[rule_format, OF DG_in_groundings]
    by blast

  then have
    DG: "DG = clause.to_ground (D  γ2)" and
    select_from_D: "clause.from_ground (selectG DG) = select D  γ2"
    by (simp_all add: select_ground_subst)

  obtain ρ1 ρ2 γ where
    ρ1: "term.is_renaming ρ1" and
    ρ2: "term.is_renaming ρ2" and
    rename_apart: "clause.vars (E  ρ1)  clause.vars (D  ρ2) = {}" and
    type_preserving_ρ1: "type_preserving_on (clause.vars E) 𝒱1 ρ1" and
    type_preserving_ρ2: "type_preserving_on (clause.vars D) 𝒱2 ρ2" and
    γ1: "x  clause.vars E. x ⋅v γ1 = x ⋅v ρ1  γ" and
    γ2: "x  clause.vars D. x ⋅v γ2 = x ⋅v ρ2  γ"
    using clause.obtain_merged_grounding[OF
        type_preserving_γ1 type_preserving_γ2 E_grounding D_grounding 𝒱2 clause.finite_vars] .

  have E_grounding: "clause.is_ground (E  ρ1  γ)"
    using clause.subst_eq γ1 E_grounding
    by fastforce

  have EG: "EG = clause.to_ground (E  ρ1  γ)"
    using clause.subst_eq γ1 EG
    by fastforce

  have D_grounding: "clause.is_ground (D  ρ2  γ)"
    using clause.subst_eq γ2 D_grounding
    by fastforce

  have DG: "DG = clause.to_ground (D  ρ2  γ)"
    using clause.subst_eq γ2 DG
    by fastforce

  have type_preserving_ρ1: "type_preserving_on (clause.vars E) 𝒱1 (ρ1  γ)"
    using type_preserving_γ1 γ1
    by fastforce

  have type_preserving_ρ2: "type_preserving_on (clause.vars D) 𝒱2 (ρ2  γ)"
    using type_preserving_γ2 γ2
    by fastforce

  have select_from_E:
    "clause.from_ground (selectG (clause.to_ground (E  ρ1  γ))) = select E  ρ1  γ"
  proof-
    have "E  γ1 = E  ρ1  γ"
      using γ1 clause.subst_eq
      by fast

    moreover have "select E  γ1 = select E  ρ1  γ"
      using clause.subst_eq γ1 select_vars_subset
      by (metis (no_types, lifting) clause.comp_subst.left.monoid_action_compatibility in_mono)

    ultimately show ?thesis
      using select_from_E
      unfolding EG
      by simp
  qed

  have select_from_D:
    "clause.from_ground (selectG (clause.to_ground (D  ρ2  γ))) = select D  ρ2  γ"
  proof-
    have "D  γ2 = D  ρ2  γ"
      using γ2 clause.subst_eq
      by fast

    moreover have "select D  γ2 = select D  ρ2  γ"
      using clause.subst_eq γ2 select_vars_subset[of D]
      by (metis (no_types, lifting) clause.comp_subst.left.monoid_action_compatibility in_mono)

    ultimately show ?thesis
      using select_from_D
      unfolding DG
      by simp
  qed

  obtain C where
    C_grounding: "clause.is_ground (C  γ)" and
    CG: "CG = clause.to_ground (C  γ)"
    by (metis clause.all_subst_ident_if_ground clause.from_ground_inverse clause.ground_is_ground)

  have "ground_instances 𝒱1 E  ground_instances 𝒱2 D   (uncurried_ground_instances ` N)"
    using E_in_N D_in_N
    by force

  obtain C' 𝒱3 where
    resolution: "resolution (𝒱2, D) (𝒱1, E) (𝒱3, C')" and
    inference_groundings: "ιG  inference_ground_instances (Infer [(𝒱2, D), (𝒱1, E)] (𝒱3, C'))" and
    C'_γ_C_γ: "C'  γ = C  γ"
    using resolution_lifting[OF ground_resolution[unfolded EG DG CG]
        ρ1 ρ2
        rename_apart
        E_grounding D_grounding C_grounding 
        select_from_E select_from_D
        type_preserving_ρ1 type_preserving_ρ2
        type_preserving_ρ1 type_preserving_ρ2
        𝒱1 𝒱2]
    unfolding ιG CG EG DG .

  let  = "Infer [(𝒱2, D), (𝒱1, E)] (𝒱3, C')"

  show ?thesis
  proof(rule that[OF _ inference_groundings])

    show "  Inf_from N"
      using E_in_N D_in_N resolution
      unfolding Inf_from_def inferences_def inference_system.Inf_from_def
      by auto
  qed
qed

lemma ground_instances:
  obtains ι where
    "ι  Inf_from N"
    "ιG  inference_ground_instances ι"
proof -

  consider
    (resolution) "ιG  ground.resolution_inferences" |
    (factoring) "ιG  ground.factoring_inferences"
    using ιG_Inf_from
    unfolding
      ground.Inf_from_q_def
      ground.G_Inf_def
      inference_system.Inf_from_def
    by fastforce

  then show ?thesis
  proof cases
    case resolution

    then show ?thesis
      using that resolution_ground_instance
      by blast
  next
    case factoring

    then show ?thesis
      using that factoring_ground_instance
      by blast
  qed
qed

end

end

context ordered_resolution_calculus
begin

lemma overapproximation:
  obtains selectG where
    "ground_Inf_overapproximated selectG premises"
    "is_grounding selectG"
proof-
  obtain selectG where
    subst_stability: "select_subst_stability_on select selectG premises" and
    "is_grounding selectG"
    using obtain_subst_stable_on_select_grounding
    by blast

  then interpret grounded_ordered_resolution_calculus
    where selectG = selectG
    by unfold_locales

  show thesis
  proof(rule that[OF _ selectG])

    show "ground_Inf_overapproximated selectG premises"
      using ground_instances[OF subst_stability]
      by auto
  qed
qed

sublocale statically_complete_calculus "F" inferences entails_𝒢 Red_I_𝒢 Red_F_𝒢
proof (unfold static_empty_ord_inter_equiv_static_inter,
    rule stat_ref_comp_to_non_ground_fam_inter,
    rule ballI)
  fix selectG
  assume "selectG  selectGs"

  then interpret grounded_ordered_resolution_calculus
    where selectG = selectG
    by unfold_locales (simp add: selectGs_def)

  show "statically_complete_calculus
          ground.G_Bot
          ground.G_Inf
          ground.G_entails
          ground.Red_I
          ground.Red_F"
    by unfold_locales
next

  show "N. selectG  selectGs. ground_Inf_overapproximated selectG N"
    using overapproximation
    unfolding selectGs_def
    by (smt (verit, best) mem_Collect_eq)
qed

end

end