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 constefac 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