Theory Nonground_Order

theory Nonground_Order
  imports
    Nonground_Clause
    Nonground_Term_Order
    Term_Order_Lifting
begin

section ‹Nonground Order›

locale nonground_order_lifting =
  grounding_lifting +
  order: total_grounded_multiset_extension +
  order: ground_subst_stable_total_multiset_extension +
  order: subst_update_stable_multiset_extension
begin

sublocale order: grounded_restricted_total_strict_order where
  less = order.multiset_extension and subst = subst and vars = vars and to_ground = to_ground and
  from_ground = "from_ground"
  by unfold_locales

end

locale nonground_term_based_order_lifting =
  "term": nonground_term +
  nonground_order_lifting where
  id_subst = Var and comp_subst = "(⊙)" and base_vars = term.vars and base_less = lesst and
  base_subst = "(⋅t)"
for lesst

(* TODO: Abstract out non-equality literal order + better name *)
locale nonground_equality_order =
  nonground_clause +
  "term": nonground_term_order
begin

sublocale restricted_term_order_lifting where
  restriction = "range term.from_ground" and literal_to_mset = mset_lit
  by unfold_locales (rule inj_mset_lit)

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

sublocale literal: nonground_term_based_order_lifting where
  less = lesst and sub_subst = "(⋅t)" and sub_vars = term.vars and sub_to_ground = term.to_ground and
  sub_from_ground = term.from_ground and map = map_uprod_literal and to_set = uprod_literal_to_set and
  to_ground_map = map_uprod_literal and from_ground_map = map_uprod_literal and
  ground_map = map_uprod_literal and to_set_ground = uprod_literal_to_set and to_mset = mset_lit
rewrites
  "l σ. functional_substitution_lifting.subst (⋅t) map_uprod_literal l σ = literal.subst l σ" and
  "l. functional_substitution_lifting.vars term.vars uprod_literal_to_set l = literal.vars l" and
  "lG. grounding_lifting.from_ground term.from_ground map_uprod_literal lG
    = literal.from_ground lG" and
  "l. grounding_lifting.to_ground term.to_ground map_uprod_literal l = literal.to_ground l"
  by unfold_locales (auto simp: inj_mset_lit mset_lit_image_mset)

notation literal.order.lessG (infix "lG" 50)
notation literal.order.less_eqG (infix "lG" 50)

sublocale 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"
  by unfold_locales simp_all

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 literal.order.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 literal.order.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 literal.order.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 literal.order.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

lemma lesslG_rewrite [simp]: "multiset_extension.multiset_extension (≺tG) mset_lit = (≺lG)"
proof-
  interpret multiset_extension "(≺tG)" mset_lit
    by unfold_locales

  interpret relation_restriction
    "(λb1 b2. multp (≺t) (mset_lit b1) (mset_lit b2))" literal.from_ground
    by unfold_locales

  show ?thesis
    unfolding multiset_extension_def  literal.order.multiset_extension_def Rr_def
    unfolding term.order.lessG_def literal.from_ground_def atom.from_ground_def
    by (metis term.inj_from_ground mset_lit_image_mset multp_image_mset_image_msetD
        multp_image_mset_image_msetI term.order.transp_on_less)
qed

lemma lesscG_rewrite [simp]:
  "multiset_extension.multiset_extension (≺lG) (λx. x) = (≺cG)"
  unfolding lesslG_rewrite
proof-
  interpret multiset_extension "(≺lG)" "λx. x"
    by unfold_locales

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

  show ?thesis
    unfolding multiset_extension_def clause.order.multiset_extension_def Rr_def
    unfolding literal.order.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 is_maximal_rewrite [simp]:
  "is_maximal_in_mset_wrt (≺lG) C l = is_maximal (literal.from_ground l) (clause.from_ground C)"
  unfolding literal.order.lessG_def is_maximal_def literal.order.restriction.is_maximal_in_mset_iff
  by (metis clause.ground_sub_in_ground clause.sub_in_ground_is_ground
      literal.order.order.strict_iff_order literal.to_ground_inverse)
 (* TODO: order.order *)
thm literal.order.order.strict_iff_order

lemma is_strictly_maximal_rewrite [simp]:
  "is_strictly_maximal_in_mset_wrt (≺lG) C l =
   is_strictly_maximal (literal.from_ground l) (clause.from_ground C)"
  unfolding
    literal.order.lessG_def is_strictly_maximal_def
    literal.order.restriction.is_strictly_maximal_in_mset_iff
    reflclp_iff
  by (metis (lifting) clause.ground_sub_in_ground clause.sub_in_ground_is_ground
      literal.obtain_grounding clause_from_ground_remove1_mset)

sublocale ground: ground_order_with_equality where
  lesst = "(≺tG)"
rewrites
  "multiset_extension.multiset_extension (≺tG) mset_lit = (≺lG)" and
  "multiset_extension.multiset_extension (≺lG) (λx. x) = (≺cG)" and
  "l C. ground.is_maximal l C  is_maximal (literal.from_ground l) (clause.from_ground C)" and
  "l C. ground.is_strictly_maximal l C  is_strictly_maximal (literal.from_ground l) (clause.from_ground C)"
  by unfold_locales auto

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)"

(* TODO: naming *)
lemma lesst_lessl:
  assumes "t1 t t2"
  shows
    lesst_lessl_pos: "t1  t3 l t2  t3" and
    lesst_lessl_neg: "t1 !≈ t3 l t2 !≈ t3"
  using assms
  unfolding lessl_def
  by (auto simp: multp_add_mset multp_add_mset')

lemma literal_order_less_if_all_lesseq_ex_less_set:
  assumes
    "t  set_uprod (atm_of l). t ⋅t σ' t t ⋅t σ"
    "t  set_uprod (atm_of l). t ⋅t σ' t t ⋅t σ"
  shows "l ⋅l σ' l l ⋅l σ"
  using literal.order.less_if_all_lesseq_ex_less[OF assms[folded set_mset_set_uprod]].

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

end