Theory Buckets

theory Buckets
  imports 
    "../../util/Continuous_Interval" 
    List_Type
begin
section ‹Buckets›

subsection ‹Entire Bucket›

definition bucket :: "('a :: {linorder,order_bot}  nat)  'a list  nat  nat set"
  where
"bucket α T b  {k |k. k < length T  α (T ! k) = b}"

definition bucket_size :: "('a :: {linorder,order_bot}  nat)  'a list  nat  nat"
  where
"bucket_size α T b  card (bucket α T b)"

definition bucket_upt :: "('a :: {linorder,order_bot}  nat)  'a list  nat  nat set"
  where
"bucket_upt α T b = {k |k. k < length T  α (T ! k) < b}"

definition bucket_start :: "('a :: {linorder,order_bot}  nat)  'a list  nat  nat"
  where
"bucket_start α T b  card (bucket_upt α T b)"

definition bucket_end :: "('a :: {linorder,order_bot}  nat)  'a list  nat  nat"
  where
"bucket_end α T b  card (bucket_upt α T (Suc b))"

lemma bucket_upt_subset:
  "bucket_upt α T b  {0..<length T}"
  by (rule subsetI, simp add: bucket_upt_def)

lemma bucket_upt_subset_Suc:
  "bucket_upt α T b  bucket_upt α T (Suc b)"
  by (rule subsetI, simp add: bucket_upt_def)

lemma bucket_upt_un_bucket:
  "bucket_upt α T b  bucket α T b = bucket_upt α T (Suc b)"
  apply (clarsimp simp: bucket_upt_def bucket_def)
  apply (intro equalityI subsetI; clarsimp)
  apply (erule disjE; clarsimp)
  done

lemma bucket_0:
  assumes "valid_list T" "α bot = 0" "strict_mono α" "length T = Suc k"
  shows "bucket α T 0 = {k}"
proof safe
  fix x
  assume "x  bucket α T 0"
  then show "x = k"
    by (metis (mono_tags, lifting) assms bucket_def diff_Suc_1 le_neq_trans le_simps(2)
                                   mem_Collect_eq strict_mono_eq valid_list_def)
next
  show "k  bucket α T 0"
    by (metis (mono_tags, lifting) assms(1,2,4) bucket_def diff_Suc_1 last_conv_nth lessI
                                   list.size(3) mem_Collect_eq order_less_irrefl valid_list_def)
qed

lemma finite_bucket:
  "finite (bucket α T x)"
  by (clarsimp simp: bucket_def)

lemma finite_bucket_upt:
  "finite (bucket_upt α T b)"
  by (meson bucket_upt_subset subset_eq_atLeast0_lessThan_finite)

lemma bucket_start_Suc:
  "bucket_start α T (Suc b) = bucket_start α T b + bucket_size α T b"
  apply (clarsimp simp: bucket_start_def bucket_size_def)
  apply (subst card_Un_disjoint[symmetric])
     apply (meson bucket_upt_subset subset_eq_atLeast0_lessThan_finite)
    apply (simp add: finite_bucket)
   apply (rule disjointI')
  apply (metis (mono_tags, lifting) bucket_def bucket_upt_def less_irrefl_nat mem_Collect_eq)
  apply (simp add: bucket_upt_un_bucket)
  done

lemma bucket_start_le:
  "b  b'  bucket_start α T b  bucket_start α T b'"
  apply (clarsimp simp: bucket_start_def)
  by (meson bucket_upt_subset bucket_upt_subset_Suc card_mono lift_Suc_mono_le
        subset_eq_atLeast0_lessThan_finite)

lemma bucket_start_Suc_eq_bucket_end:
  "bucket_start α T (Suc b) = bucket_end α T b"
  by (simp add: bucket_end_def bucket_start_def)

lemma bucket_end_le_length:
  "bucket_end α T b  length T"
  apply (clarsimp simp: bucket_end_def)
  apply (insert card_mono[OF _  bucket_upt_subset[of α T "Suc b"]])
  apply (erule meta_impE, simp)
  apply (erule order.trans)
  apply simp
  done

lemma bucket_start_le_end:
  "bucket_start α T b  bucket_end α T b"
  by (metis Suc_n_not_le_n bucket_start_Suc_eq_bucket_end bucket_start_le nat_le_linear)

lemma le_bucket_start_le_end:
  "b  b'  bucket_start α T b  bucket_end α T b'"
  using bucket_start_le bucket_start_le_end le_trans by blast

lemma bucket_end_le:
  "b  b'  bucket_end α T b  bucket_end α T b'"
  by (metis bucket_start_Suc_eq_bucket_end bucket_start_le_end lift_Suc_mono_le)

lemma less_bucket_end_le_start:
  "b < b'  bucket_end α T b  bucket_start α T b'"
  by (metis Suc_leI bucket_start_Suc_eq_bucket_end bucket_start_le)

lemma bucket_end_def':
  "bucket_end α T b = bucket_start α T b + bucket_size α T b"
  by (metis bucket_start_Suc bucket_start_Suc_eq_bucket_end)

lemma valid_list_bucket_start_0:
  "valid_list T; strict_mono α; α bot = 0 
   bucket_start α T 0 = 0"
  by (clarsimp simp: bucket_start_def bucket_upt_def)

lemma bucket_upt_0:
  "bucket_upt α T 0 = {}"
  by (clarsimp simp: bucket_upt_def)

lemma bucket_start_0:
  "bucket_start α T 0 = 0"
  by (clarsimp simp: bucket_start_def bucket_upt_def)

lemma valid_list_bucket_upt_Suc_0:
  "valid_list T; strict_mono α; α bot = 0; length T = Suc n 
   bucket_upt α T (Suc 0) = {n}"
  apply (clarsimp simp: bucket_upt_def)
  apply (intro equalityI subsetI)
   apply (clarsimp simp: valid_list_def)
   apply (metis less_antisym strict_mono_eq)
  apply (clarsimp simp: valid_list_ex_def)
  done

lemma valid_list_bucket_end_0:
  "valid_list T; strict_mono α; α bot = 0 
   bucket_end α T 0 = 1"
  apply (clarsimp simp: bucket_end_def)
  apply (frule valid_list_length_ex)
  apply clarsimp
  apply (frule (3) valid_list_bucket_upt_Suc_0)
  apply simp
  done

lemma nth_Max:
  "T  []  i < length T. T ! i = Max (set T)"
  by (metis List.finite_set Max_in in_set_conv_nth set_empty)

lemma bucket_upt_Suc_Max:
  "strict_mono α  bucket_upt α T (Suc (α (Max (set T)))) = {0..<length T}"
  apply (intro equalityI subsetI)
   apply (erule bucket_upt_subset[THEN subsetD])
  by (clarsimp simp: bucket_upt_def less_Suc_eq_le strict_mono_less_eq)

lemma bucket_end_Max:
  "strict_mono α  bucket_end α T (α (Max (set T))) = length T"
  apply (clarsimp simp: bucket_end_def)
  apply (drule bucket_upt_Suc_Max[where T = T])
  apply clarsimp
  done

lemma bucket_end_eq_length:
  "strict_mono α; b  α (Max (set T)); T  []; bucket_end α T b = length T 
   b = α (Max (set T))"
proof -
  assume "strict_mono α" "b  α (Max (set T))" "bucket_end α T b = length T" "T  []"
  show "b = α (Max (set T))"
  proof (rule ccontr)
    assume "b  α (Max (set T))"
    with b  _
    have "b < α (Max (set T))"
      by simp
    hence "b'. b' = α (Max (set T))"
      by blast
    then obtain b' where
      "b' = α (Max (set T))"
      by blast
    with b < _
    have "b < b'"
      by blast
    hence "bucket_end α T b  bucket_start α T b'"
      by (simp add: less_bucket_end_le_start)
    moreover
    from nth_Max[OF T  []]
    obtain i where
      "i < length T"
      "T ! i = Max (set T)"
      by blast
    with b' = α (Max (set T)) strict_mono α
    have "i  bucket α T b'"
      by (simp add: bucket_def)
    hence "bucket_start α T b' < bucket_end α T b'"
      by (metis add_diff_cancel_left' bucket_end_def' bucket_size_def bucket_start_le_end
            card_gt_0_iff diff_is_0_eq' empty_iff finite_bucket nat_less_le)
    moreover
    have "bucket_end α T b'  length T"
      using bucket_end_le_length by blast
    ultimately
    show False
      using bucket_end α T b = length T
      by linarith
  qed
qed

subsection ‹L-types›

definition l_bucket :: "('a :: {linorder,order_bot}  nat)  'a list  nat  nat set"
  where
"l_bucket α T b = {k |k. k  bucket α T b  suffix_type T k = L_type}"

definition l_bucket_size :: "('a :: {linorder,order_bot}  nat)  'a list  nat  nat"
  where
"l_bucket_size α T b  card (l_bucket α T b)"

definition l_bucket_end :: "('a :: {linorder,order_bot}  nat)  'a list  nat  nat"
  where
"l_bucket_end α T b = bucket_start α T b + l_bucket_size α T b"

lemma l_bucket_subset_bucket:
  "l_bucket α T b  bucket α T b"
  by (rule subsetI, simp add: l_bucket_def)

lemma bucket_upt_int_l_bucket:
  "strict_mono α  bucket_upt α T b  l_bucket α T b = {}"
  apply (rule disjoint_subset2[where B = "bucket α T b"])
   apply (simp add: l_bucket_def)
  apply (simp add: bucket_def bucket_upt_def)
  apply (rule disjointI')
  apply clarsimp
  done

lemma subset_l_bucket:
  "k < length ls. ls ! k < length T  suffix_type T (ls ! k) = L_type  α (T ! (ls ! k)) = x;
    distinct ls 
   set ls  l_bucket α T x"
  apply (rule subsetI)
  apply (clarsimp simp: l_bucket_def bucket_def in_set_conv_nth)
  done

lemma finite_l_bucket:
  "finite (l_bucket α T x)"
  apply (clarsimp simp: finite_bucket l_bucket_def)
  done

lemma l_bucket_list_eq:
  "k < length ls. ls ! k < length T  suffix_type T (ls ! k) = L_type  α (T ! (ls ! k)) = x;
    distinct ls; length ls = l_bucket_size α T x 
   set ls = l_bucket α T x"
  apply (frule (1) subset_l_bucket)
  apply (frule distinct_card)
  apply (insert finite_l_bucket[of α T x])
  by (simp add: card_subset_eq l_bucket_size_def)

lemma l_bucket_le_bucket_size:
  "l_bucket_size α T b  bucket_size α T b"
  apply (clarsimp simp: l_bucket_size_def bucket_size_def)
  apply (rule card_mono[OF finite_bucket l_bucket_subset_bucket])
  done

lemma l_bucket_not_empty:
  "i < length T; suffix_type T i = L_type  0 < l_bucket_size α T (α (T ! i))"
  apply (clarsimp simp: l_bucket_size_def)
  apply (subst card_gt_0_iff)
  apply (intro conjI finite_l_bucket)
  apply (clarsimp simp: l_bucket_def bucket_def)
  apply blast
  done

lemma l_bucket_end_le_bucket_end:
  "l_bucket_end α T b  bucket_end α T b"
  apply (clarsimp simp: l_bucket_end_def)
  apply (rule order.trans[where b = "bucket_start α T b + bucket_size α T b"])
   apply (simp add: l_bucket_le_bucket_size)
  by (metis bucket_start_Suc bucket_start_Suc_eq_bucket_end le_refl)

lemma l_bucket_Max:
  assumes "valid_list T"
  and     "Suc 0 < length T"
  and     "strict_mono α"
  shows "l_bucket α T (α (Max (set T))) = bucket α T (α (Max (set T)))"
proof (intro subsetI equalityI)
  let ?b = "α (Max (set T))"
  fix x
  assume "x  l_bucket α T ?b"
  then show "x  bucket α T ?b"
    using l_bucket_subset_bucket by blast
next
  let ?b = "α (Max (set T))"
  fix x
  assume "x  bucket α T ?b"
  hence "x < length T" "α (T ! x) = ?b"
    using bucket_def by blast+
  with suffix_max_hd_is_l_type[OF assms(1) _ assms(2)]
  have "suffix_type T x = L_type"
    by (metis Cons_nth_drop_Suc assms(3) list.sel(1) strict_mono_eq)
  then show "x  l_bucket α T ?b"
    using x  bucket α T (α (Max (set T))) l_bucket_def by blast
qed

subsection ‹LMS-types›

definition lms_bucket :: "('a :: {linorder,order_bot}  nat)  'a list  nat  nat set"
  where
"lms_bucket α T b = {k |k. k  bucket α T b  abs_is_lms T k}"

definition lms_bucket_size :: "('a :: {linorder,order_bot}  nat)  'a list  nat  nat"
  where
"lms_bucket_size α T b  card (lms_bucket α T b)"

lemma lms_bucket_subset_bucket:
  "lms_bucket α T b  bucket α T b"
  by (simp add: lms_bucket_def)

lemma finite_lms_bucket:
  "finite (lms_bucket α T b)"
  by (clarsimp simp: lms_bucket_def finite_bucket)

lemma disjoint_l_lms_bucket:
 "l_bucket α T b  lms_bucket α T b = {}"
  apply (rule disjointI')
  by (clarsimp simp: l_bucket_def lms_bucket_def abs_is_lms_def)

subsection ‹S-types›

definition s_bucket :: "('a :: {linorder,order_bot}  nat)  'a list  nat  nat set"
  where
"s_bucket α T b = {k |k. k  bucket α T b  suffix_type T k = S_type}"

definition s_bucket_size :: "('a :: {linorder,order_bot}  nat)  'a list  nat  nat"
  where
"s_bucket_size α T b  card (s_bucket α T b)"

definition s_bucket_start :: "('a :: {linorder,order_bot}  nat)  'a list  nat  nat"
  where
"s_bucket_start α T b  bucket_start α T b + l_bucket_size α T b"

lemma finite_s_bucket:
 "finite (s_bucket α T b)"
  by (clarsimp simp: s_bucket_def finite_bucket)

lemma disjoint_l_s_bucket:
 "l_bucket α T b  s_bucket α T b = {}"
  apply (rule disjointI')
  by (clarsimp simp: l_bucket_def s_bucket_def)

lemma lms_subset_s_bucket:
  "lms_bucket α T b  s_bucket α T b"
  by (clarsimp simp: s_bucket_def lms_bucket_def abs_is_lms_def)

lemma l_un_s_bucket:
  "bucket α T b = l_bucket α T b  s_bucket α T b"
  apply (rule equalityI; clarsimp simp: l_bucket_def s_bucket_def)
  by (meson suffix_type_def)

lemma s_bucket_Max:
  assumes "valid_list T"
  and     "length T > Suc 0"
  and     "strict_mono α"
shows "s_bucket α T (α (Max (set T))) = {}"
proof -
  let ?b = "α (Max (set T))"
  from l_bucket_Max[OF assms]
  have "l_bucket α T ?b = bucket α T ?b" .
  moreover
  from l_un_s_bucket
  have "bucket α T ?b = l_bucket α T ?b  s_bucket α T ?b" .
  hence "s_bucket α T ?b  bucket α T ?b"
    by blast
  moreover
  from disjoint_l_s_bucket
  have "l_bucket α T ?b  s_bucket α T ?b = {}" .
  ultimately
  show ?thesis
    by blast
qed

lemma s_bucket_0:
  assumes "valid_list T"
  and     "strict_mono α"
  and     "α bot = 0"
  and     "length T = Suc n"
shows "s_bucket α T 0 = {n}"
proof -
  have "suffix_type T n = S_type"
    using assms(4) suffix_type_last by blast
  moreover
  have "T ! n = bot"
    by (metis assms(1) assms(4) diff_Suc_1 last_conv_nth length_greater_0_conv valid_list_def)
  hence "α (T ! n) = 0"
    by (simp add: assms(3))
  ultimately have "n  s_bucket α T 0"
    by (simp add: assms(4) bucket_def s_bucket_def)
  hence "{n}  s_bucket α T 0"
    by blast
  moreover
  have "s_bucket α T 0  {n}"
    unfolding s_bucket_def
  proof safe
    fix k
    assume "k  bucket α T 0" "suffix_type T k = S_type"
    hence "k  n"
      by (simp add: assms(4) bucket_def)
    have "α (T ! k) = 0"
      using k  bucket α T 0 bucket_def by blast
    hence "T ! k = bot"
      by (metis assms(2) assms(3) strict_mono_eq)
    show "k = n"
    proof (rule ccontr)
      assume "k  n"
      hence "k < n"
        by (simp add: k  n le_neq_implies_less)
      then show False
        using k  bucket α T 0 k  n assms bucket_0 by blast
    qed
  qed
  ultimately show ?thesis
    by blast
qed

lemma s_bucket_successor:
  "valid_list T; strict_mono α; α bot = 0; b  0; x  s_bucket α T b 
    Suc x  s_bucket α T b  (b'. b < b'  Suc x  bucket α T b')"
proof -
  assume "valid_list T" "strict_mono α" "α bot = 0" "b  0" "x  s_bucket α T b"
  hence "suffix_type T x = S_type"
    by (simp add: s_bucket_def)

  from valid_list_length_ex[OF valid_list _]
  obtain n where
    "length T = Suc n"
    by blast
  moreover
  from x  s_bucket α T b
  have "x < length T" "α (T ! x) = b"
    by (simp add: s_bucket_def bucket_def)+
  ultimately have "Suc x < length T"
    by (metis Suc_lessI α bot = 0 b  0 valid_list T diff_Suc_1 last_conv_nth list.size(3)
          valid_list_def)

  have "T ! x  T ! Suc x"
    by (simp add: Suc x < length T suffix_type T x = S_type s_type_letter_le_Suc)
  hence "T ! x < T ! Suc x  T ! x = T ! Suc x"
    using le_neq_trans by blast
  moreover
  have "T ! x < T ! Suc x  ?thesis"
  proof -
    assume "T ! x < T ! Suc x"
    hence "α (T ! x) < α (T ! Suc x)"
      by (simp add: strict_mono α strict_mono_less)
    hence "b < α (T ! Suc x)"
      by (simp add: α (T ! x) = b)
    with Suc x < length T
    have "Suc x  bucket α T (α (T ! Suc x))"
      by (simp add: bucket_def)
    with b < α (T ! Suc x)
    show ?thesis
      by blast
  qed
  moreover
  have "T ! x = T ! Suc x  ?thesis"
  proof -
    assume "T ! x = T ! Suc x"
    hence "α (T ! Suc x) = b"
      using α (T ! x) = b by auto
    moreover
    from Suc x < length T T ! x = T ! Suc x suffix_type T x = S_type
    have "suffix_type T (Suc x) = S_type"
      using suffix_type_neq by force
    ultimately show ?thesis
      by (simp add: Suc x < length T bucket_def s_bucket_def)
  qed
  ultimately show ?thesis
    by blast
qed

lemma subset_s_bucket_successor:
  "valid_list T; strict_mono α; α bot = 0; b  0; A  s_bucket α T b; A  {} 
    x  A. Suc x  s_bucket α T b - A  (b'. b < b'  Suc x  bucket α T b')"
proof -
  assume "valid_list T" "strict_mono α" "α bot = 0" "b  0" "A  s_bucket α T b" "A  {}"

  have "finite A"
    using A  s_bucket α T b finite_s_bucket finite_subset by blast

  let ?B = "s_bucket α T b - A"

  have "x  A. Suc x  A"
  proof (rule ccontr)
    assume "¬ (xA. Suc x  A)"
    hence "xA. Suc x  A"
      by clarsimp
    hence "¬ finite A"
      using Max.coboundedI Max_in Suc_n_not_le_n A  {} by blast
    with finite A
    show False
      by blast
  qed
  then obtain x where
    "x  A"
    "Suc x  A"
    by blast
  with s_bucket_successor[OF valid_list _ strict_mono _ α _ = _ b  _, of x]
       A  s_bucket α T b
  have "Suc x  s_bucket α T b  (b'. b < b'  Suc x  bucket α T b')"
    by blast
  moreover
  have "Suc x  s_bucket α T b  ?thesis"
  proof -
    assume "Suc x  s_bucket α T b"
    with Suc x  A
    show ?thesis
      using x  A by blast
  qed
  moreover
  have "(b'. b < b'  Suc x  bucket α T b')  ?thesis"
    using x  A by blast
  ultimately show ?thesis
    by blast
qed

lemma valid_list_s_bucket_start_0:
  "valid_list T; strict_mono α; α bot = 0 
   s_bucket_start α T 0 = 0"
  apply (clarsimp simp: s_bucket_start_def bucket_start_0)
  apply (frule valid_list_length_ex)
  apply clarsimp
  apply (frule (3) bucket_0)
  apply (frule suffix_type_last)
  apply (clarsimp simp: l_bucket_size_def l_bucket_def)
  done

definition pure_s_bucket :: "('a :: {linorder,order_bot}  nat)  'a list  nat  nat set"
  where
"pure_s_bucket α T b = {k |k. k  s_bucket α T b  k  lms_bucket α T b}"

definition pure_s_bucket_size :: "('a :: {linorder,order_bot}  nat)  'a list  nat  nat"
  where
"pure_s_bucket_size α T b  card (pure_s_bucket α T b)"

lemma finite_pure_s_bucket:
 "finite (pure_s_bucket α T b)"
  by (clarsimp simp: pure_s_bucket_def finite_s_bucket)

lemma pure_s_subset_s_bucket:
  "pure_s_bucket α T b  s_bucket α T b"
  by (clarsimp simp: s_bucket_def pure_s_bucket_def)

lemma disjoint_lms_pure_s_bucket:
 "lms_bucket α T b  pure_s_bucket α T b = {}"
  apply (rule disjointI')
  by (clarsimp simp: lms_bucket_def pure_s_bucket_def)

lemma disjoint_pure_s_lms_bucket:
  "pure_s_bucket α T b  lms_bucket α T b = {}"
  apply (subst Int_commute)
  by (rule disjoint_lms_pure_s_bucket)

lemma s_eq_pure_s_un_lms_bucket:
  "s_bucket α T b = pure_s_bucket α T b  lms_bucket α T b"
  apply (intro equalityI; clarsimp simp: pure_s_subset_s_bucket lms_subset_s_bucket)
  apply (clarsimp simp: s_bucket_def lms_bucket_def pure_s_bucket_def)
  done

lemma l_pl_pure_s_pl_lms_size:
  "bucket_size α T b = l_bucket_size α T b + pure_s_bucket_size α T b + lms_bucket_size α T b"
  apply (clarsimp simp: bucket_size_def l_bucket_size_def pure_s_bucket_size_def
                        lms_bucket_size_def)
  apply (subst add.assoc)
  apply (subst card_Un_disjoint[symmetric,
          OF finite_pure_s_bucket finite_lms_bucket disjoint_pure_s_lms_bucket])
  apply (subst s_eq_pure_s_un_lms_bucket[symmetric])
  apply (subst card_Un_disjoint[symmetric,
          OF finite_l_bucket finite_s_bucket disjoint_l_s_bucket])
  apply (clarsimp simp: l_un_s_bucket)
  done

lemma s_bucket_start_eq_l_bucket_end:
  "s_bucket_start α T b = l_bucket_end α T b"
  by (simp add: l_bucket_end_def s_bucket_start_def)

lemma s_eq_pure_pl_lms_size:
  "s_bucket_size α T b = pure_s_bucket_size α T b + lms_bucket_size α T b"
  by (simp add: card_Un_disjoint disjoint_pure_s_lms_bucket finite_lms_bucket finite_pure_s_bucket
        lms_bucket_size_def pure_s_bucket_size_def s_bucket_size_def s_eq_pure_s_un_lms_bucket)

lemma bucket_end_eq_s_start_pl_size:
  "bucket_end α T b = s_bucket_start α T b + s_bucket_size α T b"
  by (simp add: bucket_end_def' l_bucket_end_def l_pl_pure_s_pl_lms_size
        s_bucket_start_eq_l_bucket_end s_eq_pure_pl_lms_size)

lemma bucket_start_le_s_bucket_start:
  "bucket_start α T b  s_bucket_start α T b"
  by (simp add: s_bucket_start_def)

lemma bucket_0_size1:
  assumes "valid_list T"
  and     "strict_mono α"
  and     "α bot = 0"
shows "bucket_size α T 0 = Suc 0  l_bucket_size α T 0 = 0"
proof -
  from valid_list_length_ex[OF assms(1)]
  obtain n where
    "length T = Suc n"
    by blast
  with bucket_0[OF assms(1,3,2)]
  have "bucket α T 0 = {n}"
    by blast
  hence "bucket_size α T 0 = Suc 0"
    by (simp add: bucket_size_def)
  moreover
  have "suffix_type T n = S_type"
    by (simp add: length T = Suc n suffix_type_last)
  hence "n  l_bucket α T 0"
    by (simp add: l_bucket_def)
  hence "l_bucket_size α T 0 = 0"
  proof -
    have "l_bucket α T 0  {n}"
      by (metis bucket α T 0 = {n} l_bucket_subset_bucket)
    hence "n. n  l_bucket α T 0"
      using n  l_bucket α T 0 by blast
    then show ?thesis
      by (simp add: l_bucket_size_def)
  qed
  ultimately
  show ?thesis
    by blast
qed

lemma bucket_0_size2:
  assumes "valid_list T"
  and     "strict_mono α"
  and     "α bot = 0"
  and     "length T = Suc (Suc n)"
shows "bucket_size α T 0 = Suc 0  l_bucket_size α T 0 = 0  lms_bucket_size α T 0 = Suc 0 
       pure_s_bucket_size α T 0 = 0"
proof -
  from bucket_0[OF assms(1,3,2,4)]
  have "bucket α T 0 = {Suc n}" .

  have "abs_is_lms T (Suc n)"
    using assms(1,4) abs_is_lms_last by blast
  hence "lms_bucket α T 0 = {Suc n}"
    using lms_bucket_subset_bucket[of α T 0] bucket α T 0 = {Suc n}
    by (simp add: lms_bucket_def subset_antisym)
  hence "lms_bucket_size α T 0 = Suc 0"
    by (simp add: lms_bucket_size_def)
  moreover
  from bucket α T 0 = {Suc n} lms_bucket α T 0 = {Suc n}
  have "pure_s_bucket α T 0 = {}"
    by (metis disjoint_insert(1) disjoint_l_lms_bucket disjoint_lms_pure_s_bucket
          l_bucket_subset_bucket l_un_s_bucket pure_s_subset_s_bucket singletonI
          subset_singletonD sup_bot.left_neutral)
  hence "pure_s_bucket_size α T 0 = 0"
    by (simp add: pure_s_bucket_size_def)
  moreover
  from bucket_0_size1[OF assms(1-3)]
  have "bucket_size α T 0 = Suc 0  l_bucket_size α T 0 = 0" .
  ultimately
  show ?thesis
    by blast
qed

definition lms_bucket_start :: "('a :: {linorder,order_bot}  nat)  'a list  nat  nat"
  where
"lms_bucket_start α T b = bucket_start α T b + l_bucket_size α T b + pure_s_bucket_size α T b"

lemma l_bucket_end_le_lms_bucket_start:
  "l_bucket_end α T b  lms_bucket_start α T b"
  by (simp add: l_bucket_end_def lms_bucket_start_def)

lemma lms_bucket_start_le_bucket_end:
  "lms_bucket_start α T b  bucket_end α T b"
  by (simp add: bucket_end_def' lms_bucket_start_def l_pl_pure_s_pl_lms_size)

lemma lms_bucket_pl_size_eq_end:
  "lms_bucket_start α T b + lms_bucket_size α T b = bucket_end α T b"
  by (simp add: bucket_end_def' l_pl_pure_s_pl_lms_size lms_bucket_start_def)

section ‹Continuous Buckets›

lemma continuous_buckets:
  "continuous_list (map (λb. (bucket_start α T b, bucket_end α T b)) [i..<j])"
  by (clarsimp simp: continuous_list_def bucket_start_Suc_eq_bucket_end)

lemma index_in_bucket_interval_gen:
  "i < length T; strict_mono α 
    b  α (Max (set T)). bucket_start α T b  i  i < bucket_end α T b"
  apply (insert continuous_buckets[of α T 0 "Suc (α (Max (set T)))"])
  apply (drule continuous_list_interval_2[where n = "α (Max (set T))" and i = i])
     apply clarsimp
    apply (subst nth_map)
     apply clarsimp
    apply (clarsimp split: prod.split simp: upt_rec bucket_start_0)
    apply (subst nth_map)
    apply clarsimp
   apply (clarsimp split: prod.split simp: nth_append bucket_end_Max)
  apply clarsimp
  apply (clarsimp simp: nth_append split: if_splits prod.splits)
  apply (meson dual_order.order_iff_strict)
  by blast

lemma index_in_bucket_interval:
  "i < length T; valid_list T; α bot = 0; strict_mono α 
    b  α (Max (set T)). bucket_start α T b  i  i < bucket_end α T b"
  using index_in_bucket_interval_gen by blast

section ‹Bucket Initialisation›

definition lms_bucket_init :: "('a :: {linorder,order_bot}  nat)  'a list  nat list  bool"
  where
"lms_bucket_init α T B =
  (α (Max (set T)) < length B 
   (b  α (Max (set T)). B ! b = bucket_end α T b))"

lemma lms_bucket_init_length:
  "lms_bucket_init α T B  α (Max (set T)) < length B"
  using lms_bucket_init_def by blast

lemma lms_bucket_initD:
  "lms_bucket_init α T B; b  α (Max (set T))  B ! b = bucket_end α T b"
  using lms_bucket_init_def by blast

definition l_bucket_init :: "('a :: {linorder,order_bot}  nat)  'a list  nat list  bool"
  where
"l_bucket_init α T B =
  (α (Max (set T)) < length B 
   (b  α (Max (set T)). B ! b = bucket_start α T b))"

lemma l_bucket_init_length:
  "l_bucket_init α T B  α (Max (set T)) < length B"
  using l_bucket_init_def by blast

lemma l_bucket_initD:
  "l_bucket_init α T B; b  α (Max (set T))  B ! b = bucket_start α T b"
  using l_bucket_init_def by blast

definition s_bucket_init
  where
"s_bucket_init α T B =
  (α (Max (set T)) < length B 
   (bα (Max (set T)).
    (b > 0  B ! b = bucket_end α T b) 
    (b = 0  B ! b = 0)
   )
  )"

lemma s_bucket_init_length:
  "s_bucket_init α T B  α (Max (set T)) < length B"
  using s_bucket_init_def by blast

lemma s_bucket_initD:
  "s_bucket_init α T B; b  α (Max (set T)); b > 0  B ! b = bucket_end α T b"
  "s_bucket_init α T B; b  α (Max (set T)); b = 0  B ! b = 0"
  using s_bucket_init_def by auto

section ‹Bucket Range›

definition in_s_current_bucket
  where
"in_s_current_bucket α T B b i  (b  α (Max (set T))  B ! b  i  i < bucket_end α T b)"

lemma in_s_current_bucketD:
  "in_s_current_bucket α T B b i  b  α (Max (set T))"
  "in_s_current_bucket α T B b i  B ! b  i"
  "in_s_current_bucket α T B b i  i < bucket_end α T b"
  by (simp_all add: in_s_current_bucket_def)

definition in_s_current_buckets
  where
"in_s_current_buckets α T B i  (b. in_s_current_bucket α T B b i)"

lemma in_s_current_bucket_list_slice:
  assumes "length SA = length T"
  and     "in_s_current_bucket α T B b i"
  and     "SA ! i = x"
shows "x  set (list_slice SA (B ! b) (bucket_end α T b))"
  by (metis assms bucket_end_le_length in_s_current_bucket_def list_slice_nth_mem)

definition in_l_bucket
  where
"in_l_bucket α T b i  (b  α (Max (set T))  bucket_start α T b  i  i < l_bucket_end α T b)"

end