Theory First_Order_Clause.Nonground_Order_Generic
theory Nonground_Order_Generic
  imports
    Nonground_Clause_Generic
    Nonground_Term_Order
    Term_Order_Lifting
    Ground_Order_Generic
begin
section ‹Nonground Order›
locale nonground_order_lifting =
  grounding_lifting +
  order: ground_total_multiset_extension +
  order: ground_subst_stable_multiset_extension
locale nonground_term_based_order_lifting =
  "term": nonground_term +
  nonground_order_lifting where
  id_subst = Var 
for less⇩t
locale nonground_order_generic =
  "term": nonground_term where
  Var = "Var :: 'v ⇒ 't" and term_to_ground = "term_to_ground :: 't ⇒ 't⇩G" +
 
  nonground_clause_generic where
  atom_subst = atom_subst and atom_from_ground = atom_from_ground +
  restricted_term_order_lifting where
  pos_to_mset = pos_to_mset and restriction = "range term.from_ground" +
  clause: nonground_term_based_order_lifting where
  less = "(≺⇩l)" and sub_subst = literal.subst and sub_vars = literal.vars and
  sub_to_ground = literal.to_ground and sub_from_ground = literal.from_ground and
  map = image_mset and to_set = set_mset and to_ground_map = image_mset and
  from_ground_map = image_mset and ground_map = image_mset and to_set_ground = set_mset and
  to_mset = "λx. x" +
  "term": nonground_term_order +
  ground: atom_to_mset where pos_to_mset = ground_pos_to_mset and neg_to_mset = ground_neg_to_mset
for 
  pos_to_mset :: "'a ⇒ 't multiset" and 
  atom_subst :: "'a ⇒ ('v ⇒ 't) ⇒ 'a" and
  atom_from_ground :: "'a⇩G ⇒ 'a" and
  ground_pos_to_mset ground_neg_to_mset :: "'a⇩G ⇒ 't⇩G multiset" +
assumes
  ground_pos_to_mset:
  "⋀a. image_mset term.from_ground (ground_pos_to_mset a) = pos_to_mset (atom_from_ground a)" and
  ground_neg_to_mset:
  "⋀a. image_mset term.from_ground (ground_neg_to_mset a) = neg_to_mset (atom_from_ground a)"
begin
notation term.order.less⇩G (infix "≺⇩t⇩G" 50)
notation term.order.less_eq⇩G (infix "≼⇩t⇩G" 50)
notation clause.order.sub.less⇩G (infix "≺⇩l⇩G" 50)
notation clause.order.sub.less_eq⇩G (infix "≼⇩l⇩G" 50)
notation clause.order.less⇩G (infix "≺⇩c⇩G" 50)
notation clause.order.less_eq⇩G (infix "≼⇩c⇩G" 50)
lemma obtain_maximal_literal:
  assumes
    not_empty: "C ≠ {#}" and
    grounding: "clause.is_ground (C ⋅ γ)"
  obtains l
  where "is_maximal l C" "is_maximal (l ⋅l γ) (C ⋅ γ)"
proof-
  have grounding_not_empty: "C ⋅ γ ≠ {#}"
    using not_empty
    by simp
  obtain l where
    l_in_C: "l ∈# C" and
    l_grounding_is_maximal: "is_maximal (l ⋅l γ) (C ⋅ γ)"
    using
      ex_maximal_in_mset_wrt[OF
        literal.order.transp_on_less literal.order.asymp_on_less grounding_not_empty]
      maximal_in_clause
    unfolding clause.subst_def
    by (metis (mono_tags, lifting) image_iff multiset.set_map)
  show ?thesis
  proof(cases "is_maximal l C")
    case True
    with l_grounding_is_maximal that
    show ?thesis
      by blast
  next
    case False
    then obtain l' where
      l'_in_C: "l' ∈# C" and
      l_less_l': "l ≺⇩l l'"
      unfolding is_maximal_def
      using l_in_C
      by blast
    note literals_in_C = l_in_C l'_in_C
    note literals_grounding = literals_in_C[THEN clause.to_set_is_ground_subst[OF _ grounding]]
    have "l ⋅l γ ≺⇩l l' ⋅l γ"
      using clause.order.sub.ground_subst_stability[OF literals_grounding l_less_l'] .
    then have False
     using
       l_grounding_is_maximal
       clause.subst_in_to_set_subst[OF l'_in_C]
     unfolding is_maximal_def
     by force
    then show ?thesis ..
  qed
qed
lemma obtain_strictly_maximal_literal:
  assumes
   grounding: "clause.is_ground (C ⋅ γ)" and
   ground_strictly_maximal: "is_strictly_maximal l⇩G (C ⋅ γ)"
 obtains l where
   "is_strictly_maximal l C" "l⇩G = l ⋅l γ"
proof-
  have grounding_not_empty: "C ⋅ γ ≠ {#}"
    using is_strictly_maximal_not_empty[OF ground_strictly_maximal].
  have l⇩G_in_grounding: "l⇩G ∈# C ⋅ γ"
    using strictly_maximal_in_clause[OF ground_strictly_maximal].
  obtain l where
    l_in_C: "l ∈# C" and
    l⇩G [simp]: "l⇩G = l ⋅l γ"
    using l⇩G_in_grounding
    unfolding clause.subst_def
    by blast
  show ?thesis
  proof(cases "is_strictly_maximal l C")
    case True
    show ?thesis
      using that[OF True l⇩G].
  next
    case False
    then obtain l' where
      l'_in_C: "l' ∈# C - {# l #}" and
      l_less_eq_l': "l ≼⇩l l'"
      unfolding is_strictly_maximal_def
      using l_in_C
      by blast
    note l_grounding =
       clause.to_set_is_ground_subst[OF l_in_C grounding]
    have l'_grounding: "literal.is_ground (l' ⋅l γ)"
      using l'_in_C grounding
      by (meson clause.to_set_is_ground_subst in_diffD)
    have "l ⋅l γ ≼⇩l l' ⋅l γ"
      using
        clause.order.sub.less_eq.ground_subst_stability[OF l_grounding l'_grounding l_less_eq_l'] .
    then have False
      using clause.subst_in_to_set_subst[OF l'_in_C] ground_strictly_maximal
      unfolding is_strictly_maximal_def subst_clause_remove1_mset[OF l_in_C]
      by simp
    then show ?thesis ..
  qed
qed
lemma is_maximal_if_grounding_is_maximal:
  assumes
   l_in_C: "l ∈# C" and
   C_grounding: "clause.is_ground (C ⋅ γ)" and
   l_grounding_is_maximal: "is_maximal (l ⋅l γ) (C ⋅ γ)"
 shows "is_maximal l C"
proof(rule ccontr)
  assume "¬ is_maximal l C"
  then obtain l' where l_less_l': "l ≺⇩l l'" and l'_in_C: "l' ∈# C"
    using l_in_C
    unfolding is_maximal_def
    by blast
  have l'_grounding: "literal.is_ground (l' ⋅l γ)"
    using clause.to_set_is_ground_subst[OF l'_in_C C_grounding].
  have l_grounding: "literal.is_ground (l ⋅l γ)"
    using clause.to_set_is_ground_subst[OF l_in_C C_grounding].
  have l'_γ_in_C_γ: "l' ⋅l γ ∈# C ⋅ γ"
    using clause.subst_in_to_set_subst[OF l'_in_C] .
  have "l ⋅l γ ≺⇩l l' ⋅l γ"
    using clause.order.sub.ground_subst_stability[OF l_grounding l'_grounding l_less_l'] .
  then have "¬ is_maximal (l ⋅l γ) (C ⋅ γ)"
    using l'_γ_in_C_γ
    unfolding is_maximal_def literal.subst_comp_subst
    by fastforce
  then show False
    using l_grounding_is_maximal ..
qed
lemma is_strictly_maximal_if_grounding_is_strictly_maximal:
  assumes
   l_in_C: "l ∈# C" and
   grounding: "clause.is_ground (C ⋅ γ)" and
   grounding_strictly_maximal: "is_strictly_maximal (l ⋅l γ) (C ⋅ γ)"
 shows
   "is_strictly_maximal l C"
  using
    is_maximal_if_grounding_is_maximal[OF
      l_in_C
      grounding
      is_maximal_if_is_strictly_maximal[OF grounding_strictly_maximal]
    ]
    grounding_strictly_maximal
  unfolding
    is_strictly_maximal_def is_maximal_def
    subst_clause_remove1_mset[OF l_in_C, symmetric]
    reflclp_iff
  by (metis in_diffD clause.subst_in_to_set_subst)
lemma unique_maximal_in_ground_clause:
  assumes
    "clause.is_ground C"
    "is_maximal l C"
    "is_maximal l' C"
  shows
    "l = l'"
  using assms clause.to_set_is_ground clause.order.sub.not_less_eq
  unfolding is_maximal_def reflclp_iff
  by meson
lemma unique_strictly_maximal_in_ground_clause:
  assumes
    "clause.is_ground C"
    "is_strictly_maximal l C"
    "is_strictly_maximal l' C"
  shows
    "l = l'"
  using assms unique_maximal_in_ground_clause
  by blast
 
thm literal.order.order.strict_iff_order
abbreviation ground_is_maximal where
  "ground_is_maximal l⇩G C⇩G ≡ is_maximal (literal.from_ground l⇩G) (clause.from_ground C⇩G)"
abbreviation ground_is_strictly_maximal where
  "ground_is_strictly_maximal l⇩G C⇩G ≡
     is_strictly_maximal (literal.from_ground l⇩G) (clause.from_ground C⇩G)"
sublocale ground: ground_order_generic where
  less⇩t = "(≺⇩t⇩G)" and pos_to_mset = ground_pos_to_mset and neg_to_mset = ground_neg_to_mset
rewrites
  less⇩l⇩G_rewrite [simp]:
  "multiset_extension.multiset_extension (≺⇩t⇩G) ground.literal_to_mset = (≺⇩l⇩G)" and
  less⇩c⇩G_rewrite [simp]: "multiset_extension.multiset_extension (≺⇩l⇩G) (λx. x) = (≺⇩c⇩G)" and
  is_maximal_rewrite [simp]: "⋀l⇩G C⇩G. ground.is_maximal l⇩G C⇩G ⟷ ground_is_maximal l⇩G C⇩G" and
  is_strictly_maximal_rewrite [simp]:
  "⋀l⇩G C⇩G. ground.is_strictly_maximal l⇩G C⇩G ⟷ ground_is_strictly_maximal l⇩G C⇩G" and
  "ground.literal_order_restriction = UNIV"
proof (unfold_locales; (rule ground.inj_pos_to_mset ground.inj_neg_to_mset ground.pos_neg_neq)?)
  interpret ground: ground_order_generic where
    less⇩t = "(≺⇩t⇩G)" and pos_to_mset = ground_pos_to_mset and neg_to_mset = ground_neg_to_mset
    using ground.inj_pos_to_mset ground.inj_neg_to_mset ground.pos_neg_neq
    by unfold_locales auto
  interpret multiset_extension "(≺⇩t⇩G)" ground.literal_to_mset
    by unfold_locales
  interpret relation_restriction
    "(λb1 b2. multp (≺⇩t) (literal_to_mset b1) (literal_to_mset b2))" literal.from_ground
    by unfold_locales
  have literal_to_mset: "literal_to_mset (map_literal atom_from_ground l) =
            image_mset term.from_ground (ground.literal_to_mset l)" for l
    by (cases l) (auto simp: ground_pos_to_mset ground_neg_to_mset)
  show less⇩l⇩G_rewrite: "ground.literal.order.multiset_extension = (≺⇩l⇩G)"
    unfolding
      ground.literal.order.multiset_extension_def 
      literal.order.multiset_extension_def
      R⇩r_def
    unfolding 
      literal.from_ground_def 
      literal_to_mset
      term.order.less⇩G_def
    using 
      multp_image_mset_image_msetI[OF _ term.order.transp]
      multp_image_mset_image_msetD[OF _ term.order.transp]
      term.inj_from_ground 
    by metis
  fix l⇩G C⇩G
  show "ground.is_maximal l⇩G C⇩G ⟷ ground_is_maximal l⇩G C⇩G"
    unfolding
      ground.is_maximal_def
      is_maximal_def
      less⇩l⇩G_rewrite
      clause.order.sub.restriction.is_maximal_in_mset_iff
      clause.order.sub.less⇩r_def
    by (simp add: clause.to_set_from_ground image_iff)
  show "ground.is_strictly_maximal l⇩G C⇩G ⟷ ground_is_strictly_maximal l⇩G C⇩G"
    unfolding
      ground.is_strictly_maximal_def
      is_strictly_maximal_def
      less⇩l⇩G_rewrite
      clause.order.sub.restriction.is_strictly_maximal_in_mset_iff
      clause.order.sub.less⇩r_def
      reflclp_iff
    by (metis (lifting) clause.ground_sub_in_ground clause.sub_in_ground_is_ground 
        clause_from_ground_remove1_mset literal.obtain_grounding)
  show "{b. set_mset (ground.literal_to_mset b) ⊆ UNIV} = UNIV"
    by auto
next
  interpret multiset_extension "(≺⇩l⇩G)" "λx. x"
    by unfold_locales
  interpret relation_restriction "multp (≺⇩l)" clause.from_ground
    by unfold_locales
  show less⇩c⇩G_rewrite: "(≺⇩m) = (≺⇩c⇩G)"
    unfolding multiset_extension_def clause.order.multiset_extension_def R⇩r_def
    unfolding clause.order.sub.less⇩G_def clause.from_ground_def
    by (metis literal.inj_from_ground literal.order.transp multp_image_mset_image_msetD
        multp_image_mset_image_msetI)
qed
lemma less⇩c_add_mset:
  assumes "l ≺⇩l l'" "C ≼⇩c C'"
  shows "add_mset l C ≺⇩c add_mset l' C'"
  using assms multp_add_mset_reflclp[OF literal.order.asymp literal.order.transp]
  unfolding less⇩c_def
  by blast
lemmas less⇩c_add_same [simp] =
  multp_add_same[OF literal.order.asymp literal.order.transp, folded less⇩c_def]
end
locale context_compatible_nonground_order_generic = 
  nonground_order_generic +
  "term": context_compatible_nonground_term_order +
  clause.order: subst_update_stable_multiset_extension where 
  less = "(≺⇩l)" and sub_subst = literal.subst and sub_vars = literal.vars and
  sub_to_ground = literal.to_ground and sub_from_ground = literal.from_ground and
  map = image_mset and to_set = set_mset and to_ground_map = image_mset and
  from_ground_map = image_mset and ground_map = image_mset and to_set_ground = set_mset and
  to_mset = "λx. x" and id_subst = Var and base_vars = term.vars and base_less = less⇩t and
  base_subst = "(⋅t)"
end