Theory 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 lesst

locale nonground_order_generic =
  "term": nonground_term where
  Var = "Var :: 'v  't" and term_to_ground = "term_to_ground :: 't  'tG" +
 
  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 :: "'aG  'a" and
  ground_pos_to_mset ground_neg_to_mset :: "'aG  'tG 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

(* TODO: Find way to not have this twice *)
notation term.order.lessG (infix "tG" 50)
notation term.order.less_eqG (infix "tG" 50)

(* TODO: Find way to call clause.order.sub = literal.order *)
notation clause.order.sub.lessG (infix "lG" 50)
notation clause.order.sub.less_eqG (infix "lG" 50)

notation clause.order.lessG (infix "cG" 50)
notation clause.order.less_eqG (infix "cG" 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 lG (C  γ)"
 obtains l where
   "is_strictly_maximal l C" "lG = l ⋅l γ"
proof-

  have grounding_not_empty: "C  γ  {#}"
    using is_strictly_maximal_not_empty[OF ground_strictly_maximal].

  have lG_in_grounding: "lG ∈# C  γ"
    using strictly_maximal_in_clause[OF ground_strictly_maximal].

  obtain l where
    l_in_C: "l ∈# C" and
    lG [simp]: "lG = l ⋅l γ"
    using lG_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 lG].
  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

 (* TODO: order.order *)
thm literal.order.order.strict_iff_order

abbreviation ground_is_maximal where
  "ground_is_maximal lG CG  is_maximal (literal.from_ground lG) (clause.from_ground CG)"

abbreviation ground_is_strictly_maximal where
  "ground_is_strictly_maximal lG CG 
     is_strictly_maximal (literal.from_ground lG) (clause.from_ground CG)"

sublocale ground: ground_order_generic where
  lesst = "(≺tG)" and pos_to_mset = ground_pos_to_mset and neg_to_mset = ground_neg_to_mset
rewrites
  lesslG_rewrite [simp]:
  "multiset_extension.multiset_extension (≺tG) ground.literal_to_mset = (≺lG)" and
  lesscG_rewrite [simp]: "multiset_extension.multiset_extension (≺lG) (λx. x) = (≺cG)" and
  is_maximal_rewrite [simp]: "lG CG. ground.is_maximal lG CG  ground_is_maximal lG CG" and
  is_strictly_maximal_rewrite [simp]:
  "lG CG. ground.is_strictly_maximal lG CG  ground_is_strictly_maximal lG CG" 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
    lesst = "(≺tG)" 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 "(≺tG)" 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 lesslG_rewrite: "ground.literal.order.multiset_extension = (≺lG)"
    unfolding
      ground.literal.order.multiset_extension_def 
      literal.order.multiset_extension_def
      Rr_def
    unfolding 
      literal.from_ground_def 
      literal_to_mset
      term.order.lessG_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 lG CG
  show "ground.is_maximal lG CG  ground_is_maximal lG CG"
    unfolding
      ground.is_maximal_def
      is_maximal_def
      lesslG_rewrite
      clause.order.sub.restriction.is_maximal_in_mset_iff
      clause.order.sub.lessr_def
    by (simp add: clause.to_set_from_ground image_iff)

  show "ground.is_strictly_maximal lG CG  ground_is_strictly_maximal lG CG"
    unfolding
      ground.is_strictly_maximal_def
      is_strictly_maximal_def
      lesslG_rewrite
      clause.order.sub.restriction.is_strictly_maximal_in_mset_iff
      clause.order.sub.lessr_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 "(≺lG)" "λx. x"
    by unfold_locales

  interpret relation_restriction "multp (≺l)" clause.from_ground
    by unfold_locales

  show lesscG_rewrite: "(≺m) = (≺cG)"
    unfolding multiset_extension_def clause.order.multiset_extension_def Rr_def
    unfolding clause.order.sub.lessG_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 lessc_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 lessc_def
  by blast

lemmas lessc_add_same [simp] =
  multp_add_same[OF literal.order.asymp literal.order.transp, folded lessc_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 = lesst and
  base_subst = "(⋅t)"

end