Theory Abs_Induce_S_Verification

theory Abs_Induce_S_Verification
  imports "../abs-def/Abs_SAIS"
begin

section "Abstract Induce S Simple Properties"

lemma abs_induce_s_step_ex:
  "B' SA' i'. abs_induce_s_step a b = (B', SA', i')"
  by (meson prod_cases3)

lemma abs_induce_s_step_B_length:
  "abs_induce_s_step (B, SA, i) (α, T) = (B', SA', i')  length B' = length B"
  by (clarsimp split: prod.splits if_splits nat.splits SL_types.splits simp: Let_def)

lemma abs_induce_s_step_SA_length:
  "abs_induce_s_step (B, SA, i) (α, T) = (B', SA', i')  length SA' = length SA"
  by (clarsimp split: prod.splits if_splits nat.splits SL_types.splits simp: Let_def)

lemma abs_induce_s_step_Suc:
  "abs_induce_s_step (B, SA, Suc i) (α, T) = (B', SA', i')  i' = i"
  by (clarsimp split: prod.splits if_splits nat.splits SL_types.splits simp: Let_def)

lemma abs_induce_s_step_0:
  "abs_induce_s_step (B, SA, 0) (α, T) = (B, SA, 0)"
  by (clarsimp split: prod.splits if_splits nat.splits SL_types.splits simp: Let_def)

corollary abs_induce_s_step_0_alt:
  assumes "abs_induce_s_step (B, SA, i) (α, T) = (B', SA', i')"
  and     "i = 0"
shows "B = B'  SA = SA'  i' = 0"
  using assms(1) assms(2) by auto

lemma repeat_abs_induce_s_step_index:
  "B' SA'. repeat n abs_induce_s_step (B, SA, m) (α, T) = (B', SA', m - n) 
            length SA' = length SA  length B' = length B"
proof(induct n arbitrary: m)
  case 0
  then show ?case by (clarsimp simp: repeat_0)
next
  case (Suc n)
  note IH = this

  from IH[of m]
  obtain B' SA' where
    "repeat n abs_induce_s_step (B, SA, m) (α, T) = (B', SA', m - n)"
    "length SA' = length SA"
    "length B' = length B"
    by blast
  with repeat_step[of n abs_induce_s_step "(B, SA, m)" "(α, T)"]
  have "repeat (Suc n) abs_induce_s_step (B, SA, m) (α, T) = abs_induce_s_step (B', SA', m - n) (α, T)"
    by simp
  moreover
  have "B'' SA''. abs_induce_s_step (B', SA', m - n) (α, T) = (B'', SA'', m - Suc n) 
                   length SA'' = length SA'  length B'' = length B'"
  proof (cases "n < m")
    assume "n < m"
    hence "k. m - n = Suc k"
      by presburger
    then obtain k where
      "m - n = Suc k"
      by blast

    from abs_induce_s_step_ex[of "(B',SA', m - n)" "(α, T)"]
    obtain B'' SA'' i' where
      P: "abs_induce_s_step (B', SA', m - n) (α, T) = (B'', SA'', i')"
      by blast
    with `m - n = Suc k` abs_induce_s_step_Suc[of B' SA' k α T B'' SA'' i']
    have "i' = m - Suc n"
      by auto
    with `abs_induce_s_step (B', SA', m - n) (α, T) = (B'', SA'', i')`
          abs_induce_s_step_SA_length[OF P]
          abs_induce_s_step_B_length[OF P]
    show ?thesis
      by simp
  next
    assume "¬n < m"
    hence "m  n"
      by simp
    hence "m - n = 0"
      by simp
    with abs_induce_s_step_0[of B' SA' α T]
    show ?thesis
      by simp
  qed
  ultimately show ?case
    by (simp add: `length SA' = length SA` `length B' = length B`)
qed

lemma abs_induce_s_base_index:
  "B' SA'. abs_induce_s_base α T B SA = (B', SA', 0)"
  unfolding abs_induce_s_base_def
  by (metis cancel_comm_monoid_add_class.diff_cancel repeat_abs_induce_s_step_index)

lemma abs_induce_s_length:
  "length (abs_induce_s α T B SA) = length SA"
  unfolding abs_induce_s_def abs_induce_s_base_def
  apply (rule repeat_maintain_inv; simp add: Let_def)
  apply (clarsimp split: prod.splits simp del: abs_induce_s_step.simps)
  apply (drule abs_induce_s_step_SA_length; simp)
  done

section "Preconditions"

definition l_types_init
  where
"l_types_init α T SA 
  (b  α (Max (set T)).
    set (list_slice SA (bucket_start α T b) (l_bucket_end α T b)) = l_bucket α T b 
    distinct (list_slice SA (bucket_start α T b) (l_bucket_end α T b))
  )"

lemma l_types_initD:
  "l_types_init α T SA; b  α (Max (set T)) 
   set (list_slice SA (bucket_start α T b) (l_bucket_end α T b)) = l_bucket α T b"
  "l_types_init α T SA; b  α (Max (set T)) 
   distinct (list_slice SA (bucket_start α T b) (l_bucket_end α T b))"
  using l_types_init_def by blast+

lemma l_types_init_nth:
  assumes "length SA = length T"
  and     "l_types_init α T SA"
  and     "b  α (Max (set T))"
  and     "bucket_start α T b  i"
  and     "i < l_bucket_end α T b"
shows "SA ! i  l_bucket α T b"
proof -
  have "l_bucket_end α T b  length SA"
    by (metis assms(1) bucket_end_le_length dual_order.order_iff_strict l_bucket_end_le_bucket_end
              less_le_trans)
  with l_types_initD(1)[OF assms(2,3)] list_slice_nth_mem[OF assms(4,5)]
  show ?thesis
    by blast
qed

definition s_type_init
  where
"s_type_init T SA  (n. length T = Suc n  SA ! 0 = n)"

definition s_perm_pre
  where
"s_perm_pre α T B SA n 
  s_bucket_init α T B 
  s_type_init T SA 
  strict_mono α 
  α (Max (set T)) < length B 
  length SA = length T 
  l_types_init α T SA 
  valid_list T 
  α bot = 0 
  Suc 0 < length T 
  length T  n"

definition s_sorted_pre
  where
"s_sorted_pre α T SA 
  (b  α (Max (set T)).
    ordlistns.sorted (map (suffix T) (list_slice SA (bucket_start α T b) (l_bucket_end α T b)))
  )"

lemma s_sorted_preD:
  "s_sorted_pre α T SA; b  α (Max (set T)) 
   ordlistns.sorted (map (suffix T) (list_slice SA (bucket_start α T b) (l_bucket_end α T b)))"
  using s_sorted_pre_def by blast

definition s_prefix_sorted_pre
  where
"s_prefix_sorted_pre α T SA 
  (b  α (Max (set T)).
    ordlistns.sorted (map (lms_slice T) (list_slice SA (bucket_start α T b) (l_bucket_end α T b)))
  )"

lemma s_prefix_sorted_preD:
  "s_prefix_sorted_pre α T SA; b  α (Max (set T)) 
   ordlistns.sorted (map (lms_slice T) (list_slice SA (bucket_start α T b) (l_bucket_end α T b)))"
  using s_prefix_sorted_pre_def by blast

section "Invariants"

subsection "Definitions"

subsubsection "Distinctness"

definition s_distinct_inv
  where
"s_distinct_inv α T B SA 
  (b  α (Max (set T)). distinct (list_slice SA (B ! b) (bucket_end α T b)))"

lemma s_distinct_invD:
  "s_distinct_inv α T B SA; b  α (Max (set T)) 
   distinct (list_slice SA (B ! b) (bucket_end α T b))"
  using s_distinct_inv_def by blast

subsubsection "S Bucket Ptr"

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

lemma s_bucket_ptr_lower_bound:
  assumes "s_bucket_ptr_inv α T B"
  and     "b  α (Max (set T))"
shows "s_bucket_start α T b  B ! b"
  using assms(1) assms(2) s_bucket_ptr_inv_def by blast

lemma s_bucket_ptr_upper_bound:
  assumes "s_bucket_ptr_inv α T B"
  and     "b  α (Max (set T))"
shows "B ! b  bucket_end α T b"
  by (metis assms s_bucket_ptr_inv_def)

lemma s_bucket_ptr_0:
  assumes "s_bucket_ptr_inv α T B"
  and     "b = 0"
shows "B ! b = 0"
  using assms s_bucket_ptr_inv_def by auto

subsubsection "Locations"

definition s_locations_inv ::
  "('a :: {linorder, order_bot}  nat)  'a list  nat list  nat list  bool"
  where
"s_locations_inv α T B SA 
  (b  α (Max (set T)).
    (i. B ! b  i  i < bucket_end α T b  SA ! i  s_bucket α T b))"

lemma s_locations_invD:
  "s_locations_inv α T B SA; b  α (Max (set T)); B ! b  i; i < bucket_end α T b 
   SA ! i  s_bucket α T b"
  using s_locations_inv_def by blast

lemma s_locations_inv_in_list_slice:
  assumes "s_locations_inv α T B SA"
  and     "b  α (Max (set T))"
  and     "x  set (list_slice SA (B ! b) (bucket_end α T b))"
shows "x  s_bucket α T b"
proof -
  from in_set_conv_nth[THEN iffD1, OF assms(3)]
  obtain i where
    "i < length (list_slice SA (B ! b) (bucket_end α T b))"
    "list_slice SA (B ! b) (bucket_end α T b) ! i = x"
    by blast
  with nth_list_slice
  have "SA ! (B ! b + i) = x"
    by fastforce
  moreover
  have "B ! b + i < bucket_end α T b"
    using i < length (list_slice SA (B ! b) (bucket_end α T b)) by auto
  ultimately
  show ?thesis
    using assms(1,2) le_add1 s_locations_invD by blast
qed

lemma s_locations_inv_subset_s_bucket:
  assumes "s_locations_inv α T B SA"
  and     "b  α (Max (set T))"
shows "set (list_slice SA (B ! b) (bucket_end α T b))  s_bucket α T b"
  using assms s_locations_inv_in_list_slice by blast

subsubsection "Unchanged"

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

lemma s_unchanged_invD:
  "s_unchanged_inv α T B SA SA'; b  α (Max (set T)); bucket_start α T b  i; i < B ! b 
   SA' ! i = SA ! i"
  using s_unchanged_inv_def by blast

subsubsection "Seen"

definition s_seen_inv ::
  "('a :: {linorder, order_bot}  nat)  'a list  nat list  nat list  nat  bool"
  where
"s_seen_inv α T B SA n 
  i < length SA. n  i 
    (suffix_type T (SA ! i) = S_type  in_s_current_bucket α T B (α (T ! (SA ! i))) i) 
    (suffix_type T (SA ! i) = L_type  in_l_bucket α T (α (T ! (SA ! i))) i) 
    SA ! i < length T"

lemma s_seen_invD:
  "s_seen_inv α T B SA n; i < length SA; n  i  SA ! i < length T"
  "s_seen_inv α T B SA n; i < length SA; n  i; suffix_type T (SA ! i) = L_type 
   in_l_bucket α T (α (T ! (SA ! i))) i"
  "s_seen_inv α T B SA n; i < length SA; n  i; suffix_type T (SA ! i) = S_type 
   in_s_current_bucket α T B (α (T ! (SA ! i))) i"
  unfolding s_seen_inv_def by blast+

subsubsection "Predecessor"

definition s_pred_inv ::
  "(('a :: {linorder, order_bot})  nat)  'a list  nat list  nat list  nat  bool"
  where
"s_pred_inv α T B SA n =
  (b i. in_s_current_bucket α T B b i  b  0 
    (j < length SA. SA ! j = Suc (SA ! i)  i < j  n < j)
  )"

lemma s_pred_invD:
  "s_pred_inv α T B SA k; in_s_current_bucket α T B b i; b  0 
   j < length SA. SA ! j = Suc (SA ! i)  i < j  k < j"
  using s_pred_inv_def by blast

subsubsection "Successor"

definition s_suc_inv ::
  "('a :: {linorder, order_bot}  nat)  'a list  nat list  nat list  nat  bool"
  where
"s_suc_inv α T B SA n 
  i < length SA. n < i 
    (j. SA ! i = Suc j  suffix_type T j = S_type 
      (k. in_s_current_bucket α T B (α (T ! j)) k  SA ! k = j  k < i))"

lemma s_suc_invD:
  "s_suc_inv α T B SA n; i < length SA; n < i; SA ! i = Suc j; suffix_type T j = S_type 
   k. in_s_current_bucket α T B (α (T ! j)) k  SA ! k = j  k < i"
  using s_suc_inv_def by blast

subsubsection "Combined Permutation Invariant"

definition s_perm_inv ::
  "('a :: {linorder, order_bot}  nat)  'a list  nat list  nat list  nat list  nat  bool"
  where
"s_perm_inv α T B SA SA' n 
  s_distinct_inv α T B SA' 
  s_bucket_ptr_inv α T B 
  s_locations_inv α T B SA' 
  s_unchanged_inv α T B SA SA' 
  s_seen_inv α T B SA' n 
  s_pred_inv α T B SA' n 
  s_suc_inv α T B SA' n 
  strict_mono α 
  α (Max (set T)) < length B 
  length SA = length T 
  length SA' = length T 
  l_types_init α T SA 
  valid_list T 
  α bot = 0 
  Suc 0 < length T"

lemma s_perm_inv_elims:
  "s_perm_inv α T B SA SA' n  s_distinct_inv α T B SA'"
  "s_perm_inv α T B SA SA' n  s_bucket_ptr_inv α T B"
  "s_perm_inv α T B SA SA' n  s_locations_inv α T B SA'"
  "s_perm_inv α T B SA SA' n  s_unchanged_inv α T B SA SA'"
  "s_perm_inv α T B SA SA' n  s_seen_inv α T B SA' n"
  "s_perm_inv α T B SA SA' n  s_pred_inv α T B SA' n"
  "s_perm_inv α T B SA SA' n  s_suc_inv α T B SA' n"
  "s_perm_inv α T B SA SA' n  strict_mono α"
  "s_perm_inv α T B SA SA' n  α (Max (set T)) < length B"
  "s_perm_inv α T B SA SA' n  length SA = length T"
  "s_perm_inv α T B SA SA' n  length SA' = length T"
  "s_perm_inv α T B SA SA' n  l_types_init α T SA"
  "s_perm_inv α T B SA SA' n  valid_list T"
  "s_perm_inv α T B SA SA' n  α bot = 0"
  "s_perm_inv α T B SA SA' n  Suc 0 < length T"
  by (simp_all add: s_perm_inv_def)

fun s_perm_inv_alt ::
  "('a :: {linorder, order_bot}  nat)  'a list  nat list  nat list × nat list × nat  bool"
  where
"s_perm_inv_alt α T SA (B, SA', n) = s_perm_inv α T B SA SA' n"

subsubsection "Sorted"

definition s_sorted_inv
  where
"s_sorted_inv α T B SA 
  (b  α (Max (set T)).
    ordlistns.sorted (map (suffix T) (list_slice SA (B ! b) (bucket_end α T b)))
  )"

lemma s_sorted_invD:
  "s_sorted_inv α T B SA; b  α (Max (set T)) 
   ordlistns.sorted (map (suffix T) (list_slice SA (B ! b) (bucket_end α T b)))"
  using s_sorted_inv_def by blast

fun s_sorted_inv_alt ::
  "('a :: {linorder, order_bot}  nat)  'a list  nat list  nat list × nat list × nat  bool"
  where
"s_sorted_inv_alt α T SA (B, SA', n) =
  (s_perm_inv α T B SA SA' n  s_sorted_pre α T SA  s_sorted_inv α T B SA')"

definition s_prefix_sorted_inv
  where
"s_prefix_sorted_inv α T B SA 
  (b  α (Max (set T)).
    ordlistns.sorted (map (lms_slice T) (list_slice SA (B ! b) (bucket_end α T b)))
  )"

lemma s_prefix_sorted_invD:
  "s_prefix_sorted_inv α T B SA; b  α (Max (set T)) 
   ordlistns.sorted (map (lms_slice T) (list_slice SA (B ! b) (bucket_end α T b)))"
  using s_prefix_sorted_inv_def by blast

fun s_prefix_sorted_inv_alt ::
  "('a :: {linorder, order_bot}  nat)  'a list  nat list  nat list × nat list × nat  bool"
  where
"s_prefix_sorted_inv_alt α T SA (B, SA', n) =
  (s_perm_inv α T B SA SA' n  s_prefix_sorted_pre α T SA  s_prefix_sorted_inv α T B SA')"

subsection "Helpers"

lemma s_current_bucket_pairwise_distinct:
  assumes "s_distinct_inv α T B SA"
  and     "s_locations_inv α T B SA"
  and     "b  α (Max (set T))"
  and     "b'  α (Max (set T))"
  and     "b  b'"
shows "distinct (list_slice SA (B ! b) (bucket_end α T b) @ list_slice SA (B ! b') (bucket_end α T b'))"
proof (intro distinct_append[THEN iffD2] conjI disjointI')
  from s_distinct_invD[OF assms(1,3)]
  show "distinct (list_slice SA (B ! b) (bucket_end α T b))" .
next
  from s_distinct_invD[OF assms(1,4)]
  show "distinct (list_slice SA (B ! b') (bucket_end α T b'))" .
next
  fix x y
  assume A: "x  set (list_slice SA (B ! b) (bucket_end α T b))"
            "y  set (list_slice SA (B ! b') (bucket_end α T b'))"

  from s_locations_inv_in_list_slice[OF assms(2,3) A(1)]
  have "x  s_bucket α T b" .
  moreover
  from s_locations_inv_in_list_slice[OF assms(2,4) A(2)]
  have "y  s_bucket α T b'" .
  ultimately
  show "x  y"
    using assms(5)
    by (metis (mono_tags, lifting) bucket_def s_bucket_def mem_Collect_eq)
qed

lemma s_unchanged_list_slice:
  assumes "s_unchanged_inv α T B SA0 SA"
  and     "length SA0 = length T"
  and     "length SA = length T"
  and     "b  α (Max (set T))"
  and     "bucket_start α T b  i"
  and     "j  B ! b"
shows "list_slice SA i j = list_slice SA0 i j"
proof (intro list_eq_iff_nth_eq[THEN iffD2] conjI allI impI)
  show "length (list_slice SA i j) = length (list_slice SA0 i j)"
    by (simp add: assms)
next
  fix k
  assume "k < length (list_slice SA i j)"
  hence "k < length (list_slice SA0 i j)"
    by (simp add: assms)

  from nth_list_slice[OF `k < length (list_slice SA i j)`]
  have "list_slice SA i j ! k = SA ! (i + k)" .
  moreover
  from nth_list_slice[OF `k < length (list_slice SA0 i j)`]
  have "list_slice SA0 i j ! k = SA0 ! (i + k)" .
  moreover
  {
    have "bucket_start α T b  i + k"
      by (simp add: assms(5) trans_le_add1)
    moreover
    have "i + k < j"
      using k < length (list_slice SA i j) by auto
    hence "i + k < B ! b"
      using assms(6) order.strict_trans2 by blast
    ultimately
    have "SA ! (i + k) = SA0 ! (i + k)"
      using s_unchanged_invD[OF assms(1,4)]
      by blast
  }
  ultimately show "list_slice SA i j ! k = list_slice SA0 i j ! k"
    by simp
qed

lemma l_types_init_maintained:
  assumes "s_bucket_ptr_inv α T B"
  and     "s_unchanged_inv α T B SA0 SA"
  and     "length SA0 = length T"
  and     "length SA = length T"
  and     "l_types_init α T SA0"
shows "l_types_init α T SA"
  unfolding l_types_init_def
proof(intro allI impI)
  fix b
  let ?xs = "list_slice SA (bucket_start α T b) (l_bucket_end α T b)"
  let ?ys = "list_slice SA0 (bucket_start α T b) (l_bucket_end α T b)"
  assume "b  α (Max (set T))"
  with s_bucket_ptr_lower_bound[OF assms(1), of b]
  have "l_bucket_end α T b  B ! b"
    by (simp add: s_bucket_start_eq_l_bucket_end)
  with s_unchanged_list_slice[OF assms(2-4) `b  α (Max (set T))`,
        of "bucket_start α T b" "l_bucket_end α T b"]
  have "?xs = ?ys"
    by blast
  with assms(5)[simplified l_types_init_def, THEN spec, THEN mp, OF `b  α (Max (set T))`]
  show "set ?xs = l_bucket α T b  distinct ?xs"
    by simp
qed

lemma s_sorted_pre_maintained:
  assumes "s_bucket_ptr_inv α T B"
  and     "s_unchanged_inv α T B SA0 SA"
  and     "length SA0 = length T"
  and     "length SA = length T"
  and     "s_sorted_pre α T SA0"
shows "s_sorted_pre α T SA"
  unfolding s_sorted_pre_def
proof(intro allI impI)
  fix b
  let ?xs = "list_slice SA (bucket_start α T b) (l_bucket_end α T b)"
  let ?ys = "list_slice SA0 (bucket_start α T b) (l_bucket_end α T b)"
  assume "b  α (Max (set T))"
  with s_bucket_ptr_lower_bound[OF assms(1), of b]
  have "l_bucket_end α T b  B ! b"
    by (simp add: s_bucket_start_eq_l_bucket_end)
  with s_unchanged_list_slice[OF assms(2-4) `b  α (Max (set T))`,
        of "bucket_start α T b" "l_bucket_end α T b"]
  have "?xs = ?ys"
    by blast
  then show "ordlistns.sorted (map (suffix T) ?xs)"
    using b  α (Max (set T)) assms(5) s_sorted_pre_def by auto
qed

lemma s_prefix_sorted_pre_maintained:
  assumes "s_bucket_ptr_inv α T B"
  and     "s_unchanged_inv α T B SA0 SA"
  and     "length SA0 = length T"
  and     "length SA = length T"
  and     "s_prefix_sorted_pre α T SA0"
shows "s_prefix_sorted_pre α T SA"
  unfolding s_prefix_sorted_pre_def
proof(intro allI impI)
  fix b
  let ?xs = "list_slice SA (bucket_start α T b) (l_bucket_end α T b)"
  let ?ys = "list_slice SA0 (bucket_start α T b) (l_bucket_end α T b)"
  assume "b  α (Max (set T))"
  with s_bucket_ptr_lower_bound[OF assms(1), of b]
  have "l_bucket_end α T b  B ! b"
    by (simp add: s_bucket_start_eq_l_bucket_end)
  with s_unchanged_list_slice[OF assms(2-4) `b  α (Max (set T))`,
        of "bucket_start α T b" "l_bucket_end α T b"]
  have "?xs = ?ys"
    by blast
  then show "ordlistns.sorted (map (lms_slice T) ?xs)"
    using b  α (Max (set T)) assms(5) s_prefix_sorted_pre_def by auto
qed

lemma s_next_item_not_seen:
  assumes "s_distinct_inv α T B SA"
  and     "s_bucket_ptr_inv α T B"
  and     "s_locations_inv α T B SA"
  and     "s_unchanged_inv α T B SA0 SA"
  and     "s_seen_inv α T B SA i"
  and     "s_pred_inv α T B SA i"
  and     "strict_mono α"
  and     "length SA0 = length T"
  and     "length SA = length T"
  and     "l_types_init α T SA0"
  and     "valid_list T"
  and     "α bot = 0"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
shows "j  set (list_slice SA (B ! b) (bucket_end α T b))"
proof
  let ?xs = "list_slice SA (B ! b) (bucket_end α T b)"
  let ?b = "α (T ! (Suc j))"
  assume "j  set ?xs"

  from s_seen_invD(1)[OF assms(5,14)] assms(13,15)
  have "Suc j < length T"
    by simp
  hence "?b  α (Max (set T))"
    using assms(7)
    by (simp add: strict_mono_leD)

  have "bucket_end α T ?b  length SA"
    by (simp add: assms(9) bucket_end_le_length)
  hence "l_bucket_end α T ?b  length SA"
    by (metis dual_order.trans l_bucket_end_le_bucket_end)

  have "j < length T"
    by (simp add: assms(16) suffix_type_s_bound)

  from valid_list_length_ex[OF assms(11)]
  obtain n' where
    "length T = Suc n'"
    by blast
  with `Suc j < length T`
  have "j < n'"
    by linarith
  hence "T ! j  bot"
    by (metis length T = Suc n' assms(11) diff_Suc_1 valid_list_def)
  hence "b  0"
    using assms(7,12,17) strict_mono_eq by fastforce

  with in_set_conv_nth[THEN iffD1, OF `j  set ?xs`]
  obtain a where
    "a < length ?xs"
    "?xs ! a = j"
    by blast
  hence "SA ! (B ! b + a) = j"
    using nth_list_slice by fastforce

  from assms(9)
  have "bucket_end α T b  length SA"
    by (simp add: bucket_end_le_length)
  with `a < length ?xs`
  have "B ! b + a < bucket_end α T b"
    by auto
  with assms(7,17) `j < length T`
  have "in_s_current_bucket α T B b (B ! b + a)"
    unfolding in_s_current_bucket_def
    by (simp add: strict_mono_less_eq)
  with s_pred_invD[OF assms(6) _ `b  0`, of "B ! b + a"] `SA ! (B ! b + a) = j`
  obtain m where
    "m < length SA"
    "SA ! m = Suc j"
    "B ! b + a < m"
    "i < m"
    by blast
  hence "i  m"
    by blast

  have "suffix_type T (Suc j) = L_type  False"
  proof -
    assume "suffix_type T (Suc j) = L_type"
    with s_seen_invD(2)[OF assms(5) `m < length SA`] `i < m` `SA ! m = Suc j`
    have "in_l_bucket α T ?b m"
      by simp
    hence "bucket_start α T ?b  m" "m < l_bucket_end α T ?b"
      using in_l_bucket_def by blast+
    moreover
    from `suffix_type T (Suc j) = L_type` assms(13,15)
         s_seen_invD(2)[OF assms(5) `Suc n < length SA`]
    have "in_l_bucket α T ?b i"
      by simp
    hence "bucket_start α T ?b  i" "i < l_bucket_end α T ?b"
      using in_l_bucket_def by blast+
    ultimately
    show "False"
      using list_slice_nth_eq_iff_index_eq[
              OF l_types_initD(2)[OF l_types_init_maintained[OF assms(2,4,8-10)] `?b  α _`]
                `l_bucket_end α T ?b  length SA`,
              of i m]
            `i  m` assms(13,15) `SA ! m = Suc j`
      by simp
  qed
  moreover
  have "suffix_type T (Suc j) = S_type  False"
  proof -
    assume "suffix_type T (Suc j) = S_type"
    with s_seen_invD(3)[OF assms(5) `m < length SA`] `i < m` `SA ! m = Suc j`
    have "in_s_current_bucket α T B ?b m"
      by simp
    hence "B ! ?b  m" "m < bucket_end α T ?b"
      using in_s_current_bucket_def by blast+
    moreover
    from `suffix_type T (Suc j) = S_type` assms(13,15)
         s_seen_invD(3)[OF assms(5) `Suc n < length SA`]
    have "in_s_current_bucket α T B ?b i"
      by simp
    hence "B ! ?b  i" "i < bucket_end α T ?b"
      using in_s_current_bucket_def by blast+
    ultimately
    show False
      using list_slice_nth_eq_iff_index_eq[
              OF s_distinct_invD[OF assms(1) `?b  α _`] `bucket_end α T ?b  length SA`,
              of i m]
            `i  m` assms(13,15) `SA ! m = Suc j`
      by simp
  qed
  ultimately
  show False
    using SL_types.exhaust by blast
qed

lemma s_bucket_ptr_strict_lower_bound:
  assumes "s_distinct_inv α T B SA"
  and     "s_bucket_ptr_inv α T B"
  and     "s_locations_inv α T B SA"
  and     "s_unchanged_inv α T B SA0 SA"
  and     "s_seen_inv α T B SA i"
  and     "s_pred_inv α T B SA i"
  and     "strict_mono α"
  and     "length SA0 = length T"
  and     "length SA = length T"
  and     "l_types_init α T SA0"
  and     "valid_list T"
  and     "α bot = 0"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
shows "s_bucket_start α T b < B ! b"
proof -
  have "j < length T"
    by (simp add: assms(16) suffix_type_s_bound)
  hence "b  α (Max (set T))"
    by (simp add: assms(7,17) strict_mono_leD)

  let ?xs = "list_slice SA (B ! b) (bucket_end α T b)"

  have "bucket_end α T b  length SA"
    by (simp add: assms(9) bucket_end_le_length)
  hence "length ?xs = bucket_end α T b - B ! b"
    by auto

  from s_next_item_not_seen[OF assms(1-17)]
  have "j  set ?xs" .
  moreover
  have "j  s_bucket α T b"
    by (simp add: assms(16,17) bucket_def s_bucket_def suffix_type_s_bound)
  ultimately
  have "set ?xs  s_bucket α T b"
    using s_locations_inv_subset_s_bucket[OF assms(3) `b  _`]
    by blast
  hence "card (set ?xs) < s_bucket_size α T b"
    using psubset_card_mono[OF finite_s_bucket, simplified s_bucket_size_def[symmetric]]
    by blast
  moreover
  from s_distinct_invD[OF assms(1) `b  _`]
  have "distinct ?xs" .
  ultimately
  have "length ?xs < s_bucket_size α T b"
    by (simp add: distinct_card)
  with `length ?xs = _`
  have "bucket_end α T b - B ! b < s_bucket_size α T b"
    by simp
  hence "bucket_end α T b < B ! b + s_bucket_size α T b"
    by linarith
  hence
    "s_bucket_start α T b + bucket_end α T b < B ! b + s_bucket_start α T b + s_bucket_size α T b"
    by simp
  then show "s_bucket_start α T b < B ! b"
    by (simp add: bucket_end_eq_s_start_pl_size)
qed

lemma outside_another_bucket:
  assumes "b  b'"
  and     "bucket_start α T b  i"
  and     "i < bucket_end α T b"
shows "¬(bucket_start α T b'  i  i < bucket_end α T b')"
  by (meson assms dual_order.antisym less_bucket_end_le_start not_le order.strict_trans1)

lemma s_B_val:
  assumes "s_distinct_inv α T B SA"
  and     "s_bucket_ptr_inv α T B"
  and     "s_locations_inv α T B SA"
  and     "s_unchanged_inv α T B SA0 SA"
  and     "s_seen_inv α T B SA i"
  and     "s_pred_inv α T B SA i"
  and     "strict_mono α"
  and     "length SA0 = length T"
  and     "length SA = length T"
  and     "l_types_init α T SA0"
  and     "valid_list T"
  and     "length T > Suc 0"
  and     "b  α (Max (set T))"
  and     "i < B ! b"
shows "B ! b = s_bucket_start α T b"
proof (rule ccontr; drule neq_iff[THEN iffD1]; elim disjE)
  assume "B ! b < s_bucket_start α T b"
  with s_bucket_ptr_lower_bound[OF assms(2,13)]
  show False
    by linarith
next
  let ?k = "B ! b - Suc 0"
  assume "s_bucket_start α T b < B ! b"
  hence "s_bucket_start α T b  ?k"
    by linarith
  hence "bucket_start α T b  ?k"
    using bucket_start_le_s_bucket_start le_trans by blast

  have "?k < B ! b"
    using `s_bucket_start α T b < B ! b` by auto

  from assms(14)
  have "i  ?k"
    by linarith

  from s_bucket_ptr_upper_bound[OF assms(2,13)]
  have "B ! b  bucket_end α T b" .
  hence "?k < bucket_end α T b"
    using s_bucket_start α T b < B ! b by linarith

  have "bucket_end α T b  length SA"
    by (simp add: assms(9) bucket_end_le_length)
  moreover
  have "bucket_end α T b = length SA  False"
  proof -
    assume "bucket_end α T b = length SA"
    with `s_bucket_start α T b < B ! b` `B ! b  bucket_end α T b` assms(7,9,13)
    have "b = α (Max (set T))"
      using bucket_end_eq_length by fastforce
    hence "s_bucket α T b = {}"
      by (simp add: assms(7,11,12) s_bucket_Max)
    hence "s_bucket_size α T b = 0"
      by (simp add: s_bucket_size_def)
    hence "s_bucket_start α T b = bucket_end α T b"
      by (simp add: bucket_end_eq_s_start_pl_size)
    with `B ! b  bucket_end α T b` `s_bucket_start α T b < B ! b`
    show False
      by simp
  qed
  moreover
  have "bucket_end α T b < length SA  False"
  proof -
    assume "bucket_end α T b < length SA"
    hence "B ! b < length SA"
      using `B ! b  bucket_end α T b`
      by linarith
    hence "?k < length SA"
      using less_imp_diff_less by blast
    with s_seen_invD[OF assms(5) _  `i  ?k`]
    have "SA ! ?k < length T"
      by blast

    let ?b = "α (T ! (SA ! ?k))"

    from `SA ! ?k < length T` assms(7)
    have "?b  α (Max (set T))"
      using Max_greD strict_mono_leD by blast
    with s_bucket_ptr_lower_bound[OF assms(2)]
    have "s_bucket_start α T ?b  B ! ?b"
      by blast
    hence "bucket_start α T ?b  B ! ?b"
      using bucket_start_le_s_bucket_start le_trans by blast

    have "suffix_type T (SA ! ?k) = L_type  False"
    proof -
      assume "suffix_type T (SA ! ?k) = L_type"
      with s_seen_invD(2)[OF assms(5) `?k < length SA` `i  ?k`]
      have "in_l_bucket α T ?b ?k"
        by blast
      hence "bucket_start α T ?b  ?k" "?k < l_bucket_end α T ?b"
        using in_l_bucket_def by blast+
      hence "?k < bucket_end α T ?b"
        using l_bucket_end_le_bucket_end less_le_trans by blast

      from `?k < l_bucket_end _ _ _` `s_bucket_start _ _ _  ?k`
      have "b = ?b  False"
        by (simp add: s_bucket_start_eq_l_bucket_end)
      moreover
      from outside_another_bucket[OF _ `bucket_start _ _ b  ?k` `?k < bucket_end _ _ b`]
           `bucket_start _ _ ?b  ?k` `?k < bucket_end _ _ ?b`
      have "b  ?b  False"
        by blast
      ultimately show False
        by blast
    qed
    moreover
    have "suffix_type T (SA ! ?k) = S_type  False"
    proof -
      assume "suffix_type T (SA ! ?k) = S_type"
      with s_seen_invD(3)[OF assms(5) `?k < length SA` `i  ?k`]
      have "in_s_current_bucket α T B ?b ?k "
        by blast
      hence "B ! ?b  ?k" "?k < bucket_end α T ?b"
        using in_s_current_bucket_def by blast+
      hence "bucket_start α T ?b  ?k"
        using `bucket_start α T ?b  B ! ?b` by linarith

      from `B ! ?b  ?k` `?k < B ! b`
      have "b = ?b  False"
        by simp
      moreover
      from outside_another_bucket[OF _ `bucket_start _ _ b  ?k` `?k < bucket_end _ _ b`]
           `bucket_start α T ?b  ?k` `?k < bucket_end α T ?b`
      have "b  ?b  False"
        by blast
      ultimately show False
        by blast
    qed
    ultimately show False
      using SL_types.exhaust by blast
  qed
  ultimately show False
    by linarith
qed

lemma s_bucket_eq_list_slice:
  assumes "s_distinct_inv α T B SA"
  and     "s_locations_inv α T B SA"
  and     "length SA = length T"
  and     "b  α (Max (set T))"
  and     "B ! b = s_bucket_start α T b"
shows "set (list_slice SA (s_bucket_start α T b) (bucket_end α T b)) = s_bucket α T b"
      (is "set ?xs = s_bucket α T b")
  using card_subset_eq[
          OF finite_s_bucket s_locations_inv_subset_s_bucket[OF assms(2,4), simplified assms(5)]]
        distinct_card[OF s_distinct_invD[OF assms(1,4), simplified assms(5)]]
        bucket_end_eq_s_start_pl_size[of α T b]
        s_bucket_size_def[of α T b]
  by (metis assms(3) bucket_end_le_length diff_add_inverse length_list_slice min_def)

lemma bucket_eq_list_slice:
  assumes "s_distinct_inv α T B SA"
  and     "s_bucket_ptr_inv α T B"
  and     "s_locations_inv α T B SA"
  and     "s_unchanged_inv α T B SA0 SA"
  and     "length SA0 = length T"
  and     "length SA = length T"
  and     "l_types_init α T SA0"
  and     "b  α (Max (set T))"
  and     "B ! b = s_bucket_start α T b"
shows "set (list_slice SA (bucket_start α T b) (bucket_end α T b)) = bucket α T b"
      (is "set ?xs = bucket α T b")
proof -
  let ?ys = "list_slice SA (bucket_start α T b) (l_bucket_end α T b)"
  and ?zs = "list_slice SA (s_bucket_start α T b) (bucket_end α T b)"

  have "?xs = ?ys @ ?zs"
    by (metis list_slice_append bucket_start_le_s_bucket_start l_bucket_end_le_bucket_end
          s_bucket_start_eq_l_bucket_end)
  hence "set ?xs = set ?ys  set ?zs"
    by simp
  with l_types_initD(1)[OF l_types_init_maintained[OF assms(2,4-7)] assms(8)]
       s_bucket_eq_list_slice[OF assms(1,3,6,8,9)]
  have "set ?xs = l_bucket α T b  s_bucket α T b"
    by simp
  then show ?thesis
    using l_un_s_bucket by blast
qed

lemma s_index_lower_bound:
  assumes "s_bucket_ptr_inv α T B"
  and     "s_seen_inv α T B SA n"
  and     "i < length SA"
  and     "n  i"
shows "bucket_start α T (α (T ! (SA ! i)))  i"
      (is "bucket_start α T ?b  i")
proof -

  have "?b  α (Max (set T))"
    by (meson SL_types.exhaust assms(2-) in_l_bucket_def in_s_current_bucketD(1) s_seen_invD(2,3))

  have "suffix_type T (SA ! i) = S_type  suffix_type T (SA ! i) = L_type"
    using SL_types.exhaust by blast
  moreover
  have "suffix_type T (SA ! i) = S_type  ?thesis"
  proof -
    assume "suffix_type T (SA ! i) = S_type"
    with s_seen_invD(3)[OF assms(2-)] s_bucket_ptr_lower_bound[OF assms(1)]
    show ?thesis
      by (meson ?b  α (Max (set T)) bucket_start_le_s_bucket_start dual_order.trans
            in_s_current_bucketD(2))
  qed
  moreover
  have "suffix_type T (SA ! i) = L_type  ?thesis"
  proof -
    assume "suffix_type T (SA ! i) = L_type"
    with s_seen_invD(2)[OF assms(2-)]
    show ?thesis
      using in_l_bucket_def by blast
  qed
  ultimately show ?thesis
    by blast
qed

lemma s_index_upper_bound:
  assumes "s_bucket_ptr_inv α T B"
  and     "s_seen_inv α T B SA n"
  and     "i < length SA"
  and     "n  i"
shows "i < bucket_end α T (α (T ! (SA ! i)))"
      (is "i < bucket_end α T ?b")
proof -

  have "?b  α (Max (set T))"
    by (meson SL_types.exhaust assms(2-) in_l_bucket_def in_s_current_bucketD(1) s_seen_invD(2,3))

  have "suffix_type T (SA ! i) = S_type  suffix_type T (SA ! i) = L_type"
    using SL_types.exhaust by blast
  moreover
  have "suffix_type T (SA ! i) = S_type  ?thesis"
  proof -
    assume "suffix_type T (SA ! i) = S_type"
    with s_seen_invD(3)[OF assms(2-)] s_bucket_ptr_upper_bound[OF assms(1)]
    show ?thesis
      by (simp add: in_s_current_bucket_def)
  qed
  moreover
  have "suffix_type T (SA ! i) = L_type  ?thesis"
  proof -
    assume "suffix_type T (SA ! i) = L_type"
    with s_seen_invD(2)[OF assms(2-)]
    show ?thesis
      using in_l_bucket_def l_bucket_end_le_bucket_end less_le_trans by blast
  qed
  ultimately show ?thesis
    by blast
qed

subsection "Establishment and Maintenance Steps"

subsubsection "Distinctness"

lemma s_distinct_inv_established:
  assumes "s_bucket_init α T B"
  and     "valid_list T"
  and     "strict_mono α"
  and     "α bot = 0"
  shows "s_distinct_inv α T B SA"
  unfolding s_distinct_inv_def
proof (intro allI impI)
  fix b
  let ?goal = "distinct (list_slice SA (B ! b) (bucket_end α T b))"
  assume "b  α (Max (set T))"

  have "b > 0  ?goal"
  proof -
    assume "b > 0"
    with s_bucket_initD(1)[OF assms(1) `b  _`]
    have "B ! b = bucket_end α T b"
      by blast
    then show ?goal
      using list_slice_n_n 
      by (metis distinct.simps(1))
  qed
  moreover
  have "b = 0  ?goal"
  proof -
    assume "b = 0"
    with s_bucket_initD(2)[OF assms(1) `b  _`]
    have "B ! b = 0" .
    moreover
    from `b = 0` assms(2-4)
    have "bucket_end α T b = Suc 0"
      by (simp add: valid_list_bucket_end_0)
    ultimately show ?thesis
      by (simp add: distinct_conv_nth)
  qed
  ultimately show ?goal
    by blast
qed

lemma s_distinct_inv_maintained_step:
  assumes "s_distinct_inv α T B SA"
  and     "s_bucket_ptr_inv α T B"
  and     "s_locations_inv α T B SA"
  and     "s_unchanged_inv α T B SA0 SA"
  and     "s_seen_inv α T B SA i"
  and     "s_pred_inv α T B SA i"
  and     "strict_mono α"
  and     "α (Max (set T)) < length B"
  and     "length SA0 = length T"
  and     "length SA = length T"
  and     "l_types_init α T SA0"
  and     "valid_list T"
  and     "α bot = 0"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
  and     "k = B ! b - Suc 0"
shows "s_distinct_inv α T (B[b := k]) (SA[k := j])"
  unfolding s_distinct_inv_def
proof (intro allI impI)
  fix b'

  let ?goal = "distinct (list_slice (SA[k := j]) (B[b := k] ! b') (bucket_end α T b'))"

  assume "b'  α (Max (set T))"

  from s_next_item_not_seen[OF assms(1-7,9-18)]
  have "j  set (list_slice SA (B ! b) (bucket_end α T b))".

  from s_bucket_ptr_strict_lower_bound[OF assms(1-7,9-18)]
  have "s_bucket_start α T b < B ! b" .
  hence "s_bucket_start α T b  k" "k < B ! b"
    using assms(19) by linarith+
  hence "bucket_start α T b  k"
    using bucket_start_le_s_bucket_start le_trans by blast

  from assms(17)
  have "j < length T"
    by (simp add: suffix_type_s_bound)
  hence "b  α (Max (set T))"
    by (simp add: assms(7,18) strict_mono_less_eq)
  with s_bucket_ptr_upper_bound[OF assms(2)] `k < B ! b`
  have "k < bucket_end α T b"
    using less_le_trans by auto
  hence "k < length SA"
    using assms(10) bucket_end_le_length less_le_trans by fastforce

  have "b = b'  ?goal"
  proof -
    assume "b = b'"
    hence "B[b := k] ! b' = k"
      using b  α (Max (set T)) assms(8) by auto
    from s_distinct_invD[OF assms(1) `b  _`]
    have "distinct (list_slice SA (B ! b) (bucket_end α T b))" .
    moreover
    from B[b := k] ! b' = k b = b' k < B ! b k < bucket_end α T b k < length SA assms(19)
    have "list_slice (SA[k := j]) (B[b := k] ! b') (bucket_end α T b')
          = j # list_slice SA (B ! b) (bucket_end α T b)"
      by (metis Suc_pred diff_is_0_eq' dual_order.order_iff_strict gr0I length_list_update
            list_slice_Suc list_slice_update_unchanged_1 nth_list_update_eq)
    ultimately show ?thesis
      using `j  set (list_slice SA (B ! b) (bucket_end α T b))`
      by simp
  qed
  moreover
  have "b  b'  ?goal"
  proof -
    assume "b  b'"
    hence "B[b := k] ! b' = B ! b'"
      by simp

    from outside_another_bucket[OF `b  b'` `bucket_start _ _ _  k` `k < bucket_end _ _ _`]
    have "k < bucket_start α T b'  bucket_end α T b'  k"
      using leI by auto
    moreover
    have "k < bucket_start α T b' 
          list_slice (SA[k := j]) (B[b := k] ! b') (bucket_end α T b')
            = list_slice SA (B ! b') (bucket_end α T b')"
    proof -
      assume "k < bucket_start α T b'"
      hence "k < B ! b'"
        by (meson b'  α (Max (set T)) assms(2) bucket_start_le_s_bucket_start less_le_trans
              s_bucket_ptr_inv_def)
      with list_slice_update_unchanged_1 `B[b := k] ! b' = B ! b'`
      show ?thesis
        by simp
    qed
    moreover
    from `B[b := k] ! b' = B ! b'`
    have "bucket_end α T b'  k 
          list_slice (SA[k := j]) (B[b := k] ! b') (bucket_end α T b')
            = list_slice SA (B ! b') (bucket_end α T b')"
      by (simp add: list_slice_update_unchanged_2)
    moreover
    from s_distinct_invD[OF assms(1) `b'  _`]
    have "distinct (list_slice SA (B ! b') (bucket_end α T b'))" .
    ultimately show ?goal
      by auto
  qed
  ultimately
  show ?goal
    by blast
qed

corollary s_distinct_inv_maintained_perm_step:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
  and     "k = B ! b - Suc 0"
shows "s_distinct_inv α T (B[b := k]) (SA[k := j])"
  using s_distinct_inv_maintained_step[OF s_perm_inv_elims(1-6,8-14)[OF assms(1)] assms(2-)]
  by blast

subsubsection "Bucket Pointer"

lemma s_bucket_ptr_inv_established:
  assumes "s_bucket_init α T B"
  and     "valid_list T"
  and     "strict_mono α"
  and     "α bot = 0"
  shows "s_bucket_ptr_inv α T B"
  unfolding s_bucket_ptr_inv_def
proof(intro allI impI)
  fix b
  let ?goal = "s_bucket_start α T b  B ! b  B ! b  bucket_end α T b  (b = 0  B ! b = 0)"
  assume "b  α (Max (set T))"

  have "b > 0  ?goal"
  proof -
    assume "b > 0"
    with s_bucket_initD(1)[OF assms(1) `b  _`]
    have "B ! b = bucket_end α T b" .
    then show ?thesis
      by (metis 0 < b l_bucket_end_le_bucket_end less_numeral_extra(3) order_refl
            s_bucket_start_eq_l_bucket_end)
  qed
  moreover
  have "b = 0  ?goal"
  proof -
    assume "b = 0"
    with s_bucket_initD(2)[OF assms(1) `b  _`]
    have "B ! b = 0" .
    with `b = 0`
         valid_list_bucket_end_0[OF assms(2-)]
         valid_list_s_bucket_start_0[OF assms(2-)]
    show ?thesis
      by auto
  qed
  ultimately show "?goal"
    by auto
qed

lemma s_bucket_ptr_inv_maintained_step:
  assumes "s_distinct_inv α T B SA"
  and     "s_bucket_ptr_inv α T B"
  and     "s_locations_inv α T B SA"
  and     "s_unchanged_inv α T B SA0 SA"
  and     "s_seen_inv α T B SA i"
  and     "s_pred_inv α T B SA i"
  and     "strict_mono α"
  and     "α (Max (set T)) < length B"
  and     "length SA0 = length T"
  and     "length SA = length T"
  and     "l_types_init α T SA0"
  and     "valid_list T"
  and     "α bot = 0"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
  and     "k = B ! b - Suc 0"
shows "s_bucket_ptr_inv α T (B[b := k])"
  unfolding s_bucket_ptr_inv_def
proof(intro allI impI)
  fix b'
  assume "b'  α (Max (set T))"

  let ?goal = "s_bucket_start α T b'  B[b := k] ! b'   B[b := k] ! b'  bucket_end α T b' 
               (b' = 0  B[b := k] ! b' = 0)"

  from valid_list_length_ex[OF assms(12)]
  obtain m where
    "length T = Suc m"
    by blast
  moreover
  have "j < length T"
    by (simp add: assms(17) suffix_type_s_bound)
  moreover
  from s_seen_invD(1)[OF assms(5,15)] assms(14,16)
  have "Suc j < length T"
    by simp
  ultimately have "j < m"
    by linarith
  hence "b  0"
    by (metis  length T = Suc m assms(7,12,13,18) diff_Suc_1 strict_mono_eq valid_list_def)

  have "b  b'  ?goal"
  proof -
    assume "b  b'"
    hence "B[b := k] ! b' = B ! b'"
      by simp
    with s_bucket_ptr_lower_bound[OF assms(2) `b'  α (Max (set T))`]
         s_bucket_ptr_upper_bound[OF assms(2) `b'  α (Max (set T))`]
         s_bucket_ptr_0[OF assms(2)]
    show ?thesis
      by auto
  qed
  moreover
  have "b = b'  ?goal"
  proof -
    assume "b = b'"
    from s_bucket_ptr_strict_lower_bound[OF assms(1-7,9-13,14-18)]
    have "s_bucket_start α T b < B ! b".
    hence "s_bucket_start α T b  k"
      using assms(19) by linarith
    moreover
    from b = b' b'  α (Max (set T)) assms(2,19)
    have "k  bucket_end α T b"
      using le_diff_conv s_bucket_ptr_inv_def trans_le_add1 by blast
    moreover
    have "B[b := k] ! b' = k"
      using b = b' b'  α (Max (set T)) assms(8) by auto
    ultimately show ?thesis
      using b = b' b  0 by auto
  qed
  ultimately show ?goal
    by linarith
qed

corollary s_bucket_ptr_inv_maintained_perm_step:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
  and     "k = B ! b - Suc 0"
shows "s_bucket_ptr_inv α T (B[b := k])"
  using s_bucket_ptr_inv_maintained_step[OF s_perm_inv_elims(1-6,8-14)[OF assms(1)] assms(2-)]
  by blast

subsubsection "Locations"

lemma s_locations_inv_established:
  assumes "s_bucket_init α T B"
  and     "s_type_init T SA"
  and     "valid_list T"
  and     "strict_mono α"
  and     "α bot = 0"
  shows "s_locations_inv α T B SA"
  unfolding s_locations_inv_def
proof(safe)
  fix b i
  assume "b  α (Max (set T))" "B ! b  i" "i < bucket_end α T b"
  hence "b > 0  SA ! i  s_bucket α T b"
    by (metis assms(1) not_le s_bucket_init_def)
  moreover
  have "b = 0  SA ! i  s_bucket α T b"
  proof -
    assume "b = 0"
    have "0  i"
      by blast
    moreover
    have "bucket_end α T 0 = 1"
      using assms(3-5) valid_list_bucket_end_0 by blast
    with `i < bucket_end α T b` `b = 0`
    have "i < 1"
      by simp
    ultimately have "i = 0"
      by blast
    moreover
    from s_type_init_def[of T SA] assms(2)
    obtain n where
      "length T = Suc n"
      "SA ! 0 = n"
      by blast
    with suffix_type_last[of T n]
    have "suffix_type T n = S_type"
      by blast
    moreover
    have "T ! n = bot"
      by (metis length T = Suc n assms(3) diff_Suc_1 last_conv_nth less_numeral_extra(3)
            list.size(3) valid_list_def)
    hence "α (T ! n) = 0"
      by (simp add: assms(5))
    ultimately show ?thesis
      by (simp add: SA ! 0 = nb = 0 length T = Suc n bucket_def s_bucket_def)
  qed
  ultimately show "SA ! i  s_bucket α T b"
    by linarith
qed

lemma s_locations_inv_maintained_step:
  assumes "s_distinct_inv α T B SA"
  and     "s_bucket_ptr_inv α T B"
  and     "s_locations_inv α T B SA"
  and     "s_unchanged_inv α T B SA0 SA"
  and     "s_seen_inv α T B SA i"
  and     "s_pred_inv α T B SA i"
  and     "strict_mono α"
  and     "α (Max (set T)) < length B"
  and     "length SA0 = length T"
  and     "length SA = length T"
  and     "l_types_init α T SA0"
  and     "valid_list T"
  and     "α bot = 0"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
  and     "k = B ! b - Suc 0"
shows "s_locations_inv α T (B[b := k]) (SA[k := j])"
  unfolding s_locations_inv_def
proof(safe)
  fix b' i'
  assume "b'  α (Max (set T))" "B[b := k] ! b'  i'" "i' < bucket_end α T b'"

  from s_bucket_ptr_strict_lower_bound[OF assms(1-7,9-18)]
  have "s_bucket_start α T b < B ! b".
  hence "s_bucket_start α T b  k"
    using assms(19) by linarith

  from `s_bucket_start α T b < B ! b`
  have "k < B ! b"
    using assms(19) by linarith

  have "j < length T"
    by (simp add: assms(17) suffix_type_s_bound)
  hence "b  α (Max (set T))"
    by (simp add: assms(18) assms(7) strict_mono_less_eq)
  with s_bucket_ptr_upper_bound[OF assms(2)]
  have "B ! b  bucket_end α T b"
    by blast

  have "b  b'  SA[k := j] ! i'  s_bucket α T b'"
  proof -
    assume "b  b'"
    hence "B[b := k] ! b' = B ! b'"
      by simp
    with `B[b := k] ! b'  i'`
    have "B ! b'  i'"
      by simp
    with s_locations_invD[OF assms(3) `b'  α (Max (set T))` _ `i' < bucket_end α T b'`]
    have "SA ! i'  s_bucket α T b'"
      by linarith
    moreover
    from s_bucket_ptr_lower_bound[OF assms(2) `b'  α (Max (set T))`] `B ! b'  i'`
    have "bucket_start α T b'  i'"
      by (meson bucket_start_le_s_bucket_start dual_order.trans)
    with outside_another_bucket[OF `b  b'`[symmetric] _ `i' < _`]
         B ! b  bucket_end α T b k < B ! b s_bucket_start α T b  k
    have "k  i'"
      using bucket_start_le_s_bucket_start le_trans less_le_trans by blast
    hence "SA[k := j] ! i' = SA ! i'"
      by simp
    ultimately show ?thesis
      by simp
  qed
  moreover
  have "b = b'  SA[k := j] ! i'  s_bucket α T b'"
  proof -
    assume "b = b'"
    hence "k  i'"
      using B[b := k] ! b'  i' b'  α (Max (set T)) assms(8) by auto
    hence "k = i'  k < i'"
      by linarith
    moreover
    have "k = i'  ?thesis"
    proof -
      assume "k = i'"
      hence "SA[k := j] ! i' = j"
        by (metis i' < bucket_end α T b' assms(10) bucket_end_le_length dual_order.strict_trans1
              nth_list_update)
      with assms(17,18) `b = b'` `j < length T`
      show ?thesis
        by (simp add: bucket_def s_bucket_def)
    qed
    moreover
    have "k < i'  ?thesis"
    proof -
      assume "k < i'"
      hence "B ! b  i'"
        using assms(19) by linarith
      with s_locations_invD[OF assms(3) `b'  _` _ `i' < bucket_end _ _ _`] `b = b'`
      have "SA ! i'  s_bucket α T b'"
        by blast
      moreover
      have "SA[k := j] ! i' = SA ! i'"
        using k < i' by auto
      ultimately show ?thesis
        by simp
    qed
    ultimately show ?thesis
      by linarith
  qed
  ultimately show "SA[k := j] ! i'  s_bucket α T b'"
    by blast
qed

corollary s_locations_inv_maintained_perm_step:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
  and     "k = B ! b - Suc 0"
shows "s_locations_inv α T (B[b := k]) (SA[k := j])"
  using s_locations_inv_maintained_step[OF s_perm_inv_elims(1-6,8-14)[OF assms(1)] assms(2-)]
  by blast

subsubsection "Unchanged"

lemma s_unchanged_inv_established:
  shows "s_unchanged_inv α T B SA SA"
  by (simp add: s_unchanged_inv_def)

lemma s_unchanged_inv_maintained_step:
  assumes "s_distinct_inv α T B SA"
  and     "s_bucket_ptr_inv α T B"
  and     "s_locations_inv α T B SA"
  and     "s_unchanged_inv α T B SA0 SA"
  and     "s_seen_inv α T B SA i"
  and     "s_pred_inv α T B SA i"
  and     "strict_mono α"
  and     "α (Max (set T)) < length B"
  and     "length SA0 = length T"
  and     "length SA = length T"
  and     "l_types_init α T SA0"
  and     "valid_list T"
  and     "α bot = 0"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
  and     "k = B ! b - Suc 0"
shows "s_unchanged_inv α T (B[b := k]) SA0 (SA[k := j])"
  unfolding s_unchanged_inv_def
proof(safe)
  fix b' i'
  assume "b'  α (Max (set T))" "bucket_start α T b'  i'" "i' < B[b := k] ! b'"

  from s_bucket_ptr_strict_lower_bound[OF assms(1-7,9-18)]
  have "s_bucket_start α T b < B ! b".
  hence "s_bucket_start α T b  k"
    using assms(19) by linarith
  hence "bucket_start α T b  k"
    using bucket_start_le_s_bucket_start le_trans by blast

  from `s_bucket_start α T b < B ! b`
  have "k < B ! b"
    using assms(19) by linarith

  have "j < length T"
    by (simp add: assms(17) suffix_type_s_bound)
  hence "b  α (Max (set T))"
    by (simp add: assms(7,18) strict_mono_less_eq)
  with s_bucket_ptr_upper_bound[OF assms(2)]
  have "B ! b  bucket_end α T b"
    by blast
  with `k < B ! b`
  have "k < bucket_end α T b"
    by linarith

  have "b = b'  SA[k := j] ! i' = SA0 ! i'"
  proof -
    assume "b = b'"
    hence "B[b := k] ! b' = k"
      using b'  α (Max (set T)) assms(8) by auto
    with `i' < B[b := k] ! b'`
    have "i' < k"
      by linarith
    hence "SA[k := j] ! i' = SA ! i'"
      by simp
    moreover
    from `i' < k` `k < B ! b` `b = b'`
    have "i' < B ! b'"
      by simp
    with s_unchanged_invD[OF assms(4) `b'  _` `bucket_start _ _ _  i'`]
    have "SA ! i' = SA0 ! i'"
      by simp
    ultimately show ?thesis
      by simp
  qed
  moreover
  have "b  b'  SA[k := j] ! i' = SA0 ! i'"
  proof -
    assume "b  b'"
    with `i' < B[b := k] ! b'`
    have "i' < B ! b'"
      by simp
    with s_unchanged_invD[OF assms(4) `b'  _` `bucket_start _ _ b'  _`]
    have "SA ! i' = SA0 ! i'"
      by blast
    moreover
    from s_bucket_ptr_upper_bound[OF assms(2) `b'  _`] `i' < B ! b'`
    have "i' < bucket_end α T b'"
      by linarith
    with outside_another_bucket[OF `b  b'` `bucket_start _ _ _  k` `k < bucket_end _ _ _`]
         `bucket_start _ _ b'  i'`
    have "k  i'"
      by blast
    hence "SA[k := j] ! i' = SA ! i'"
      by simp
    ultimately show ?thesis
      by simp
  qed
  ultimately show "SA[k := j] ! i' = SA0 ! i'"
    by blast
qed

corollary s_unchanged_inv_maintained_perm_step:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
  and     "k = B ! b - Suc 0"
shows "s_unchanged_inv α T (B[b := k]) SA0 (SA[k := j])"
  using s_unchanged_inv_maintained_step[OF s_perm_inv_elims(1-6,8-14)[OF assms(1)] assms(2-)]
  by blast

subsubsection "Seen"

lemma s_seen_inv_established:
  assumes "length SA = length T"
  and     "length T  n"
shows "s_seen_inv α T B SA n"
  unfolding s_seen_inv_def
  using assms by auto

lemma s_seen_inv_maintained_step_c1:
  assumes "s_bucket_ptr_inv α T B"
  and     "s_unchanged_inv α T B SA0 SA"
  and     "s_seen_inv α T B SA i"
  and     "strict_mono α"
  and     "length SA0 = length T"
  and     "length SA = length T"
  and     "l_types_init α T SA0"
  and     "valid_list T"
  and     "Suc 0 < length T"
  and     "i = Suc n"
  and     "length SA  Suc n"
  shows "s_seen_inv α T B SA n"
  unfolding s_seen_inv_def
proof (intro allI impI)
  fix j
  assume "j < length SA" "n  j"
  hence "n < length SA"
    by simp
  with assms(10,11)
  have "length SA = Suc n"
    by linarith

  let ?b = "α (T ! (SA ! j))"
  let ?g1 = "(suffix_type T (SA ! j) = S_type  in_s_current_bucket α T B ?b j)"
  and ?g2 = "(suffix_type T (SA ! j) = L_type  in_l_bucket α T ?b j)"
  and ?g3 = "SA ! j < length T"

  from `n  j`
  have "n = j  Suc n  j"
    using dual_order.antisym not_less_eq_eq by auto
  moreover
  have "n = j  ?g1  ?g2  ?g3"
  proof -
    let ?b_max = "α (Max (set T))"
    assume "n = j"
    hence "j < bucket_end α T ?b_max"
      using j < length SA assms(4,6) bucket_end_Max by fastforce
    hence "j < l_bucket_end α T ?b_max"
      using l_bucket_Max[OF assms(8,9,4)]
      by (simp add: bucket_end_def' bucket_size_def l_bucket_end_def l_bucket_size_def)
    moreover
    from n = j j < length SA length SA = Suc n assms(4,6,10)
    have "bucket_start α T ?b_max  j"
      by (metis Suc_leI antisym bucket_end_eq_length bucket_end_le_length gr_implies_not0
                index_in_bucket_interval_gen length_0_conv)
    moreover
    have "?b_max  α (Max (set T))"
      by simp
    ultimately have "SA ! j  l_bucket α T ?b_max"
      using l_types_init_nth[OF assms(6) l_types_init_maintained[OF assms(1,2,5-7)] ]
      by blast
    hence "?b_max = α (T ! (SA ! j))"
      by (simp add: bucket_def l_bucket_def)
    moreover
    from `SA ! j  l_bucket α T ?b_max`
    have ?g3
      by (simp add: bucket_def l_bucket_def)
    moreover
    from `SA ! j  l_bucket α T ?b_max`
    have "suffix_type T (SA ! j) = L_type"
      by (simp add: bucket_def l_bucket_def)
    moreover
    have "in_l_bucket α T (α (T ! (SA ! j))) j"
      using bucket_start _ _ _   j j < l_bucket_end _ _ _ calculation(1) in_l_bucket_def
      by fastforce
    hence "?g2"
      using calculation(3) by blast
    moreover
    from calculation(3)
    have "?g1"
      by simp
    ultimately show ?thesis
      by simp
  qed
  moreover
  have "Suc n  j  ?g1  ?g2  ?g3"
  proof -
    assume "Suc n  j"
    with s_seen_invD[OF assms(3) `j < length SA`] assms(10)
    show ?thesis
      by blast
  qed
  ultimately show "?g1  ?g2  ?g3"
    by blast
qed

corollary s_seen_inv_maintained_perm_step_c1:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "length SA  Suc n"
  shows "s_seen_inv α T B SA n"
  using s_seen_inv_maintained_step_c1[OF s_perm_inv_elims(2,4,5,8,10-13,15)[OF assms(1)] assms(2-)]
  by blast

lemma s_seen_inv_maintained_step_c1_alt:
  assumes "s_bucket_ptr_inv α T B"
  and     "s_unchanged_inv α T B SA0 SA"
  and     "s_seen_inv α T B SA i"
  and     "strict_mono α"
  and     "length SA0 = length T"
  and     "length SA = length T"
  and     "l_types_init α T SA0"
  and     "valid_list T"
  and     "Suc 0 < length T"
  and     "i = Suc n"
  and     "length T  SA ! Suc n"
  shows "s_seen_inv α T B SA n"
proof (cases "length SA  Suc n")
  assume "length SA  Suc n"
  then show ?thesis
    using assms(1-10) s_seen_inv_maintained_step_c1 by blast
next
  assume "¬ length SA  Suc n"
  hence "Suc n < length SA"
    by simp
  show ?thesis
    unfolding s_seen_inv_def
  proof (intro allI impI)
    fix j
    assume "j < length SA" "n  j"
    hence "n < length SA"
      by simp

    let ?b = "α (T ! (SA ! j))"
    let ?g1 = "(suffix_type T (SA ! j) = S_type  in_s_current_bucket α T B ?b j)"
    and ?g2 = "(suffix_type T (SA ! j) = L_type  in_l_bucket α T ?b j)"
    and ?g3 = "SA ! j < length T"
  
   from `n  j`
    have "n = j  Suc n  j"
      using dual_order.antisym not_less_eq_eq by auto
    moreover
    have "n = j  ?g1  ?g2  ?g3"
      by (metis Suc_le_mono Suc n < length SA n  j assms(3,10,11) linorder_not_le
                s_seen_invD(1))
    moreover
    have "Suc n  j  ?g1  ?g2  ?g3"
    proof -
      assume "Suc n  j"
      with s_seen_invD[OF assms(3) `j < length SA`] assms(10)
      show ?thesis
        by blast
    qed
    ultimately show "?g1  ?g2  ?g3"
      by blast
  qed
qed

corollary s_seen_inv_maintained_perm_step_c1_alt:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "length T  SA ! Suc n"
  shows "s_seen_inv α T B SA n"
  using s_seen_inv_maintained_step_c1_alt[OF s_perm_inv_elims(2,4,5,8,10-13,15)[OF assms(1)] assms(2-)]
  by blast

lemma s_seen_inv_maintained_step_c2:
  assumes "s_distinct_inv α T B SA"
  and     "s_bucket_ptr_inv α T B"
  and     "s_locations_inv α T B SA"
  and     "s_unchanged_inv α T B SA0 SA"
  and     "s_seen_inv α T B SA i"
  and     "s_pred_inv α T B SA i"
  and     "s_suc_inv α T B SA i"
  and     "strict_mono α"
  and     "α (Max (set T)) < length B"
  and     "length SA0 = length T"
  and     "length SA = length T"
  and     "l_types_init α T SA0"
  and     "valid_list T"
  and     "α bot = 0"
  and     "Suc 0 < length T"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = 0"
  shows "s_seen_inv α T B SA n"
 unfolding s_seen_inv_def
proof (intro allI impI)
  fix j
  assume "j < length SA" "n  j"
  hence "n < length SA"
    by simp
  hence "n < length T"
    by (simp add: assms(11))


  let ?b = "α (T ! (SA ! j))"
  let ?g1 = "(suffix_type T (SA ! j) = S_type  in_s_current_bucket α T B ?b j)"
  and ?g2 = "(suffix_type T (SA ! j) = L_type  in_l_bucket α T ?b j)"
  and ?g3 = "SA ! j < length T"

 from `n  j`
  have "n = j  Suc n  j"
    by linarith
  moreover
  have "n = j  ?g1  ?g2  ?g3"
  proof -
    assume "n = j"
    with index_in_bucket_interval_gen[OF `n < length T` assms(8)]
    obtain b where
      "b  α (Max (set T))"
      "bucket_start α T b  j"
      "j < bucket_end α T b"
      by blast

    have "j < l_bucket_end α T b  s_bucket_start α T b  j"
      by (metis not_le s_bucket_start_eq_l_bucket_end)
    moreover
    have "j < l_bucket_end α T b  ?thesis"
    proof -
      assume "j < l_bucket_end α T b"
      with l_types_init_nth[OF assms(11) l_types_init_maintained[OF assms(2,4,10-12)] `b  _`
            `bucket_start _ _ _  j`]
      have "SA ! j  l_bucket α T b" .
      hence "suffix_type T (SA ! j) = L_type" "SA ! j < length T"
        by (simp add: l_bucket_def bucket_def)+
      moreover
      have ?g1
        by(simp add: calculation(1) SL_types.exhaust)
      moreover
      from `SA ! j  l_bucket α T b`
      have "b = α (T ! (SA ! j))"
        by (metis (mono_tags, lifting)  bucket_def l_bucket_def mem_Collect_eq)
      with `bucket_start α T b  j` `j < l_bucket_end α T b` `b  _`
      have "in_l_bucket α T (α (T ! (SA ! j))) j"
        using in_l_bucket_def by blast
      ultimately show ?thesis
        by blast
    qed
    moreover
    have "s_bucket_start α T b  j  ?thesis"
    proof -
      assume "s_bucket_start α T b  j"
      hence "s_bucket_start α T b < i"
        by (simp add: n = j assms(16))

      have "B ! b  i"
      proof(rule ccontr)
        assume "¬B ! b  i"
        hence "i < B ! b"
          by simp
        with s_B_val[OF assms(1-6,8,10-13,15) `b  α _`]
        have "B ! b = s_bucket_start α T b" .
        with `s_bucket_start α T b < i` `i < B ! b`
        show False
          by linarith
      qed
      hence "B ! b < i  B ! b = i"
        using dual_order.order_iff_strict by blast
      moreover
      have "B ! b < i  ?thesis"
      proof -
        assume "B ! b < i"
        hence "B ! b  j"
          by (simp add: n = j assms(16))
        with s_locations_invD[OF assms(3) `b  _` _ `j < bucket_end _ _ _`]
        have "SA ! j  s_bucket α T b" .
        hence "SA ! j < length T" "suffix_type T (SA ! j) = S_type"
          by (simp add: s_bucket_def bucket_def)+
        moreover
        from calculation(2)
        have ?g2
          by simp
        moreover
        from `SA ! j  s_bucket α T b`
        have "α (T ! (SA ! j)) = b"
          by (simp add: s_bucket_def bucket_def)
        with `B ! b  j` `j < bucket_end α T b` `b  _`
        have "in_s_current_bucket α T B (α (T ! (SA ! j))) j"
          by (simp add: in_s_current_bucket_def)
        ultimately show ?thesis
          by blast
      qed
      moreover
      have "B ! b = i  ?thesis"
      proof -
        assume "B ! b = i"
        hence "s_bucket_start α T b < B ! b"
          using s_bucket_start α T b < i by blast

        have "b  0"
          using B ! b = i assms(2,16) less_Suc_eq_0_disj s_bucket_ptr_0 by fastforce

        let ?xs = "list_slice SA (B ! b) (bucket_end α T b)"
        let ?B = "set ?xs"
        let ?A = "s_bucket α T b - ?B"

       from s_locations_inv_subset_s_bucket[OF assms(3) `b  _`]
        have "?B  s_bucket α T b" .
        hence "?A  s_bucket α T b"
          by blast

        have "card (s_bucket α T b) = bucket_end α T b - s_bucket_start α T b"
          by (simp add: bucket_end_eq_s_start_pl_size s_bucket_size_def)

        from s_distinct_invD[OF assms(1) `b  _`]
        have "card ?B = bucket_end α T b - B ! b"
          by (metis assms(11) bucket_end_le_length distinct_card length_list_slice min.absorb_iff1)
        hence "card ?B < card (s_bucket α T b)"
          using card (s_bucket α T b) = bucket_end α T b - s_bucket_start α T b
                j < bucket_end α T b s_bucket_start α T b < B ! b s_bucket_start α T b  j
          by linarith
        with card_psubset[OF finite_s_bucket `?B  s_bucket α T b`]
        have "?B  s_bucket α T b" .
        hence "?A  {}"
          by blast
        with subset_s_bucket_successor[OF assms(13,8,14) `b  _` `?A  _`]
        obtain x where
          "x  ?A"
          "Suc x  ?B  (b'. b < b'  Suc x  bucket α T b')"
          by blast
        hence "suffix_type T x = S_type" "α (T ! x) = b" "x < length T"
          by (simp add: s_bucket_def bucket_def)+

        from `x  ?A`
        have "x  ?B"
          by blast

        have "Suc x  ?B  ?thesis"
        proof -
          assume "Suc x  ?B"
          from nth_mem_list_slice[OF `Suc x  ?B`]
          obtain i' where
            "i' < length SA"
            "B ! b  i'"
            "i' < bucket_end α T b"
            "SA ! i' = Suc x"
            by blast

          have "i  i'"
          proof (rule ccontr)
            assume "¬ i  i'"
            hence "i = i'"
              by auto
            with assms(16,18) `SA ! i' = Suc x`
            show False
              by simp
          qed
          with `B ! b = i` `B ! b  i'`
          have "i < i'"
            by simp
          with s_suc_invD[OF assms(7) `i' < length SA` _ `SA ! i' = Suc x` `suffix_type T x = _`,
                simplified `α (T ! x) = b`]
          obtain k where
            "in_s_current_bucket α T B b k"
            "SA ! k = x"
            "k < i'"
            by blast
          hence "x  ?B"
            by (meson assms(11) in_s_current_bucket_list_slice)
          with `x  ?B`
          have False
            by blast
          then show ?thesis
            by blast
        qed
        moreover
        have "b'. b < b'  Suc x  bucket α T b'  ?thesis"
        proof -
          assume "b'. b < b'  Suc x  bucket α T b'"
          then obtain b' where
            "b < b'"
            "Suc x  bucket α T b'"
            by blast
          hence "bucket_end α T b  bucket_start α T b'"
            by (simp add: less_bucket_end_le_start)
          with s_bucket_ptr_upper_bound[OF assms(2) `b  _ `] `B ! b = i`
          have "i  bucket_start α T b'"
            by linarith

          from Suc x  bucket α T b'
          have "b'  α (Max (set T))"
            by (metis (mono_tags, lifting) Max_greD assms(8) bucket_def mem_Collect_eq
                  strict_mono_less_eq)
          with `i  bucket_start α T b'` s_bucket_ptr_lower_bound[OF assms(2), of b']
          have "i  B ! b'"
            by (metis nat_le_iff_add s_bucket_start_def trans_le_add1)
          hence "i = B ! b'  i < B ! b'"
            using antisym_conv1 by blast
          hence "B ! b' = s_bucket_start α T b'"
          proof
            assume "i = B ! b'"
            with `i  bucket_start α T b'` s_bucket_ptr_lower_bound[OF assms(2) `b'  _`]
            show ?thesis
              by (simp add: s_bucket_start_def)
          next
            assume "i < B ! b'"
            with s_B_val[OF assms(1-6,8,10-13,15) `b'  _`]
            show ?thesis .
          qed

          from `Suc x  bucket α T b'`
          have "Suc x  l_bucket α T b'  Suc x  s_bucket α T b'"
            by (simp add: l_un_s_bucket)
          moreover
          have "Suc x  l_bucket α T b'  ?thesis"
          proof -
            assume "Suc x  l_bucket α T b'"
            with l_types_initD(1)[OF l_types_init_maintained[OF assms(2,4,10-12)] `b'  _`]
            have "Suc x  set (list_slice SA (bucket_start α T b') (l_bucket_end α T b'))"
              by simp
            with nth_mem_list_slice[of "Suc x" SA "bucket_start α T b'" "l_bucket_end α T b'"]
            obtain i' where
              "i' < length SA"
              "bucket_start α T b'  i'"
              "i' < l_bucket_end α T b'"
              "SA ! i' = Suc x"
              by blast

            have "i  i'"
            proof (rule ccontr)
              assume "¬ i  i'"
              hence "i = i'"
                by auto
              with `SA ! i' = Suc x` assms(16,18)
              show False
                by simp
            qed
            hence "i < i'"
              using bucket_start α T b'  i' i  bucket_start α T b' by auto
            with s_suc_invD[OF assms(7) `i' < length _` _ `SA ! i' = _` `suffix_type T x = _`,
                  simplified `α (T ! x) = b`]
            obtain k where
              "in_s_current_bucket α T B b k"
              "SA ! k = x"
              "k < i'"
              by blast
            hence "x  ?B"
              by (meson assms(11) in_s_current_bucket_list_slice)
            with `x  ?B`
            have False
              by blast
            then show ?thesis
              by blast
          qed
          moreover
          have "Suc x  s_bucket α T b'  ?thesis"
          proof -
            assume "Suc x  s_bucket α T b'"

          let ?ys = "list_slice SA (s_bucket_start α T b') (bucket_end α T b')"

            from distinct_card[OF s_distinct_invD[OF assms(1) `b'  _`],
                  simplified `B ! b' = s_bucket_start _ _ _`]
            have "card (set ?ys) = card (s_bucket α T b')"
              by (metis add_diff_cancel_left' assms(11) bucket_end_eq_s_start_pl_size
                    bucket_end_le_length length_list_slice min_def s_bucket_size_def)
            with card_subset_eq[
                  OF finite_s_bucket s_locations_inv_subset_s_bucket[OF assms(3) `b'  _`],
                  simplified `B ! b' = s_bucket_start α T b'`]
            have "set ?ys = s_bucket α T b'"
              by blast
            with `Suc x  s_bucket α T b'`
            have "Suc x  set ?ys"
              by simp
            with nth_mem_list_slice[of "Suc x"]
            obtain i' where
              "i' < length SA"
              "s_bucket_start α T b'  i'"
              "i' < bucket_end α T b'"
              "SA ! i' = Suc x"
              by blast

            from `SA ! i' = Suc x` assms(16,18)
            have "i  i'"
              using nat.discI by blast
            hence "i < i'"
              using B ! b' = s_bucket_start α T b' i  B ! b' s_bucket_start α T b'  i'
              by linarith
            with s_suc_invD[OF assms(7) `i' < length _` _ `SA ! i' = _` `suffix_type T x = _`,
                  simplified `α (T ! x) = b`]
            obtain k where
              "in_s_current_bucket α T B b k"
              "SA ! k = x"
              "k < i'"
              by blast
            hence "x  ?B"
              by (meson assms(11) in_s_current_bucket_list_slice)
            with `x  ?B`
            have False
              by blast
            then show ?thesis
              by blast
          qed
          ultimately show ?thesis
            by blast
        qed
        ultimately show ?thesis
          using `Suc x  ?B  (b'. b < b'  Suc x  bucket α T b')` by blast
      qed
      ultimately show ?thesis
        by blast
    qed
    ultimately show ?thesis
      by blast
  qed
  moreover
  have "Suc n  j  ?g1  ?g2  ?g3"
  proof -
    assume "Suc n  j"
    with s_seen_invD[OF assms(5) `j < length SA`] assms(16)
    show ?thesis
      by blast
  qed
  ultimately show "?g1  ?g2  ?g3"
    by blast
qed

corollary s_seen_inv_maintained_perm_step_c2:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = 0"
shows "s_seen_inv α T B SA n"
  using s_seen_inv_maintained_step_c2[OF s_perm_inv_elims[OF assms(1)] assms(2-)]
  by blast

lemma s_seen_inv_maintained_step_c3:
  assumes "s_distinct_inv α T B SA"
  and     "s_bucket_ptr_inv α T B"
  and     "s_locations_inv α T B SA"
  and     "s_unchanged_inv α T B SA0 SA"
  and     "s_seen_inv α T B SA i"
  and     "s_pred_inv α T B SA i"
  and     "s_suc_inv α T B SA i"
  and     "strict_mono α"
  and     "α (Max (set T)) < length B"
  and     "length SA0 = length T"
  and     "length SA = length T"
  and     "l_types_init α T SA0"
  and     "valid_list T"
  and     "α bot = 0"
  and     "Suc 0 < length T"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = L_type"
shows "s_seen_inv α T B SA n"
 unfolding s_seen_inv_def
proof (intro allI impI)
  fix k
  assume "k < length SA" "n  k"
  hence "n < length SA"
    by simp
  hence "n < length T"
    by (simp add: assms(11))

  let ?b = "α (T ! (SA ! k))"
  let ?g1 = "(suffix_type T (SA ! k) = S_type  in_s_current_bucket α T B ?b k)"
  and ?g2 = "(suffix_type T (SA ! k) = L_type  in_l_bucket α T ?b k)"
  and ?g3 = "SA ! k < length T"

 from `n  k`
  have "n = k  Suc n  k"
    by linarith
  moreover
  have "n = k  ?g1  ?g2  ?g3"
  proof -
    assume "n = k"
    with index_in_bucket_interval_gen[OF `n < length T` assms(8)]
    obtain b where
      "b  α (Max (set T))"
      "bucket_start α T b  k"
      "k < bucket_end α T b"
      by blast

    have "k < l_bucket_end α T b  s_bucket_start α T b  k"
      by (metis not_le s_bucket_start_eq_l_bucket_end)
    moreover
    have "k < l_bucket_end α T b  ?thesis"
    proof -
      assume "k < l_bucket_end α T b"
      with l_types_init_nth[OF assms(11) l_types_init_maintained[OF assms(2,4,10-12)]
            `b  _` `bucket_start _ _ _  _`]
      have "SA ! k  l_bucket α T b" .
      hence "SA ! k < length T" "suffix_type T (SA ! k) = L_type"
        by (simp add: l_bucket_def bucket_def)+
      moreover
      from calculation(2)
      have ?g1
        by simp
      moreover
      from `SA ! k  l_bucket α T b`
      have "b = (α (T ! (SA ! k)))"
        by (simp add: l_bucket_def bucket_def)
      with `b  _` `bucket_start _ _ _  _` `k < l_bucket_end _ _ _`
      have "in_l_bucket α T (α (T ! (SA ! k))) k"
        using in_l_bucket_def by blast
      ultimately show ?thesis
        by blast
    qed
    moreover
    have "s_bucket_start α T b  k  ?thesis"
    proof -
      assume "s_bucket_start α T b  k"
      hence "s_bucket_start α T b < i"
        by (simp add: n = k assms(16))

      have "B ! b  i"
      proof(rule ccontr)
        assume "¬B ! b  i"
        hence "i < B ! b"
          by simp
        with s_B_val[OF assms(1-6,8,10-13,15) `b  α _`]
        have "B ! b = s_bucket_start α T b" .
        with `s_bucket_start α T b < i` `i < B ! b`
        show False
          by linarith
      qed
      hence "i = B ! b  B ! b < i"
        by linarith
      moreover
      have "B ! b < i  ?thesis"
      proof -
        assume "B ! b < i"
        hence "B ! b  k"
          by (simp add: n = k assms(16))
        with s_locations_invD[OF assms(3) `b  _` _ `k < bucket_end _ _ _`]
        have "SA ! k  s_bucket α T b" .
        hence "SA ! k < length T" "suffix_type T (SA ! k) = S_type"
          by (simp add: s_bucket_def bucket_def)+
        moreover
        from calculation(2)
        have ?g2
          by simp
        moreover
        from `SA ! k  s_bucket α T b`
        have "α (T ! (SA ! k)) = b"
          by (simp add: s_bucket_def bucket_def)
        with `B ! b  k` `k < bucket_end α T b` `b  _`
        have "in_s_current_bucket α T B (α (T ! (SA ! k))) k"
          by (simp add: in_s_current_bucket_def)
        ultimately show ?thesis
          by blast
      qed
      moreover
      have "i = B ! b  ?thesis"
      proof -
        assume "i = B ! b"
        hence "k < B ! b"
          using n = k assms(16) by linarith

        have "s_bucket_start α T b < B ! b"
          using i = B ! b s_bucket_start α T b < i by blast

        have "b  0"
          by (metis k < B ! b assms(2) not_less_zero s_bucket_ptr_0)

        let ?xs = "list_slice SA (B ! b) (bucket_end α T b)"
        let ?B = "set ?xs"
        let ?A = "s_bucket α T b - ?B"

        from s_locations_inv_subset_s_bucket[OF assms(3) `b  _`]
        have "?B  s_bucket α T b" .
        hence "?A  s_bucket α T b"
          by blast

        have "card (s_bucket α T b) = bucket_end α T b - s_bucket_start α T b"
          by (simp add: bucket_end_eq_s_start_pl_size s_bucket_size_def)

        from s_distinct_invD[OF assms(1) `b  _`]
        have "card ?B = bucket_end α T b - B ! b"
          by (metis assms(11) bucket_end_le_length distinct_card length_list_slice min.absorb_iff1)
        hence "card ?B < card (s_bucket α T b)"
          using card (s_bucket α T b) = bucket_end α T b - s_bucket_start α T b
                k < bucket_end α T b s_bucket_start α T b < B ! b s_bucket_start α T b  k
          by linarith
        with card_psubset[OF finite_s_bucket `?B  s_bucket α T b`]
        have "?B  s_bucket α T b" .
        hence "?A  {}"
          by blast
        with subset_s_bucket_successor[OF assms(13,8,14) `b  0` `?A  s_bucket α T b`]
        obtain x where
          "x  ?A"
          "Suc x  s_bucket α T b - ?A  (b'. b < b'  Suc x  bucket α T b')"
          by blast
        hence "Suc x  ?B  (b'. b < b'  Suc x  bucket α T b')"
          by blast

        from `x  ?A` `?A  s_bucket α T b`
        have "suffix_type T x = S_type" "α (T ! x) = b"
          by (simp add: s_bucket_def bucket_def)+

        have "x  ?B"
          using x  ?A by blast

        from `Suc x  ?B  (b'. b < b'  Suc x  bucket α T b')`
        have False
        proof
          assume "Suc x  ?B"
          from nth_mem_list_slice[OF `Suc x  ?B`]
          obtain i' where
            "i' < length SA"
            "B ! b  i'"
            "i' < bucket_end α T b"
            "SA ! i' = Suc x"
            by blast

          have "i  i'"
          proof (rule ccontr)
            assume "¬ i  i'"
            hence "i = i'"
              by auto
            hence "j = x"
              using SA ! i' = Suc x assms(16,18) by auto
            with assms(19) `suffix_type T x = _`
            show False
              by simp
          qed
          with `B ! b  i'` `i = B ! b`
          have "i < i'"
            using nat_less_le by blast
          with s_suc_invD[OF assms(7) `i' < length SA ` _ `SA ! i' = _` `suffix_type T x = _`]
               `α (T ! x) = b`
          obtain k where
            "in_s_current_bucket α T B b k"
            "SA ! k = x"
            "k < i'"
            by blast
          hence "x  ?B"
            by (meson assms(11) in_s_current_bucket_list_slice)
          with `x  ?B`
          show False
            by blast
        next
          assume "b'. b < b'  Suc x  bucket α T b'"
          then obtain b' where
            "b < b'"
            "Suc x  bucket α T b'"
            by blast
          hence "b'  α (Max (set T))"
            by (metis (mono_tags, lifting) Max_greD assms(8) bucket_def mem_Collect_eq
                  strict_mono_less_eq)

          have "suffix_type T (Suc x) = S_type  suffix_type T (Suc x) = L_type"
            by (simp add: suffix_type_def)
          hence "Suc x  l_bucket α T b'  Suc x  s_bucket α T b'"
            using Suc x  bucket α T b' l_bucket_def s_bucket_def by fastforce
          moreover
          have "Suc x  l_bucket α T b'  False"
          proof -
            assume "Suc x  l_bucket α T b'"
            with l_types_initD(1)[OF l_types_init_maintained[OF assms(2,4,10-12)] `b'  _`]
            have "Suc x  set (list_slice SA (bucket_start α T b') (l_bucket_end α T b'))"
              by blast
            with nth_mem_list_slice[of "Suc x"]
            obtain i' where
              "i' < length SA"
              "bucket_start α T b'  i'"
              "i' < l_bucket_end α T b'"
              "SA ! i' = Suc x"
              by blast

            have "i  i'"
            proof (rule ccontr)
              assume "¬ i  i'"
              hence "i = i'"
                by auto
              hence "j = x"
                using SA ! i' = Suc x assms(16,18) by auto
              with assms(19) `suffix_type T x = _`
              show False
                by simp
            qed
            moreover
            from `b < b'`
            have "bucket_end α T b  bucket_start α T b'"
              by (simp add: less_bucket_end_le_start)
            hence "B ! b  i'"
              using s_bucket_ptr_upper_bound[OF assms(2) `b  α (Max (set T))`]
                    `bucket_start α T b'  i'`
              by linarith
            ultimately have "i < i'"
              using i = B ! b nat_less_le by blast
            with s_suc_invD[OF assms(7) `i' < length SA ` _ `SA ! i' = _` `suffix_type T x = _`]
                 `α (T ! x) = b`
            obtain k where
              "in_s_current_bucket α T B b k"
              "SA ! k = x"
              "k < i'"
              by blast
            hence "x  ?B"
              by (meson assms(11) in_s_current_bucket_list_slice)
            with `x  ?B`
            show False
              by blast
          qed
          moreover
          have "Suc x  s_bucket α T b'  False"
          proof -
            assume "Suc x  s_bucket α T b'"

            have "i  bucket_end α T b"
              by (simp add: Suc_le_eq k < bucket_end α T b n = k assms(16))
            hence "i  bucket_start α T b'"
              using b < b' less_bucket_end_le_start order.trans by blast
            hence "i  B ! b'"
              using s_bucket_ptr_lower_bound[OF assms(2) `b'  _`]
              by (metis l_bucket_end_def le_trans nat_le_iff_add s_bucket_start_eq_l_bucket_end)
            hence "i < B ! b'  i = B ! b'"
              using nat_less_le by blast
            hence "B ! b' = s_bucket_start α T b'"
            proof
              assume "i < B ! b'"
              with s_B_val[OF assms(1-6,8,10-13,15) `b'  _`]
              show "B ! b' = s_bucket_start α T b'"
                by blast
            next
              assume "i = B ! b'"
              with s_bucket_ptr_lower_bound[OF assms(2) `b'  _`]
                   `i  bucket_start α T b'`
              show "B ! b' = s_bucket_start α T b'"
                by (simp add: s_bucket_start_def)
            qed

            let ?ys = "list_slice SA (s_bucket_start α T b') (bucket_end α T b')"

            from distinct_card[OF s_distinct_invD[OF assms(1) `b'  _`],
                  simplified `B ! b' = s_bucket_start _ _ _`]
            have "card (set ?ys) = card (s_bucket α T b')"
              by (metis add_diff_cancel_left' assms(11) bucket_end_eq_s_start_pl_size
                    bucket_end_le_length length_list_slice min_def s_bucket_size_def)
            with card_subset_eq[
                  OF finite_s_bucket s_locations_inv_subset_s_bucket[OF assms(3) `b'  _`],
                  simplified `B ! b' = s_bucket_start α T b'`]
            have "set ?ys = s_bucket α T b'"
              by blast
            with `Suc x  s_bucket α T b'`
            have "Suc x  set ?ys"
              by simp
            with nth_mem_list_slice[of "Suc x"]
            obtain i' where
              "i' < length SA"
              "s_bucket_start α T b'  i'"
              "i' < bucket_end α T b'"
              "SA ! i' = Suc x"
              by blast

            have "i  i'"
            proof (rule ccontr)
              assume "¬ i  i'"
              hence "i = i'"
                by auto
              hence "j = x"
                using SA ! i' = Suc x assms(16,18) by auto
              with assms(19) `suffix_type T x = _`
              show False
                by simp
            qed
            moreover
            have "i  i'"
              using B ! b' = s_bucket_start α T b' i  B ! b' s_bucket_start α T b'  i'
              by linarith
            ultimately have "i < i'"
              using dual_order.order_iff_strict by blast
            with s_suc_invD[OF assms(7) `i' < length SA ` _ `SA ! i' = _` `suffix_type T x = _`]
                 `α (T ! x) = b`
            obtain k where
              "in_s_current_bucket α T B b k"
              "SA ! k = x"
              "k < i'"
              by blast
            hence "x  ?B"
              by (meson assms(11) in_s_current_bucket_list_slice)
            with `x  ?B`
            show False
              by blast
          qed
          ultimately show False
            by blast
        qed
        then show ?thesis
          by blast
      qed
      ultimately show ?thesis
        by blast
    qed
    ultimately show ?thesis
      by blast
  qed
  moreover
  have "Suc n  k  ?g1  ?g2  ?g3"
  proof -
    assume "Suc n  k"
    with s_seen_invD[OF assms(5) `k < length SA`] assms(16)
    show ?thesis
      by blast
  qed
  ultimately show "?g1  ?g2  ?g3"
    by blast
qed

corollary s_seen_inv_maintained_perm_step_c3:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = L_type"
shows "s_seen_inv α T B SA n"
  using s_seen_inv_maintained_step_c3[OF s_perm_inv_elims[OF assms(1)] assms(2-)]
  by blast

lemma s_seen_inv_maintained_step_c4:
  assumes "s_distinct_inv α T B SA"
  and     "s_bucket_ptr_inv α T B"
  and     "s_locations_inv α T B SA"
  and     "s_unchanged_inv α T B SA0 SA"
  and     "s_seen_inv α T B SA i"
  and     "s_pred_inv α T B SA i"
  and     "s_suc_inv α T B SA i"
  and     "strict_mono α"
  and     "α (Max (set T)) < length B"
  and     "length SA0 = length T"
  and     "length SA = length T"
  and     "l_types_init α T SA0"
  and     "valid_list T"
  and     "α bot = 0"
  and     "Suc 0 < length T"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
  and     "k = B ! b - Suc 0"
shows "s_seen_inv α T (B[b := k]) (SA[k := j]) n"
  unfolding s_seen_inv_def
proof(intro allI impI)
  fix i'
  assume "i' < length (SA[k := j])" "n  i'"

  let ?g1 = "(suffix_type T (SA[k := j] ! i') = S_type 
              in_s_current_bucket α T (B[b := k]) (α (T ! (SA[k := j] ! i'))) i')" and
      ?g2 = "(suffix_type T (SA[k := j] ! i') = L_type 
              in_l_bucket α T (α (T ! (SA[k := j] ! i'))) i')" and
      ?g3 = "SA[k := j] ! i' < length T"

  from s_bucket_ptr_strict_lower_bound[OF assms(1-6,8,10-14,16-20)]
  have "s_bucket_start α T b < B ! b".
  hence "s_bucket_start α T b  k"
    using assms(21) by linarith
  hence "bucket_start α T b  k"
    using bucket_start_le_s_bucket_start le_trans by blast

  from `s_bucket_start α T b < B ! b`
  have "k < B ! b"
    using assms(21) by linarith

  have "j < length T"
    by (simp add: assms(19) suffix_type_s_bound)
  hence "b  α (Max (set T))"
    by (simp add: assms(8,20) strict_mono_less_eq)
  with s_bucket_ptr_upper_bound[OF assms(2)]
  have "B ! b  bucket_end α T b"
    by blast
  with `k < B ! b`
  have "k < bucket_end α T b"
    by linarith

  have "B ! b  i"
  proof(rule ccontr)
    assume "¬B ! b  i"
    hence "i < B ! b"
      by simp
    with s_B_val[OF assms(1-6,8,10-13,15) `b  α _`]
    have "B ! b = s_bucket_start α T b" .
    with `s_bucket_start α T b < B ! b`
    show False
      by linarith
  qed
  hence "k < i"
    using k < B ! b less_le_trans by blast

  have "k = i'  n = i'"
    using k < i n  i' assms(16) le_less_Suc_eq by blast

  have "k  i'"
    using k < i n  i' assms(16) by linarith

  have "i' < length T"
    using i' < length (SA[k := j]) assms(11) by auto
  with index_in_bucket_interval_gen[OF _ assms(8), of i' T]
  obtain b' where
    "b'  α (Max (set T))"
    "bucket_start α T b'  i'"
    "i' < bucket_end α T b'"
    by blast
  hence "n < bucket_end α T b'"
    using n  i' dual_order.strict_trans2 by blast
  hence "i  bucket_end α T b'"
    using assms(16) by linarith

  have "b  b'"
  proof (rule ccontr)
    assume "¬b  b'"
    hence "b' < b"
      by linarith
    hence "bucket_end α T b'  bucket_start α T b"
      by (simp add: less_bucket_end_le_start)
    with `i  bucket_end α T b'` `bucket_start α T b  k` `k < B ! b`
    have "i < B ! b"
      by linarith
    with `B ! b  i`
    show False
      by linarith
  qed

  have "in_s_current_bucket α T (B[b := k]) b k"
    unfolding in_s_current_bucket_def
    using b  α (Max (set T)) k < bucket_end α T b assms(9) by auto

  have "b < b'  ?g1  ?g2  ?g3"
  proof -
    assume "b < b'"
    hence "bucket_end α T b  bucket_start α T b'"
      by (simp add: less_bucket_end_le_start)
    with `k < bucket_end _ _ b` `bucket_start _ _ b'  i'`
    have "k < i'"
      by linarith
    hence "SA[k := j] ! i' = SA ! i'"
      by simp

    from `b < b'`
    have "B[b := k] ! b' = B ! b'"
      by simp

    have "i' < l_bucket_end α T b'  B ! b'  i'  (s_bucket_start α T b'  i'  i' < B ! b')"
      by (metis not_le s_bucket_start_eq_l_bucket_end)
    moreover
    have "B ! b'  i'  ?thesis"
    proof -
      assume "B ! b'  i'"
      with s_locations_invD[OF assms(3) `b'  _` _ `i' < bucket_end _ _ _`]
      have "SA ! i'  s_bucket α T b'" .
      hence "suffix_type T (SA ! i') = S_type" "α (T ! (SA ! i')) = b'" "SA ! i' < length T"
        by (simp add: s_bucket_def bucket_def)+
      moreover
      from `B[b := k] ! b' = B ! b'` `b'  α _` `B ! b'  i'` `i' < bucket_end α T b'`
      have "in_s_current_bucket α T (B[b := k]) b' i'"
        by (simp add: in_s_current_bucket_def)
      ultimately show ?thesis
        by (simp add: `SA[k := j] ! i' = SA ! i'`)
    qed
    moreover
    have "i' < l_bucket_end α T b'  ?thesis"
    proof -
      assume "i' < l_bucket_end α T b'"
      hence "in_l_bucket α T b' i'"
        by (simp add: `bucket_start α T b'  i'` `b'  α _` in_l_bucket_def)
      moreover
      from l_types_init_nth[OF assms(11) l_types_init_maintained[OF assms(2,4,10-12)]
            `b'  α _` `bucket_start _ _ _  i'` `i' < l_bucket_end _ _ _`]
      have "SA ! i'  l_bucket α T b'" .
      hence "SA ! i' < length T" "α (T ! (SA ! i')) = b'" "suffix_type T (SA ! i') = L_type"
        by (simp add: l_bucket_def bucket_def)+
      ultimately show ?thesis
        using `SA[k := j] ! i' = SA ! i'`
        by simp
    qed
    moreover
    have "s_bucket_start α T b'  i'; i' < B ! b'  ?thesis"
    proof -
      assume "s_bucket_start α T b'  i'" "i' < B ! b'"
      have "B ! b' = i"
      proof (rule ccontr)
        assume "B ! b'  i"
        hence "i < B ! b'  B ! b' < i"
          by linarith
        moreover
        have "B ! b' < i  False"
          using `i' < B ! b'` n  i' assms(16) by linarith
        moreover
        have "i < B ! b'  False"
        proof -
          assume "i < B ! b'"
          with s_B_val[OF assms(1-6,8,10-13,15) `b'  α _`]
          have "B ! b' = s_bucket_start α T b'" .
          with `s_bucket_start α T b'  i'` `i' < B ! b'`
          show False
            by linarith
        qed
        ultimately show False
          by linarith
      qed

      have "s_bucket_start α T b' < B ! b'"
        using i' < B ! b' s_bucket_start α T b'  i' by linarith
      hence "s_bucket_start α T b' < bucket_end α T b'"
        using B ! b' = i i  bucket_end α T b' order.strict_trans2 by blast
      hence "s_bucket α T b'  {}"
        by (metis add.commute bucket_end_eq_s_start_pl_size distinct_card distinct_conv_nth
              empty_set less_irrefl_nat less_nat_zero_code list.size(3) plus_nat.add_0
              s_bucket_size_def)

      have "bucket_end α T b'  length SA"
        by (simp add: assms(11) bucket_end_le_length)

      let ?xs = "list_slice SA (B ! b') (bucket_end α T b')"

      have "set ?xs  s_bucket α T b'"
      proof
        from s_locations_inv_subset_s_bucket[OF assms(3) `b'  _`]
        show "set ?xs  s_bucket α T b'" .
      next
        from `s_bucket_start α T b' < B ! b'` `s_bucket_start α T b' < bucket_end α T b'`
        have "bucket_end α T b' - B ! b' < bucket_end α T b' - s_bucket_start α T b'"
          using diff_less_mono2 by blast
        hence "length ?xs < s_bucket_size α T b'"
          by (metis bucket_end α T b'  length SA add_diff_cancel_left'
                bucket_end_eq_s_start_pl_size length_list_slice min_def)
        hence "card (set ?xs)  card (s_bucket α T b')"
          by (metis card_length not_le s_bucket_size_def)
        then show "set ?xs  s_bucket α T b'"
          by auto
      qed

      have P0: "i0 < length T. α (T ! i0) = b'  T ! i0  bot"
        using b < b' assms(8,20) strict_mono_less by fastforce
      hence P1: "i0 < length T. α (T ! i0) = b'  Suc i0 < length T"
        by (metis Suc_leI assms(13) diff_Suc_1 last_conv_nth le_imp_less_or_eq length_greater_0_conv
              valid_list_def)

      let ?S = "s_bucket α T b' - set ?xs"

      from `set ?xs  s_bucket α T b'`
      have "?S  {}"
        by blast
      have "?S  s_bucket α T b'"
        by blast
      hence P2: "x  ?S. α (T ! x) = b'  suffix_type T x = S_type  x < length T"
        by (simp add: bucket_def s_bucket_def)

      have P3: "x  ?S. Suc x < length T  α (T ! Suc x)  b'"
      proof
        fix x
        assume "x  ?S"
        with P2
        have "α (T ! x) = b'" "suffix_type T x = S_type" "x < length T"
          by blast+
        with P1
        have "Suc x < length T"
          by blast
        moreover
        from `suffix_type T x = S_type` `x < length T`
        have "T ! x  T ! Suc x"
          using calculation nth_gr_imp_l_type by fastforce
        hence "α (T ! Suc x)  b'"
          using α (T ! x) = b' assms(8) strict_mono_leD by blast
        ultimately show "Suc x < length T  α (T ! Suc x)  b'"
          by blast
      qed

      have "finite ?S"
        by (simp add: finite_s_bucket)

      have "x  ?S. α (T ! Suc x) > b'  Suc x  set ?xs"
      proof (rule ccontr)
        assume "¬ (x  ?S. b' < α (T ! Suc x)  Suc x  set ?xs)"
        hence "x  ?S. α (T ! Suc x)  b'  Suc x  set ?xs"
          using not_le_imp_less by blast
        with P3
        have P4: "x  ?S. α (T ! Suc x) = b'  Suc x  set ?xs"
          using dual_order.antisym by blast
        hence P5: "x  ?S. suffix_type T (Suc x) = S_type"
          by (metis P2 P3 assms(8) strict_mono_eq suffix_type_neq)
        hence P6: "x  ?S. Suc x  ?S"
          by (metis (mono_tags, lifting) Diff_iff P3 P4 bucket_def mem_Collect_eq s_bucket_def)
        with `?S  {}` `finite ?S`
        show False
          using Suc_le_lessD infinite_growing by blast
      qed
      then obtain x where
        "x  ?S"
        "α (T ! Suc x) > b'  Suc x  set ?xs"
        by blast
      with P3
      have "Suc x < length T"
        by blast

      from `x  ?S`
      have "suffix_type T x = S_type" "α (T ! x) = b'" "x < length T"
        using P2 by blast+

      have P4: "b0  α (Max (set T)). b' < b0  B ! b0 = s_bucket_start α T b0"
      proof(safe)
        fix b0
        assume "b0  α (Max (set T))" "b' < b0"
        hence "bucket_end α T b'  bucket_start α T b0"
          by (simp add: less_bucket_end_le_start)
        with s_bucket_ptr_upper_bound[OF assms(2) `b'  _ `]
             s_bucket_ptr_lower_bound[OF assms(2) `b0  _ `]
        have "B ! b'  B ! b0"
          by (meson bucket_start_le_s_bucket_start le_trans)
        hence "B ! b' = B ! b0  B ! b' < B ! b0"
          by linarith
        moreover
        have "B ! b' = B ! b0  B ! b0 = s_bucket_start α T b0"
          by (metis B ! b' = i bucket_end α T b'  bucket_start α T b0 le_trans
              i  bucket_end α T b' s_bucket_start α T b0  B ! b0  dual_order.antisym
                bucket_start_le_s_bucket_start)
        moreover
        have "B ! b' < B ! b0  i < B ! b0"
          by (simp add: B ! b' = i)
        with s_B_val[OF assms(1-6,8,10-13,15) `b0  _`]
        have "B ! b' < B ! b0  B ! b0 = s_bucket_start α T b0"
          by blast
        ultimately show "B ! b0 = s_bucket_start α T b0"
          by blast
      qed

      from `α (T ! Suc x) > b'  Suc x  set ?xs`
      show ?thesis
      proof
        let ?b = "α (T ! Suc x)"
        let ?ys = "list_slice SA (bucket_start α T ?b) (l_bucket_end α T ?b)"
        and ?zs = "list_slice SA (s_bucket_start α T ?b) (bucket_end α T ?b)"

        assume "b' < ?b"
        with P4 `Suc x < length T`
        have "B ! ?b = s_bucket_start α T ?b"
          by (simp add: assms(8) strict_mono_less_eq)

        from `Suc x < length T`
        have "?b  α (Max (set T))"
          by (simp add: assms(8) strict_mono_leD)

        have "bucket_end α T b'  bucket_start α T ?b"
          using b' < α (T ! Suc x) less_bucket_end_le_start by blast
        hence "i  bucket_start α T ?b"
          using i  bucket_end α T b' order.trans by blast

        have "set ?zs = s_bucket α T ?b"
        proof (rule card_subset_eq[OF finite_s_bucket])
          show "set ?zs  s_bucket α T ?b"
            by (metis Max_greD B ! ?b = s_bucket_start α T ?b Suc x < length T assms(3,8)
                  s_locations_inv_subset_s_bucket strict_mono_leD)
        next
          from distinct_card[OF s_distinct_invD[OF assms(1) `?b  _`]]
               `B ! ?b = s_bucket_start α T ?b`
          have "card (set ?zs) = length ?zs"
            by simp
          moreover
          have "length ?zs = bucket_end α T ?b - s_bucket_start α T ?b"
            by (metis assms(11) bucket_end_le_length length_list_slice min_def)
          moreover
          have "s_bucket_size α T ?b = bucket_end α T ?b - s_bucket_start α T ?b"
            by (simp add: bucket_end_eq_s_start_pl_size)
          hence "card (s_bucket α T ?b) = bucket_end α T ?b - s_bucket_start α T ?b"
            by (simp add: s_bucket_size_def)
          ultimately show "card (set ?zs) = card (s_bucket α T ?b)"
            by simp
        qed

        have "suffix_type T (Suc x) = L_type  ?thesis"
        proof -
          assume "suffix_type T (Suc x) = L_type"
          with l_types_initD(1)[OF l_types_init_maintained[OF assms(2,4,10-12)] `?b  _`]
          have "Suc x  set ?ys"
            by (simp add: Suc x < length T bucket_def l_bucket_def)

          from nth_mem_list_slice[OF `Suc x  set ?ys`]
          obtain i0 where
            "i0 < length SA"
            "bucket_start α T ?b  i0"
            "i0 < l_bucket_end α T ?b"
            "SA ! i0 = Suc x"
            by blast
          hence "i  i0"
            using i  bucket_start α T ?b dual_order.trans by blast
          hence "i = i0  i < i0"
            by linarith
          then show ?thesis
          proof
            assume "i = i0"
            hence "x = j"
              using SA ! i0 = Suc x assms(16,18) by auto
            then show ?thesis
              using α (T ! x) = b' b < b' assms(20) by blast
          next
            assume "i < i0"
            with s_suc_invD[OF assms(7) `i0 < length _` _ `SA ! i0 = _` `suffix_type T x = S_type`]
                 `α (T ! x) = b'`
            obtain i1 where
              "in_s_current_bucket α T B b' i1"
              "SA ! i1 = x"
              "i1 < i0"
              by auto
            with in_s_current_bucket_list_slice[OF assms(11)]
            have "x  set ?xs"
              by blast
            then show ?thesis
              using x  ?S by blast
          qed
        qed
        moreover
        have "suffix_type T (Suc x) = S_type  ?thesis"
        proof -
          assume "suffix_type T (Suc x) = S_type"
          with `set ?zs = s_bucket α T ?b` `Suc x < length T`
          have "Suc x  set ?zs"
            by (simp add: s_bucket_def bucket_def)

          from nth_mem_list_slice[OF `Suc x  set ?zs`]
          obtain i0 where
            "i0 < length SA"
            "s_bucket_start α T ?b  i0"
            "i0 < bucket_end α T ?b"
            "SA ! i0 = Suc x"
            by blast
          hence "i  i0"
            by (meson i  bucket_start α T ?b bucket_start_le_s_bucket_start dual_order.trans)
          hence "i = i0  i < i0"
            by linarith
          then show ?thesis
          proof
            assume "i = i0"
            hence "x = j"
              using SA ! i0 = Suc x assms(16,18) by auto
            then show ?thesis
              using α (T ! x) = b' b < b' assms(20) by blast
          next
            assume "i < i0"
            with s_suc_invD[OF assms(7) `i0 < length _` _ `SA ! i0 = _` `suffix_type T x = S_type`]
                 `α (T ! x) = b'`
            obtain i1 where
              "in_s_current_bucket α T B b' i1"
              "SA ! i1 = x"
              "i1 < i0"
              by auto
            with in_s_current_bucket_list_slice[OF assms(11)]
            have "x  set ?xs"
              by blast
            then show ?thesis
              using x  ?S by blast
          qed
        qed
        ultimately show ?thesis
          using SL_types.exhaust by blast
      next
        assume "Suc x  set ?xs"

        from nth_mem_list_slice[OF `Suc x  set ?xs`]
        obtain i0 where
          "i0 < length SA"
          "B ! b'  i0"
          "i0 < bucket_end α T b'"
          "SA ! i0 = Suc x"
          by blast
        with `B ! b' = i`
        have "i  i0"
          by blast
        hence "i = i0  i < i0"
          by linarith
        then show ?thesis
        proof
          assume "i = i0"
          hence "x = j"
            using SA ! i0 = Suc x assms(16,18) by auto
          then show ?thesis
            using α (T ! x) = b' b < b'  assms(20) by blast
        next
          assume "i < i0"
          with s_suc_invD[OF assms(7) `i0 < length _` _ `SA ! i0 = _` `suffix_type T x = _`]
               `α (T ! x) = b'`
          obtain i1 where
            "in_s_current_bucket α T B b' i1"
            "SA ! i1 = x"
            "i1 < i0"
            by blast
          with in_s_current_bucket_list_slice[OF assms(11)]
          have "x  set ?xs"
            by blast
          then show ?thesis
            using x  ?S by blast
        qed
      qed
    qed
    ultimately show ?thesis
      by linarith
  qed
  moreover
  have "b = b'  ?g1  ?g2  ?g3"
  proof -
    assume "b = b'"
    have "k = i'  ?thesis"
    proof -
      assume "k = i'"
      hence "SA[k := j] ! i' = j"
        using i' < length (SA[k := j]) by auto
      with `suffix_type T j = S_type` `j < length T` `in_s_current_bucket α T (B[b := k]) b k`
           assms(20) `k = i'`
      show ?thesis
        by simp
    qed
    moreover
    have "k < i'  ?thesis"
    proof -
      assume "k < i'"
      hence "B ! b  i'"
        using assms(21) by linarith
      with s_locations_invD[OF assms(3) `b'  α _` _ `i' < bucket_end _ _ _`] `b = b'`
      have "SA ! i'  s_bucket α T b'"
        by blast
      hence "suffix_type T (SA ! i') = S_type" "α (T ! (SA ! i')) = b'"
        by (simp add: s_bucket_def bucket_def)+
      moreover
      have "SA[k := j] ! i' = SA ! i'"
        using `k < i'` by simp
      moreover
      have "in_s_current_bucket α T (B[b := k]) b' i'"
        by (metis (no_types, lifting) b = b' b'  α (Max (set T)) i' < bucket_end α T b'
              k  i' assms(9) dual_order.strict_trans2 in_s_current_bucket_def nth_list_update_eq)
      ultimately show ?thesis
        by (simp add: suffix_type_s_bound)
    qed
    ultimately show ?thesis
      using `k  i'` dual_order.order_iff_strict by blast
  qed
  ultimately show "?g1  ?g2  ?g3"
    using b  b' dual_order.order_iff_strict by blast
qed

corollary s_seen_inv_maintained_perm_step_c4:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
  and     "k = B ! b - Suc 0"
shows "s_seen_inv α T (B[b := k]) (SA[k := j]) n"
  using s_seen_inv_maintained_step_c4[OF s_perm_inv_elims[OF assms(1)] assms(2-)]
  by blast

lemmas s_seen_inv_maintained_perm_step =
  s_seen_inv_maintained_perm_step_c1
  s_seen_inv_maintained_perm_step_c2
  s_seen_inv_maintained_perm_step_c3
  s_seen_inv_maintained_perm_step_c4

subsubsection "Predecessor"

lemma s_pred_inv_established:
  assumes "s_bucket_init α T B"
shows "s_pred_inv α T B SA n"
  unfolding s_pred_inv_def
proof (safe)
  fix b i
  assume A: "in_s_current_bucket α T B b i" "0 < b"

  let ?goal = "j<length SA. SA ! j = Suc (SA ! i)  i < j  n < j"

  have "b = 0  0 < b"
    by blast
  moreover
  from A(2)
  have "b = 0  ?goal"
    by blast
  moreover
  have "0 < b  ?goal"
  proof -
    assume "0 < b"
    with s_bucket_initD(1)[OF assms(1) in_s_current_bucketD(1)[OF A(1)]]
    have "B ! b = bucket_end α T b" .
    with in_s_current_bucketD(2,3)[OF A(1)]
    show ?goal
      by linarith
  qed
  ultimately show ?goal
    by blast
qed

lemma s_pred_inv_maintained_step_alt:
  assumes "s_pred_inv α T B SA i"
  and     "i = Suc n"
shows "s_pred_inv α T B SA n"
  unfolding s_pred_inv_def
proof (intro allI impI; elim conjE)
  fix b i'
  assume "in_s_current_bucket α T B b i'" "b  0"
  with s_pred_invD[OF assms(1), of b i'] assms(2)
  show  "j<length SA. SA ! j = Suc (SA ! i')  i' < j  n < j"
    using Suc_lessD by blast
qed

corollary s_pred_inv_maintained_perm_step_alt:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
shows "s_pred_inv α T B SA n"
  using s_pred_inv_maintained_step_alt[OF s_perm_inv_elims(6), OF assms]
  by blast

lemma s_pred_inv_maintained_step:
  assumes "s_distinct_inv α T B SA"
  and     "s_bucket_ptr_inv α T B"
  and     "s_locations_inv α T B SA"
  and     "s_unchanged_inv α T B SA0 SA"
  and     "s_seen_inv α T B SA i"
  and     "s_pred_inv α T B SA i"
  and     "s_suc_inv α T B SA i"
  and     "strict_mono α"
  and     "α (Max (set T)) < length B"
  and     "length SA0 = length T"
  and     "length SA = length T"
  and     "l_types_init α T SA0"
  and     "valid_list T"
  and     "α bot = 0"
  and     "Suc 0 < length T"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
  and     "k = B ! b - Suc 0"
shows "s_pred_inv α T (B[b := k]) (SA[k := j]) n"
  unfolding s_pred_inv_def
proof(safe)
  fix b' i'
  assume "in_s_current_bucket α T (B[b := k]) b' i'" "0 < b'"
  hence "b'  0"
    by linarith

  let ?goal = "j'<length (SA[k := j]). SA[k := j] ! j' = Suc (SA[k := j] ! i')  i' < j'  n < j'"

  from s_bucket_ptr_strict_lower_bound[OF assms(1-6,8,10-14,16-20)]
  have "s_bucket_start α T b < B ! b".
  hence "s_bucket_start α T b  k"
    using assms(21) by linarith
  hence "bucket_start α T b  k"
    using bucket_start_le_s_bucket_start le_trans by blast

  from `s_bucket_start α T b < B ! b`
  have "k < B ! b"
    using assms(21) by linarith

  have "j < length T"
    by (simp add: assms(19) suffix_type_s_bound)
  hence "b  α (Max (set T))"
    by (simp add: assms(8,20) strict_mono_less_eq)
  with s_bucket_ptr_upper_bound[OF assms(2)]
  have "B ! b  bucket_end α T b"
    by blast
  with `k < B ! b`
  have "k < bucket_end α T b"
    by linarith

  have "B ! b  i"
  proof(rule ccontr)
    assume "¬B ! b  i"
    hence "i < B ! b"
      by simp
    with s_B_val[OF assms(1-6,8,10-13,15) `b  α (Max (set T))`] `s_bucket_start α T b < B ! b`
    show False
      by simp
  qed
  with `k < B ! b`
  have "k < i"
    by linarith

  have "b  b'  ?goal"
  proof -
    assume "b  b'"
    hence "B[b := k] ! b' = B ! b'"
      by simp
    with `in_s_current_bucket α T (B[b := k]) b' i'`
    have "in_s_current_bucket α T B b' i'"
      by (simp add: in_s_current_bucket_def)
    with s_pred_invD[OF assms(6) _ `b'  0`]
    obtain j' where
      "j' < length SA"
      "SA ! j' = Suc (SA ! i')"
      "i' < j'"
      "i < j'"
      by blast
    moreover
    from `in_s_current_bucket α T B b' i'`
    have "B ! b'  i'" "i' < bucket_end α T b'"
      by (simp_all add: in_s_current_bucket_def)
    with s_bucket_ptr_lower_bound[OF assms(2)]
         in_s_current_bucketD(1)[OF `in_s_current_bucket _ _ B _ _`]
    have "bucket_start α T b'  i'"
      by (meson bucket_start_le_s_bucket_start le_trans)
    with outside_another_bucket[OF `b  b'` `bucket_start _ _ _  k` `k < bucket_end _ _ _`]
         `i' < bucket_end α T b'`
    have "k  i'"
      by blast
    hence "SA[k := j] ! i' = SA ! i'"
      by simp
    moreover
    from `i < j'` assms(16)
    have "n < j'"
      using Suc_lessD by blast
    moreover
    have "SA[k := j] ! j' = SA ! j'"
      using k < i calculation(4) by auto
    ultimately show ?thesis
      by auto
  qed
  moreover
  have "b = b'  ?goal"
  proof -
    assume "b = b'"
    hence "B[b := k] ! b' = k"
      using b  α (Max (set T)) assms(9) by auto

    have "k = i'  ?goal"
    proof -
      assume "k = i'"
      hence "SA[k := j] ! i' = j"
        using k < i assms(16,17) by auto
      moreover
      have "SA[k := j] ! i = SA ! i"
        using k < i by auto
      ultimately show ?goal
        using assms(16-18) `k = i'` `k < i`
        by auto
    qed
    moreover
    have "k  i'  ?goal"
    proof -
      assume "k  i'"
      with `in_s_current_bucket α T (B[b := k]) b' i'` `B[b := k] ! b' = k`
      have "k < i'"
        by (simp add: in_s_current_bucket_def)
      hence "B ! b'  i'"
        using assms(21) `b = b'` `k < B ! b` by simp
      hence "in_s_current_bucket α T B b' i'"
        using in_s_current_bucket α T (B[b := k]) b' i' in_s_current_bucket_def by blast
      with s_pred_invD[OF assms(6) _ `b'  0`]
      obtain j' where
        "j' < length SA"
        "SA ! j' = Suc (SA ! i')"
        "i' < j'"
        "i < j'"
        by blast
      moreover
      have "SA[k := j] ! i' = SA ! i'"
        using `k  i'` by simp
      moreover
      have "SA[k := j] ! j' = SA ! j'"
        using `k < i'` `i' < j'`
        by auto
      ultimately show ?goal
        using assms(16) by auto
    qed
    ultimately show ?goal
      by blast
  qed
  ultimately show ?goal
    by blast
qed

corollary s_pred_inv_maintained_perm_step:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
  and     "k = B ! b - Suc 0"
shows "s_pred_inv α T (B[b := k]) (SA[k := j]) n"
  using s_pred_inv_maintained_step[OF s_perm_inv_elims[OF assms(1)] assms(2-)]
  by blast

subsubsection "Successor"

lemma s_suc_inv_established:
  assumes "length SA = length T"
  and     "length T  n"
shows "s_suc_inv α T B SA n"
  unfolding s_suc_inv_def
  using assms(1) assms(2) by linarith

lemma s_suc_inv_maintained_step_c1:
  assumes "length SA  Suc n"
shows "s_suc_inv α T B SA n"
  unfolding s_suc_inv_def
proof (intro allI impI; elim conjE)
  fix i' j
  assume "i' < length SA" "n < i'" "SA ! i' = Suc j" "suffix_type T j = S_type"
  with assms
  have False
    using less_trans_Suc not_less by blast
  then show "k. in_s_current_bucket α T B (α (T ! j)) k  SA ! k = j  k < i'"
    by blast
qed

corollary s_suc_inv_maintained_perm_step_c1:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "length SA  Suc n"
shows "s_suc_inv α T B SA n"
  by (simp add: assms(3) s_suc_inv_maintained_step_c1)

lemma s_suc_inv_maintained_step_c1_alt:
  assumes "s_suc_inv α T B SA i"
  and     "s_bucket_ptr_inv α T B"
  and     "s_locations_inv α T B SA"
  and     "strict_mono α"
  and     "α (Max (set T)) < length B"
  and     "valid_list T"
  and     "α bot = 0"
  and     "i = Suc n"
  and     "length T  SA ! Suc n"
  shows "s_suc_inv α T B SA n"
proof (cases "length SA  Suc n")
  case True
  then show ?thesis
    by (simp add: s_suc_inv_maintained_step_c1)
next
  case False
  hence "Suc n < length SA"
    by simp
  show ?thesis
    unfolding s_suc_inv_def
  proof (intro allI impI; elim conjE)
    fix i' j
    let ?goal = "k. in_s_current_bucket α T B (α (T ! j)) k  SA ! k = j  k < i'"
    assume "i' < length SA" "n < i'" "SA ! i' = Suc j" "suffix_type T j = S_type"
    hence "i' = Suc n  Suc n < i'"
      using Suc_lessI by blast
    moreover
    from s_suc_invD[OF assms(1) i' < length SA _ SA ! i' = Suc j suffix_type T j = S_type]
    have "Suc n < i'  ?goal"
      using i = Suc n by blast
    moreover
    have "i' = Suc n  ?goal"
    proof -
      assume "i' = Suc n"
      have "j < length T  length T  j"
        using linorder_not_le by blast
      moreover
      have "length T  j  ?goal"
        by (meson suffix_type T j = S_type linorder_not_le suffix_type_s_bound)
      moreover
      have "j < length T  ?goal"
      proof -
        assume "j < length T"
        hence "length T = Suc j"
          using SA ! i' = Suc j i' = Suc n length T  SA ! Suc n by force
        hence "T ! j = bot"
          by (metis valid_list T diff_Suc_1 last_conv_nth length_greater_0_conv valid_list_def)
        hence "α (T ! j) = 0"
          using α bot = 0 by presburger
        hence "in_s_current_bucket α T B (α (T ! j)) 0"
          unfolding in_s_current_bucket_def
          using One_nat_def assms(2,4,6,7) lessI s_bucket_ptr_0 valid_list_bucket_end_0
          by fastforce
        moreover
        {
          have "0 < bucket_end α T 0"
            using α (T ! j) = 0 calculation in_s_current_bucket_def by fastforce
          with s_bucket_ptr_0[OF assms(2), of 0, simplified]
               s_locations_invD[OF assms(3), of 0 0, simplified]
          have "SA ! 0  s_bucket α T 0"
            by simp
          moreover
          have "s_bucket α T 0 = {j}"
            by (simp add: length T = Suc j assms(4) assms(6) assms(7) s_bucket_0)
          ultimately have "SA ! 0 = j"
            by blast
        }
        ultimately show ?goal
          using i' = Suc n by blast
      qed
      ultimately show ?goal
        by blast
    qed
    ultimately show ?goal
      by blast
  qed
qed

corollary s_suc_inv_maintained_perm_step_c1_alt:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "length T  SA ! Suc n"
shows "s_suc_inv α T B SA n"
  using assms s_perm_inv_def s_suc_inv_maintained_step_c1_alt by blast

lemma s_suc_inv_maintained_step_c2:
  assumes "s_suc_inv α T B SA i"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = 0"
shows "s_suc_inv α T B SA n"
  unfolding s_suc_inv_def
proof (intro allI impI; elim conjE)
  fix i' j
  assume "i' < length SA" "n < i'" "SA ! i' = Suc j" "suffix_type T j = S_type"

  let ?goal = "k. in_s_current_bucket α T B (α (T ! j)) k  SA ! k = j  k < i'"

  from `n < i'` `i = Suc n`
  have "i = i'  i < i'"
    by linarith
  moreover
  from assms(2,4) `SA ! i' = Suc j`
  have "i = i'  ?goal"
    by simp
  moreover
  from s_suc_invD[OF assms(1) `i' < _` _ `SA ! i' = _` `suffix_type T j = _`] assms(2)
  have "i < i'  ?goal"
    by blast
  ultimately show ?goal
    by blast
qed

corollary s_suc_inv_maintained_perm_step_c2:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = 0"
shows "s_suc_inv α T B SA n"
  using assms s_perm_inv_elims(7) s_suc_inv_maintained_step_c2 by blast

lemma s_suc_inv_maintained_step_c3:
  assumes "s_suc_inv α T B SA i"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = L_type"
shows "s_suc_inv α T B SA n"
  unfolding s_suc_inv_def
proof (intro allI impI; elim conjE)
  fix i' j'
  assume "i' < length SA" "n < i'" "SA ! i' = Suc j'" "suffix_type T j' = S_type"

  let ?goal = "k. in_s_current_bucket α T B (α (T ! j')) k  SA ! k = j'  k < i'"

  from `n < i'` assms(2)
  have "i = i'  i < i'"
    using Suc_lessI by blast
  moreover
  from assms(2,4,5) `SA ! i' = _` `suffix_type T j' = _`
  have "i = i'  ?goal"
    by simp
  moreover
  from s_suc_invD[OF assms(1) `i' < _` _ `SA ! i' = _` `suffix_type T j' = _`]
  have "i < i'  ?goal"
    by blast
  ultimately show ?goal
    by blast
qed

corollary s_suc_inv_maintained_perm_step_c3:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = L_type"
shows "s_suc_inv α T B SA n"
  using assms s_perm_inv_elims(7) s_suc_inv_maintained_step_c3 by blast

lemma s_suc_inv_maintained_step_c4:
  assumes "s_distinct_inv α T B SA"
  and     "s_bucket_ptr_inv α T B"
  and     "s_locations_inv α T B SA"
  and     "s_unchanged_inv α T B SA0 SA"
  and     "s_seen_inv α T B SA i"
  and     "s_pred_inv α T B SA i"
  and     "s_suc_inv α T B SA i"
  and     "strict_mono α"
  and     "α (Max (set T)) < length B"
  and     "length SA0 = length T"
  and     "length SA = length T"
  and     "l_types_init α T SA0"
  and     "valid_list T"
  and     "α bot = 0"
  and     "Suc 0 < length T"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
  and     "k = B ! b - Suc 0"
shows "s_suc_inv α T (B[b := k]) (SA[k := j]) n"
  unfolding s_suc_inv_def
proof(safe)
  fix i' j'
  assume "i' < length (SA[k := j])" "n < i'" "SA[k := j] ! i' = Suc j'" "suffix_type T j' = S_type"
  hence "i' < length SA"
    by simp

  let ?b = "α (T ! j')"
  and ?B = "B[b := k]"
  and ?SA = "SA[k := j]"

  let ?goal = "k'. in_s_current_bucket α T ?B ?b k'  ?SA ! k' = j'  k' < i'"

  from `suffix_type T j' = _`
  have "j' < length T"
    by (simp add: suffix_type_s_bound)
  hence "?b  α (Max (set T))"
    using `strict_mono _`
    by (simp add: strict_mono_less_eq)

  from s_bucket_ptr_strict_lower_bound[OF assms(1-6,8,10-14,16-20)]
  have "s_bucket_start α T b < B ! b".
  hence "s_bucket_start α T b  k"
    using assms(21) by linarith
  hence "bucket_start α T b  k"
    using bucket_start_le_s_bucket_start le_trans by blast

  from `s_bucket_start α T b < B ! b`
  have "k < B ! b"
    using assms(21) by linarith

  have "j < length T"
    by (simp add: assms(19) suffix_type_s_bound)
  hence "b  α (Max (set T))"
    by (simp add: assms(8,20) strict_mono_less_eq)
  with s_bucket_ptr_upper_bound[OF assms(2)]
  have "B ! b  bucket_end α T b"
    by blast
  with `k < B ! b`
  have "k < bucket_end α T b"
    by linarith

  have "B ! b  i"
  proof(rule ccontr)
    assume "¬B ! b  i"
    hence "i < B ! b"
      by simp
    with s_B_val[OF assms(1-6,8,10-13,15) `b  α (Max (set T))`] `s_bucket_start α T b < B ! b`
    show False
      by simp
  qed
  with `k < B ! b`
  have "k < i"
    by linarith
  hence "k  n"
    by (simp add: assms(16))
  with `n < i'`
  have "k < i'"
    using dual_order.strict_trans2 by blast
  hence "SA[k := j] ! i' = SA ! i'"
    by simp
  with `SA[k := j] ! i' = Suc j'`
  have "SA ! i' = Suc j'"
    by simp

  have "i  i'"
    by (simp add: Suc_leI n < i' assms(16))
  hence "i = i'  i < i'"
    by (simp add: nat_less_le)
  moreover
  have "i = i'  ?goal"
  proof -
    assume "i = i'"
    hence "j = j'"
      using SA ! i' = Suc j' assms(16,18) by auto
    hence "SA[k := j] ! k = j'"
      using k  n assms(17) by auto
    moreover
    have "?b = b"
      using j = j' assms(20) by blast
    hence "in_s_current_bucket α T ?B ?b k = in_s_current_bucket α T ?B b k"
      by simp
    moreover
    from `α (T ! j')  α (Max (set T))`
         `?b = b`[symmetric]
    have "in_s_current_bucket α T ?B b k"
      unfolding in_s_current_bucket_def
      using k < bucket_end α T b assms(9) by auto
    ultimately show ?goal
      using `k < i'` by blast
  qed
  moreover
  have "i < i'  ?goal"
  proof -
    assume "i < i'"
    with s_suc_invD[OF assms(7) `i' < length SA` _ `SA ! i' = Suc j'` `suffix_type T j' = _`]
    obtain k' where
      "in_s_current_bucket α T B ?b k'"
      "SA ! k' = j'"
      "k' < i'"
      by blast
    moreover
    from in_s_current_bucketD[OF `in_s_current_bucket α T B ?b k'`]
    have "in_s_current_bucket α T ?B ?b k'"
      unfolding in_s_current_bucket_def
    proof (safe)
      show "?B ! ?b  k'"
        by (metis B ! ?b  k' k < B ! b dual_order.trans list_update_beyond nat_le_linear
              not_less nth_list_update_eq nth_list_update_neq)
    qed
    moreover
    from in_s_current_bucketD(2)[OF `in_s_current_bucket α T B ?b k'`]
    have "B ! ?b  k'" .
    hence "s_bucket_start α T ?b  k'"
      by (meson ?b  α (Max (set T)) assms(2) le_less_trans not_le s_bucket_ptr_inv_def)
    hence "bucket_start α T ?b  k'"
      using bucket_start_le_s_bucket_start dual_order.trans by blast

    have "b = ?b  b  ?b"
      by blast
    hence "k  k'"
    proof
      assume "b = ?b"
      with `B ! ?b  k'` `k < B ! b`
      show ?thesis
        by simp
    next
      assume "b  ?b"
      with outside_another_bucket[OF _  `bucket_start _ _ _  k` `k < bucket_end _ _ _`]
           `bucket_start α T ?b  k'` in_s_current_bucketD(3)[OF `in_s_current_bucket α T B ?b k'`]
      show ?thesis
        by blast
    qed
    hence "SA[k := j] ! k' = SA ! k'"
      by simp
    ultimately show ?goal
      by blast
  qed
  ultimately show ?goal
    by blast
qed

corollary s_suc_inv_maintained_perm_step_c4:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
  and     "k = B ! b - Suc 0"
shows "s_suc_inv α T (B[b := k]) (SA[k := j]) n"
  using s_suc_inv_maintained_step_c4[OF s_perm_inv_elims[OF assms(1)] assms(2-)]
  by blast

lemmas s_suc_inv_maintained_perm_step =
  s_suc_inv_maintained_step_c1
  s_suc_inv_maintained_perm_step_c2
  s_suc_inv_maintained_perm_step_c3
  s_suc_inv_maintained_perm_step_c4

subsubsection "Combined Permutation Invariant"

lemma s_perm_inv_established:
  assumes "s_bucket_init α T B"
  and     "s_type_init T SA"
  and     "strict_mono α"
  and     "α (Max (set T)) < length B"
  and     "length SA = length T"
  and     "l_types_init α T SA"
  and     "valid_list T"
  and     "α bot = 0"
  and     "Suc 0 < length T"
  and     "length T  n"
shows "s_perm_inv α T B SA SA n"
  unfolding s_perm_inv_def
  by (simp add: assms s_distinct_inv_established s_bucket_ptr_inv_established
                s_locations_inv_established s_unchanged_inv_established s_seen_inv_established
                s_pred_inv_established s_suc_inv_established)

lemma s_perm_inv_maintained_step_c1:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "length SA  Suc n"
shows "s_perm_inv α T B SA0 SA n"
  unfolding s_perm_inv_def
  by (clarsimp simp: s_perm_inv_elims[OF assms(1)]
                     s_seen_inv_maintained_perm_step_c1[OF assms]
                     s_pred_inv_maintained_perm_step_alt[OF assms(1,2)]
                     s_suc_inv_maintained_step_c1[OF assms(3)])

lemma s_perm_inv_maintained_step_c1_alt:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "length T  SA ! Suc n"
shows "s_perm_inv α T B SA0 SA n"
proof (cases "length T  Suc n")
  case True
  then show ?thesis
    by (metis assms(1) assms(2) s_perm_inv_elims(11) s_perm_inv_maintained_step_c1)
next
  case False
  hence "Suc n < length T"
    by simp
  then show ?thesis
    unfolding s_perm_inv_def
    by (metis assms s_perm_inv_def s_pred_inv_maintained_step_alt
              s_seen_inv_maintained_perm_step_c1_alt s_suc_inv_maintained_perm_step_c1_alt)
qed

lemma s_perm_inv_maintained_step_c2:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = 0"
shows "s_perm_inv α T B SA0 SA n"
  unfolding s_perm_inv_def
  by (clarsimp simp: s_perm_inv_elims[OF assms(1)]
                     s_seen_inv_maintained_perm_step_c2[OF assms]
                     s_pred_inv_maintained_perm_step_alt[OF assms(1,2)]
                     s_suc_inv_maintained_perm_step_c2[OF assms])

lemma s_perm_inv_maintained_step_c3:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = L_type"
shows "s_perm_inv α T B SA0 SA n"
  unfolding s_perm_inv_def
  by (clarsimp simp: s_perm_inv_elims[OF assms(1)]
                     s_seen_inv_maintained_perm_step_c3[OF assms]
                     s_pred_inv_maintained_perm_step_alt[OF assms(1,2)]
                     s_suc_inv_maintained_perm_step_c3[OF assms])

lemma s_perm_inv_maintained_step_c4:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
  and     "k = B ! b - Suc 0"
shows "s_perm_inv α T (B[b := k]) SA0 (SA[k := j]) n"
  unfolding s_perm_inv_def
  by (clarsimp simp: s_perm_inv_elims[OF assms(1)]
                     s_distinct_inv_maintained_perm_step[OF assms]
                     s_bucket_ptr_inv_maintained_perm_step[OF assms]
                     s_locations_inv_maintained_perm_step[OF assms]
                     s_unchanged_inv_maintained_perm_step[OF assms]
                     s_seen_inv_maintained_perm_step_c4[OF assms]
                     s_pred_inv_maintained_perm_step[OF assms]
                     s_suc_inv_maintained_perm_step_c4[OF assms])

theorem abs_induce_s_perm_step:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "abs_induce_s_step (B, SA, i) (α, T) = (B', SA', i')"
shows "s_perm_inv α T B' SA0 SA' i'"
proof (cases i)
  case 0
  then show ?thesis
    using assms by force
next
  case (Suc n)
  assume "i = Suc n"
  have "T  []"
    using s_perm_inv_elims(15)[OF assms(1)] by fastforce
  show ?thesis
  proof (cases "Suc n < length SA  SA ! Suc n < length T")
    assume "Suc n < length SA  SA ! Suc n < length T"
    hence "Suc n < length SA" "SA ! Suc n < length T"
      by blast+
    show ?thesis
    proof (cases "SA ! Suc n")
      case 0
      then show ?thesis
        using s_perm_inv_maintained_step_c2[OF assms(1) i = Suc n Suc n < length SA "0"] assms
        by (clarsimp simp: i = Suc n Suc n < length SA "0" T  [])
    next
      case (Suc j)
      assume "SA ! Suc n = Suc j"
      hence "Suc j < length T"
        using SA ! Suc n < length T by auto
      show ?thesis
      proof (cases "suffix_type T j")
        case S_type
        then show ?thesis
          using assms i = Suc n Suc n < length SA SA ! Suc n = Suc j
                s_perm_inv_maintained_step_c4[OF assms(1), of n j "α (T ! j)" "B ! α (T ! j) - Suc 0"]
          by (clarsimp simp: Let_def Suc j < length T)
      next
        case L_type
        then show ?thesis
          using assms i = Suc n Suc n < length SA SA ! Suc n = Suc j
                s_perm_inv_maintained_step_c3[OF assms(1)]
          by (clarsimp simp: Let_def Suc j < length T)
      qed
    qed
  next
    assume "¬(Suc n < length SA  SA ! Suc n < length T)" 
    hence "¬ Suc n < length SA  ¬ SA ! Suc n < length T"
      by blast
    then show ?thesis
    proof
      assume "¬ Suc n < length SA"
      then show ?thesis
        using assms i = Suc n s_perm_inv_maintained_step_c1[OF assms(1)] by force
    next
      assume "¬ SA ! Suc n < length T"
      hence "length T  SA ! Suc n"
        by simp
      then show ?thesis
        using assms i = Suc n s_perm_inv_maintained_step_c1_alt[OF assms(1)] by simp
    qed
  qed
qed

corollary abs_induce_s_perm_step_alt:
 "a. s_perm_inv_alt α T SA0 a  s_perm_inv_alt α T SA0 (abs_induce_s_step a (α, T))"
  by (metis abs_induce_s_perm_step s_perm_inv_alt.elims(2) s_perm_inv_alt.elims(3))

theorem abs_induce_s_perm_alt_maintained:
  assumes "s_perm_inv_alt α T SA0 (B, SA, length T)"
  shows "s_perm_inv_alt α T SA0 (abs_induce_s_base α T B SA)"
  unfolding abs_induce_s_base_def
  using repeat_maintain_inv[of "s_perm_inv_alt α T SA0" abs_induce_s_step "(α, T)", OF _ assms(1)]
        abs_induce_s_perm_step_alt
  by blast

corollary abs_induce_s_perm_maintained:
  assumes "abs_induce_s_base α T B SA = (B', SA', n)"
  and     "s_perm_inv α T B SA0 SA (length T)"
shows "s_perm_inv α T B' SA0 SA' n"
  using assms abs_induce_s_perm_alt_maintained by force


lemma s_perm_inv_0_B_val:
  assumes "s_perm_inv α T B SA SA' 0"
  and     "b  α (Max (set T))"
shows "B ! b = s_bucket_start α T b"
proof -
  from s_bucket_ptr_lower_bound[OF s_perm_inv_elims(2)[OF assms(1)] assms(2)]
  have "s_bucket_start α T b  B ! b" .

  have "s_bucket_start α T b  0"
    by blast
  hence "s_bucket_start α T b = 0  0 < s_bucket_start α T b"
    by blast
  with `s_bucket_start α T b  B ! b`
  have "B ! b = s_bucket_start α T b  0 < B ! b"
    by linarith
  then show ?thesis
  proof
    assume "B ! b = s_bucket_start α T b"
    then show ?thesis .
  next
    assume "0 < B ! b"
    with s_B_val[OF s_perm_inv_elims(1-6,8,10-13,15)[OF assms(1)] assms(2)]
    show ?thesis .
  qed
qed

lemma s_perm_inv_0_list_slice_bucket:
  assumes "s_perm_inv α T B SA SA' 0"
  and     "b  α (Max (set T))"
shows "set (list_slice SA' (bucket_start α T b) (bucket_end α T b)) = bucket α T b"
  by (meson assms bucket_eq_list_slice s_perm_inv_0_B_val s_perm_inv_elims(1-4,10-12))

lemma s_perm_inv_0_distinct_list_slice:
  assumes "s_perm_inv α T B SA SA' 0"
  and     "b  α (Max (set T))"
shows "distinct (list_slice SA' (bucket_start α T b) (bucket_end α T b))"
      (is "distinct ?xs")
proof -
  let ?ys = "list_slice SA' (bucket_start α T b) (l_bucket_end α T b)"
  and ?zs = "list_slice SA' (s_bucket_start α T b) (bucket_end α T b)"

  have "?xs = ?ys @ ?zs"
    by (metis list_slice_append bucket_start_le_s_bucket_start l_bucket_end_le_bucket_end
          s_bucket_start_eq_l_bucket_end)

  from l_types_initD(1)[OF l_types_init_maintained[OF s_perm_inv_elims(2,4,10-12)[OF assms(1)]]
        assms(2)]
  have "set ?ys = l_bucket α T b" .
  moreover
  from s_bucket_eq_list_slice[OF s_perm_inv_elims(1,3,11)[OF assms(1)] assms(2)
        s_perm_inv_0_B_val[OF assms]]
  have "set ?zs = s_bucket α T b" .
  ultimately have "set ?ys  set ?zs = {}"
    using disjoint_l_s_bucket by blast
  with s_distinct_invD[OF s_perm_inv_elims(1), OF assms, simplified s_perm_inv_0_B_val[OF assms]]
       l_types_initD(2)[OF l_types_init_maintained[OF s_perm_inv_elims(2,4,10-12)[OF assms(1)]]
         assms(2)]
       `?xs = ?ys @ ?zs`
  show ?thesis
    by auto
qed

lemma abs_induce_s_base_distinct:
  assumes "abs_induce_s_base α T B SA = (B', SA', n)"
  and     "s_perm_inv α T B' SA SA' n"
shows "distinct SA'"
proof(intro distinct_conv_nth[THEN iffD2] allI impI)
  fix i j
  assume "i < length SA'" "j < length SA'" "i  j"
  hence "i < length T" "j < length T"
    using assms(2) s_perm_inv_elims(11) by fastforce+

  from abs_induce_s_base_index[of α T B SA] assms(1)
  have "n = 0"
    by simp

  from index_in_bucket_interval_gen[OF `i < length T` s_perm_inv_elims(8)[OF assms(2)]]
  obtain b0 where
    "b0  α (Max (set T))"
    "bucket_start α T b0  i"
    "i < bucket_end α T b0"
    by blast

  have "bucket_end α T b0  length SA'"
    using assms(2) bucket_end_le_length s_perm_inv_elims(11) by fastforce

  let ?xs = "list_slice SA' (bucket_start α T b0) (bucket_end α T b0)"

  from index_in_bucket_interval_gen[OF `j < length T` s_perm_inv_elims(8)[OF assms(2)]]
  obtain b1 where
    "b1  α (Max (set T))"
    "bucket_start α T b1  j"
    "j < bucket_end α T b1"
    by blast

  have "bucket_end α T b1  length SA'"
    using assms(2) bucket_end_le_length s_perm_inv_elims(11) by fastforce

  have "b0  b1  SA' ! i  SA' ! j"
  proof -
    assume "b0  b1"
    hence "bucket α T b0  bucket α T b1 = {}"
      by (metis (mono_tags, lifting) Int_emptyI bucket_def mem_Collect_eq)
    moreover
    from s_perm_inv_0_list_slice_bucket[OF assms(2)[simplified `n = 0`] `b0  _`]
         list_slice_nth_mem[OF `bucket_start α T b0  i` `i < bucket_end α T b0`
           `bucket_end α T b0  _`]
    have "SA' ! i  bucket α T b0"
      by blast
    moreover
    from s_perm_inv_0_list_slice_bucket[OF assms(2)[simplified `n = 0`] `b1  _`]
         list_slice_nth_mem[OF `bucket_start α T b1  j` `j < bucket_end α T b1`
           `bucket_end α T b1  _`]
    have "SA' ! j  bucket α T b1"
      by blast
    ultimately show ?thesis
      by auto
  qed
  moreover
  have "b0 = b1  SA' ! i  SA' ! j"
  proof -
    assume "b0 = b1"
    with `bucket_start α T b1  j` `j < bucket_end α T b1`
    have "bucket_start α T b0  j" "j < bucket_end α T b0"
      by simp_all
    with list_slice_nth_eq_iff_index_eq[
          OF s_perm_inv_0_distinct_list_slice[OF assms(2)[simplified`n = 0`] `b0  _`]
            `bucket_end _ _ b0  _` `bucket_start α T b0  i` `i < bucket_end α T b0`, of j]
         `i  j`
    show ?thesis
      by blast
  qed
  ultimately show "SA' ! i  SA' ! j"
    by blast
qed

lemma abs_induce_s_base_subset_upt:
  assumes "abs_induce_s_base α T B SA = (B', SA', n)"
  and     "s_perm_inv α T B' SA SA' n"
shows "set SA'  {0..<length T}"
proof
  fix x
  assume "x  set SA'"
  from in_set_conv_nth[THEN iffD1, OF `x  set SA'`]
  obtain i where
    "i < length SA'"
    "SA' ! i = x"
    by blast
  hence "i < length T"
    using assms(2) s_perm_inv_elims(11) by fastforce
  with index_in_bucket_interval_gen[OF _ s_perm_inv_elims(8)[OF assms(2)]]
  obtain b where
    "b  α (Max (set T))"
    "bucket_start α T b  i"
    "i < bucket_end α T b"
    by blast

  from abs_induce_s_base_index[of α T B SA] assms(1)
  have "n = 0"
    by simp

  have "bucket_end α T b  length SA'"
    using assms(2) bucket_end_le_length s_perm_inv_elims(11) by fastforce
  with s_perm_inv_0_list_slice_bucket[OF assms(2)[simplified `n = 0`] `b  _`]
       `SA' ! i = x` `bucket_start α T b  i` `i < bucket_end α T b`
  have "x  bucket α T b"
    using list_slice_nth_mem by blast
  hence "x < length T"
    using bucket_def by blast
  then show "x  {0..< length T}"
    by simp
qed

corollary abs_induce_s_base_eq_upt:
  assumes "abs_induce_s_base α T B SA = (B', SA', n)"
  and     "s_perm_inv α T B' SA SA' n"
shows "set SA' = {0..<length T}"
  by (rule card_subset_eq[OF finite_atLeastLessThan abs_induce_s_base_subset_upt[OF assms]];
      clarsimp simp: distinct_card[OF abs_induce_s_base_distinct[OF assms]]
                     s_perm_inv_elims(11)[OF assms(2)])

theorem abs_induce_s_base_perm:
  assumes "abs_induce_s_base α T B SA = (B', SA', n)"
  and     "s_perm_inv α T B' SA SA' n"
shows "SA' <~~> [0..< length T]"
  by (rule perm_distinct_set_of_upt_iff[THEN iffD2];
      clarsimp simp: abs_induce_s_base_distinct[OF assms] abs_induce_s_base_eq_upt[OF assms])

subsubsection "Sorted"

lemma s_sorted_established:
  assumes "s_bucket_init α T B"
  and     "strict_mono α"
  and     "valid_list T"
  and     "α bot = 0"
  and     "b  α (Max (set T))"
shows "sorted_wrt R (list_slice SA (B ! b) (bucket_end α T b))"
      (is "sorted_wrt R ?xs")
proof -
  have "b = 0  0 < b"
    by blast
  moreover
  have "0 < b  ?thesis"
  proof -
    assume "0 < b"
    hence "B ! b = bucket_end α T b"
      by (simp add: b  α (Max (set T)) assms(1) s_bucket_initD)
    then show ?thesis 
      by simp
  qed
  moreover
  have "b = 0  ?thesis"
  proof -
    assume "b = 0"
    hence "bucket_end α T b = Suc 0"
      by (simp add: assms(2-4) valid_list_bucket_end_0)
    moreover
    from `b = 0`
    have "B ! b = 0"
      using assms(1) s_bucket_initD(2) by auto
    ultimately show ?thesis
      by (simp add: sorted_wrt01)
  qed
  ultimately show ?thesis
    by blast
qed

lemma s_sorted_inv_established:
  assumes "s_bucket_init α T B"
  and     "strict_mono α"
  and     "valid_list T"
  and     "α bot = 0"
shows "s_sorted_inv α T B SA"
  unfolding s_sorted_inv_def
  using assms ordlistns.sorted_map s_sorted_established by blast

lemma s_prefix_sorted_inv_established:
  assumes "s_bucket_init α T B"
  and     "strict_mono α"
  and     "valid_list T"
  and     "α bot = 0"
shows "s_prefix_sorted_inv α T B SA"
  unfolding s_prefix_sorted_inv_def
  using assms ordlistns.sorted_map s_sorted_established by blast

lemma s_sorted_maintained_unchanged_step:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
  and     "k = B ! b - Suc 0"
  and     "b'  α (Max (set T))"
  and     "sorted_wrt R (list_slice SA (B ! b') (bucket_end α T b'))"
  and     "b  b'"
shows "sorted_wrt R (list_slice (SA[k := j]) ((B[b := k]) ! b') (bucket_end α T b'))"
proof -
  let ?xs = "list_slice (SA[k := j]) (B[b := k] ! b') (bucket_end α T b')"

  have "bucket_end α T b  length T"
    using bucket_end_le_length by blast
  moreover
  have "B ! b  bucket_end α T b"
    using assms(1,5,6) s_bucket_ptr_upper_bound s_perm_inv_elims(2,8) strict_mono_less_eq
          suffix_type_s_bound by fastforce
  ultimately have "k < length T"
    using assms(1,7) s_perm_inv_elims(15) by fastforce
  hence "k < length SA"
    by (metis assms(1) s_perm_inv_def)

  from s_bucket_ptr_strict_lower_bound[OF s_perm_inv_elims(1-6,8,10-14)[OF assms(1)] assms(2-6)]
  have "s_bucket_start α T b < B ! b" .
  hence "k < B ! b"
    using assms(7) diff_less gr_implies_not_zero by blast

  have "s_bucket_start α T b  k"
    using assms s_bucket_ptr_strict_lower_bound s_perm_inv_def by fastforce
  hence "bucket_start α T b  k"
    using bucket_start_le_s_bucket_start le_trans by blast

  from `b  b'`
  have "B[b := k] ! b' = B ! b'"
    by simp

  have "k < B ! b'  bucket_end α T b'  k"
  proof -
    from `b  b'`
    have "b < b'  b' < b"
      using nat_neq_iff by blast
    moreover
    have "b < b'  k < B ! b'"
    proof -
      assume "b < b'"
      hence "bucket_end α T b  bucket_start α T b'"
        by (simp add: less_bucket_end_le_start)
      hence "k < bucket_start α T b'"
        using B ! b  bucket_end α T b k < B ! b by linarith
      with s_bucket_ptr_lower_bound[OF s_perm_inv_elims(2)[OF assms(1)] `b'  _`]
      show ?thesis
        by (meson bucket_start_le_s_bucket_start order.strict_trans2)
    qed
    moreover
    have "b' < b  bucket_end α T b'  k"
    proof -
      assume "b' < b"
      hence "bucket_end α T b'  bucket_start α T b"
        by (simp add: less_bucket_end_le_start)
      then show ?thesis
        using bucket_start α T b  k by linarith
    qed
    ultimately show ?thesis
      by blast
  qed
  with list_slice_update_unchanged_1
       list_slice_update_unchanged_2
  have "?xs = list_slice SA (B ! b') (bucket_end α T b')"
    using B[b := k] ! b' = B ! b' by auto
  then show ?thesis
    using assms(9) by auto
qed

lemma s_sorted_inv_maintained_step:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "s_sorted_pre α T SA0"
  and     "s_sorted_inv α T B SA"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
  and     "k = B ! b - Suc 0"
shows "s_sorted_inv α T (B[b := k]) (SA[k := j])"
  unfolding s_sorted_inv_def
proof (safe)
  fix b'
  assume "b'  α (Max (set T))"
  let ?xs = "list_slice (SA[k := j]) (B[b := k] ! b') (bucket_end α T b')"

  have "bucket_end α T b  length T"
    using bucket_end_le_length by blast

  moreover
  have "B ! b  bucket_end α T b"
    using assms(1,7,8) s_bucket_ptr_upper_bound suffix_type_s_bound
          s_perm_inv_elims(2,8) strict_mono_less_eq
    by fastforce

  ultimately have "k < length T"
    using assms(1,9) s_perm_inv_elims(15) by fastforce
  hence "k < length SA"
    by (metis assms(1) s_perm_inv_def)

  from s_bucket_ptr_strict_lower_bound
          [OF s_perm_inv_elims(1-6,8,10-14)
          [OF assms(1)] assms(4-8)]
  have "s_bucket_start α T b < B ! b" .
  hence "k < B ! b"
    using assms(9) diff_less gr_implies_not_zero by blast

  have "s_bucket_start α T b  k"
    using assms s_bucket_ptr_strict_lower_bound s_perm_inv_def 
    by fastforce
  hence "bucket_start α T b  k"
    using bucket_start_le_s_bucket_start le_trans 
    by blast
  hence "b  α (Max (set T))"
    by (metis k < length SA assms(1) bucket_end_Max dual_order.trans
              less_bucket_end_le_start s_perm_inv_elims(8,11) leD leI)

  have "b = b'  b  b'"
    by blast
  moreover
  have "b = b'  ordlistns.sorted (map (suffix T) ?xs)"
  proof -
    assume "b = b'"
    hence "B[b := k] ! b' = k"
      by (meson b'  α (Max (set T)) assms(1) le_less_trans nth_list_update_eq
            s_perm_inv_elims(9))

    have "SA[k := j] ! k = j"
      by (simp add: k < length SA)

    from list_slice_update_unchanged_1
         `k < B ! b` 
         `SA[k := j] ! k = j` 
         `B[b := k] ! b' = k` 
         `B ! b  bucket_end α T b`
         `b = b'` `k < length SA`
    have "?xs = j # list_slice SA (B ! b) (bucket_end α T b)"
      by (metis Suc_pred  assms(9) length_list_update not_le  
                less_nat_zero_code list_slice_Suc less_le_trans)
    moreover
    have "ordlistns.sorted 
            (map (suffix T) (j # list_slice SA (B ! b) (bucket_end α T b)))"
    proof -
      let ?ys = "list_slice SA (B ! b) (bucket_end α T b)"

      have A: "map (suffix T) (j # ?ys) = (suffix T j) # map (suffix T) ?ys"
        by simp

      from s_sorted_invD[OF assms(3) `b  _`]
      have B: "ordlistns.sorted (map (suffix T) ?ys)" .

      have "?ys = []  ?ys  []"
        by blast
      hence "map (suffix T) ?ys = []  map (suffix T) ?ys  []"
        by simp
      moreover
      have "map (suffix T) ?ys = []  ?thesis"
        using ordlistns.sorted_cons_nil by fastforce
      moreover
      have "map (suffix T) ?ys  [] 
             ordlistns.sorted ((suffix T j) # map (suffix T) ?ys)"
      proof (rule ordlistns.sorted_consI[OF _ B])
        assume "map (suffix T) (list_slice SA (B ! b) (bucket_end α T b))  []"
        then 
        show "map (suffix T) (list_slice SA (B ! b) (bucket_end α T b))  []"
          by simp
      next
        assume "map (suffix T) ?ys  []"
        hence "map (suffix T) ?ys ! 0 = suffix T (?ys ! 0)"
          by (metis length_greater_0_conv list.simps(8) nth_map)
        moreover
        have "list_less_eq_ns (suffix T j) (suffix T (?ys ! 0))"
        proof -
          have "?ys ! 0  s_bucket α T b"
            by (metis assms(1) length_greater_0_conv s_perm_inv_elims(3)
                      length_map nth_mem s_locations_inv_in_list_slice
                      b = b' 
                      b'  α (Max (set T))
                      map (suffix T) ?ys  [] )
          hence "α (T ! (?ys ! 0)) = b" "suffix_type T (?ys ! 0) = S_type"
            by (simp add: s_bucket_def bucket_def)+
          hence "T ! j = T ! (?ys ! 0)"
            using assms(1,8) s_perm_inv_elims(8) strict_mono_eq by fastforce

          have "?ys ! 0 = SA ! (B ! b)"
            using map (suffix T) ?ys  [] nth_list_slice by fastforce

          have "b  0"
            by (metis s_bucket_start α T b < B ! b assms(1)
                      gr_implies_not_zero s_bucket_ptr_0 s_perm_inv_elims(2))

          have "in_s_current_bucket α T B b (B ! b)"
            using b = b' b'  α (Max (set T)) map (suffix T) ?ys  []  
            by (metis B ! b  bucket_end α T b in_s_current_bucket_def
                      le_eq_less_or_eq list.map_disc_iff list_slice_n_n)
            with s_pred_invD
                  [OF s_perm_inv_elims(6)[OF assms(1)] _ `b  0`, 
                   of "B ! b"]
          obtain i' where i'_assms:
            "i' < length SA"
            "SA ! i' = Suc (SA ! (B ! b))"
            "B ! b < i'"
            "i < i'"
            by blast

          let ?b0 = "α (T ! (Suc j))"
          and ?b1 = "α (T ! (Suc (SA ! (B ! b))))"

          have i_less: "i < length SA"
            by (simp add: assms(4-5))

          have "?b0  α (Max (set T))"
            by (metis Max_greD Suc_leI assms(1,4-6) strict_mono_leD
                      s_perm_inv_elims(5,8) s_seen_invD(1) lessI)

          have "?b1  α (Max (set T))"
            by (metis Max_greD i'_assms(1,2,4) assms(1)
                  less_imp_le_nat s_perm_inv_elims(5,8) 
                  s_seen_invD(1) strict_mono_leD)

          have S0: "suffix T j = T ! j # suffix T (Suc j)"
            using assms(7) suffix_cons_Suc suffix_type_s_bound 
            by blast

          have S1: "suffix T (?ys ! 0) = 
                      T ! (?ys ! 0) # suffix T (Suc (SA ! (B ! b)))"
            using ?ys ! 0 = SA ! (B ! b) 
                  suffix_type T (?ys ! 0) = S_type suffix_cons_Suc
                  suffix_type_s_bound by auto

          have "?b0  ?b1"
          proof(rule ccontr)
            assume "¬?b0  ?b1"
            hence "?b1 < ?b0"
              by simp
            hence "bucket_end α T ?b1  bucket_start α T ?b0"
              by (simp add: less_bucket_end_le_start)
            with s_index_upper_bound[OF s_perm_inv_elims(2,5)[OF assms(1)] i'_assms(1)]
                 s_index_lower_bound[OF s_perm_inv_elims(2,5)[OF assms(1)] i_less,
                                     simplified]
                 order.strict_implies_order[OF i'_assms(4)]
            show False
              using i'_assms(2) assms(4,6) by auto
          qed
          hence "?b0 = ?b1  ?b0 < ?b1"
            by linarith
          moreover
          have "?b0 < ?b1  
                list_less_eq_ns 
                  (suffix T (Suc j)) 
                  (suffix T (Suc (SA ! (B ! b))))"
          proof -
            assume "?b0 < ?b1"
            hence "T ! (Suc j) < T ! (Suc (SA ! (B ! b)))"
              using assms(1) s_perm_inv_elims(8) strict_mono_less by blast
            then show ?thesis
              by (metis i'_assms(1,2,4) assms(1,4-6) s_perm_inv_def
                        leD  s_seen_invD(1) list_less_eq_ns_linear
                        suffix_cons_Suc list_less_eq_ns_cons)
          qed
          moreover
          have "?b0 = ?b1  
                  list_less_eq_ns 
                    (suffix T (Suc j)) 
                    (suffix T (Suc (SA ! (B ! b))))"
          proof -
            assume "?b0 = ?b1"
            with s_index_upper_bound
                   [OF s_perm_inv_elims(2,5)[OF assms(1)]
                 `i' < _`] i'_assms(4)
            have "i' < bucket_end α T ?b0"
              by (simp add: SA ! i' = Suc (SA ! (B ! b)))

            have "suffix_type T (SA ! i) = S_type  
                  suffix_type T (SA ! i) = L_type"
              using SL_types.exhaust by blast
            moreover
            have "suffix_type T (SA ! i) = S_type  ?thesis"
            proof -
              assume "suffix_type T (SA ! i) = S_type"
              with s_seen_invD(3)
                    [OF s_perm_inv_elims(5)[OF assms(1)] i_less, 
                     simplified]
              have "in_s_current_bucket α T B ?b0 i"
                by (simp add: assms(4) assms(6))
              hence "B ! ?b0  i"
                using in_s_current_bucket_def by blast
              hence "m. B ! ?b0 + m = i"
                using less_eqE by blast
              then obtain m0 where m0_assm:
                "B ! ?b0 + m0 = i"
                by blast

              from `B ! ?b0  i` i'_assms(4) 
              have "m. B ! ?b0 + m = i'"
                by presburger
              then obtain m1 where m1_assm:
                "B ! ?b0 + m1 = i'"
                by blast
              hence "B ! ?b0 + m0  B ! ?b0 + m1"
                by (simp add: m0_assm i'_assms(4) dual_order.order_iff_strict)
              hence "m0  m1"
                using add_le_imp_le_left by blast

              have "(list_slice SA (B ! ?b0) (bucket_end α T ?b0)) ! m0 = 
                    Suc j"
                using m0_assm i_less
                      in_s_current_bucket α T B ?b0 i assms(4,6) 
                      in_s_current_bucketD(3) 
                by (metis B ! α (T ! Suc j)  i diff_add_inverse list_slice_nth)
              moreover
              have "(list_slice  SA (B ! ?b0) (bucket_end α T ?b0)) ! m1 = 
                    Suc (SA ! (B ! b))"
                using m1_assm i'_assms
                       i' < bucket_end α T ?b0
                by (metis diff_add_inverse le_add1 list_slice_nth)
              moreover
              have "length (list_slice SA (B ! ?b0) (bucket_end α T ?b0)) = 
                    (bucket_end α T ?b0) - B ! ?b0"
                by (metis assms(1) bucket_end_le_length length_list_slice min_def s_perm_inv_def)
              with `B ! ?b0 + m1 = i'` 
                    `i' < bucket_end α T ?b0`
              have "m1 < length (list_slice SA (B ! ?b0) (bucket_end α T ?b0))"
                by linarith
              ultimately
              show ?thesis
                using ordlistns.sorted_nth_mono
                        [OF s_sorted_invD[OF assms(3) `?b0  α (Max _)`]
                            `m0  m1`]
                      m0  m1 
                by auto
            qed
            moreover
            have "suffix_type T (SA ! i) = L_type  ?thesis"
            proof -
              assume "suffix_type T (SA ! i) = L_type"
              with s_seen_invD(2)
                    [OF s_perm_inv_elims(5)[OF assms(1)] i_less, 
                     simplified]
              have "in_l_bucket α T ?b0 i"
                by (simp add: assms(4) assms(6))
              hence "bucket_start α T ?b0  i"
                by (simp add: in_l_bucket_def)
              hence "m. bucket_start α T ?b0 + m = i"
                using less_eqE by blast
              then obtain m0 where start_plus_m0_eq:
                "bucket_start α T ?b0 + m0 = i"
                by blast

              have "suffix_type T (SA ! i') = L_type  
                    suffix_type T (SA ! i') = S_type"
                using SL_types.exhaust by blast
              moreover
              have "suffix_type T (SA ! i') = S_type  ?thesis"
              proof -
                assume "suffix_type T (SA ! i') = S_type"

                have "SA ! i < length T"
                  by (meson i < length SA assms(1) order_refl s_perm_inv_elims(5) s_seen_invD(1))

                have "SA ! i' < length T"
                  by (simp add: suffix_type T (SA ! i') = S_type suffix_type_s_bound)

                from `?b0 = ?b1`
                have "T ! (Suc j) = T ! Suc (SA ! (B ! b))"
                  using assms(1) s_perm_inv_def strict_mono_eq by blast
                hence "hd (suffix T (SA ! i')) = hd (suffix T (SA ! i))"
                  by (metis assms(4,6) list.sel(1) suffix_cons_Suc
                        SA ! i < length T SA ! i' < length T 
                        SA ! i' = Suc (SA ! (B ! b)))
                with l_less_than_s_type
                      [OF s_perm_inv_elims(13)[OF assms(1)] 
                          `SA ! i' < length T`
                          `SA ! i < length T` _ 
                          `suffix_type T (SA ! i') = _`
                          `suffix_type T (SA ! i) = _`]
                have "list_less_ns (suffix T (SA ! i)) (suffix T (SA ! i'))".
                then show ?thesis
                  by (simp add: SA ! i' = Suc (SA ! (B ! b)) assms(4,6))
              qed
              moreover
              have "suffix_type T (SA ! i') = L_type  ?thesis"
              proof -
                assume "suffix_type T (SA ! i') = L_type"
                with s_seen_invD(2)
                      [OF s_perm_inv_elims(5)[OF assms(1)] 
                          `i' < length SA`,
                       simplified 
                         `?b0 = ?b1`[symmetric]
                         `SA ! i' = Suc (SA ! (B ! b))`]
                         `SA ! i' = Suc (SA ! (B ! b))`
                have "in_l_bucket α T ?b0 i'"
                  by (simp add: i < i' dual_order.order_iff_strict)
                hence i'_le_end: "i' < l_bucket_end α T ?b0"
                  by (simp add: in_l_bucket_def)
                hence "m. bucket_start α T ?b0 + m = i'"
                  by (metis in_l_bucket α T ?b0 i' in_l_bucket_def less_eqE)
                then obtain m1 where start_plus_m1_eq:
                  "bucket_start α T ?b0 + m1 = i'"
                  by blast

                let ?zs = 
                    "list_slice SA 
                      (bucket_start α T ?b0) 
                      (l_bucket_end α T ?b0)"

                have "?zs ! m0 = Suc j" 
                  by (metis bucket_start α T (α (T ! Suc j))  i 
                            assms(4,6)  i'_assms(4) i'_le_end 
                            diff_add_inverse dual_order.order_iff_strict
                            i_less list_slice_nth order.strict_trans1 
                            start_plus_m0_eq)
                moreover
                have "?zs ! m1 = Suc (SA ! (B ! b))"
                  using list_slice_nth dual_order.order_iff_strict i'_assms(4)
                        le_trans [OF bucket_start α T (α (T ! Suc j))  i]
                        SA ! i' = Suc (SA ! (B ! b)) 
                        bucket_start α T ?b0 + m1 = i'
                        i' < l_bucket_end α T ?b0 
                        i' < length SA 
                  by (metis diff_add_inverse)             
                moreover
                have "m0  m1"
                  using start_plus_m0_eq start_plus_m1_eq i'_assms(4)
                  by linarith
                moreover
                have "length ?zs = l_bucket_end α T ?b0 - bucket_start α T ?b0"
                  by (metis ?b0  α (Max (set T)) assms(1)
                            add_diff_cancel_left' distinct_card
                            l_bucket_end_def l_bucket_size_def 
                            l_types_init_def s_perm_inv_def
                            l_types_init_maintained)
                hence "m1 < length ?zs"
                  using start_plus_m1_eq i'_le_end by linarith
                moreover
                from s_sorted_pre_maintained
                      [OF s_perm_inv_elims(2,4,10,11)[OF assms(1)] 
                          assms(2)]
                have "s_sorted_pre α T SA" .
                ultimately show ?thesis
                  using ordlistns.sorted_nth_mono
                        [OF s_sorted_preD
                            [of α T SA,
                             OF _ `?b0  α (Max _)`], 
                        of m0 m1]
                  by (simp add: m1 < length ?zs le_less_trans
                                s_sorted_pre α T SA)
              qed
              ultimately show ?thesis
                by blast
            qed
            ultimately show ?thesis
              by blast
          qed
          ultimately 
          have "list_less_eq_ns 
                  (suffix T (Suc j)) 
                  (suffix T (Suc (SA ! (B ! b))))"
            by blast
          with S0 S1 `T ! j = T ! (?ys ! 0)`
          show ?thesis
            by (simp add: list_less_eq_ns_cons)
        qed
        ultimately 
        show "list_less_eq_ns (suffix T j) (map (suffix T) ?ys ! 0)"
          by simp
      qed
      ultimately show ?thesis
        using A by fastforce
    qed
    ultimately show ?thesis
      by simp
  qed
  moreover
  have "b  b'  ordlistns.sorted (map (suffix T) ?xs)"
  proof -
    assume "b  b'"
    with s_sorted_maintained_unchanged_step[OF assms(1,4-) `b'  _`]
         s_sorted_invD[OF assms(3) `b'  _`]
    show ?thesis
      using ordlistns.sorted_map by blast
  qed
  ultimately show "ordlistns.sorted (map (suffix T) ?xs)"
    by blast
qed

lemma s_prefix_sorted_inv_maintained_step:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "s_prefix_sorted_pre α T SA0"
  and     "s_prefix_sorted_inv α T B SA"
  and     "i = Suc n"
  and     "Suc n < length SA"
  and     "SA ! Suc n = Suc j"
  and     "suffix_type T j = S_type"
  and     "b = α (T ! j)"
  and     "k = B ! b - Suc 0"
shows "s_prefix_sorted_inv α T (B[b := k]) (SA[k := j])"
  unfolding s_prefix_sorted_inv_def
proof (safe)
  fix b'
  assume "b'  α (Max (set T))"
  let ?xs = "list_slice (SA[k := j]) (B[b := k] ! b') (bucket_end α T b')"

  have "bucket_end α T b  length T"
    using bucket_end_le_length by blast
  moreover
  have "B ! b  bucket_end α T b"
    using assms(1,7,8) s_bucket_ptr_upper_bound s_perm_inv_elims(2,8) strict_mono_less_eq
          suffix_type_s_bound by fastforce

  ultimately have "k < length T"
    using assms(1,9) s_perm_inv_elims(15) by fastforce
  hence "k < length SA"
    by (metis assms(1) s_perm_inv_def)

  from s_bucket_ptr_strict_lower_bound
        [OF s_perm_inv_elims(1-6,8,10-14)[OF assms(1)] assms(4-8)]
  have "s_bucket_start α T b < B ! b" .
  hence "k < B ! b"
    using assms(9) diff_less gr_implies_not_zero by blast

  have "s_bucket_start α T b  k"
    using assms s_bucket_ptr_strict_lower_bound s_perm_inv_def by fastforce
  hence "bucket_start α T b  k"
    using bucket_start_le_s_bucket_start le_trans by blast
  hence "b  α (Max (set T))"
    by (metis k < length SA assms(1) bucket_end_Max dual_order.trans 
              leD leI  s_perm_inv_elims(8,11) less_bucket_end_le_start)

  have "b = b'  b  b'"
    by blast
  moreover
  have "b = b'  ordlistns.sorted (map (lms_slice T) ?xs)"
  proof -
    assume "b = b'"
    hence "B[b := k] ! b' = k"
      by (meson b'  α (Max (set T)) assms(1) le_less_trans 
                nth_list_update_eq s_perm_inv_elims(9))

    have "SA[k := j] ! k = j"
      by (simp add: k < length SA)

    from list_slice_update_unchanged_1[OF `k < B ! b`]
         `k < B ! b` `SA[k := j] ! k = j` `B[b := k] ! b' = k` 
         `B ! b  bucket_end α T b`
         `b = b'` `k < length SA`
    have "?xs = j # list_slice SA (B ! b) (bucket_end α T b)"
      by (metis Suc_pred assms(9) length_list_update not_le
                less_nat_zero_code list_slice_Suc less_le_trans)
    moreover
    have "ordlistns.sorted 
              (map (lms_slice T)
                   (j # list_slice SA (B ! b) 
                   (bucket_end α T b)))"
    proof -
      let ?ys = "list_slice SA (B ! b) (bucket_end α T b)"

      have A: "map (lms_slice T) (j # ?ys) = (lms_slice T j) # map (lms_slice T) ?ys"
        by simp

      from s_prefix_sorted_invD[OF assms(3) `b  _`]
      have B: "ordlistns.sorted (map (lms_slice T) ?ys)" .

      have "?ys = []  ?ys  []"
        by blast
      hence "map (lms_slice T) ?ys = []  map (lms_slice T) ?ys  []"
        by simp
      moreover
      have "map (lms_slice T) ?ys = []  ?thesis"
        using ordlistns.sorted_cons_nil by fastforce
      moreover
      have "map (lms_slice T) ?ys  [] 
            ordlistns.sorted ((lms_slice T j) # map (lms_slice T) ?ys)"
      proof (rule ordlistns.sorted_consI[OF _ B])
        assume "map (lms_slice T) ?ys  []"
        hence "map (lms_slice T) ?ys ! 0 = lms_slice T (?ys ! 0)"
          by (metis length_greater_0_conv list.simps(8) nth_map)
        moreover
        have "list_less_eq_ns (lms_slice T j) (lms_slice T (?ys ! 0))"
        proof -
          have "?ys ! 0  s_bucket α T b"
            by (metis b = b' b'  α (Max (set T)) map (lms_slice T) ?ys  [] assms(1)
                      length_greater_0_conv length_map nth_mem s_locations_inv_in_list_slice
                      s_perm_inv_elims(3))
          hence "α (T ! (?ys ! 0)) = b" "suffix_type T (?ys ! 0) = S_type"
            by (simp add: s_bucket_def bucket_def)+
          hence "T ! j = T ! (?ys ! 0)"
            using assms(1,8) s_perm_inv_elims(8) strict_mono_eq by fastforce

          have "?ys ! 0 = SA ! (B ! b)"
            using map (lms_slice T) ?ys  [] nth_list_slice by fastforce

          have "b  0"
            by (metis s_bucket_start α T b < B ! b assms(1)
                  gr_implies_not_zero s_bucket_ptr_0 s_perm_inv_elims(2))

          have "in_s_current_bucket α T B b (B ! b)"
            using b = b' b'  α (Max (set T)) 
                  map (lms_slice T) ?ys  []
                  in_s_current_bucket_def 
            by (metis B ! b  bucket_end α T b 
                      dual_order.order_iff_strict list.map_disc_iff 
                      list_slice_n_n)
            with s_pred_invD
                    [OF s_perm_inv_elims(6)[OF assms(1)] _ `b  0`, 
                     of "B ! b"]
          obtain i' where
            "i' < length SA"
            "SA ! i' = Suc (SA ! (B ! b))"
            "B ! b < i'"
            "i < i'"
            by blast

          let ?b0 = "α (T ! (Suc j))"
          and ?b1 = "α (T ! (Suc (SA ! (B ! b))))"

          have "i < length SA"
            by (simp add: assms(4-5))

          have "?b0  α (Max (set T))"
            by (metis Max_greD Suc_leI assms(1,4-6) lessI s_perm_inv_elims(5,8) s_seen_invD(1)
                  strict_mono_leD)

          have "?b1  α (Max (set T))"
            by (metis Max_greD SA ! i' = Suc (SA ! (B ! b)) i < i' i' < length SA assms(1)
                  less_imp_le_nat s_perm_inv_elims(5) s_perm_inv_elims(8) s_seen_invD(1)
                  strict_mono_leD)

          have S0: "lms_slice T j = T ! j # lms_slice T (Suc j)"
            using assms(7) lms_slice_cons suffix_type_s_bound by blast

          have S1:
            "lms_slice T (?ys ! 0) = T ! (?ys ! 0) # lms_slice T (Suc (SA ! (B ! b)))"
            using ?ys ! 0 = SA ! (B ! b) suffix_type T (?ys ! 0) = S_type lms_slice_cons
                  suffix_type_s_bound by auto

          have "?b0  ?b1"
          proof(rule ccontr)
            assume "¬?b0  ?b1"
            hence "?b1 < ?b0"
              by simp
            hence "bucket_end α T ?b1  bucket_start α T ?b0"
              by (simp add: less_bucket_end_le_start)
            with s_index_upper_bound[OF s_perm_inv_elims(2,5)[OF assms(1)] `i' < length SA`]
                 s_index_lower_bound[OF s_perm_inv_elims(2,5)[OF assms(1)] `i < length SA`,
                   simplified]
                 order.strict_implies_order[OF `i < i'`]
            show False
              using SA ! i' = Suc (SA ! (B ! b)) assms(4,6) by auto
          qed
          hence "?b0 = ?b1  ?b0 < ?b1"
            by linarith
          moreover
          have
            "?b0 < ?b1 
             list_less_eq_ns (lms_slice T (Suc j)) (lms_slice T (Suc (SA ! (B ! b))))"
          proof -
            assume "?b0 < ?b1"
            hence "T ! (Suc j) < T ! (Suc (SA ! (B ! b)))"
              using assms(1) s_perm_inv_elims(8) strict_mono_less by blast
            moreover
            have "Suc j < length T"
              using i < length SA assms(1,4,6) s_perm_inv_elims(5) s_seen_invD(1) by fastforce
            hence "as. lms_slice T (Suc j) = T ! (Suc j) # as"
              by (metis dual_order.strict_trans abs_find_next_lms_lower_bound_1 lessI list_slice_Suc
                        lms_slice_def)
            then obtain as where
              "lms_slice T (Suc j) = T ! (Suc j) # as"
              by blast
            moreover
            have "Suc (SA ! (B ! b)) < length T"
              using SA ! i' = Suc (SA ! (B ! b)) i < i' i' < length SA assms(1)
                    s_perm_inv_elims(5) s_seen_invD(1) by fastforce
            hence "bs. lms_slice T (Suc (SA ! (B ! b))) = T ! (Suc (SA ! (B ! b))) # bs"
              by (metis abs_find_next_lms_lower_bound_1 less_Suc_eq 
                        list_slice_Suc lms_slice_def)
            then obtain bs where
              "lms_slice T (Suc (SA ! (B ! b))) = T ! (Suc (SA ! (B ! b))) # bs"
              by blast
            ultimately show ?thesis
              using list_less_eq_ns_cons by fastforce
          qed
          moreover
          have
            "?b0 = ?b1 
             list_less_eq_ns (lms_slice T (Suc j)) (lms_slice T (Suc (SA ! (B ! b))))"
          proof -
            assume "?b0 = ?b1"
            with s_index_upper_bound[OF s_perm_inv_elims(2,5)[OF assms(1)] `i' < _`] `i < i'`
            have "i' < bucket_end α T ?b0"
              by (simp add: SA ! i' = Suc (SA ! (B ! b)))

            have "suffix_type T (SA ! i) = S_type  suffix_type T (SA ! i) = L_type"
              using SL_types.exhaust by blast
            moreover
            have "suffix_type T (SA ! i) = S_type  ?thesis"
            proof -
              assume "suffix_type T (SA ! i) = S_type"
              with s_seen_invD(3)[OF s_perm_inv_elims(5)[OF assms(1)] `i < length SA`, simplified]
              have "in_s_current_bucket α T B ?b0 i"
                by (simp add: assms(4) assms(6))
              hence "B ! ?b0  i"
                using in_s_current_bucket_def by blast
              hence "m. B ! ?b0 + m = i"
                using less_eqE by blast
              then obtain m0 where
                "B ! ?b0 + m0 = i"
                by blast

              from `B ! ?b0  i` `i < i'`
              have "m. B ! ?b0 + m = i'"
                by presburger
              then obtain m1 where
                "B ! ?b0 + m1 = i'"
                by blast
              hence "B ! ?b0 + m0  B ! ?b0 + m1"
                by (simp add: B ! α (T ! Suc j) + m0 = i 
                    i < i' dual_order.order_iff_strict)
              hence "m0  m1"
                using add_le_imp_le_left by blast

              have "(list_slice SA (B ! ?b0) (bucket_end α T ?b0)) ! m0 = Suc j"
                using B ! α (T ! Suc j) + m0 = i i < length SA
                      in_s_current_bucket α T B ?b0 i assms(4,6) 
                      in_s_current_bucketD(3)
                by (metis B ! α (T ! Suc j)  i diff_add_inverse list_slice_nth)
              moreover
              have "(list_slice SA (B ! ?b0) (bucket_end α T ?b0)) ! m1 = Suc (SA ! (B ! b))"
                using B ! ?b0 + m1 = i' SA ! i' = Suc (SA ! (B ! b)) i' < bucket_end α T ?b0
                      i' < length SA 
                by (metis diff_add_inverse le_add1 list_slice_nth)
              moreover
              have "length (list_slice SA (B ! ?b0) (bucket_end α T ?b0))
                    = (bucket_end α T ?b0) - B ! ?b0"
                by (metis assms(1) bucket_end_le_length length_list_slice min_def s_perm_inv_def)
              with `B ! ?b0 + m1 = i'` `i' < bucket_end α T ?b0`
              have "m1 < length (list_slice SA (B ! ?b0) (bucket_end α T ?b0))"
                by linarith
              ultimately
              show ?thesis
                using ordlistns.sorted_nth_mono[OF
                        s_prefix_sorted_invD[OF assms(3) `?b0  α (Max _)`] `m0  m1`]
                      m0  m1 by auto
            qed
            moreover
            have "suffix_type T (SA ! i) = L_type  ?thesis"
            proof -
              assume "suffix_type T (SA ! i) = L_type"
              with s_seen_invD(2)[OF s_perm_inv_elims(5)[OF assms(1)] `i < length SA`, simplified]
              have "in_l_bucket α T ?b0 i"
                by (simp add: assms(4) assms(6))
              hence "bucket_start α T ?b0  i"
                by (simp add: in_l_bucket_def)
              hence "m. bucket_start α T ?b0 + m = i"
                using less_eqE by blast
              then obtain m0 where
                "bucket_start α T ?b0 + m0 = i"
                by blast

              have "suffix_type T (SA ! i') = L_type  suffix_type T (SA ! i') = S_type"
                using SL_types.exhaust by blast
              moreover
              have "suffix_type T (SA ! i') = S_type  ?thesis"
              proof -
                assume "suffix_type T (SA ! i') = S_type"

                have "SA ! i < length T"
                  by (meson i < length SA assms(1) order_refl s_perm_inv_elims(5) s_seen_invD(1))

                have "SA ! i' < length T"
                  by (simp add: suffix_type T (SA ! i') = S_type suffix_type_s_bound)

                from `?b0 = ?b1`
                have "T ! (Suc j) = T ! Suc (SA ! (B ! b))"
                  using assms(1) s_perm_inv_def strict_mono_eq by blast
                hence "hd (suffix T (SA ! i')) = hd (suffix T (SA ! i))"
                  by (metis SA ! i < length T SA ! i' < length T SA ! i' = Suc (SA ! (B ! b))
                            assms(4) assms(6) list.sel(1) suffix_cons_Suc)
                hence "list_less_ns (lms_slice T (SA ! i)) (lms_slice T (SA ! i'))"
                  using SA ! i < length T SA ! i' < length T SA ! i' = Suc (SA ! (B ! b))
                        T ! Suc j = T ! Suc (SA ! (B ! b)) suffix_type T (SA ! i') = S_type
                        suffix_type T (SA ! i) = L_type assms(1,4,6) s_perm_inv_elims(13)
                        lms_slice_l_less_than_s_type by fastforce
                then show ?thesis
                  by (simp add: SA ! i' = Suc (SA ! (B ! b)) assms(4,6))
              qed
              moreover
              have "suffix_type T (SA ! i') = L_type  ?thesis"
              proof -
                assume "suffix_type T (SA ! i') = L_type"
                with s_seen_invD(2)[OF s_perm_inv_elims(5)[OF assms(1)] `i' < length SA`,
                      simplified `?b0 = ?b1`[symmetric] `SA ! i' = Suc (SA ! (B ! b))`]
                     `SA ! i' = Suc (SA ! (B ! b))`
                have "in_l_bucket α T ?b0 i'"
                  by (simp add: i < i' dual_order.order_iff_strict)
                hence "i' < l_bucket_end α T ?b0"
                  by (simp add: in_l_bucket_def)
                hence "m. bucket_start α T ?b0 + m = i'"
                  by (metis in_l_bucket α T ?b0 i' in_l_bucket_def less_eqE)
                then obtain m1 where
                  "bucket_start α T ?b0 + m1 = i'"
                  by blast

                let ?zs = "list_slice SA (bucket_start α T ?b0) (l_bucket_end α T ?b0)"

                have "?zs ! m0 = Suc j"
                  using bucket_start α T ?b0 + m0 = i i < i' i < length SA
                        i' < l_bucket_end α T ?b0 assms(4,6)
                  by (metis bucket_start α T (α (T ! Suc j))  i 
                            diff_add_inverse dual_order.order_iff_strict 
                            list_slice_nth order.strict_trans1)
                moreover
                have "?zs ! m1 = Suc (SA ! (B ! b))"
                  using SA ! i' = Suc (SA ! (B ! b)) bucket_start α T ?b0 + m1 = i'
                        i' < l_bucket_end α T ?b0 i' < length SA 
                  by (metis in_l_bucket α T (α (T ! Suc j)) i' 
                            diff_add_inverse in_l_bucket_def list_slice_nth)
                moreover
                have "m0  m1"
                  using bucket_start α T ?b0 + m0 = i bucket_start α T ?b0 + m1 = i' i < i'
                  by linarith
                moreover
                have "length ?zs = l_bucket_end α T ?b0 - bucket_start α T ?b0"
                  by (metis ?b0  α (Max (set T)) add_diff_cancel_left' assms(1) distinct_card
                        l_bucket_end_def l_bucket_size_def l_types_init_def l_types_init_maintained
                        s_perm_inv_def)
                hence "m1 < length ?zs"
                  using bucket_start α T ?b0 + m1 = i' i' < l_bucket_end α T ?b0 by linarith
                moreover
                from s_prefix_sorted_pre_maintained[OF s_perm_inv_elims(2,4,10,11)[OF assms(1)]
                      assms(2)]
                have "s_prefix_sorted_pre α T SA" .
                ultimately show ?thesis
                  using ordlistns.sorted_nth_mono[OF s_prefix_sorted_preD[of α T SA,
                          OF _ `?b0  α (Max _)`], of m0 m1]
                  by (simp add: m1 < length ?zs s_prefix_sorted_pre α T SA le_less_trans)
              qed
              ultimately show ?thesis
                by blast
            qed
            ultimately show ?thesis
              by blast
          qed
          ultimately have
            "list_less_eq_ns (lms_slice T (Suc j)) (lms_slice T (Suc (SA ! (B ! b))))"
            by blast
          with S0 S1 `T ! j = T ! (?ys ! 0)`
          show ?thesis
            by (simp add: list_less_eq_ns_cons)
        qed
        ultimately show "list_less_eq_ns (lms_slice T j) (map (lms_slice T) ?ys ! 0)"
          by simp
      qed 
      ultimately show ?thesis
        using A by fastforce
    qed
    ultimately show ?thesis
      by simp
  qed
  moreover
  have "b  b'  ordlistns.sorted (map (lms_slice T) ?xs)"
  proof -
    assume "b  b'"
    with s_sorted_maintained_unchanged_step[OF assms(1,4-) `b'  _`]
         s_prefix_sorted_invD[OF assms(3) `b'  _`]
    show ?thesis
      using ordlistns.sorted_map by blast
  qed
  ultimately show "ordlistns.sorted (map (lms_slice T) ?xs)"
    by blast
qed

theorem abs_induce_s_sorted_step:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "s_sorted_pre α T SA0"
  and     "s_sorted_inv α T B SA"
  and     "abs_induce_s_step (B, SA, i) (α, T) = (B', SA', i')"
shows " s_sorted_inv α T B' SA'"
proof (rule abs_induce_s_step.elims[OF assms(4)];
       clarsimp simp: assms(3,4) Let_def not_less
                split: if_splits SL_types.splits nat.splits[where ?nat = i] nat.splits)
  assume "B = B'" "SA' = SA"
  with assms(3)
  show "s_sorted_inv α T B' SA"
    by simp
next
  assume "B = B'" "SA' = SA"
  with assms(3)
  show "s_sorted_inv α T B' SA"
    by simp
next
  assume "B = B'" "SA' = SA"
  with assms(3)
  show "s_sorted_inv α T B' SA"
    by simp
next
  assume "B = B'" "SA' = SA"
  with assms(3)
  show "s_sorted_inv α T B' SA"
    by simp
next
  fix j

  let ?b = "α (T ! j)"
  let ?k = "B ! ?b - Suc 0"

  assume A: "i = Suc i'" "Suc i' < length SA" "SA ! Suc i' = Suc j" "suffix_type T j = S_type"
            "B' = B[?b := ?k]" "SA' = SA[?k := j]"

  from s_sorted_inv_maintained_step[OF assms(1-3) A(1-4), of ?b ?k, simplified]
  show "s_sorted_inv α T (B[?b := ?k]) (SA[?k := j])" .
qed

corollary abs_induce_s_sorted_step_alt:
 "a. s_sorted_inv_alt α T SA0 a  s_sorted_inv_alt α T SA0 (abs_induce_s_step a (α, T))"
proof -
  fix a
  assume "s_sorted_inv_alt α T SA0 a"

  have "B SA i. a = (B, SA, i)"
    by (meson prod_cases3)
  then obtain B SA i where
    "a = (B, SA, i)"
    by blast
  with `s_sorted_inv_alt α T SA0 a`
  have P: "s_perm_inv α T B SA0 SA i" "s_sorted_pre α T SA0" "s_sorted_inv α T B SA"
    by simp_all

  from abs_induce_s_step_ex[of "(B, SA, i)" "(α, T)"]
  obtain B' SA' i' where
    Q: "abs_induce_s_step (B, SA, i) (α, T) = (B', SA', i')"
    by blast

  from abs_induce_s_sorted_step[OF P Q] abs_induce_s_perm_step[OF P(1) Q] `s_sorted_pre _ _ _`
  show "s_sorted_inv_alt α T SA0 (abs_induce_s_step a (α, T))"
    using Q a = (B, SA, i) by auto
qed

theorem abs_induce_s_sorted_alt_maintained:
  assumes "s_sorted_inv_alt α T SA0 (B, SA, length T)"
  shows "s_sorted_inv_alt α T SA0 (abs_induce_s_base α T B SA)"
  unfolding abs_induce_s_base_def
  using repeat_maintain_inv
          [of "s_sorted_inv_alt α T SA0" abs_induce_s_step "(α, T)", OF _ assms(1)]
              abs_induce_s_sorted_step_alt
  by blast

corollary abs_induce_s_sorted_maintained:
  assumes "abs_induce_s_base α T B SA = (B', SA', n)"
  and     "s_perm_inv α T B SA0 SA (length T)"
  and     "s_sorted_pre α T SA0"
  and     "s_sorted_inv α T B SA"
shows "s_sorted_inv α T B' SA'"
  using assms abs_induce_s_sorted_alt_maintained by force

theorem abs_induce_s_prefix_sorted_step:
  assumes "s_perm_inv α T B SA0 SA i"
  and     "s_prefix_sorted_pre α T SA0"
  and     "s_prefix_sorted_inv α T B SA"
  and     "abs_induce_s_step (B, SA, i) (α, T) = (B', SA', i')"
shows "s_prefix_sorted_inv α T B' SA'"
proof (rule abs_induce_s_step.elims[OF assms(4)];
       clarsimp simp: assms(3,4) Let_def not_less
                split: if_splits SL_types.splits nat.splits[where ?nat = i] nat.splits)
  assume "B = B'"
  with assms(3)
  show "s_prefix_sorted_inv α T B' SA"
    by simp
next
  assume "B = B'"
  with assms(3)
  show "s_prefix_sorted_inv α T B' SA"
    by simp
next
  assume "B = B'"
  with assms(3)
  show "s_prefix_sorted_inv α T B' SA"
    by simp
next
  assume "B = B'"
  with assms(3)
  show "s_prefix_sorted_inv α T B' SA"
    by simp
next
  fix j

  let ?b = "α (T ! j)"
  let ?k = "B ! ?b - Suc 0"

  assume A: "i = Suc i'" "Suc i' < length SA" "SA ! Suc i' = Suc j" "suffix_type T j = S_type"
            "B' = B[?b := ?k]" "SA' = SA[?k := j]"

  from s_prefix_sorted_inv_maintained_step[OF assms(1-3) A(1-4), of ?b ?k, simplified]
  show "s_prefix_sorted_inv α T (B[?b := ?k]) (SA[?k := j])" .
qed

corollary abs_induce_s_prefix_sorted_step_alt:
 "a. s_prefix_sorted_inv_alt α T SA0 a 
      s_prefix_sorted_inv_alt α T SA0 (abs_induce_s_step a (α, T))"
proof -
  fix a
  assume "s_prefix_sorted_inv_alt α T SA0 a"

  have "B SA i. a = (B, SA, i)"
    by (meson prod_cases3)
  then obtain B SA i where
    "a = (B, SA, i)"
    by blast
  with `s_prefix_sorted_inv_alt α T SA0 a`
  have P: "s_perm_inv α T B SA0 SA i" "s_prefix_sorted_pre α T SA0" "s_prefix_sorted_inv α T B SA"
    by simp_all

  from abs_induce_s_step_ex[of "(B, SA, i)" "(α, T)"]
  obtain B' SA' i' where
    Q: "abs_induce_s_step (B, SA, i) (α, T) = (B', SA', i')"
    by blast

  from abs_induce_s_prefix_sorted_step[OF P Q] abs_induce_s_perm_step[OF P(1) Q] `s_prefix_sorted_pre _ _ _`
  show "s_prefix_sorted_inv_alt α T SA0 (abs_induce_s_step a (α, T))"
    using Q a = (B, SA, i) by auto
qed

theorem abs_induce_s_prefix_sorted_alt_maintained:
  assumes "s_prefix_sorted_inv_alt α T SA0 (B, SA, length T)"
  shows "s_prefix_sorted_inv_alt α T SA0 (abs_induce_s_base α T B SA)"
  unfolding abs_induce_s_base_def
  using repeat_maintain_inv[of "s_prefix_sorted_inv_alt α T SA0" abs_induce_s_step "(α, T)",
          OF _ assms(1)]
        abs_induce_s_prefix_sorted_step_alt
  by blast

corollary abs_induce_s_prefix_sorted_maintained:
  assumes "abs_induce_s_base α T B SA = (B', SA', n)"
  and     "s_perm_inv α T B SA0 SA (length T)"
  and     "s_prefix_sorted_pre α T SA0"
  and     "s_prefix_sorted_inv α T B SA"
shows "s_prefix_sorted_inv α T B' SA'"
  using assms abs_induce_s_prefix_sorted_alt_maintained by force

theorem s_sorted_bucket:
  assumes "s_perm_inv α T B SA0 SA 0"
  and     "s_sorted_pre α T SA0"
  and     "s_sorted_inv α T B SA"
  and     "b  α (Max (set T))"
shows "ordlistns.sorted (map (suffix T) (list_slice SA (bucket_start α T b) (bucket_end α T b)))"
      (is "ordlistns.sorted (map (suffix T) ?xs)")
proof -
  let ?ys = "list_slice SA (bucket_start α T b) (l_bucket_end α T b)"
  and ?zs = "list_slice SA (s_bucket_start α T b) (bucket_end α T b)"

  from s_perm_inv_0_B_val[OF assms(1,4)]
  have "B ! b = s_bucket_start α T b" .

  from s_sorted_pre_maintained[OF s_perm_inv_elims(2,4,10,11)[OF assms(1)] assms(2)]
  have "s_sorted_pre α T SA" .

  have "?xs = ?ys @ ?zs"
    by (metis bucket_start_le_s_bucket_start l_bucket_end_le_bucket_end list_slice_append
          s_bucket_start_eq_l_bucket_end)
  hence "map (suffix T) ?xs = map (suffix T) ?ys @ map (suffix T) ?zs"
    by simp
  moreover
  from s_sorted_preD[OF `s_sorted_pre _ _ SA` `b  _`]
  have "ordlistns.sorted (map (suffix T) ?ys)" .
  moreover
  from s_sorted_invD[OF assms(3,4), simplified `_ = s_bucket_start α _ _`]
  have "ordlistns.sorted (map (suffix T) ?zs)" .
  moreover
  have "y  set (map (suffix T) ?ys). z  set (map (suffix T) ?zs). list_less_eq_ns y z"
  proof(safe)
    fix y z
    assume "y  set (map (suffix T) ?ys)" "z  set (map (suffix T) ?zs)"
    with in_set_mapD[of y "suffix T" ?ys]
         in_set_mapD[of z "suffix T" ?zs]
    obtain i j where
      "y = suffix T i" "i  set ?ys" 
      "z = suffix T j" "j  set ?zs"
      by blast

    from l_types_initD(1)[OF l_types_init_maintained[OF s_perm_inv_elims(2,4,10-12)[OF assms(1)]]
          `b  _`]
         `i  set ?ys`
    have "i  l_bucket α T b"
      by blast
    hence "suffix_type T i = L_type" "α (T ! i) = b" "i < length T"
      by (simp add: l_bucket_def bucket_def)+
    moreover
    from s_bucket_eq_list_slice[OF s_perm_inv_elims(1,3,11)[OF assms(1)] `b  _`
          `B ! b = s_bucket_start α _ _`]
         `j  set ?zs`
    have "j  s_bucket α T b"
      by blast
    hence "suffix_type T j = S_type" "α (T ! j) = b" "j < length T"
      by (simp add: s_bucket_def bucket_def)+
    moreover
    have "T ! i = T ! j"
      using calculation(2,5) s_perm_inv_elims(8)[OF assms(1)] strict_mono_eq by fastforce
    ultimately have "list_less_eq_ns (suffix T i) (suffix T j)"
      using l_less_than_s_type_suffix[of j T i] by simp
    then show "list_less_eq_ns y z"
      using y = suffix T i z = suffix T j by blast
  qed
  ultimately show ?thesis
    by (simp add: ordlistns.sorted_append)
qed

theorem abs_induce_s_base_sorted:
  assumes "abs_induce_s_base α T B SA = (B', SA', n)"
  and     "s_perm_inv α T B SA0 SA (length T)"
  and     "s_sorted_pre α T SA0"
  and     "s_sorted_inv α T B SA"
shows "ordlistns.sorted (map (suffix T) SA')"
proof (intro sorted_wrt_mapI)
  fix i j
  assume "i < j" "j < length SA'"
  hence "i < length T" "j < length T"
    by (metis (no_types, lifting) abs_induce_s_perm_maintained 
              assms(1,2) order.strict_trans s_perm_inv_elims(11))+

  let ?goal = "list_less_eq_ns (suffix T (SA' ! i)) (suffix T (SA' ! j))"

  from index_in_bucket_interval_gen[OF `i < length _` s_perm_inv_elims(8)[OF assms(2)]]
  obtain b0 where
    "b0  α (Max (set T))"
    "bucket_start α T b0  i"
    "i < bucket_end α T b0"
    by blast

  from index_in_bucket_interval_gen[OF `j < length T` s_perm_inv_elims(8)[OF assms(2)]]
  obtain b1 where
    "b1  α (Max (set T))"
    "bucket_start α T b1  j"
    "j < bucket_end α T b1"
    by blast

  from abs_induce_s_perm_maintained[OF assms(1,2)]
  have "s_perm_inv α T B' SA0 SA' n" .
  moreover
  have "n = 0"
    by (metis Pair_inject assms(1) abs_induce_s_base_index)
  ultimately have "s_perm_inv α T B' SA0 SA' 0"
    by simp

  let ?xs = "list_slice SA' (bucket_start α T b0) (bucket_end α T b0)"
  and ?ys = "list_slice SA' (bucket_start α T b1) (bucket_end α T b1)"

  have "b0  b1"
  proof (rule ccontr)
    assume "¬ b0  b1"
    hence "b1 < b0"
      by (simp add: not_le)
    hence "bucket_end α T b1  bucket_start α T b0"
      by (simp add: less_bucket_end_le_start)
    with `j < bucket_end α T b1` `bucket_start α T b0  i` `i < j`
    show False
      by linarith
  qed
  hence "b0 = b1  b0 < b1"
    by (simp add: nat_less_le)
  moreover
  have "b0 < b1  ?goal"
  proof -
    assume "b0 < b1"
    moreover
    from s_perm_inv_0_list_slice_bucket[OF `s_perm_inv _ _ _ _ _ 0` `b0  α _`]
    have "set ?xs = bucket α T b0" .
    hence "SA' ! i  bucket α T b0"
      by (metis bucket_start α T b0  i i < bucket_end α T b0 s_perm_inv α T B' SA0 SA' 0
            bucket_end_le_length list_slice_nth_mem s_perm_inv_elims(11))
    hence "α (T ! (SA' ! i)) = b0" "SA' ! i < length T"
      by (simp add: bucket_def)+
    moreover
    from s_perm_inv_0_list_slice_bucket[OF `s_perm_inv _ _ _ _ _ 0` `b1  α _`]
    have "set ?ys = bucket α T b1" .
    hence "SA' ! j  bucket α T b1"
      by (metis bucket_start α T b1  j j < bucket_end α T b1 s_perm_inv α T B' SA0 SA' 0
            bucket_end_le_length list_slice_nth_mem s_perm_inv_elims(11))
    hence "α (T ! (SA' ! j)) = b1" "SA' ! j < length T"
      by (simp add: bucket_def)+
    ultimately have "T ! (SA' ! i) < T ! (SA' ! j)"
      using assms(2) s_perm_inv_elims(8) strict_mono_less by blast
    then show ?thesis
      by (metis SA' ! i < length T SA' ! j < length T less_imp_le list_less_eq_ns_cons neq_iff
            suffix_cons_Suc)
  qed
  moreover
  have "b0 = b1  ?goal"
  proof -
    assume "b0 = b1"
    with `j < bucket_end α T b1`
    have "j < bucket_end α T b0"
      by simp

    have "i'. i = bucket_start α T b0 + i'"
      using bucket_start α T b0  i nat_le_iff_add by blast
    then obtain i' where
      "i = bucket_start α T b0 + i'"
      by blast

    have "j'. j = bucket_start α T b0 + j'"
      by (simp add: b0 = b1 bucket_start α T b1  j le_Suc_ex)
    then obtain j' where
      "j = bucket_start α T b0 + j'"
      by blast
    with `i < j` `i = bucket_start α T b0 + i'`
    have "i'  j'"
      by linarith

    have "j' < length ?xs"
      by (metis b0 = b1 j < bucket_end α T b1 j = bucket_start α T b0 + j'
                s_perm_inv α T B' SA0 SA' n add.commute bucket_end_le_length length_list_slice
                less_diff_conv min_def s_perm_inv_elims(11))
    with ordlistns.sorted_nth_mono[OF s_sorted_bucket[OF `s_perm_inv _ _ _ _ _ 0` assms(3)
          abs_induce_s_sorted_maintained[OF assms] `b0  α _`] `i'  j'`]
    have "list_less_eq_ns (suffix T (?xs ! i')) (suffix T (?xs ! j'))"
      using i'  j' nth_map by auto
    moreover
    have "SA' ! i = ?xs ! i'"
      using i < bucket_end α T b0 i < length T i = bucket_start α T b0 + i'
            s_perm_inv α T B' SA0 SA' n s_perm_inv_elims(11) 
      by (metis bucket_start α T b0  i diff_add_inverse list_slice_nth)
     moreover
    have "SA' ! j = ?xs ! j'"
      using j < bucket_end α T b0 j < length SA' 
            j = bucket_start α T b0 + j' 
      by (simp add: nth_list_slice)
    ultimately show ?goal
      by simp
  qed
  ultimately show ?goal
    by blast
qed

theorem s_prefix_sorted_bucket:
  assumes "s_perm_inv α T B SA0 SA 0"
  and     "s_prefix_sorted_pre α T SA0"
  and     "s_prefix_sorted_inv α T B SA"
  and     "b  α (Max (set T))"
shows "ordlistns.sorted (map (lms_slice T) (list_slice SA (bucket_start α T b) (bucket_end α T b)))"
      (is "ordlistns.sorted (map (lms_slice T) ?xs)")
proof -
  let ?ys = "list_slice SA (bucket_start α T b) (l_bucket_end α T b)"
  and ?zs = "list_slice SA (s_bucket_start α T b) (bucket_end α T b)"

  from s_perm_inv_0_B_val[OF assms(1,4)]
  have "B ! b = s_bucket_start α T b" .

  from s_prefix_sorted_pre_maintained[OF s_perm_inv_elims(2,4,10,11)[OF assms(1)] assms(2)]
  have "s_prefix_sorted_pre α T SA" .

  have "?xs = ?ys @ ?zs"
    by (metis bucket_start_le_s_bucket_start l_bucket_end_le_bucket_end list_slice_append
          s_bucket_start_eq_l_bucket_end)
  hence "map (lms_slice T) ?xs = map (lms_slice T) ?ys @ map (lms_slice T) ?zs"
    by simp
  moreover
  from s_prefix_sorted_preD[OF `s_prefix_sorted_pre _ _ SA` `b  _`]
  have "ordlistns.sorted (map (lms_slice T) ?ys)" .
  moreover
  from s_prefix_sorted_invD[OF assms(3,4), simplified `_ = s_bucket_start α _ _`]
  have "ordlistns.sorted (map (lms_slice T) ?zs)" .
  moreover
  have "y  set (map (lms_slice T) ?ys). z  set (map (lms_slice T) ?zs).
          list_less_eq_ns y z"
  proof safe
    fix y z
    assume "y  set (map (lms_slice T) ?ys)"
           "z  set (map (lms_slice T) ?zs)"
    with in_set_mapD[of y "lms_slice T" ?ys]
         in_set_mapD[of z "lms_slice T" ?zs]
    obtain i j where
      "y = lms_slice T i" 
      "i  set ?ys"
      "z = lms_slice T j"
      "j  set ?zs"
      by blast

    from l_types_initD(1)[OF l_types_init_maintained[OF s_perm_inv_elims(2,4,10-12)[OF assms(1)]]
          `b  _`]
         `i  set ?ys`
    have "i  l_bucket α T b"
      by blast
    hence "suffix_type T i = L_type" "α (T ! i) = b" "i < length T"
      by (simp add: l_bucket_def bucket_def)+
    moreover
    from s_bucket_eq_list_slice[OF s_perm_inv_elims(1,3,11)[OF assms(1)] `b  _`
          `B ! b = s_bucket_start α _ _`]
         `j  set ?zs`
    have "j  s_bucket α T b"
      by blast
    hence "suffix_type T j = S_type" "α (T ! j) = b" "j < length T"
      by (simp add: s_bucket_def bucket_def)+
    moreover
    have "T ! i = T ! j"
      using assms(1) calculation(2,5) s_perm_inv_elims(8) strict_mono_eq by fastforce
    ultimately have "list_less_eq_ns (lms_slice T i) (lms_slice T j)"
      using lms_slice_l_less_than_s_type[of i T j] by simp
    then show "list_less_eq_ns y z"
      by (simp add: y = lms_slice T i z = lms_slice T j)
  qed
  ultimately show ?thesis
    by (simp add: ordlistns.sorted_append)
qed

theorem abs_induce_s_base_prefix_sorted:
  assumes "abs_induce_s_base α T B SA = (B', SA', n)"
  and     "s_perm_inv α T B SA0 SA (length T)"
  and     "s_prefix_sorted_pre α T SA0"
  and     "s_prefix_sorted_inv α T B SA"
shows "ordlistns.sorted (map (lms_slice T) SA')"
proof (intro sorted_wrt_mapI)
  fix i j
  assume "i < j" "j < length SA'"
  hence "i < length T" "j < length T"
    by (metis (no_types, lifting) abs_induce_s_perm_maintained 
              assms(1,2) order.strict_trans s_perm_inv_elims(11))+

  let ?goal = "list_less_eq_ns (lms_slice T (SA' ! i)) (lms_slice T (SA' ! j))"

  from index_in_bucket_interval_gen[OF `i < length _` s_perm_inv_elims(8)[OF assms(2)]]
  obtain b0 where
    "b0  α (Max (set T))"
    "bucket_start α T b0  i"
    "i < bucket_end α T b0"
    by blast

  from index_in_bucket_interval_gen[OF `j < length T` s_perm_inv_elims(8)[OF assms(2)]]
  obtain b1 where
    "b1  α (Max (set T))"
    "bucket_start α T b1  j"
    "j < bucket_end α T b1"
    by blast

  from abs_induce_s_perm_maintained[OF assms(1,2)]
  have "s_perm_inv α T B' SA0 SA' n" .
  moreover
  have "n = 0"
    by (metis Pair_inject assms(1) abs_induce_s_base_index)
  ultimately have "s_perm_inv α T B' SA0 SA' 0"
    by simp

  let ?xs = "list_slice SA' (bucket_start α T b0) (bucket_end α T b0)"
  and ?ys = "list_slice SA' (bucket_start α T b1) (bucket_end α T b1)"

  have "b0  b1"
  proof (rule ccontr)
    assume "¬b0  b1"
    hence "b1 < b0"
      by (simp add: not_le)
    hence "bucket_end α T b1  bucket_start α T b0"
      by (simp add: less_bucket_end_le_start)
    with `j < bucket_end α T b1` `bucket_start α T b0  i` `i < j`
    show False
      by linarith
  qed
  hence "b0 = b1  b0 < b1"
    by (simp add: nat_less_le)
  moreover
  have "b0 < b1  ?goal"
  proof -
    assume "b0 < b1"
    moreover
    from s_perm_inv_0_list_slice_bucket[OF `s_perm_inv _ _ _ _ _ 0` `b0  α _`]
    have "set ?xs = bucket α T b0" .
    hence "SA' ! i  bucket α T b0"
      by (metis bucket_start α T b0  i i < bucket_end α T b0 s_perm_inv α T B' SA0 SA' 0
            bucket_end_le_length list_slice_nth_mem s_perm_inv_elims(11))
    hence "α (T ! (SA' ! i)) = b0" "SA' ! i < length T"
      by (simp add: bucket_def)+
    moreover
    from s_perm_inv_0_list_slice_bucket[OF `s_perm_inv _ _ _ _ _ 0` `b1  α _`]
    have "set ?ys = bucket α T b1" .
    hence "SA' ! j  bucket α T b1"
      by (metis bucket_start α T b1  j j < bucket_end α T b1 s_perm_inv α T B' SA0 SA' 0
            bucket_end_le_length list_slice_nth_mem s_perm_inv_elims(11))
    hence "α (T ! (SA' ! j)) = b1" "SA' ! j < length T"
      by (simp add: bucket_def)+
    ultimately have "T ! (SA' ! i) < T ! (SA' ! j)"
      using assms(2) s_perm_inv_elims(8) strict_mono_less by blast
    then show ?thesis
      by (metis SA' ! i < length T SA' ! j < length T abs_find_next_lms_lower_bound_1 
            less_SucI less_imp_le list_less_eq_ns_cons list_slice_Suc neq_iff lms_slice_def)
  qed
  moreover
  have "b0 = b1  ?goal"
  proof -
    assume "b0 = b1"
    with `j < bucket_end α T b1`
    have "j < bucket_end α T b0"
      by simp

    have "i'. i = bucket_start α T b0 + i'"
      using bucket_start α T b0  i nat_le_iff_add by blast
    then obtain i' where
      "i = bucket_start α T b0 + i'"
      by blast

    have "j'. j = bucket_start α T b0 + j'"
      by (simp add: b0 = b1 bucket_start α T b1  j le_Suc_ex)
    then obtain j' where
      "j = bucket_start α T b0 + j'"
      by blast
    with `i < j` `i = bucket_start α T b0 + i'`
    have "i'  j'"
      by linarith

    have "j' < length ?xs"
      by (metis b0 = b1 
            j < bucket_end α T b1 
            j = bucket_start α T b0 + j'
            s_perm_inv α T B' SA0 SA' n 
            add.commute bucket_end_le_length length_list_slice
            less_diff_conv min_def s_perm_inv_elims(11))
    with ordlistns.sorted_nth_mono
           [OF s_prefix_sorted_bucket
                 [OF `s_perm_inv _ _ _ _ _ 0` assms(3)
                     abs_induce_s_prefix_sorted_maintained
                        [OF assms] `b0  α _`] `i'  j'`]
    have "list_less_eq_ns (lms_slice T (?xs ! i')) (lms_slice T (?xs ! j'))"
      using i'  j' nth_map by auto
    moreover
    have "SA' ! i = ?xs ! i'"
      using i < bucket_end α T b0 
            i < length T 
            i = bucket_start α T b0 + i'
            s_perm_inv α T B' SA0 SA' n  
            j' < length (list_slice SA' 
                     (bucket_start α T b0) 
                     (bucket_end α T b0)) 
      by (metis i'  j' nth_list_slice order.strict_trans1)
    moreover
    have "SA' ! j = ?xs ! j'"
      using j < bucket_end α T b0 j < length SA' 
            j = bucket_start α T b0 + j' 
      by (simp add: nth_list_slice)
    ultimately show ?goal
      by simp
  qed
  ultimately show ?goal
    by blast
qed

section "Induce S Correctness Theorems"

theorem abs_induce_s_perm:
  assumes "s_perm_pre α T B SA (length T)"
  shows "abs_induce_s α T B SA <~~> [0..< length T]"
proof -
  from s_perm_inv_established assms[simplified s_perm_pre_def]
  have "s_perm_inv α T B SA SA (length T)"
    by blast
  moreover
  from abs_induce_s_base_index[of α T B SA]
  obtain B' SA' where
    "abs_induce_s_base α T B SA = (B', SA', 0)"
    by blast
  ultimately have "s_perm_inv α T B' SA SA' 0"
    using abs_induce_s_perm_maintained[of α T B SA B' SA' 0 SA]
    by blast
  hence "SA' <~~> [0..< length T]"
    using abs_induce_s_base_perm[OF `abs_induce_s_base α T B SA = (B', SA', 0)`]
    by blast
  with `abs_induce_s_base α T B SA = (B', SA', 0)`
  show ?thesis
    by (simp add: abs_induce_s_def)
qed


 ―‹ Used in SAIS algorithm as part of inducing the suffix ordering based on LMS ›
theorem abs_induce_s_sorted:
  assumes "s_perm_pre α T B SA (length T)"
  and     "s_sorted_pre α T SA"
shows "ordlistns.sorted (map (suffix T) (abs_induce_s α T B SA))"
proof -
  from s_perm_inv_established assms(1)[simplified s_perm_pre_def]
  have "s_perm_inv α T B SA SA (length T)"
    by blast
  moreover
  from abs_induce_s_base_index[of α T B SA]
  obtain B' SA' where
    "abs_induce_s_base α T B SA = (B', SA', 0)"
    by blast
  moreover
  from s_sorted_inv_established assms(1)[simplified s_perm_pre_def]
  have "s_sorted_inv α T B SA"
    by blast
  ultimately have "ordlistns.sorted (map (suffix T) SA')"
    using abs_induce_s_base_sorted[OF _ _ assms(2), of B SA B' SA' 0]
    by blast
  then show ?thesis
    by (simp add: abs_induce_s_base α T B SA = (B', SA', 0) abs_induce_s_def)
qed

 ―‹ Used in SAIS algorithm as part of inducing the prefix ordering based on LMS ›
theorem abs_induce_s_prefix_sorted:
  assumes "s_perm_pre α T B SA (length T)"
  and     "s_prefix_sorted_pre α T SA"
shows "ordlistns.sorted (map (lms_slice T) (abs_induce_s α T B SA))"
proof -

  from s_perm_inv_established assms(1)[simplified s_perm_pre_def]
  have "s_perm_inv α T B SA SA (length T)"
    by blast
  moreover
  from abs_induce_s_base_index[of α T B SA]
  obtain B' SA' where
    "abs_induce_s_base α T B SA = (B', SA', 0)"
    by blast
  moreover
  from s_prefix_sorted_inv_established assms(1)[simplified s_perm_pre_def]
  have "s_prefix_sorted_inv α T B SA"
    by blast
  ultimately have "ordlistns.sorted (map (lms_slice T) SA')"
    using abs_induce_s_base_prefix_sorted[OF _ _ assms(2), of B SA B' SA' 0]
    by blast
  then show ?thesis
    by (simp add: abs_induce_s_base α T B SA = (B', SA', 0) abs_induce_s_def)
qed

end