Theory Rank_Util

theory Rank_Util
  imports "HOL-Library.Multiset"
          Count_Util
          "SuffixArray.Prefix"
begin

section "Rank Definition"

text ‹Count how many occurrences of an element are in a certain index in the list›

text ‹Definition 3.7 from cite"Cheung_CPP_2025": Rank›
definition rank :: "'a list  'a  nat  nat"
  where
"rank s x i  count_list (take i s) x"

section "Rank Properties"

subsection "List Properties"

lemma rank_cons_same:
  "rank (x # xs) x (Suc i) = Suc (rank xs x i)"
  by (simp add: rank_def)

lemma rank_cons_diff:
  "a  x  rank (a # xs) x (Suc i) = rank xs x i"
  by (simp add: rank_def)

subsection "Counting Properties"

lemma rank_length:
  "rank xs x (length xs) = count_list xs x"
  by (simp add: rank_def)

lemma rank_gre_length:
  "length xs  n  rank xs x n = count_list xs x"
  by (simp add: rank_def)

lemma rank_not_in:
  "x  set xs  rank xs x i = 0"
  by (metis gr_zeroI in_count rank_def set_take_subset subset_code(1))

lemma rank_0:
  "rank xs x 0 = 0"
  by (simp add: rank_def)

text ‹Theorem 3.11 from cite"Cheung_CPP_2025": Rank Equivalence›
lemma rank_card_spec:
  "rank xs x i = card {j. j < length xs  j < i  xs ! j = x}"
proof -
  have "rank xs x i = count_list (take i xs) x"
    by (meson rank_def)
  moreover
  have "count_list (take i xs) x = card {j. j < length (take i xs)  (take i xs) ! j = x}"
    by (metis count_list_card)
  moreover
  have "{j. j < length (take i xs)  (take i xs) ! j = x} = 
        {j. j < length xs  j < i  xs ! j = x}"
    by fastforce
  ultimately show ?thesis
    by simp
qed


lemma le_rank_plus_card:
  "i  j 
   rank xs x j = rank xs x i + card {k. k < length xs  i  k  k < j  xs ! k = x}"
proof -
  assume "i  j"

  let ?X = "{k. k < length xs  k < j  xs ! k = x}"
  have "rank xs x j = card ?X"
    by (simp add: rank_card_spec)
  moreover
  let ?Y = "{k. k < length xs  k < i  xs ! k = x}"
  have "rank xs x i = card ?Y"
    by (simp add: rank_card_spec)
  moreover
  let ?Z = "{k. k < length xs  i  k  k < j  xs ! k = x}"
  have "?Y  ?Z = ?X"
  proof safe
    fix k
    assume "k < i"
    then show "k < j"
      using i  j order_less_le_trans by blast
  next
    fix k
    assume "¬ i  k"
    then show "k < i"
      using linorder_le_less_linear by blast
  qed
  moreover
  have "?Y  ?Z = {}"
    by force
  hence "card (?Y  ?Z) = card ?Y + card ?Z"
    by (simp add: card_Un_disjoint)
  ultimately show ?thesis
    by presburger
qed

subsection "Bound Properties"

lemma rank_lower_bound:
  assumes "k < rank xs x i"
  shows "k < i"
proof -
  from rank_card_spec[of xs x i]
  have "rank xs x i = card {j. j < length xs  j < i  xs ! j = x}" .
  hence "k < card {j. j < length xs  j < i  xs ! j = x}"
    using assms by presburger
  moreover
  {
    have "i  length xs  length xs < i"
      using linorder_not_less by blast
    moreover
    have "i  length xs  {j. j < length xs  j < i  xs ! j = x}  {0..<i}"
      using atLeast0LessThan by blast
    hence "i  length xs  card {j. j < length xs  j < i  xs ! j = x}  i"
      using subset_eq_atLeast0_lessThan_card by presburger
    moreover
    have "length xs < i  {j. j < length xs  j < i  xs ! j = x}  {0..<length xs}"
      using atLeast0LessThan by blast
    hence "length xs < i  card {j. j < length xs  j < i  xs ! j = x}  length xs"
      using subset_eq_atLeast0_lessThan_card by presburger
    hence "length xs < i  card {j. j < length xs  j < i  xs ! j = x}  i"
      by linarith
    ultimately have "card {j. j < length xs  j < i  xs ! j = x}  i"
      by blast
  }
  ultimately show ?thesis
    using dual_order.strict_trans1 by blast
qed

corollary rank_Suc_ex:
  assumes "k < rank xs x i"
  shows "l. i = Suc l"
  by (metis Nat.lessE assms rank_lower_bound)

lemma rank_upper_bound:
  "i < length xs; xs ! i = x  rank xs x i < count_list xs x"
proof (induct xs arbitrary: i)
  case Nil
  then show ?case
    by (simp add: rank_def)
next
  case (Cons a xs i)
  then show ?case
  proof (cases i)
    case 0
    then show ?thesis
      by (metis Cons.prems(2) count_in list.set_intros(1) nth_Cons_0 rank_0)
  next
    case (Suc n)
    then show ?thesis
      by (metis Cons.hyps Cons.prems Suc_less_eq length_Cons nth_Cons_Suc rank_cons_diff 
                rank_cons_same rank_length)
  qed
qed

lemma rank_idx_mono:
  "i  j  rank xs x i  rank xs x j"
proof (cases "i = j")
  assume "i = j"
  then show ?thesis
    by simp
next
  assume "i  j" "i  j"
  hence "i < j"
    using antisym_conv2 by blast
  hence "prefix xs j = prefix xs i @ list_slice xs i j"
    by (metis i  j append_take_drop_id list_slice.elims min.absorb1 take_take)
  hence "rank xs x j = rank xs x i + count_list (list_slice xs i j) x"
    by (metis count_list_append rank_def)
  then show ?thesis
    by fastforce
qed

lemma rank_less:
  "i < length xs; i < j; xs ! i = x  rank xs x i < rank xs x j"
proof -
  let ?X = "{k. k < length xs  i  k  k < j  xs ! k = x}"
  assume "i < length xs" "i < j" "xs ! i = x"
  with le_rank_plus_card[of i j xs x]
  have "rank xs x j = rank xs x i + card ?X"
    using nless_le by blast
  moreover
  have "i  ?X"
    using i < j i < length xs xs ! i = x by blast
  hence "card ?X > 0"
    using card_gt_0_iff by fastforce
  ultimately show ?thesis
    by linarith
qed

lemma rank_upper_bound_gen:
  "rank xs x i  count_list xs x"
  by (metis nat_le_linear rank_gre_length rank_idx_mono)


subsection "Sorted Properties"

lemma sorted_card_rank_idx:
  assumes "sorted xs"
  and     "i < length xs"
shows "i = card {j. j < length xs  xs ! j < xs ! i} + rank xs (xs ! i) i"
proof -

  let ?A = "{j. j < length xs  xs ! j < xs ! i}"
  let ?B = "{j. j < length xs  xs ! j = xs ! i}"


  have "?B  {}"
    using assms(2) by blast

  have "Min ?B  ?B"
    by (metis (no_types, lifting) Min_in ?B  {} finite_nat_set_iff_bounded mem_Collect_eq)
  hence "Min ?B < length xs" "xs ! (Min ?B) = xs ! i"
    by simp_all

  have "Min ?B  i"
    by (simp add: assms(2))

  have P: "k < Min ?B. xs ! k < xs ! i"
  proof (intro allI impI)
    fix k
    assume "k < Min ?B"
    with sorted_nth_mono[OF assms(1) _ Min ?B < length xs]
    have "xs ! k  xs ! (Min ?B)"
      using le_eq_less_or_eq by presburger
    
    show "xs ! k < xs ! i"
    proof (rule ccontr)
      assume "¬ xs ! k < xs ! i"
      with xs ! k  xs ! (Min ?B) xs ! (Min ?B) = xs ! i
      have "xs ! k = xs ! i"
        by order
      with k < Min ?B Min ?B < length xs
      have "k  ?B"
        by auto
      then show False
        by (metis (mono_tags, lifting) Min_gr_iff k < Min ?B ?B  {} finite_nat_set_iff_bounded 
                                       less_irrefl_nat mem_Collect_eq)
    qed
  qed

  have "?A = {0..<Min ?B}"
  proof (intro equalityI subsetI)
    fix x
    assume "x  ?A"
    hence "x < length xs" "xs ! x < xs ! i"
      by blast+
    hence "xs ! x < xs ! Min ?B"
      using xs ! Min ?B = xs ! i by simp
    hence "x < Min ?B"
      using assms(1) x < length xs Min ?B < length xs
      by (meson dual_order.strict_iff_not not_le_imp_less sorted_nth_mono)
    then show "x  {0..<Min ?B}"
      using atLeastLessThan_iff by blast
  next
    fix x 
    assume "x  {0..<Min ?B}"
    with P Min ?B < length xs
    show "x  ?A"
      by auto
  qed
  moreover
  {
    let ?C = "{j. j < length xs  j < i  xs ! j = xs ! i}"
    from rank_card_spec[of xs "xs ! i" i]
    have "rank xs (xs ! i) i = card ?C" .
    moreover
    have "?C = {Min ?B..<i}" 
    proof (intro equalityI subsetI)
      fix x
      assume "x  ?C"
      hence "x < length xs" "x < i" "xs ! x = xs ! i"
        by blast+
      hence "Min ?B  x"
        by simp
      with x < i
      show "x  {Min ?B..<i}"
        using atLeastLessThan_iff by blast
    next
      fix x
      assume "x  {Min ?B..<i}"
      hence "Min ?B  x" "x < i"
        using atLeastLessThan_iff by blast+
      moreover
      have "xs ! x = xs ! i"
      proof -
        have "xs ! x  xs ! i"
          using assms(1,2) x < i 
          by (simp add: sorted_wrt_nth_less)
        moreover
        have "xs ! Min ?B  xs ! x"
          using assms(1,2) Min ?B  x x < i
          by (meson order.strict_trans sorted_iff_nth_mono)
        ultimately show ?thesis
          using xs ! Min ?B = xs ! i by order
      qed
      ultimately show "x  ?C"
        using assms(2) by fastforce
    qed
    ultimately have "rank xs (xs ! i) i = card {Min ?B..<i}"
      by presburger
  }
  ultimately show ?thesis
    by (simp add: Min ?B  i)
qed

lemma sorted_rank:
  assumes "sorted xs"
  and     "i < length xs"
  and     "xs ! i = a"
shows "rank xs a i = i - card {k. k < length xs  xs ! k < a}"
  using assms(1) assms(2) assms(3) sorted_card_rank_idx by fastforce

lemma sorted_rank_less:
  assumes "sorted xs"
  and     "i < length xs"
  and     "xs ! i < a"
shows "rank xs a i = 0"
proof -
  have "rank xs a i = card {k. k < length xs  k < i  xs ! k = a}"
    by (simp add: rank_card_spec)
  moreover
  have "{k. k < length xs  k < i  xs ! k = a} = {}"
    using assms sorted_wrt_nth_less by fastforce
  ultimately show ?thesis
    by fastforce
qed

lemma sorted_rank_greater:
  assumes "sorted xs"
  and     "i < length xs"
  and     "xs ! i > a"
shows "rank xs a i = count_list xs a"
proof -
  let ?A = "{k. k < length xs  k < i  xs ! k = a}"
  have "rank xs a i = card ?A"
    by (simp add: rank_card_spec)
  moreover
  let ?B = "{k. k < length xs  k  i  xs ! k = a}"
  let ?C = "{k. k < length xs  xs ! k = a}"
  {
    have "?A  ?B = ?C"
    proof safe
      fix x
      assume "¬ i  x"
      then show "x < i"
        using linorder_le_less_linear by blast
    qed
    moreover
    have "?B = {}"
    proof -
      have "k < length xs. k  i  xs ! k > a"
        by (meson assms(1) assms(3) dual_order.strict_trans1 sorted_nth_mono)
      then show ?thesis
        by blast
    qed
    ultimately have "?A = ?C"
      by blast
  }
  ultimately show ?thesis
    by (simp add: count_list_card)
qed

end