Theory First_Order_Ordering

theory First_Order_Ordering
  imports 
    First_Order_Clause
    Ground_Ordering
    Relation_Extra
begin

context ground_ordering
begin

lemmas lesslG_transitive_on = literal_order.transp_on_less
lemmas lesslG_asymmetric_on = literal_order.asymp_on_less
lemmas lesslG_total_on = literal_order.totalp_on_less

lemmas lesscG_transitive_on = clause_order.transp_on_less
lemmas lesscG_asymmetric_on = clause_order.asymp_on_less
lemmas lesscG_total_on = clause_order.totalp_on_less

lemmas is_maximal_lit_def = is_maximal_in_mset_wrt_iff[OF lesslG_transitive_on lesslG_asymmetric_on]
lemmas is_strictly_maximal_lit_def = 
  is_strictly_maximal_in_mset_wrt_iff[OF lesslG_transitive_on lesslG_asymmetric_on]

end

section ‹First order ordering›

locale first_order_ordering = term_ordering_lifting lesst
  for
    lesst :: "('f, 'v) term  ('f, 'v) term  bool" (infix "t" 50) +
  assumes
    lesst_total_on [intro]: "totalp_on {term. term.is_ground term} (≺t)" and
    lesst_wellfounded_on: "wfp_on {term. term.is_ground term} (≺t)" and    
    lesst_ground_context_compatible:
      "context term1 term2. 
        term1 t term2 
        term.is_ground term1  
        term.is_ground term2  
        context.is_ground context 
        contextterm1 t contextterm2" and
    lesst_ground_subst_stability: 
      "term1 term2 (γ :: 'v  ('f, 'v) term). 
        term.is_ground (term1 ⋅t γ) 
        term.is_ground (term2 ⋅t γ) 
        term1 t term2 
        term1 ⋅t γ t term2 ⋅t γ" and
    lesst_ground_subterm_property: 
      "termG contextG.
         term.is_ground termG 
         context.is_ground contextG  
         contextG    
         termG t contextGtermG"
begin

lemmas lesst_transitive = transp_less_trm 
lemmas lesst_asymmetric = asymp_less_trm


subsection ‹Definitions›

abbreviation less_eqt (infix "t" 50) where
  "less_eqt  (≺t)=="

definition lesstG :: "'f ground_term  'f ground_term  bool" (infix "tG" 50) where
  "termG1 tG termG2  term.from_ground termG1 t term.from_ground termG2"

notation less_lit (infix "l" 50)
notation less_cls (infix "c" 50)

lemma
  assumes
    L_in: "L ∈# C" and
    subst_stability: "L K. L l K  (L ⋅l σ) l (K ⋅l σ)" and
    Lσ_max_in_Cσ: "literal_order.is_maximal_in_mset (C  σ) (L ⋅l σ)"
  shows "literal_order.is_maximal_in_mset C L"
proof -
  have Lσ_in: "L ⋅l σ ∈# C  σ" and Lσ_max: "y∈#C  σ. y  L ⋅l σ  ¬ L ⋅l σ l y"
    using Lσ_max_in_Cσ
    unfolding atomize_conj literal_order.is_maximal_in_mset_iff
    by argo

  show "literal_order.is_maximal_in_mset C L"
    unfolding literal_order.is_maximal_in_mset_iff
  proof (intro conjI ballI impI)
    show "L ∈# C"
      using L_in .
  next
    show "y. y ∈# C  y  L  ¬ L l y"
      using subst_stability
      by (metis Lσ_max clause.subst_in_to_set_subst literal_order.order.strict_iff_order)
  qed
qed

lemmas lessl_def = less_lit_def
lemmas lessc_def = less_cls_def

abbreviation less_eql (infix "l" 50) where
  "less_eql  (≺l)=="

abbreviation less_eqc (infix "c" 50) where
  "less_eqc  (≺c)=="

abbreviation is_maximall :: 
  "('f, 'v) atom literal  ('f, 'v) atom clause  bool" where
  "is_maximall literal clause  is_maximal_in_mset_wrt (≺l) clause literal"

abbreviation is_strictly_maximall :: 
  "('f, 'v) atom literal  ('f, 'v) atom clause  bool" where
  "is_strictly_maximall literal clause  is_strictly_maximal_in_mset_wrt (≺l) clause literal"


subsection ‹Term ordering›

lemmas lesst_asymmetric_on = term_order.asymp_on_less
lemmas lesst_irreflexive_on = term_order.irreflp_on_less
lemmas lesst_transitive_on = term_order.transp_on_less

lemma lesst_wellfounded_on': "Wellfounded.wfp_on (term.from_ground ` termsG) (≺t)"
proof (rule Wellfounded.wfp_on_subset)
  show "Wellfounded.wfp_on {term. term.is_ground term} (≺t)"
    using lesst_wellfounded_on .
next
  show "term.from_ground ` termsG  {term. term.is_ground term}"
    by force
qed

lemma lesst_total_on': "totalp_on (term.from_ground ` termsG) (≺t)"
  using lesst_total_on
  by (simp add: totalp_on_def)

lemma lesstG_wellfounded: "wfp (≺tG)"
proof -
  have "Wellfounded.wfp_on (range term.from_ground) (≺t)"
    using lesst_wellfounded_on' by metis
  hence "wfp (λtermG1 termG2. term.from_ground termG1 t term.from_ground termG2)"
    unfolding Wellfounded.wfp_on_image[symmetric] .
  thus "wfp (≺tG)"
    unfolding lesstG_def .
qed

subsection ‹Ground term ordering›

lemma lesstG_asymmetric [intro]: "asymp (≺tG)"
  by (simp add: wfp_imp_asymp lesstG_wellfounded)

lemmas lesstG_asymmetric_on = lesstG_asymmetric[THEN asymp_on_subset, OF subset_UNIV]

lemma lesstG_transitive [intro]: "transp (≺tG)"
  using lesstG_def lesst_transitive transpE transpI
  by (metis (full_types))

lemmas lesstG_transitive_on = lesstG_transitive[THEN transp_on_subset, OF subset_UNIV]

lemma lesstG_total [intro]: "totalp (≺tG)"
  unfolding lesstG_def
  using totalp_on_image[OF inj_term_of_gterm] lesst_total_on'
  by blast

lemmas lesstG_total_on = lesstG_total[THEN totalp_on_subset, OF subset_UNIV]

lemma lesstG_context_compatible [simp]: 
  assumes "term1 tG term2"  
  shows "contextterm1G tG contextterm2G"
  using assms lesst_ground_context_compatible
  unfolding lesstG_def
  by (metis context.ground_is_ground term.ground_is_ground ground_term_with_context(3)) 

lemma lesstG_subterm_property [simp]: 
  assumes "context  G" 
  shows "term tG contexttermG"
  using 
    assms
    lesst_ground_subterm_property[OF term.ground_is_ground context.ground_is_ground] 
    context_from_ground_hole
  unfolding lesstG_def ground_term_with_context(3)  
  by blast

lemma lesst_lesstG [clause_simp]: 
  assumes "term.is_ground term1" and "term.is_ground term2"
  shows "term1 t term2  term.to_ground term1 tG term.to_ground term2"
  by (simp add: assms lesstG_def)

lemma less_eqt_ground_subst_stability:
  assumes "term.is_ground (term1 ⋅t γ)" "term.is_ground (term2 ⋅t γ)"  "term1 t term2"
  shows "term1 ⋅t γ t term2 ⋅t γ"
  using lesst_ground_subst_stability[OF assms(1, 2)] assms(3)
  by auto

subsection ‹Literal ordering›

lemmas lessl_asymmetric [intro] = literal_order.asymp_on_less[of UNIV]
lemmas lessl_asymmetric_on [intro] = literal_order.asymp_on_less

lemmas lessl_transitive [intro] = literal_order.transp_on_less[of UNIV]
lemmas lessl_transitive_on = literal_order.transp_on_less
                                                            
lemmas is_maximall_def = is_maximal_in_mset_wrt_iff[OF lessl_transitive_on lessl_asymmetric_on]

lemmas is_strictly_maximall_def =
  is_strictly_maximal_in_mset_wrt_iff[OF lessl_transitive_on lessl_asymmetric_on]

lemmas is_maximall_if_is_strictly_maximall =
  is_maximal_in_mset_wrt_if_is_strictly_maximal_in_mset_wrt[OF 
    lessl_transitive_on lessl_asymmetric_on
  ]

lemma lessl_ground_subst_stability: 
  assumes 
    "literal.is_ground (literal ⋅l γ)" 
    "literal.is_ground (literal' ⋅l γ)" 
  shows "literal l literal'  literal ⋅l γ l literal' ⋅l γ"
  unfolding lessl_def mset_mset_lit_subst[symmetric]
proof (elim multp_map_strong[rotated -1])
  show "monotone_on (set_mset (mset_lit literal + mset_lit literal')) (≺t) (≺t) (λterm. term ⋅t γ)"
    by (rule monotone_onI)
      (metis assms(1,2) lesst_ground_subst_stability ground_term_in_ground_literal_subst union_iff)
qed (use lesst_asymmetric lesst_transitive in simp_all)

lemma maximall_in_clause:
  assumes "is_maximall literal clause"
  shows "literal ∈# clause"
  using assms 
  unfolding is_maximall_def
  by(rule conjunct1)

lemma strictly_maximall_in_clause:
  assumes "is_strictly_maximall literal clause"
  shows "literal ∈# clause"
  using assms 
  unfolding is_strictly_maximall_def
  by(rule conjunct1)

subsection ‹Clause ordering›

lemmas lessc_asymmetric [intro] = clause_order.asymp_on_less[of UNIV]
lemmas lessc_asymmetric_on [intro] = clause_order.asymp_on_less
lemmas lessc_transitive [intro] = clause_order.transp_on_less[of UNIV]
lemmas lessc_transitive_on [intro] = clause_order.transp_on_less

lemma lessc_ground_subst_stability: 
  assumes 
    "clause.is_ground (clause  γ)" 
    "clause.is_ground (clause'  γ)" 
  shows "clause c clause'  clause  γ c clause'  γ"
  unfolding clause.subst_def lessc_def
proof (elim multp_map_strong[rotated -1])
  show "monotone_on (set_mset (clause + clause')) (≺l) (≺l) (λliteral. literal ⋅l γ)"
    by (rule monotone_onI)
      (metis assms(1,2) clause.to_set_is_ground_subst lessl_ground_subst_stability union_iff)
qed (use lessl_asymmetric lessl_transitive in simp_all)

subsection ‹Grounding›

sublocale ground: ground_ordering "(≺tG)" 
  apply unfold_locales
  by(simp_all add: lesstG_transitive lesstG_asymmetric lesstG_wellfounded lesstG_total)

notation ground.less_lit (infix "lG" 50)
notation ground.less_cls (infix "cG" 50)

notation ground.lesseq_trm (infix "tG" 50)
notation ground.lesseq_lit (infix "lG" 50)
notation ground.lesseq_cls (infix "cG" 50)

lemma not_less_eqtG: "¬ termG2 tG termG1  termG1 tG termG2"
  using ground.term_order.not_le .

lemma less_eqt_less_eqtG:
  assumes "term.is_ground term1" and "term.is_ground term2" 
  shows "term1 t term2  term.to_ground term1 tG term.to_ground term2"
  unfolding reflclp_iff lesst_lesstG[OF assms]
  using assms[THEN term.to_ground_inverse]
  by auto

lemma less_eqtG_less_eqt:
   "termG1 tG termG2  term.from_ground termG1 t term.from_ground termG2"
  unfolding 
    less_eqt_less_eqtG[OF term.ground_is_ground term.ground_is_ground] 
    term.from_ground_inverse
  ..

lemma not_less_eqt: 
  assumes "term.is_ground term1" and "term.is_ground term2"
  shows "¬ term2 t term1  term1 t term2"
  unfolding lesst_lesstG[OF assms] less_eqt_less_eqtG[OF assms(2, 1)] not_less_eqtG
  ..

lemma lesslG_lessl: 
  "literalG1 lG literalG2  literal.from_ground literalG1 l literal.from_ground literalG2"
  unfolding lessl_def ground.less_lit_def lesstG_def mset_literal_from_ground
  using
     multp_image_mset_image_msetI[OF _ lesst_transitive]
     multp_image_mset_image_msetD[OF _ lesst_transitive_on term.inj_from_ground]
   by blast

lemma lessl_lesslG: 
  assumes "literal.is_ground literal1" "literal.is_ground literal2" 
  shows "literal1 l literal2  literal.to_ground literal1 lG literal.to_ground literal2"
  using assms
  by (simp add: lesslG_lessl)

lemma less_eql_less_eqlG:
  assumes "literal.is_ground literal1" and "literal.is_ground literal2" 
  shows "literal1 l literal2  literal.to_ground literal1 lG literal.to_ground literal2"
  unfolding reflclp_iff lessl_lesslG[OF assms]
  using assms[THEN literal.to_ground_inverse]
  by auto

lemma less_eqlG_less_eql:
   "literalG1 lG literalG2  literal.from_ground literalG1 l literal.from_ground literalG2"
  unfolding 
    less_eql_less_eqlG[OF literal.ground_is_ground literal.ground_is_ground] 
    literal.from_ground_inverse
  ..

lemma maximal_lit_in_clause:
  assumes "ground.is_maximal_lit literalG clauseG"
  shows "literalG ∈# clauseG"
  using assms 
  unfolding ground.is_maximal_lit_def
  by(rule conjunct1)

lemma is_maximall_empty [simp]: 
  assumes "is_maximall literal {#}"  
  shows False
  using assms maximall_in_clause
  by fastforce

lemma is_strictly_maximall_empty [simp]: 
  assumes "is_strictly_maximall literal {#}"  
  shows False
  using assms strictly_maximall_in_clause
  by fastforce

lemma is_maximal_lit_iff_is_maximall: 
  "ground.is_maximal_lit literalG clauseG  
    is_maximall (literal.from_ground literalG) (clause.from_ground clauseG)"
   unfolding 
    is_maximall_def
    ground.is_maximal_lit_def
    clause.ground_sub_in_ground[symmetric]
   using 
     lessl_lesslG[OF literal.ground_is_ground clause.sub_in_ground_is_ground] 
     clause.sub_in_ground_is_ground
     clause.ground_sub_in_ground
   by (metis literal.to_ground_inverse literal.from_ground_inverse)

lemma is_strictly_maximalGl_iff_is_strictly_maximall:
  "ground.is_strictly_maximal_lit literalG clauseG 
     is_strictly_maximall (literal.from_ground literalG) (clause.from_ground clauseG)"
  unfolding 
    is_strictly_maximal_in_mset_wrt_iff_is_greatest_in_mset_wrt[OF 
      ground.lesslG_transitive_on ground.lesslG_asymmetric_on ground.lesslG_total_on, symmetric
    ]
    ground.is_strictly_maximal_lit_def
    is_strictly_maximall_def
    clause.ground_sub_in_ground[symmetric]
    remove1_mset_literal_from_ground
    clause.ground_sub
    less_eqlG_less_eql
  ..
 
lemma not_less_eqlG: "¬ literalG2 lG literalG1  literalG1 lG literalG2"
  using asympD[OF ground.lesslG_asymmetric_on] totalpD[OF ground.lesslG_total_on]
  by blast

lemma not_less_eql: 
  assumes "literal.is_ground literal1" and "literal.is_ground literal2"
  shows "¬ literal2 l literal1  literal1 l literal2"
  unfolding lessl_lesslG[OF assms] less_eql_less_eqlG[OF assms(2, 1)] not_less_eqlG
  ..

lemma lesscG_lessc: 
  "clauseG1 cG clauseG2  clause.from_ground clauseG1 c clause.from_ground clauseG2"
proof (rule iffI)
  show "clauseG1 cG clauseG2  clause.from_ground clauseG1 c clause.from_ground clauseG2"
    unfolding lessc_def
    by (auto simp: clause.from_ground_def ground.less_cls_def lesslG_lessl
        intro!: multp_image_mset_image_msetI elim: multp_mono_strong)
next
  have "transp (λx y. literal.from_ground x l literal.from_ground y)"
    by (metis (no_types, lifting) literal_order.less_trans transpI)
  thus "clause.from_ground clauseG1 c clause.from_ground clauseG2  clauseG1 cG clauseG2"
    unfolding ground.less_cls_def clause.from_ground_def lessc_def
    by (auto simp: lesslG_lessl
        dest!: multp_image_mset_image_msetD[OF _ lessl_transitive literal.inj_from_ground]
        elim!: multp_mono_strong)
qed

lemma lessc_lesscG: 
  assumes "clause.is_ground clause1" "clause.is_ground clause2"
  shows "clause1 c clause2  clause.to_ground clause1 cG  clause.to_ground clause2"
  using assms
  by (simp add: lesscG_lessc)

lemma less_eqc_less_eqcG:
  assumes "clause.is_ground clause1" and "clause.is_ground clause2" 
  shows "clause1 c clause2  clause.to_ground clause1 cG clause.to_ground clause2"
  unfolding reflclp_iff lessc_lesscG[OF assms]
  using assms[THEN clause.to_ground_inverse]
  by fastforce

lemma less_eqcG_less_eqc:
   "clauseG1 cG clauseG2  clause.from_ground clauseG1 c clause.from_ground clauseG2"
  unfolding 
    less_eqc_less_eqcG[OF clause.ground_is_ground clause.ground_is_ground] 
    clause.from_ground_inverse
  ..

lemma not_less_eqcG: "¬ clauseG2 cG clauseG1  clauseG1 cG clauseG2"
  using asympD[OF ground.lesscG_asymmetric_on] totalpD[OF ground.lesscG_total_on]
  by blast

lemma not_less_eqc: 
  assumes "clause.is_ground clause1" and "clause.is_ground clause2"
  shows "¬ clause2 c clause1  clause1 c clause2"
  unfolding lessc_lesscG[OF assms] less_eqc_less_eqcG[OF assms(2, 1)] not_less_eqcG
  ..

lemma lesst_ground_context_compatible':
  assumes 
    "context.is_ground context" 
    "term.is_ground term" 
    "term.is_ground term'" 
    "contextterm t contextterm'"
  shows "term t term'"
  using assms 
  by (metis lesst_ground_context_compatible not_less_eqt term_order.dual_order.asym 
        term_order.order.not_eq_order_implies_strict)
  

lemma lesst_ground_context_compatible_iff:
   assumes 
    "context.is_ground context" 
    "term.is_ground term" 
    "term.is_ground term'" 
  shows "contextterm t contextterm'  term t term'"
  using assms lesst_ground_context_compatible lesst_ground_context_compatible'
  by blast

subsection ‹Stability under ground substitution›

lemma lesst_less_eqt_ground_subst_stability:
  assumes 
    "term.is_ground (term1 ⋅t γ)"
    "term.is_ground (term2 ⋅t γ)"
    "term1 ⋅t γ t term2 ⋅t γ"
  shows
    "¬ term2 t term1"
proof
  assume assumption: "term2 t term1"

  have "term2 ⋅t γ t term1 ⋅t γ"
    using less_eqt_ground_subst_stability[OF 
            assms(2, 1)
            assumption
           ].

  then show False 
    using assms(3) by order
qed

lemma less_eql_ground_subst_stability:
  assumes   
    "literal.is_ground (literal1 ⋅l γ)" 
    "literal.is_ground (literal2 ⋅l γ)"  
    "literal1 l literal2"
  shows "literal1 ⋅l γ l literal2 ⋅l γ"
  using lessl_ground_subst_stability[OF assms(1, 2)] assms(3)
  by auto

lemma lessl_less_eql_ground_subst_stability: assumes 
  "literal.is_ground (literal1 ⋅l γ)"
  "literal.is_ground (literal2 ⋅l γ)"
  "literal1 ⋅l γ l literal2 ⋅l γ"
shows
  "¬ literal2 l literal1"
  by (meson assms less_eql_ground_subst_stability not_less_eql)

lemma less_eqc_ground_subst_stability:
  assumes   
    "clause.is_ground (clause1  γ)" 
    "clause.is_ground (clause2  γ)"  
    "clause1 c clause2"
  shows "clause1  γ c clause2  γ"
  using lessc_ground_subst_stability[OF assms(1, 2)] assms(3)
  by auto

lemma lessc_less_eqc_ground_subst_stability: assumes 
  "clause.is_ground (clause1  γ)"
  "clause.is_ground (clause2  γ)"
  "clause1  γ c clause2  γ"
shows
  "¬ clause2 c clause1"
  by (meson assms less_eqc_ground_subst_stability not_less_eqc)
  
lemma is_maximall_ground_subst_stability:
  assumes 
    clause_not_empty: "clause  {#}" and
    clause_grounding: "clause.is_ground (clause  γ)" 
  obtains literal
  where "is_maximall literal clause" "is_maximall (literal ⋅l γ) (clause  γ)"
proof-
  assume assumption: 
    "literal. is_maximall literal clause  is_maximall (literal ⋅l γ) (clause  γ)  thesis"

  from clause_not_empty 
  have clause_grounding_not_empty: "clause  γ  {#}"
    unfolding clause.subst_def
    by simp

  obtain literal where 
    literal: "literal ∈# clause" and
    literal_grounding_is_maximal: "is_maximall (literal ⋅l γ) (clause  γ)" 
    using
      ex_maximal_in_mset_wrt[OF lessl_transitive_on lessl_asymmetric_on clause_grounding_not_empty]  
      maximall_in_clause
    unfolding clause.subst_def
    by force

  from literal_grounding_is_maximal
  have no_bigger_than_literal: 
    "literal' ∈# clause  γ. literal'  literal ⋅l γ  ¬ literal ⋅l γ l literal'"
    unfolding is_maximall_def
    by simp

  show ?thesis
  proof(cases "is_maximall literal clause")
    case True
    with literal_grounding_is_maximal assumption show ?thesis
      by blast
  next
    case False
    then obtain literal' where 
      literal': "literal' ∈# clause" "literal l literal'" 
      unfolding is_maximall_def
      using literal
      by blast 

    note literals_in_clause = literal(1) literal'(1)
    note literals_grounding = literals_in_clause[THEN 
         clause.to_set_is_ground_subst[OF _ clause_grounding]
      ]

    have "literal ⋅l γ l literal' ⋅l γ"
      using lessl_ground_subst_stability[OF literals_grounding literal'(2)].
   
    then have False
     using 
       no_bigger_than_literal
       clause.subst_in_to_set_subst[OF literal'(1)] 
     by (metis asymp_onD lessl_asymmetric_on)
       
    then show ?thesis..
  qed
qed

lemma is_maximall_ground_subst_stability':
  assumes 
   "literal ∈# clause"
   "clause.is_ground (clause  γ)"
   "is_maximall (literal ⋅l γ) (clause  γ)"
 shows 
   "is_maximall literal clause"
proof(rule ccontr)
  assume "¬ is_maximall literal clause"
  
  then obtain literal' where literal':
      "literal l literal'" 
      "literal' ∈# clause "
  using assms(1)
  unfolding is_maximall_def
  by blast

  then have literal'_grounding: "literal.is_ground (literal' ⋅l γ)"
    using assms(2) clause.to_set_is_ground_subst by blast

  have literal_grounding: "literal.is_ground (literal ⋅l γ)"
    using assms(1) assms(2) clause.to_set_is_ground_subst by blast

  have literal_γ_in_premise: "literal' ⋅l γ ∈# clause  γ"
    using clause.subst_in_to_set_subst[OF literal'(2)]
    by simp
     
  have "literal ⋅l γ l literal' ⋅l γ"
    using lessl_ground_subst_stability[OF literal_grounding literal'_grounding literal'(1)].
  
  then have "¬ is_maximall (literal ⋅l γ) (clause  γ)"
    using literal_γ_in_premise 
    unfolding is_maximall_def literal.subst_comp_subst
    by (metis asympD lessl_asymmetric)
  
  then show False
    using assms(3)
    by blast
qed

lemma lessl_total_on [intro]: "totalp_on (literal.from_ground ` literalsG) (≺l)"
  by (smt (verit, best) image_iff lesslG_lessl totalpD ground.lesslG_total_on totalp_on_def)

lemmas lessl_total_on_set_mset =
  lessl_total_on[THEN totalp_on_subset, OF clause.to_set_from_ground[THEN equalityD1]]

lemma lessc_total_on: "totalp_on (clause.from_ground ` clauses) (≺c)"
  by (smt ground.clause_order.totalp_on_less image_iff lesscG_lessc totalpD totalp_onI)

lemma unique_maximal_in_ground_clause:
  assumes
    "clause.is_ground clause" 
    "is_maximall literal clause"
    "is_maximall literal' clause"
  shows
    "literal = literal'"
  using assms(2, 3)
  unfolding is_maximall_def
  by (metis assms(1) lessl_total_on_set_mset clause.to_ground_inverse totalp_onD)

lemma unique_strictly_maximal_in_ground_clause:
  assumes
    "clause.is_ground clause" 
    "is_strictly_maximall literal clause"
    "is_strictly_maximall literal' clause"
  shows
    "literal = literal'"
proof-
  note are_maximall = assms(2, 3)[THEN is_maximall_if_is_strictly_maximall]
   
  show ?thesis
    using unique_maximal_in_ground_clause[OF assms(1) are_maximall].
qed

lemma is_strictly_maximall_ground_subst_stability:
  assumes 
   clause_grounding: "clause.is_ground (clause  γ)" and
   ground_strictly_maximal: "is_strictly_maximall literalG (clause  γ)"
 obtains literal where 
   "is_strictly_maximall literal clause" "literal ⋅l γ = literalG"
proof-
  assume assumption: "literal. 
    is_strictly_maximall literal clause  literal ⋅l γ = literalG  thesis"

  have clause_grounding_not_empty: "clause  γ  {#}"
    using ground_strictly_maximal
    unfolding is_strictly_maximall_def
    by fastforce

  have literalG_in_clause_grounding: "literalG ∈# clause  γ"
    using ground_strictly_maximal is_strictly_maximall_def by blast

  obtain literal where literal: "literal ∈# clause" "literal ⋅l γ = literalG"
    by (smt (verit, best) clause.subst_def imageE literalG_in_clause_grounding multiset.set_map)

  show ?thesis
  proof(cases "is_strictly_maximall literal clause")
    case True
    then show ?thesis
      using assumption
      using literal(2) by blast
  next
    case False

    then obtain literal' where literal': 
      "literal' ∈# clause - {# literal #}"  
      "literal l literal'" 
      unfolding is_strictly_maximall_def
      using literal(1)
      by blast 

    note literal_grounding = 
       clause.to_set_is_ground_subst[OF literal(1) clause_grounding]

    have literal'_grounding: "literal.is_ground (literal' ⋅l γ)"
      using literal'(1) clause_grounding
      by (meson clause.to_set_is_ground_subst in_diffD)

    have "literal ⋅l γ l literal' ⋅l γ"
      using less_eql_ground_subst_stability[OF literal_grounding literal'_grounding literal'(2)].

    then have False
      using  clause.subst_in_to_set_subst[OF literal'(1)]  ground_strictly_maximal 
      unfolding 
        is_strictly_maximall_def 
        literal(2)[symmetric]
        subst_clause_remove1_mset[OF literal(1)]
      by blast
   
    then show ?thesis..
  qed
qed

lemma is_strictly_maximall_ground_subst_stability':
  assumes 
   "literal ∈# clause"
   "clause.is_ground (clause  γ)"
   "is_strictly_maximall (literal ⋅l γ) (clause  γ)"
 shows 
   "is_strictly_maximall literal clause"
  using 
    is_maximall_ground_subst_stability'[OF 
      assms(1,2) 
      is_maximall_if_is_strictly_maximall[OF assms(3)]
    ]
    assms(3)
  unfolding 
    is_strictly_maximall_def is_maximall_def
    subst_clause_remove1_mset[OF assms(1), symmetric]
  by (metis in_diffD clause.subst_in_to_set_subst reflclp_iff)

lemma lesst_lessl: 
  assumes "term1 t term2"
  shows 
    "term1  term3 l term2  term3"
    "term1 !≈ term3 l term2 !≈ term3"
  using assms
  unfolding lessl_def multp_eq_multpHO[OF lesst_asymmetric lesst_transitive] multpHO_def 
  by (auto simp: add_mset_eq_add_mset)

lemma lesst_lessl':
  assumes 
    "term  set_uprod (atm_of literal). term ⋅t σ' t term ⋅t σ"
    "term  set_uprod (atm_of literal). term ⋅t σ' t term ⋅t σ"
  shows "literal ⋅l σ' l literal ⋅l σ"
proof(cases literal)
  case (Pos atom)
  show ?thesis
  proof(cases atom)
    case (Upair term1 term2)
    have "term2 ⋅t σ' t term2 ⋅t σ  
          multp (≺t) {#term1 ⋅t σ, term2 ⋅t σ'#} {#term1 ⋅t σ, term2 ⋅t σ#}"
      using multp_add_mset'[of "(≺t)" "term2 ⋅t σ'"  "term2 ⋅t σ" "{#term1 ⋅t σ#}"] add_mset_commute
      by metis

    then show ?thesis 
      using assms
      unfolding lessl_def Pos subst_literal(1) Upair subst_atom
      by (auto simp: multp_add_mset multp_add_mset')
  qed
next
  case (Neg atom)
  show ?thesis
   proof(cases atom)
     case (Upair term1 term2)
     have "term2 ⋅t σ' t term2 ⋅t σ  
            multp (≺t) 
              {#term1 ⋅t σ, term1 ⋅t σ, term2 ⋅t σ', term2 ⋅t σ'#} 
              {#term1 ⋅t σ, term1 ⋅t σ, term2 ⋅t σ, term2 ⋅t σ#}"
       using multp_add_mset' multp_add_same[OF lesst_asymmetric lesst_transitive]
       by simp

     then show ?thesis 
      using assms
      unfolding lessl_def Neg subst_literal(2) Upair subst_atom
      by (auto simp: multp_add_mset multp_add_mset' add_mset_commute)
  qed
qed

lemmas lessc_add_mset = multp_add_mset_reflclp[OF lessl_asymmetric lessl_transitive, folded lessc_def] 

lemmas lessc_add_same = multp_add_same[OF lessl_asymmetric lessl_transitive, folded lessc_def]

lemma less_eql_less_eqc:
  assumes "literal ∈# clause. literal ⋅l σ' l literal ⋅l σ"
  shows "clause  σ' c clause  σ"
  using assms 
  by(induction clause)(clause_auto simp: lessc_add_same lessc_add_mset)
   
lemma lessl_lessc:
  assumes 
    "literal ∈# clause. literal ⋅l σ' l literal ⋅l σ"
    "literal ∈# clause. literal ⋅l σ' l literal ⋅l σ"
  shows "clause  σ' c clause  σ"
  using assms
proof(induction clause)
  case empty
  then show ?case by auto
next
  case (add literal clause)
  then have less_eq: "literal ∈# clause. literal ⋅l σ' l literal ⋅l σ"
    by (metis add_mset_remove_trivial in_diffD)

  show ?case 
  proof(cases "literal ⋅l σ' l literal ⋅l σ")
    case True
    moreover have "clause  σ' c clause  σ"
      using less_eql_less_eqc[OF less_eq].

    ultimately show ?thesis
      using lessc_add_mset
      unfolding subst_clause_add_mset lessc_def
      by blast
  next
    case False
    then have less: "literal ∈# clause. literal ⋅l σ' l literal ⋅l σ"
      using add.prems(2) by auto

   from False have eq: "literal ⋅l σ' = literal ⋅l σ"
      using add.prems(1) by force

   show ?thesis
     using add(1)[OF less_eq less] lessc_add_same
     unfolding subst_clause_add_mset eq lessc_def
     by blast
  qed
qed

subsection ‹Substitution update›

lemma lesst_subst_upd:
  fixes γ :: "('f, 'v) subst"
  assumes 
    update_is_ground: "term.is_ground update" and
    update_less: "update t γ var" and
    term_grounding: "term.is_ground (term ⋅t γ)" and
    var: "var  term.vars term"
  shows "term ⋅t γ(var := update) t term ⋅t γ"
  using assms(3, 4)
proof(induction "term")
  case Var
  then show ?case 
    using update_is_ground update_less
    by simp
next
  case (Fun f terms)

  then have "term  set terms. term ⋅t γ(var := update) t term ⋅t γ"
    by (metis eval_with_fresh_var is_ground_iff reflclp_iff term.set_intros(4))

  moreover then have "term  set terms. term ⋅t γ(var := update) t term ⋅t γ"
    using Fun assms(2)
    by (metis (full_types) fun_upd_same  term.distinct(1) term.sel(4) term.set_cases(2) 
          term_order.dual_order.strict_iff_order term_subst_eq_rev)

  ultimately show ?case
    using Fun(2, 3)
  proof(induction "filter (λterm. term ⋅t γ(var := update) t term ⋅t γ) terms" 
          arbitrary: terms)
    case Nil
    then show ?case
      unfolding empty_filter_conv
      by blast
  next
    case first: (Cons t ts)

    have update_grounding [simp]: "term.is_ground (t ⋅t γ(var := update))"
      using first.prems(3) update_is_ground first.hyps(2)
      by (metis (no_types, lifting) filter_eq_ConsD fun_upd_other fun_upd_same in_set_conv_decomp 
            is_ground_iff term.set_intros(4))

    then have t_grounding [simp]: "term.is_ground (t ⋅t γ)"
      using update_grounding Fun.prems(1,2)
      by (metis fun_upd_other is_ground_iff)
    
    show ?case
    proof(cases ts)
      case Nil
      then obtain ss1 ss2 where terms: "terms = ss1 @ t # ss2"
        using filter_eq_ConsD[OF first.hyps(2)[symmetric]]
        by blast

      have ss1: "term  set ss1. term ⋅t γ(var := update) = term ⋅t γ"
        using first.hyps(2) first.prems(1) 
        unfolding Nil terms
        by (smt (verit, del_insts) Un_iff append_Cons_eq_iff filter_empty_conv filter_eq_ConsD 
              set_append term_order.antisym_conv2)

      have ss2: "term  set ss2. term ⋅t γ(var := update) = term ⋅t γ"
        using first.hyps(2) first.prems(1) 
        unfolding Nil terms
        by (smt (verit, ccfv_SIG) Un_iff append_Cons_eq_iff filter_empty_conv filter_eq_ConsD 
              list.set_intros(2) set_append term_order.antisym_conv2)

      let ?context = "More f (map (λterm. (term ⋅t γ)) ss1)  (map (λterm. (term ⋅t γ)) ss2)"

      have 1: "term.is_ground (t ⋅t γ)"
        using terms first(5)
        by auto

      moreover then have "term.is_ground (t ⋅t γ(var := update))"
        by (metis assms(1) fun_upd_other fun_upd_same is_ground_iff)

      moreover have "context.is_ground ?context"
        using terms first(5)
        by auto

      moreover have "t ⋅t γ(var := update) t t ⋅t γ" 
        using first.hyps(2)
        by (meson Cons_eq_filterD)

      ultimately have "?contextt ⋅t γ(var := update) t ?contextt ⋅t γ"
        using lesst_ground_context_compatible
        by blast

      moreover have "Fun f terms ⋅t γ(var := update) = ?contextt ⋅t γ(var := update)"
        unfolding terms
        using ss1 ss2
        by simp

      moreover have "Fun f terms ⋅t γ = ?contextt ⋅t γ"
        unfolding terms
        by auto

      ultimately show ?thesis
        by argo
    next
      case (Cons t' ts')

      from first(2) 
      obtain ss1 ss2 where
        terms: "terms = ss1 @ t # ss2" and
        ss1: "sset ss1. ¬ s ⋅t γ(var := update) t s ⋅t γ" and
        less: "t ⋅t γ(var := update) t t ⋅t γ" and 
        ts: "ts = filter (λterm. term ⋅t γ(var := update)t term ⋅t γ) ss2"
        using Cons_eq_filter_iff[of t ts "(λterm. term ⋅t γ(var := update) t term ⋅t γ)"]
        by blast

      let ?terms' = "ss1 @ (t ⋅t γ(var := update))  # ss2"

      have [simp]: "t ⋅t γ(var := update) ⋅t γ = t ⋅t γ(var := update)"
        using first.prems(3) update_is_ground
        unfolding terms
        by (simp add: is_ground_iff)

      have [simp]: "t ⋅t γ(var := update) ⋅t γ(var := update) = t ⋅t γ(var := update)"
        using first.prems(3) update_is_ground
        unfolding terms
        by (simp add: is_ground_iff)

      have "ts = filter (λterm. term ⋅t γ(var := update) t term ⋅t γ) ?terms'" 
        using ss1 ts
        by auto
    
      moreover have "term  set ?terms'. term ⋅t γ(var := update) t term ⋅t γ"
        using first.prems(1)
        unfolding terms
        by simp
    
      moreover have "term  set ?terms'. term ⋅t γ(var := update) t term ⋅t γ"
        using calculation(1) Cons neq_Nil_conv by force

      moreover have terms'_grounding: "term.is_ground (Fun f ?terms' ⋅t γ)"
        using first.prems(3)
        unfolding terms
        by simp
       
      moreover have "var  term.vars (Fun f ?terms')"
        by (metis calculation(3) eval_with_fresh_var term.set_intros(4) term_order.less_irrefl)

      ultimately have less_terms': "Fun f ?terms' ⋅t γ(var := update) t Fun f ?terms' ⋅t γ"
        using first.hyps(1) first.prems(3) by blast

      have context_grounding: "context.is_ground (More f ss1  ss2 ⋅tc γ)"
        using terms'_grounding
        by auto

      have "Fun f (ss1 @ t ⋅t γ(var := update) # ss2) ⋅t γ t Fun f terms ⋅t γ"
        unfolding terms
        using lesst_ground_context_compatible[OF less _ _ context_grounding]
        by simp

      with less_terms' show ?thesis 
        unfolding terms 
        by auto
    qed
  qed
qed

lemma lessl_subst_upd:
  fixes γ :: "('f, 'v) subst"
  assumes 
    update_is_ground: "term.is_ground update" and
    update_less: "update t γ var" and
    literal_grounding: "literal.is_ground (literal ⋅l γ)" and
    var: "var  literal.vars literal"
  shows "literal ⋅l γ(var := update) l literal ⋅l γ"
proof-
  note lesst_subst_upd = lesst_subst_upd[of _ γ, OF update_is_ground update_less] 

  have all_ground_terms: "term  set_uprod (atm_of literal). term.is_ground (term ⋅t γ)"
    using assms(3)
    apply(cases literal)
    by (simp add: ground_term_in_ground_literal_subst)+
     
  then have 
    "term  set_uprod (atm_of literal). 
       var  term.vars term  term ⋅t γ(var := update) t term ⋅t γ"
    using lesst_subst_upd
    by blast

  moreover have
    "term  set_uprod (atm_of literal). 
       var  term.vars term  term ⋅t γ(var := update) = term ⋅t γ"
    by (meson eval_with_fresh_var)  

  ultimately have "term  set_uprod (atm_of literal). term ⋅t γ(var := update) t term ⋅t γ" 
    by blast

  moreover have "term  set_uprod (atm_of literal). term ⋅t γ(var := update) t term ⋅t γ"
    using update_less var lesst_subst_upd all_ground_terms
    unfolding literal.vars_def atom.vars_def set_literal_atm_of
    by blast

  ultimately show ?thesis
    using lesst_lessl'
    by blast
qed

lemma lessc_subst_upd:
  assumes 
    update_is_ground: "term.is_ground update" and
    update_less: "update t γ var" and
    literal_grounding: "clause.is_ground (clause  γ)" and
    var: "var  clause.vars clause"
  shows "clause  γ(var := update) c clause  γ"
proof-
  note lessl_subst_upd = lessl_subst_upd[of _ γ, OF update_is_ground update_less] 

  have all_ground_literals: "literal ∈# clause. literal.is_ground (literal ⋅l γ)"
    using clause.to_set_is_ground_subst[OF _ literal_grounding] by blast

  then have 
    "literal ∈# clause. 
      var  literal.vars literal  literal ⋅l γ(var := update) l literal ⋅l γ"
    using lessl_subst_upd
    by blast

  then have "literal ∈# clause. literal ⋅l γ(var := update) l literal ⋅l γ"
    by fastforce

  moreover have "literal ∈# clause. literal ⋅l γ(var := update) l literal ⋅l γ"
    using update_less var lessl_subst_upd all_ground_literals
    unfolding clause.vars_def
    by blast

  ultimately show ?thesis
    using lessl_lessc
    by blast
qed

end

end