Theory Exhaustive_Factorization
theory Exhaustive_Factorization
  imports Background
begin
section ‹Function for full factorization›
context simulation_SCLFOL_ground_ordered_resolution begin
definition efac :: "'f gterm clause ⇒ 'f gterm clause" where
  "efac C = (THE C'. ord_res.ground_factoring⇧*⇧* C C' ∧ (∄C''. ord_res.ground_factoring C' C''))"
text ‹The function \<^const>‹efac› performs exhaustive factorization of its input clause.›
lemma ex1_efac_eq_factoring_chain:
  "∃!C'. efac C = C' ∧ ord_res.ground_factoring⇧*⇧* C C' ∧ (∄C''. ord_res.ground_factoring C' C'')"
proof -
  have "right_unique (λx y. ord_res.ground_factoring⇧*⇧* x y ∧ (∄z. ord_res.ground_factoring y z))"
    using ord_res.unique_ground_factoring right_unique_terminating_rtranclp right_unique_iff
    by blast
  moreover obtain C' where "ord_res.ground_factoring⇧*⇧* C C' ∧ (∄C''. ord_res.ground_factoring C' C'')"
    using ex_terminating_rtranclp[OF ord_res.termination_ground_factoring]
    by metis
  ultimately have "efac C = C'"
    by (simp add: efac_def right_unique_def the_equality)
  then show ?thesis
    using ‹ord_res.ground_factoring⇧*⇧* C C' ∧ (∄C''. ord_res.ground_factoring C' C'')› by blast
qed
lemma efac_eq_disj:
  "efac C = C ∨ (∃!C'. efac C = C' ∧ ord_res.ground_factoring⇧*⇧* C C' ∧ (∄C''. ord_res.ground_factoring C' C''))"
  using ex1_efac_eq_factoring_chain
  by (metis is_pos_def)
lemma member_mset_if_count_eq_Suc: "count X x = Suc n ⟹ x ∈# X"
  by (simp add: count_inI)
lemmas member_fsetE = mset_add
lemma ord_res_ground_factoring_iff: "ord_res.ground_factoring C C' ⟷
  (∃A. ord_res.is_maximal_lit (Pos A) C ∧ (∃n. count C (Pos A) = Suc (Suc n) ∧ C' = C - {#Pos A#}))"
proof (rule iffI)
  assume "ord_res.ground_factoring C C'"
  thus "∃A. ord_res.is_maximal_lit (Pos A) C ∧ (∃n. count C (Pos A) = Suc (Suc n) ∧ C' = C - {#Pos A#})"
  proof (cases C C' rule: ord_res.ground_factoring.cases)
    case (ground_factoringI A P')
    show ?thesis
    proof (intro exI conjI)
      show "ord_res.is_maximal_lit (Pos A) C"
        using ‹ord_res.is_maximal_lit (Pos A) C› .
    next
      show "count C (Pos A) = Suc (Suc (count P' (Pos A)))"
        unfolding ‹C = add_mset (Pos A) (add_mset (Pos A) P')› by simp
    next
      show "C' = remove1_mset (Pos A) C"
        unfolding ‹C = add_mset (Pos A) (add_mset (Pos A) P')› ‹C' = add_mset (Pos A) P'› by simp
    qed
  qed
next
  assume "∃A. ord_res.is_maximal_lit (Pos A) C ∧
    (∃n. count C (Pos A) = Suc (Suc n) ∧ C' = C - {#Pos A#})"
  then obtain A n where
    "ord_res.is_maximal_lit (Pos A) C" and
    "count C (Pos A) = Suc (Suc n)" and
    "C' = C - {#Pos A#}"
    by metis
  have "Pos A ∈# C"
    using ‹count C (Pos A) = Suc (Suc n)› member_mset_if_count_eq_Suc by metis
  then obtain C'' where "C = add_mset (Pos A) C''"
    by (auto elim: member_fsetE)
  with ‹count C (Pos A) = Suc (Suc n)› have "count C'' (Pos A) = Suc n"
    by simp
  hence "Pos A ∈# C''"
    using member_mset_if_count_eq_Suc by metis
  then obtain C''' where "C'' = add_mset (Pos A) C'''"
    by (auto elim: member_fsetE)
  show "ord_res.ground_factoring C C'"
  proof (rule ord_res.ground_factoringI)
    show "C = add_mset (Pos A) (add_mset (Pos A) C''')"
      using ‹C = add_mset (Pos A) C''› ‹C'' = add_mset (Pos A) C'''› by metis
  next
    show "ord_res.is_maximal_lit (Pos A) C"
      using ‹ord_res.is_maximal_lit (Pos A) C› .
  next
    show "C' = add_mset (Pos A) C'''"
      using ‹C' = C - {#Pos A#}› ‹C = add_mset (Pos A) C''› ‹C'' = add_mset (Pos A) C'''› by simp
  qed simp_all
qed
lemma tranclp_ord_res_ground_factoring_iff:
  "ord_res.ground_factoring⇧+⇧+ C C' ∧ (∄C''. ord_res.ground_factoring C' C'') ⟷
  (∃A. ord_res.is_maximal_lit (Pos A) C ∧ (∃n. count C (Pos A) = Suc (Suc n) ∧
    C' = C - replicate_mset (Suc n) (Pos A)))"
proof (intro iffI; elim exE conjE)
  assume "ord_res.ground_factoring⇧+⇧+ C C'" and "(∄C''. ord_res.ground_factoring C' C'')"
  then show "∃A. ord_res.is_maximal_lit (Pos A) C ∧ (∃n. count C (Pos A) = Suc (Suc n) ∧
    C' = C - replicate_mset (Suc n) (Pos A))"
  proof (induction C rule: converse_tranclp_induct)
    case (base C)
    from base.hyps obtain A n where
      "ord_res.is_maximal_lit (Pos A) C" and
      "count C (Pos A) = Suc (Suc n)" and
      "C' = remove1_mset (Pos A) C"
      unfolding ord_res_ground_factoring_iff by auto
    moreover have "n = 0"
    proof (rule ccontr)
      assume "n ≠ 0"
      then obtain C'' where "C' = add_mset (Pos A) (add_mset (Pos A) C'')"
        by (metis (no_types, lifting) Zero_not_Suc calculation(2,3) count_add_mset count_inI
            diff_Suc_1 insert_DiffM)
      hence "ord_res.ground_factoring C' (add_mset (Pos A) C'')"
        using ord_res.ground_factoringI
        by (metis calculation(1,3) linorder_lit.is_maximal_in_mset_iff more_than_one_mset_mset_diff
            union_single_eq_member)
      with base.prems show False
        by metis
    qed
    ultimately show ?case
      by (metis replicate_mset_0 replicate_mset_Suc)
  next
    case (step C C'')
    from step.IH step.prems obtain A n where
      "ord_res.is_maximal_lit (Pos A) C''" and
      "count C'' (Pos A) = Suc (Suc n)" and
      "C' = C'' - replicate_mset (Suc n) (Pos A)"
      by metis
    from step.hyps(1) obtain A' m where
      "ord_res.is_maximal_lit (Pos A') C" and
      "count C (Pos A') = Suc (Suc m)" and
      "C'' = remove1_mset (Pos A') C"
      unfolding ord_res_ground_factoring_iff by metis
    have "A' = A"
      using ‹ord_res.is_maximal_lit (Pos A) C''› ‹ord_res.is_maximal_lit (Pos A') C›
      by (metis ‹C'' = remove1_mset (Pos A') C› ‹count C (Pos A') = Suc (Suc m)›
          add_mset_remove_trivial_eq count_add_mset count_greater_zero_iff diff_Suc_1
          linorder_lit.antisym_conv3 linorder_lit.is_maximal_in_mset_iff literal.inject(1)
          zero_less_Suc)
    have "m = Suc n"
      using ‹count C'' (Pos A) = Suc (Suc n)› ‹count C (Pos A') = Suc (Suc m)›
      unfolding ‹C'' = remove1_mset (Pos A') C› ‹A' = A›
      by simp
    show ?case
    proof (intro exI conjI)
      show "ord_res.is_maximal_lit (Pos A) C"
        using ‹ord_res.is_maximal_lit (Pos A') C› ‹A' = A› by metis
    next
      show "count C (Pos A) = Suc (Suc m)"
        using ‹count C (Pos A') = Suc (Suc m)› ‹A' = A› by metis
    next
      show "C' = C - replicate_mset (Suc m) (Pos A)"
        unfolding ‹C' = C'' - replicate_mset (Suc n) (Pos A)› ‹C'' = remove1_mset (Pos A') C›
          ‹A' = A› ‹m = Suc n›
        by simp
    qed
  qed
next
  fix A n assume "ord_res.is_maximal_lit (Pos A) C"
  thus "count C (Pos A) = Suc (Suc n) ⟹ C' = C - replicate_mset (Suc n) (Pos A) ⟹
    ord_res.ground_factoring⇧+⇧+ C C' ∧ (∄C''. ord_res.ground_factoring C' C'')"
  proof (induction n arbitrary: C)
    case 0
    hence "(ord_res.is_maximal_lit (Pos A) C ∧
         (count C (Pos A) = Suc (Suc 0) ∧
              C' = remove1_mset (Pos A) C))"
      by (metis replicate_mset_0 replicate_mset_Suc)
    hence "ord_res.ground_factoring C C' ∧ (∄a. ord_res.ground_factoring C' a)"
      unfolding ord_res_ground_factoring_iff
      by (metis Zero_not_Suc add_mset_remove_trivial_eq count_add_mset count_inI
          linorder_lit.antisym_conv3 linorder_lit.is_maximal_in_mset_iff nat.inject)
    thus ?case
      by blast
  next
    case (Suc n)
    have "ord_res.ground_factoring⇧+⇧+ (C - {#Pos A#}) C' ∧ (∄a. ord_res.ground_factoring C' a)"
    proof (rule Suc.IH)
      show "count (remove1_mset (Pos A) C) (Pos A) = Suc (Suc n)"
        using Suc.prems by simp
    next
      show "C' = remove1_mset (Pos A) C - replicate_mset (Suc n) (Pos A)"
        using Suc.prems by simp
    next
      show "ord_res.is_maximal_lit (Pos A) (remove1_mset (Pos A) C)"
        using Suc.prems
        by (smt (verit, ccfv_SIG) Zero_not_Suc add_diff_cancel_left' add_mset_remove_trivial_eq
            count_add_mset count_inI linorder_lit.is_maximal_in_mset_iff plus_1_eq_Suc)
    qed
    moreover have "ord_res.ground_factoring C (C - {#Pos A#})"
      unfolding ord_res_ground_factoring_iff
    proof (intro exI conjI)
      show "ord_res.is_maximal_lit (Pos A) C"
        using Suc.prems by metis
    next
      show "count C (Pos A) = Suc (Suc (Suc n))"
        using Suc.prems by metis
    next
      show "remove1_mset (Pos A) C = remove1_mset (Pos A) C" ..
    qed
    ultimately show ?case
      by auto
  qed
qed
lemma minus_mset_replicate_mset_eq_add_mset_filter_mset:
  assumes "count X x = Suc n"
  shows "X - replicate_mset n x = add_mset x {#y ∈# X. y ≠ x#}"
  using assms
  by (metis add_diff_cancel_left' add_mset_diff_bothsides filter_mset_eq filter_mset_neq
      multiset_partition replicate_mset_Suc union_mset_add_mset_right)
lemma minus_mset_replicate_mset_eq_add_mset_add_mset_filter_mset:
  assumes "count X x = Suc (Suc n)"
  shows "X - replicate_mset n x = add_mset x (add_mset x {#y ∈# X. y ≠ x#})"
  using assms
  by (metis add_diff_cancel_left' add_mset_diff_bothsides filter_mset_eq filter_mset_neq
      multiset_partition replicate_mset_Suc union_mset_add_mset_right)
lemma rtrancl_ground_factoring_iff:
  shows "ord_res.ground_factoring⇧*⇧* C C' ∧ (∄C''. ord_res.ground_factoring C' C'') ⟷
  ((∄A. ord_res.is_maximal_lit (Pos A) C ∧ count C (Pos A) ≥ 2) ∧ C = C' ∨
   (∃A. ord_res.is_maximal_lit (Pos A) C ∧ C' = add_mset (Pos A) {#L ∈# C. L ≠ Pos A#}))"
proof (intro iffI; elim exE conjE disjE)
  show "ord_res.ground_factoring⇧*⇧* C C' ⟹ ∄C''. ord_res.ground_factoring C' C'' ⟹
    (∄A. ord_res.is_maximal_lit (Pos A) C ∧ 2 ≤ count C (Pos A)) ∧ C = C' ∨
    (∃A. ord_res.is_maximal_lit (Pos A) C ∧ C' = add_mset (Pos A) {#L ∈# C. L ≠ Pos A#})"
  proof (induction C rule: converse_rtranclp_induct)
    case base
    thus ?case
      by (metis add_2_eq_Suc le_Suc_ex ord_res_ground_factoring_iff)
  next
    case (step y z)
    hence "ord_res.ground_factoring⇧+⇧+ y C' ∧ (∄x. ord_res.ground_factoring C' x)"
      by simp
    thus ?case
      unfolding tranclp_ord_res_ground_factoring_iff
      by (metis minus_mset_replicate_mset_eq_add_mset_filter_mset)
  qed
next
  assume "∄A. ord_res.is_maximal_lit (Pos A) C ∧ 2 ≤ count C (Pos A)" and "C = C'"
  thus "ord_res.ground_factoring⇧*⇧* C C' ∧ (∄C''. ord_res.ground_factoring C' C'')"
    by (metis One_nat_def Suc_1 Suc_le_eq Suc_le_mono ord_res_ground_factoring_iff
        rtranclp.rtrancl_refl zero_less_Suc)
next
  fix A assume "ord_res.is_maximal_lit (Pos A) C"
  then obtain n where "count C (Pos A) = Suc n"
    by (meson in_countE linorder_lit.is_maximal_in_mset_iff)
  with ‹ord_res.is_maximal_lit (Pos A) C› show "C' = add_mset (Pos A) {#L ∈# C. L ≠ Pos A#} ⟹
    ord_res.ground_factoring⇧*⇧* C C' ∧ (∄C''. ord_res.ground_factoring C' C'')"
  proof (induction n arbitrary: C)
    case 0
    have "(∄a. ord_res.ground_factoring C a)"
    proof (intro notI, elim exE)
      fix D assume "ord_res.ground_factoring C D"
      thus False
      proof (cases rule: ord_res.ground_factoring.cases)
        case (ground_factoringI A' P')
        hence "A' = A"
          using ‹ord_res.is_maximal_lit (Pos A) C›
          using linorder_lit.Uniq_is_maximal_in_mset
          by (metis Uniq_D literal.inject(1))
        thus False
          using ‹count C (Pos A) = Suc 0› ‹C = add_mset (Pos A') (add_mset (Pos A') P')› by simp
      qed
    qed
    thus ?case
      by (metis "0.prems"(1) "0.prems"(3) diff_zero
          minus_mset_replicate_mset_eq_add_mset_filter_mset replicate_mset_0 rtranclp.rtrancl_refl)
  next
    case (Suc x)
    then show ?case
      by (metis minus_mset_replicate_mset_eq_add_mset_filter_mset tranclp_into_rtranclp
          tranclp_ord_res_ground_factoring_iff)
  qed
qed
lemma efac_spec: "efac C = C ∨
  (∃A. ord_res.is_maximal_lit (Pos A) C ∧ efac C = add_mset (Pos A) {#L ∈# C. L ≠ Pos A#})"
  using efac_eq_disj[of C]
proof (elim disjE)
  assume "efac C = C"
  thus "efac C = C ∨
    (∃A. ord_res.is_maximal_lit (Pos A) C ∧ efac C = add_mset (Pos A) {#L ∈# C. L ≠ Pos A#})"
    by metis
next
  assume "∃!C'. efac C = C' ∧ ord_res.ground_factoring⇧*⇧* C C' ∧
    (∄C''. ord_res.ground_factoring C' C'')"
  then obtain C' where
    "efac C = C'" and
    "ord_res.ground_factoring⇧*⇧* C C' ∧ (∄C''. ord_res.ground_factoring C' C'')"
    by metis
  thus "efac C = C ∨
    (∃A. ord_res.is_maximal_lit (Pos A) C ∧ efac C = add_mset (Pos A) {#L ∈# C. L ≠ Pos A#})"
    unfolding rtrancl_ground_factoring_iff
    by metis
qed
lemma efac_spec_if_pos_lit_is_maximal:
  assumes L_pos: "is_pos L" and L_max: "ord_res.is_maximal_lit L C"
  shows "efac C = add_mset L {#K ∈# C. K ≠ L#}"
proof -
  from assms obtain C' where
    "efac C = C'" and
    "ord_res.ground_factoring⇧*⇧* C C' ∧ (∄C''. ord_res.ground_factoring C' C'')"
    using ex1_efac_eq_factoring_chain by metis
  thus ?thesis
    unfolding rtrancl_ground_factoring_iff
  proof (elim disjE conjE)
    assume hyps: "∄A. ord_res.is_maximal_lit (Pos A) C ∧ 2 ≤ count C (Pos A)" "C = C'"
    with assms have "count C L = 1"
      by (metis One_nat_def in_countE is_pos_def le_less_linear less_2_cases_iff
          linorder_lit.is_maximal_in_mset_iff nat_less_le zero_less_Suc)
    hence "C = add_mset L {#K ∈# C. K ≠ L#}"
      by (metis One_nat_def diff_zero minus_mset_replicate_mset_eq_add_mset_filter_mset
          replicate_mset_0)
    thus "efac C = add_mset L {#K ∈# C. K ≠ L#}"
      using ‹efac C = C'› ‹C = C'› by argo
  next
    assume "∃A. ord_res.is_maximal_lit (Pos A) C ∧ C' = add_mset (Pos A) {#L ∈# C. L ≠ Pos A#}"
    thus "efac C = add_mset L {#K ∈# C. K ≠ L#}"
      by (metis L_max Uniq_D ‹efac C = C'› linorder_lit.Uniq_is_maximal_in_mset)
  qed
qed
lemma efac_mempty[simp]: "efac {#} = {#}"
  by (metis empty_iff linorder_lit.is_maximal_in_mset_iff set_mset_empty efac_spec)
lemma set_mset_efac[simp]: "set_mset (efac C) = set_mset C"
  using efac_spec[of C]
proof (elim disjE exE conjE)
  show "efac C = C ⟹ set_mset (efac C) = set_mset C"
    by simp
next
  fix A
  assume "ord_res.is_maximal_lit (Pos A) C"
  hence "Pos A ∈# C"
    by (simp add: linorder_lit.is_maximal_in_mset_iff)
  assume efac_C_eq: "efac C = add_mset (Pos A) {#L ∈# C. L ≠ Pos A#}"
  show "set_mset (efac C) = set_mset C"
  proof (intro Set.subset_antisym Set.subsetI)
    fix L assume "L ∈# efac C"
    then show "L ∈# C"
      unfolding efac_C_eq
      using ‹Pos A ∈# C› by auto
  next
    fix L assume "L ∈# C"
    then show "L ∈# efac C"
      unfolding efac_C_eq
      by simp
  qed
qed
lemma efac_subset: "efac C ⊆# C"
  using efac_spec[of C]
proof (elim disjE exE conjE)
  show "efac C = C ⟹ efac C ⊆# C"
    by simp
next
  fix A
  assume "ord_res.is_maximal_lit (Pos A) C" and
    efac_C_eq: "efac C = add_mset (Pos A) {#L ∈# C. L ≠ Pos A#}"
  then show "efac C ⊆# C"
    by (smt (verit, ccfv_SIG) filter_mset_add_mset insert_DiffM insert_subset_eq_iff
        linorder_lit.is_maximal_in_mset_iff multiset_filter_subset)
qed
lemma true_cls_efac_iff[simp]:
  fixes ℐ :: "'f gterm set" and C :: "'f gclause"
  shows "ℐ ⊫ efac C ⟷ ℐ ⊫ C"
  by (metis set_mset_efac true_cls_iff_set_mset_eq)
lemma obtains_positive_greatest_lit_if_efac_not_ident:
  assumes "efac C ≠ C"
  obtains L where "is_pos L" and "linorder_lit.is_greatest_in_mset (efac C) L"
proof -
  from ‹efac C ≠ C› obtain A where
    Pos_A_maximal: "linorder_lit.is_maximal_in_mset C (Pos A)" and
    efac_C_eq: "efac C = add_mset (Pos A) {#L ∈# C. L ≠ Pos A#}"
    using efac_spec by metis
  assume hyp: "⋀L. is_pos L ⟹ linorder_lit.is_greatest_in_mset (efac C) L ⟹ thesis"
  show thesis
  proof (rule hyp)
    show "is_pos (Pos A)"
      by simp
  next
    show "linorder_lit.is_greatest_in_mset(efac C) (Pos A)"
      unfolding efac_C_eq linorder_lit.is_greatest_in_mset_iff
      using Pos_A_maximal[unfolded linorder_lit.is_maximal_in_mset_iff]
      by auto
  qed
qed
lemma mempty_in_image_efac_iff[simp]: "{#} ∈ efac ` N ⟷ {#} ∈ N"
  by (metis empty_iff imageE image_eqI linorder_lit.is_maximal_in_mset_iff set_mset_empty set_mset_efac efac_spec)
lemma greatest_literal_in_efacI:
  assumes "is_pos L" and C_max_lit: "linorder_lit.is_maximal_in_mset C L"
  shows "linorder_lit.is_greatest_in_mset (efac C) L"
  unfolding efac_spec_if_pos_lit_is_maximal[OF assms] linorder_lit.is_greatest_in_mset_iff
proof (intro conjI ballI)
  show "L ∈# add_mset L {#K ∈# C. K ≠ L#}"
    by simp
next
  fix y :: "'f gterm literal"
  assume "y ∈# remove1_mset L (add_mset L {#K ∈# C. K ≠ L#})"
  then show "y ≺⇩l L"
    using C_max_lit[unfolded linorder_lit.is_maximal_in_mset_iff]
    by  auto
qed
lemma "linorder_lit.is_maximal_in_mset (efac C) L ⟷ linorder_lit.is_maximal_in_mset C L"
  by (simp add: linorder_lit.is_maximal_in_mset_iff)
lemma
  assumes "is_pos L"
  shows "linorder_lit.is_greatest_in_mset (efac C) L ⟷ linorder_lit.is_maximal_in_mset C L"
  by (metis (no_types, opaque_lifting) Uniq_D assms efac_spec greatest_literal_in_efacI
      linorder_lit.Uniq_is_greatest_in_mset linorder_lit.is_maximal_in_mset_if_is_greatest_in_mset
      literal.disc(1))
lemma factorizable_if_neq_efac:
  assumes "C ≠ efac C"
  shows "∃C'. ord_res.ground_factoring C C'"
  using assms
  by (metis converse_rtranclpE ex1_efac_eq_factoring_chain)
lemma nex_strictly_maximal_pos_lit_if_neq_efac:
  assumes "C ≠ efac C"
  shows "∄L. is_pos L ∧ ord_res.is_strictly_maximal_lit L C"
  using assms factorizable_if_neq_efac nex_strictly_maximal_pos_lit_if_factorizable by metis
lemma efac_properties_if_not_ident:
  assumes "efac C ≠ C"
  shows "efac C ≺⇩c C" and "{efac C} ⊫e {C}"
proof -
  have "efac C ⊆# C"
    using efac_subset .
  hence "efac C ≼⇩c C"
    using subset_implies_reflclp_multp by blast
  thus "efac C ≺⇩c C"
    using ‹efac C ≠ C› by order
  show "{efac C} ⊫e {C}"
    using ‹efac C ⊆# C› true_clss_subclause by metis
qed
end
end