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