Theory Suffix_Util

theory Suffix_Util
  imports 
    "../util/List_Slice"
    Suffix
    Valid_List
    Valid_List_Util

begin

section ‹Valid Lists and Suffixes›

lemma valid_suffix:
  "valid_list s; i < length s  valid_list (suffix s i)"
  by (clarsimp simp: valid_list_ex_def)

lemma last_suffix_index:
  assumes "valid_list s"
  and     "i < length s"
  shows "hd (suffix s i) = bot  i = length s - 1"
proof -
  from iffD1[OF valid_list_ex_def `valid_list s`]
  obtain xs where
    "s = xs @ [bot]"
    "i < length xs. xs ! i  bot"
    by blast
  show ?thesis
  proof
    from s = xs @ [bot] i < length xs. xs ! i  bot
    show "i = length s - 1  hd (suffix s i) = bot"
      by simp
  next
    from s = xs @ [bot] i < length xs. xs ! i  bot i < length s
    show "hd (suffix s i) = bot  i = length s - 1"
      by (clarsimp simp: hd_append hd_drop_conv_nth split: if_splits)
  qed
qed

section ‹Prefixes and Suffixes›

lemma suffix_has_no_prefix_suffix:
  assumes valid_list: "valid_list s"
  and     i_less_len_s:  "i < length s"
  and     j_less_len_s:  "j < length s"
  and     i_neq_j:       "i  j"
  shows "¬ (s'. suffix s i = (suffix s j) @ s')"
proof
  assume "s'. suffix s i = suffix s j @ s'"
  then obtain s' where
    pref: "suffix s i = suffix s j @ s'"
    by blast
  with i_neq_j i_less_len_s j_less_len_s
  have "i < j"
    by (metis diff_less_mono2 length_append length_drop less_Suc_eq not_add_less1
          not_less_eq)
  with pref i_less_len_s j_less_len_s
    have s_not_nil: "s'  []"
    by (metis append_Nil2 diff_less_mono2 length_drop less_irrefl_nat)

  from valid_list i_less_len_s valid_suffix
  have valid_suf_i: "valid_list (suffix s i)"
    by force

  from valid_list j_less_len_s valid_suffix
  have "valid_list (suffix s j)"
    by force
  with pref valid_list_ex_def
  have "xs. suffix s i = xs @ [bot] @ s'"
    using append_assoc by auto
  then obtain xs where
    suf_i: "suffix s i = xs @ [bot] @ s'"
    by blast

  from valid_suf_i valid_list_ex_def
  have "ys. suffix s i = ys @ [bot]  (k < length ys. ys ! k  bot)"
    by blast
  then obtain ys where
                  "suffix s i = ys @ [bot]" and
    all_ys_not_0: "k < length ys. ys ! k  bot"
    by blast
  with suf_i
  have suf_i_eq: "xs @ [bot] @ s' = ys @ [bot]"
    by force
  with s_not_nil
  have "length xs < length ys"
    by (metis (no_types, lifting) append_assoc append_eq_append_conv 
              length_append length_append_singleton less_trans_Suc 
              linorder_neqE_nat not_add_less1 self_append_conv)
  with suf_i_eq all_ys_not_0
  show "False"
    by (metis append_Cons butlast_snoc nth_append_length nth_butlast)
qed


section ‹Suffix Comparisons›

subsection ‹Lexicographical Ordering›

lemma suffix_less_ex:
  fixes s :: "('a :: {linorder, order_bot}) list"
  assumes "valid_list s"
  and     "i < length s"
  and     "j < length s"
  and     "suffix s i < suffix s j"
  shows "b c as bs cs. suffix s i = as @ b # bs  
                      suffix s j = as @ c # cs  b < c"
proof -
  have "valid_list (suffix s i)"
    using assms(1) assms(2) valid_suffix by blast
  moreover
  have "valid_list (suffix s j)"
    using assms(1) assms(3) valid_suffix by blast
  moreover
  have "suffix s i  suffix s j"
    using assms(4) nless_le by blast
  ultimately have
    "b c as bs cs. suffix s i = as @ b # bs  suffix s j = as @ c # cs  b  c"
    using valid_list_neqE by blast
  then obtain b c as bs cs where
    "suffix s i = as @ b # bs" "suffix s j = as @ c # cs" "b  c"
    by blast
  hence "b < c"
    by (metis assms(4) linorder_less_linear list_less_ex order_less_imp_not_less)
  then show ?thesis
    using suffix s i = as @ b # bs suffix s j = as @ c # cs by blast
qed

lemma suffix_less_nth:
  assumes "valid_list s"
  and     "i < length s"
  and     "j < length s"
  and     "suffix s i < suffix s j"
  shows
  "n. n < length (suffix s i) 
       n < length (suffix s j) 
       (k < n. (suffix s i) ! k = (suffix s j) ! k) 
                (suffix s i) ! n < (suffix s j) ! n"
proof -
  from suffix_less_ex[OF assms]
  obtain b c as bs cs where
    suf_i:    "suffix s i = as @ b # bs" and
    suf_j:    "suffix s j = as @ c # cs" and
    b_less_c: "b < c"
    by blast
  hence "length as < length (suffix s i)" and
        "length as < length (suffix s j)" and
        "(suffix s i) ! length as = b"    and
        "(suffix s j) ! length as = c"
    by fastforce+
  with b_less_c suf_i suf_j
  show ?thesis
    by (metis nth_append)
qed

lemma suffix_less_butlast:
 assumes "valid_list s"
  and    "i < length s"
  and    "j < length s"
  and    "suffix s i < suffix s j"
  shows "butlast (suffix s i) < butlast (suffix s j)"
  by (metis append_butlast_last_id assms suffix_neq_nil valid_list_def valid_list_list_less_imp
            valid_suffix)

subsection ‹Non-standard List Ordering›

lemma suffix_less_ns_ex:
  assumes "valid_list s"
  and     "i < length s"
  and     "j < length s"
  and     "list_less_ns (suffix s i) (suffix s j)"
  shows "b c as bs cs. 
          suffix s i = as @ b # bs  
          suffix s j = as @ c # cs  b < c"
  by (meson assms suffix_less_ex valid_suffix
      valid_list_list_less_equiv_list_less_ns)


lemma suffix_less_ns_nth:
  assumes "valid_list s"
  and     "i < length s"
  and     "j < length s"
  and     "list_less_ns (suffix s i) (suffix s j)"
  shows
  "n. n < length (suffix s i) 
       n < length (suffix s j) 
       (k < n. (suffix s i) ! k = (suffix s j) ! k) 
       (suffix s i) ! n < (suffix s j) ! n"
  by (meson assms suffix_less_nth valid_list_list_less_equiv_list_less_ns valid_suffix)

section ‹List Slice›

declare list_slice.simps[simp del]

lemma list_slice_to_suffix:
  "list_slice T i j = take (j - i) (suffix T i)"
  by (simp add: list_slice.simps drop_take)

lemma suffix_eq_list_slice:
  "suffix T i = list_slice T i (length T)"
  by (simp add: list_slice.simps)

lemma list_slice_suffix:
  "list_slice T i j = list_slice (suffix T i) 0 (j - i)"
  by (metis drop0 drop_take list_slice.simps)
lemma suffix_to_list_slice_app:
  "i  j  suffix T i = (list_slice T i j) @ (list_slice T j (length T))"
  apply (cases "j  length T")
   apply (subst list_slice_append[symmetric]; simp?)
   apply (clarsimp simp: list_slice.simps)
  apply (clarsimp simp: not_le)
  apply (subst list_slice_end_gre_length, arith)
  apply (simp add: list_slice_start_gre_length list_slice.simps)
  done

section ‹Sorting›

lemma ordlist_strict_mono_strict_sorted_1:
  assumes "strict_mono α"
  and     "strict_sorted (map (suffix (map α s)) xs)"
  shows "strict_sorted (map (suffix s) xs)"
proof (intro sorted_wrt_mapI)
  fix i j
  assume "i < j" "j < length xs"
  with sorted_wrt_nth_less[OF assms(2)]
  have "suffix (map α s) (xs ! i) < suffix (map α s) (xs ! j)"
    by auto
  then show "suffix s (xs ! i) < suffix s (xs ! j)"
    by (metis assms(1) strict_mono_map_list_less suffix_map)
qed

lemma ordlist_strict_mono_on_strict_sorted_1:
  assumes "strict_mono_on A α"
  and     "set s  A"
  and     "strict_sorted (map (suffix (map α s)) xs)"
  shows "strict_sorted (map (suffix s) xs)"
proof (intro sorted_wrt_mapI)
  fix i j
  assume "i < j" "j < length xs"
  with sorted_wrt_nth_less[OF assms(3)]
  have "suffix (map α s) (xs ! i) < suffix (map α s) (xs ! j)"
    by auto
  hence "map α (suffix s (xs ! i)) < map α (suffix s (xs ! j))"
    by (metis suffix_map)
  then show "suffix s (xs ! i) < suffix s (xs ! j)"
    by (meson assms(1,2) dual_order.trans set_suffix_subset 
              strict_mono_on_map_list_less)
qed

lemma ordlist_strict_mono_strict_sorted_2:
  assumes "strict_mono α"
  and     "strict_sorted (map (suffix s) xs)"
  shows "strict_sorted (map (suffix (map α s)) xs)"
proof (intro sorted_wrt_mapI)
  fix i j
  assume "i < j" "j < length xs"
  with sorted_wrt_nth_less[OF assms(2)]
  have "suffix s (xs ! i) < suffix s (xs ! j)"
    by auto
  then show "suffix (map α s) (xs ! i) < suffix (map α s) (xs ! j)"
    by (metis assms(1) strict_mono_list_less_map suffix_map)
qed

lemma ordlist_strict_mono_on_strict_sorted_2:
  assumes "strict_mono_on A α"
  and     "set s  A"
  and     "strict_sorted (map (suffix s) xs)"
  shows "strict_sorted (map (suffix (map α s)) xs)"
proof (intro sorted_wrt_mapI)
  fix i j
  assume "i < j" "j < length xs"
  with sorted_wrt_nth_less[OF assms(3)]
  have "suffix s (xs ! i) < suffix s (xs ! j)"
    by auto
  moreover
  have "set (suffix s (xs ! i))  A"
    by (meson assms(2) dual_order.trans set_suffix_subset)
  moreover
  have "set (suffix s (xs ! j))  A"
    by (meson assms(2) dual_order.trans set_suffix_subset)
  ultimately show "suffix (map α s) (xs ! i) < suffix (map α s) (xs ! j)"
    using strict_mono_on_list_less_map[OF assms(1)]
    by (metis suffix_map)
qed

lemma valid_list_ordlist_ordlistns_strict_sorted_eq:
  assumes "valid_list T"
  and     "set xs  {0..<length T}"
  shows "ordlistns.strict_sorted (map (suffix T) xs)  
         strict_sorted (map (suffix T) xs)"
using assms
proof (safe) 
  assume A: "valid_list T" and
         B: "set xs  {0..<length T}" and
         C: "sorted_wrt list_less_ns (map (suffix T) xs)"
  show "sorted_wrt (<) (map (suffix T) xs)"
  proof (intro sorted_wrt_mapI)
    fix i j
    assume "i < j" "j < length xs"
    with sorted_wrt_nth_less[OF C i < j]
    have R1: "list_less_ns (suffix T (xs ! i)) (suffix T (xs ! j))"
      by auto

    from B i < j j < length xs
    have "xs ! i < length T"
      by (meson atLeastLessThan_iff less_trans nth_mem subsetD)
    with valid_suffix[OF A]
    have R2: "valid_list (suffix T (xs ! i))"
      by simp

    from B j < length xs
    have "xs ! j < length T"
      by (meson atLeastLessThan_iff less_trans nth_mem subsetD)
    with valid_suffix[OF A]
    have R3: "valid_list (suffix T (xs ! j))"
      by simp

    from R1 valid_list_list_less_equiv_list_less_ns[OF R2 R3]
    show "suffix T (xs ! i) < suffix T (xs ! j)"
      by simp
  qed
next
  assume A: "valid_list T" and
         B: "set xs  {0..<length T}" and
         C: "sorted_wrt (<) (map (suffix T) xs)"
  show "sorted_wrt list_less_ns (map (suffix T) xs)"
  proof (intro sorted_wrt_mapI)
    fix i j
    assume "i < j" "j < length xs"
    with sorted_wrt_nth_less[OF C i < j]
    have R1: "suffix T (xs ! i) < suffix T (xs ! j)"
      by auto

    from B i < j j < length xs
    have "xs ! i < length T"
      by (meson atLeastLessThan_iff less_trans nth_mem subsetD)
    with valid_suffix[OF A]
    have R2: "valid_list (suffix T (xs ! i))"
      by simp

    from B j < length xs
    have "xs ! j < length T"
      by (meson atLeastLessThan_iff less_trans nth_mem subsetD)
    with valid_suffix[OF A]
    have R3: "valid_list (suffix T (xs ! j))"
      by simp

    from R1 valid_list_list_less_equiv_list_less_ns[OF R2 R3]
    show "list_less_ns (suffix T (xs ! i)) (suffix T (xs ! j))"
      by simp
  qed
qed

lemma Min_valid_suffix:
  assumes "valid_list T"
  and     "length T = Suc n"
shows "ordlistns.Min {suffix T i |i. i < length T} = suffix T n"
proof -
  from assms
  have "suffix T n = [bot]"
    by (metis add_diff_cancel_left' butlast_snoc length_butlast lessI list_slice_n_n
          nth_append_length plus_1_eq_Suc suffix_cons_Suc suffix_eq_list_slice valid_list_ex_def)

  have "i < n. (suffix T i) ! 0  bot"
    by (metis add_diff_cancel_left' assms last_suffix_index less_SucI list.sel(1) nat_neq_iff
          nth_Cons_0 plus_1_eq_Suc suffix_cons_Suc)
  hence A: "i < n. bot < (suffix T i) ! 0"
    using bot.not_eq_extremum by blast

  have B: "i < length T. length (suffix T i) > 0"
    by auto

  show ?thesis
  proof (intro ordlistns.Min_eqI conjI)
    show "finite {suffix T i |i. i < length T}"
      by simp
  next
    fix ys
    assume "ys  {suffix T i |i. i < length T}"
    hence "i < length T. ys = suffix T i"
      by blast
    then obtain i where
      "i < length T"
      "ys = suffix T i"
      by blast

    with ys = suffix T i
    have R1: "i = n  list_less_eq_ns (suffix T n) ys"
      by simp

    from i < length T assms(2)
    have R2_1: "i  n  i < n"
      by linarith

    from A suffix T n = [bot] i < length T ys = suffix T i
    have R2_2: "i < n  list_less_eq_ns (suffix T n) ys"
      by (metis list_less_ns_cons_diff nth_Cons_0 ordlistns.less_imp_le suffix_cons_ex)

    from R1 R2_2[OF R2_1]
    show "list_less_eq_ns (suffix T n) ys"
      by blast
  next
    show "suffix T n  {suffix T i |i. i < length T}"
      using assms(2) by auto
  qed
qed

end