Theory Count_Util

theory Count_Util
  imports "HOL-Library.Multiset" 
          "HOL-Combinatorics.List_Permutation" 
          "SuffixArray.List_Util"
          "SuffixArray.List_Slice"
begin

section "Counting"

subsection "Count List"

lemma count_in:
  "x  set xs  count_list xs x > 0"
  by (meson count_list_0_iff gr0I)

lemma in_count:
  "count_list xs x > 0  x  set xs"
  by (metis count_notin less_irrefl)

lemma notin_count:
  "count_list xs x = 0  x  set xs"
  by (simp add: count_list_0_iff)

lemma count_list_eq_count:
  "count_list xs x = count (mset xs) x"
  by (induct xs; simp)

lemma count_list_perm:
  "xs <~~> ys  count_list xs x = count_list ys x"
  by (simp add: count_list_eq_count)

lemma in_count_nth_ex:
  "count_list xs x > 0  i < length xs. xs ! i = x"
  by (meson in_count in_set_conv_nth)

lemma in_count_list_slice_nth_ex:
  "count_list (list_slice xs i j) x > 0  k < length xs. i  k  k < j  xs ! k = x"
  by (meson in_count nth_mem_list_slice)

subsection "Cardinality"

lemma count_list_card:
  "count_list xs x = card {j. j < length xs  xs ! j = x}"
proof (induct xs rule: rev_induct)
  case Nil
  then show ?case
    by simp
next
  case (snoc y xs)

  let ?A = "{j. j < length xs  xs ! j = x}"
  let ?B = "{j. j < length (xs @ [y])  (xs @ [y]) ! j = x}"

  have "length xs  ?A"
    by simp

  have "?B - {length xs} = ?A"
    by (intro equalityI subsetI; clarsimp simp: nth_append)

  {
    have "y = x  count_list (xs @ [y]) x = Suc (card ?A)"
      by (simp add: snoc)
    moreover
    have "y = x  ?B = insert (length xs) ?A"
      by (metis (mono_tags, lifting) ?B - {length xs} = ?A insert_Diff length_append_singleton
                                     lessI mem_Collect_eq nth_append_length)
    with card_insert_disjoint[OF _ `length xs  _`]
    have "y = x  card ?B = Suc (card ?A)"
      by simp
    ultimately have "y = x  ?case"
      by simp
  }
  moreover
  have "y  x  count_list (xs @ [y]) x = card ?A"
    by (simp add: snoc)
  hence "y  x  ?case"
    using ?B - {length xs} = ?A by force
  ultimately show ?case
    by blast
qed

lemma card_le_eq_card_less_pl_count_list:
  fixes s :: "'a :: linorder list"
  shows "card {k. k < length s  s ! k  a} = card {k. k < length s  s ! k < a} + count_list s a"
proof -
  let ?A = "{k. k < length s  s ! k  a}"
  let ?B = "{k. k < length s  s ! k < a}"
  let ?C = "{k. k < length s  s ! k = a}"

  have "?B  ?C = {}"
    by blast
  hence "card (?B  ?C) = card ?B + count_list s a"
    by (simp add: card_Un_disjoint count_list_card)
  moreover
  have "?A = ?B  ?C"
  proof safe
    fix x
    assume "s ! x  a" "s ! x  a"
    then show "s ! x < a"
      by simp
  next
    fix x
    assume "s ! x < a"
    then show "s ! x  a"
      by simp
  qed
  hence "card ?A = card (?B  ?C)"
    by simp
  ultimately show ?thesis
    by simp
qed

lemma card_less_idx_upper_strict:
  fixes s :: "'a :: linorder list"
  assumes "a  set s"
  shows "card {k. k < length s  s ! k < a} < length s"
proof -
  have "i < length s. s ! i = a"
    by (meson assms in_set_conv_nth)
  then obtain i where P:
    "i < length s" "s ! i = a"
    by blast

  have "{k. k < length s  s ! k < a}  {0..<length s}"
    using atLeastLessThan_iff by blast
  moreover
  have "i  {0..<length s}"
    by (simp add: P(1))
  moreover
  have "i  {k. k < length s  s ! k < a}"
    by (simp add: P(2))
  ultimately have "{k. k < length s  s ! k < a}  {0..<length s}"
    by blast
  then show ?thesis
    by (metis card_upt finite_atLeastLessThan psubset_card_mono)
qed

lemma card_less_idx_upper:
  shows "card {k. k < length s  s ! k < a}  length s"
  by (metis (no_types, lifting) atLeastLessThan_iff bot_nat_0.extremum mem_Collect_eq subsetI 
                                subset_eq_atLeast0_lessThan_card)

lemma card_pl_count_list_strict_upper:
  fixes s :: "'a :: linorder list"
  shows "card {i. i < length s  s ! i < a} + count_list s a  length s"
proof -
  let ?X = "{i. i < length s  s ! i < a}"
  let ?Y = "{i. i < length s  s ! i = a}"

  have "?X  ?Y = {}"
    by blast
  hence "card (?X  ?Y) = card ?X + card ?Y"
    by (simp add: card_Un_disjoint)
  moreover
  have "card ?Y = count_list s a"
    by (simp add: count_list_card)
  moreover
  have "?X  ?Y  {0..<length s}"
    by (simp add: subset_iff)
  hence "card (?X  ?Y)  length s"
    using subset_eq_atLeast0_lessThan_card by blast
  ultimately show ?thesis
    by presburger
qed

subsection "Sorting"

lemma sorted_nth_le:
  assumes "sorted xs"
  and     "card {k. k < length xs  xs ! k < c} < length xs"
shows "c  xs ! card {k. k < length xs  xs ! k < c}"
  using assms
proof (induct xs)
  case Nil
  then show ?case
    by simp
next
  case (Cons a xs)
  note IH = this

  let ?A = "{k. k < length (a # xs)  (a # xs) ! k < c}"
  let ?B = "{k. k < length xs  xs ! k < c}"

  have "a < c  c  a"
    by fastforce
  then show ?case
  proof
    assume "a < c"

    have "finite ?B"
      by auto
    hence "finite (Suc ` ?B)"
      by blast

    have "card (Suc ` ?B) = card ?B"
      using card_image inj_Suc by blast

    have "{0}  Suc ` ?B = {}"
      by blast

    have "?A = {0}  Suc ` ?B"
    proof (intro equalityI subsetI)
      fix x
      assume "x  {0}  Suc ` ?B"
      then show "x  ?A"
      proof
        assume "x  {0}"
        hence "x = 0"
          by simp
        then show ?thesis
          by (simp add: a < c)
      next
        assume "x  Suc ` ?B"
        hence "y. x = Suc y  xs ! y < c"
          by blast
        then show ?thesis
          using x  Suc ` ?B by force
      qed
    next
      fix x
      assume "x  ?A"
      hence "x = 0  (y. x = Suc y  xs ! y < c)"
        using not0_implies_Suc by fastforce
      then show "x  {0}  Suc ` ?B"
      proof
        assume "x = 0"
        then show ?thesis
          by blast
      next
        assume "y. x = Suc y  xs ! y < c"
        then show ?thesis
          using x  ?A by fastforce
      qed
    qed
    with card_Un_disjoint[OF _ finite (Suc ` ?B) _  _ = _]
    have "card ?A = Suc (card ?B)"
      by (simp add: card (Suc ` ?B) = card ?B)
    hence "(a # xs) ! card {k. k < length (a # xs)  (a # xs) ! k < c} = 
           xs ! card {k. k < length xs  xs ! k < c}"
      by simp
    then show ?case
      using Cons.hyps IH(2) IH(3) card ?A = Suc (card ?B) by auto
  next
    assume "c  a"
    have "{k. k < length (a # xs)  (a # xs) ! k < c} = {}"
    proof safe
      fix x
      assume A: "x < length (a # xs)" "(a # xs) ! x < c"
      show "x  {}"
      proof (cases x)
        case 0
        then show ?thesis
          using A(2) c  a by auto
      next
        case (Suc n)
        hence "a  (a # xs) ! x"
          using A(1) IH(2) by auto
        then show ?thesis
          using A(2) c  a by auto
      qed
    qed
    then show ?thesis
      by (metis c  a card.empty nth_Cons_0)
  qed
qed

lemma sorted_nth_le_gen:
  assumes "sorted xs"
  and     "card {k. k < length xs  xs ! k < c} + i < length xs"
shows "c  xs ! (card {k. k < length xs  xs ! k < c} + i)"
proof (cases i)
  case 0
  then show ?thesis
    using assms(1) assms(2) sorted_nth_le by auto
next
  let ?x = "card {k. k < length xs  xs ! k < c }"
  case (Suc n)
  with sorted_wrt_nth_less[OF assms(1), of ?x "?x + i"]
  have "xs ! ?x  xs ! (?x + i)"
    using assms(1) assms(2) le_add1 sorted_nth_mono by blast
  moreover
  have "c  xs ! ?x"
    using add_lessD1 assms(1) assms(2) sorted_nth_le by blast
  ultimately show ?thesis
    by order
qed

lemma sorted_nth_less_gen:
  assumes "sorted xs"
  and     "i < card {k. k < length xs  xs ! k < c}"
shows     "xs ! i < c"
proof (rule ccontr)
  assume "¬ xs ! i < c"
  hence "i  {k. k < length xs  xs ! k < c}"
    by simp
  hence "k < length xs. i  k  k  {k. k < length xs  xs ! k < c}"
    using assms(1) sorted_iff_nth_mono by fastforce
  hence "{k. k < length xs  xs ! k < c}  {0..<i}"
    by fastforce
  moreover
  have "card {0..<i} = i"
    by auto
  ultimately show False
    by (metis assms(2) card_mono finite_atLeastLessThan verit_comp_simplify1(3))
qed

lemma sorted_nth_gr_gen:
  assumes "sorted xs"
  and     "card {k. k < length xs  xs ! k < c} + i < length xs"
  and     "count_list xs c  i"
shows     "xs ! (card {k. k < length xs  xs ! k < c} + i) > c"
proof -
  let ?A = "{k. k < length xs  xs ! k < c}"
  have "xs ! (card ?A + i)  c"
    using assms(1) assms(2) sorted_nth_le_gen by blast
  hence "xs ! (card ?A + i) = c  xs ! (card ?A + i) > c"
    by force
  then show ?thesis
  proof
    assume "xs ! (card ?A + i) > c"
    then show ?thesis .
  next
    assume "xs ! (card ?A + i) = c"

    from sorted_nth_le_gen[OF assms(1)]
    have P1: "k < length xs. card ?A  k  c  xs ! k"
      by (metis (mono_tags, lifting) assms(1) dual_order.strict_trans2 linorder_not_le
                                     sorted_iff_nth_mono sorted_nth_le)

    have P2: "k < length xs. k < card ?A + Suc i  xs ! k  c"
      by (metis (mono_tags, lifting) Suc_leI xs ! (card ?A + i) = c add_Suc_right
                                      add_le_cancel_left assms(1,2) plus_1_eq_Suc sorted_nth_mono)

    have P3: "x  {card ?A..<card ?A + Suc i}. xs ! x = c"
    proof safe
      fix x
      assume "x  {card ?A..<card ?A + Suc i}"
      hence A: "card ?A  x" "x < card ?A + Suc i"
        by simp+

      have "c  xs ! x"
        using P1 A assms(2) by auto
      moreover
      have "xs ! x  c"
        using A(2) P2 assms(2) by force
      ultimately show "xs ! x = c"
        by simp
    qed

    have "{card ?A..<card ?A + Suc i}  {k. k < length xs  xs ! k = c}"
    proof
      fix x
      assume A: "x  {card ?A..<card ?A + Suc i}"
      have "x < card ?A + Suc i"
        using A by simp+
      hence "x < length xs"
        using assms(2) by linarith
      moreover
      have "xs ! x = c"
        using P3 A by blast
      ultimately show "x  {k. k < length xs  xs ! k = c}"
        by blast
    qed
    hence "count_list xs c  card {card ?A..<card ?A + Suc i}"
      using count_list_card[of xs c] card_mono
      by (metis (mono_tags, lifting) xs ! (card ?A + i) = c assms(2) card_ge_0_finite count_in
                                     nth_mem)

    moreover
    have "card {card ?A..<card ?A + Suc i} = Suc i"
      by simp
    ultimately have False
      using assms(3) by linarith
    then show ?thesis
      by blast
  qed
qed

end