Theory SAIS_Verification

theory SAIS_Verification
  imports 
      Get_Types_Verification 
      Induce_Verification
      "../abs-proof/Abs_SAIS_Verification_With_Valid_Precondition" 
      "../def/SAIS"
          
begin

section "SAIS"

termination sais_r0
  apply (relation "measure (λxs. length xs)")
   apply simp
  apply (simp (no_asm_simp) 
              del: List.list.size(4)
              only: extract_lms_eq[OF length_get_suffix_types get_suffix_types_correct]
                    rename_mapping_refinement[OF length_get_suffix_types 
                    get_suffix_types_correct] get_suffix_types_eq)
  apply (simp (no_asm_simp) 
            del: List.list.size(4) 
            add: rename_list_length length_filter_lms)
  done

lemma abs_sais_r0_distinct_simp:
  assumes "T = a # b # xs"
  and     "ST = abs_get_suffix_types T"
  and     "LMS0 = extract_lms ST [0..<length T]"
  and     "SA = sa_induce id T ST LMS0"
  and     "LMS = extract_lms ST SA"
  and     "names = rename_mapping T ST LMS"
  and     "T' = rename_string LMS0 names"
  and     "distinct T'"
  shows "sais_r0 T = sa_induce id T ST LMS"
proof -
  let ?P = "λys. sais_r0 (a # b # xs) = ys"
  from subst[OF sais_r0.simps(3), of ?P a b xs, simplified Let_def
        assms(1-7)[symmetric] assms(8), simplified]
  show ?thesis
    by simp
qed

lemma abs_sais_r0_not_distinct_simp:
  assumes "T = a # b # xs"
  and     "ST = abs_get_suffix_types T"
  and     "LMS0 = extract_lms ST [0..<length T]"
  and     "SA = sa_induce id T ST LMS0"
  and     "LMS = extract_lms ST SA"
  and     "names = rename_mapping T ST LMS"
  and     "T' = rename_string LMS0 names"
  and     "LMS1 = order_lms LMS0 (sais_r0 T')"
  and     "¬distinct T'"
  shows "sais_r0 T = sa_induce id T ST LMS1"
proof -
  let ?P = "λys. sais_r0 (a # b # xs) = ys"
  from subst[OF sais_r0.simps(3), of ?P a b xs, simplified Let_def
        assms(1-8)[symmetric] assms(9), simplified]
  show ?thesis
    by simp
qed

lemma abs_sais_to_r0:
  "valid_list T  abs_sais T = sais_r0 T"
proof(induct rule: abs_sais.induct[of _ T])
  case 1
  then show ?case
    by simp
next
  case (2 x)
  then show ?case
    by simp
next
  case (3 a b xs)
  note IH = this

  let ?T = "a # b # xs"
  have T: "?T = a # b # xs"
    by (simp only:)

 let ?ST = "abs_get_suffix_types ?T"
  have ST: "?ST = abs_get_suffix_types ?T"
    by (simp only:)
  from get_suffix_types_correct[of ?T] length_abs_get_suffix_types[of ?T]
  have "i < length ?ST. ?ST ! i = suffix_type ?T i"
    by (simp add: get_suffix_types_eq)
  note st_thms = length_get_suffix_types[of ?T] 
                 `i < length ?ST. ?ST ! i = suffix_type ?T i`

  let ?LMS1 = "abs_extract_lms ?T [0..<length ?T]"
  let ?LMS1' = "extract_lms ?ST [0..<length ?T]"
  have LMS1: "?LMS1 = abs_extract_lms ?T [0..<length ?T]"
    by (simp only:)
  have LMS1': "?LMS1' = extract_lms ?ST [0..<length ?T]"
    by (simp only:)
  have "distinct ?LMS1"
    using distinct_abs_extract_lms
    by fastforce
  have "set ?LMS1 = {i. abs_is_lms ?T i}"
    using set_abs_extract_lms_eq_all_lms
    by (metis comp_apply)
  have "?LMS1 = ?LMS1'"
    by (metis extract_lms_eq get_suffix_types_correct length_get_suffix_types)
  note lms1_thms = `set ?LMS1 = {i. abs_is_lms ?T i}` `distinct ?LMS1` `?LMS1 = ?LMS1'`

  have id: "strict_mono (id :: nat  nat)" "(id :: nat  nat) bot = 0"
    by (simp add: strict_mono_def bot_nat_def)+

  have len: "Suc 0 < length ?T"
    by simp

  let ?SA1 = "abs_sa_induce id ?T ?LMS1"
  have SA1: "?SA1 = abs_sa_induce id ?T ?LMS1"
    by (simp only:)
  let ?SA1' = "sa_induce id ?T ?ST ?LMS1'"
  have SA1': "?SA1' = sa_induce id ?T ?ST ?LMS1'"
    by (simp only:)
  have "?SA1 = ?SA1'"
    by (metis "3.prems" len lms1_thms id  st_thms abs_sa_induce_to_r2)

  let ?LMS2 = "abs_extract_lms ?T ?SA1"
  let ?LMS2' = "extract_lms ?ST ?SA1'"
  have LMS2: "?LMS2 = abs_extract_lms ?T ?SA1"
    by (simp only:)
  have LMS2': "?LMS2' = extract_lms ?ST ?SA1'"
    by (simp only:)
  have "?LMS2 = ?LMS2'"
    using `?SA1 = ?SA1'` st_thms comp_apply is_lms_refinement 
    by (metis (no_types, lifting) get_suffix_types_eq)
  have "?LMS1 <~~> ?LMS2"
    by (metis "3.prems" distinct_filter_abs_sa_induce lms1_thms len id
              distinct_set_imp_perm filter_abs_sa_induce_eq_all_lms)
  hence "distinct ?LMS2" "set ?LMS2 = {i. abs_is_lms ?T i}"
    using lms1_thms perm_distinct_iff perm_set_eq by blast+
  have "ordlistns.sorted (map (lms_slice ?T) ?LMS2)"
    by (metis "3.prems" distinct ?LMS1 set ?LMS1 = {i. abs_is_lms ?T i} comp_apply len id
              ordlistns.sorted_filter abs_sa_induce_prefix_sorted)
  note lms2_thms = distinct ?LMS2 set ?LMS2 = {i. abs_is_lms ?T i}
                   ordlistns.sorted (map (lms_slice ?T) ?LMS2)
                   ?LMS2 = ?LMS2'

  let ?names = "abs_rename_mapping ?T ?LMS2"
  let ?names' = "rename_mapping ?T ?ST ?LMS2'"
  have names: "?names = abs_rename_mapping ?T ?LMS2"
    by (simp only:)
  have names': "?names' = rename_mapping ?T ?ST ?LMS2'"
    by (simp only:)
  have "?names = ?names'"
    by (metis st_thms lms2_thms(4) rename_mapping_refinement)

  let ?T' = "rename_string ?LMS1 ?names"
  let ?T'' = "rename_string ?LMS1' ?names'"
  have T': "?T' = rename_string ?LMS1 ?names"
    by (simp only:)
  have T'': "?T'' = rename_string ?LMS1' ?names'"
    by (simp only:)
  have "?T' = ?T''"
    using ?names = ?names' lms1_thms(3) by argo

  let ?LMS3 = "order_lms ?LMS1 (abs_sais ?T')"
  let ?LMS3' = "order_lms ?LMS1' (sais_r0 ?T'')"
  have LMS3: "?LMS3 = order_lms ?LMS1 (abs_sais ?T')"
    by (simp only:)
  have LMS3': "?LMS3' = order_lms ?LMS1' (sais_r0 ?T'')"
    by (simp only:)

  have "?LMS1 = lms0_seq ?T"
    by (metis comp_apply lms_seq_0_zeroth_lms lms_seq_def)
  with abs_sais_reduced_string[OF _ lms2_thms(1-3) names T']
  have "?T' = lms0_map ?T"
    by blast

  have "abs_is_lms ?T (lms0 ?T)"
    by (metis "3.prems" abs_find_next_lms_less_length_abs_is_lms abs_is_lms_last 
              len length_Cons no_lms_between_i_and_next not_less_eq)

  from valid_list_lms_map[OF IH(2) abs_is_lms ?T (lms0 ?T)]
  have "valid_list (lms0_map ?T)" .
  hence "valid_list ?T'"
    by (simp only: ?T' = (lms0_map ?T))

  have "distinct ?T'  ?case"
  proof -
    assume "distinct ?T'"
    hence "distinct ?T''"
      by (simp only: `?T' = ?T''`)
    note lms2_thms = filter_abs_sa_induce_eq_all_lms[OF lms1_thms(1,2) IH(2) id len]
                     distinct_filter_abs_sa_induce[OF lms1_thms(1,2) IH(2) id len]
    from abs_sa_induce_to_r2 lms2_thms(1,2) IH(2) id len st_thms
    have "abs_sa_induce id ?T ?LMS2 = sa_induce id ?T ?ST ?LMS2'"
      by (metis `?LMS2 = ?LMS2'` comp_apply)
    with abs_sais_distinct_simp[OF T LMS1 SA1 LMS2 names T' `distinct ?T'`]
         abs_sais_r0_distinct_simp[OF T ST LMS1' SA1' LMS2' names' T'' `distinct ?T''`]
    show ?thesis
      by presburger
  qed
  moreover
  have "¬distinct ?T'  ?case"
  proof -
    assume "¬distinct ?T'"
    hence "¬distinct ?T''"
      using `?T' = ?T''` by argo

    from IH(1)[OF T LMS1 SA1 LMS2 names T', OF `¬distinct ?T'` `valid_list ?T'`]
    have "abs_sais ?T' = sais_r0 ?T''"
      using ?T' = ?T'' by argo
    hence "?LMS3' = ?LMS3"
      using lms1_thms(3) by argo

    have abs_sais_perm: "abs_sais ?T' <~~> [0..<length ?LMS1]"
      using abs_sais_permutation[OF `valid_list ?T'`, simplified rename_list_length]
      by blast

    note lms3_thms = abs_order_lms_eq_all_lms[OF abs_sais_perm lms1_thms(1)]
                     distinct_abs_order_lms[OF abs_sais_perm lms1_thms(2)]
    from abs_sa_induce_to_r2[OF lms3_thms valid_list ?T id len st_thms]
    have "abs_sa_induce id ?T ?LMS3 = sa_induce id ?T ?ST ?LMS3'"
      using abs_sais ?T' = sais_r0 ?T'' lms1_thms(3) by argo
    with abs_sais_not_distinct_simp[OF T LMS1 SA1 LMS2 names T' LMS3 `¬distinct ?T'`]
         abs_sais_r0_not_distinct_simp[OF T ST LMS1' SA1' LMS2' names' T'' LMS3' `¬distinct ?T''`]
         `abs_sais ?T' = sais_r0 ?T'`
    show ?thesis
     by presburger
  qed
  ultimately show ?case
    by blast
qed

termination sais_r1
  apply (relation "measure (λxs. length xs)")
   apply simp
  apply (simp (no_asm_simp) 
              del: List.list.size(4)
              only: extract_lms_eq[OF length_abs_get_suffix_types get_suffix_types_correct]
                    rename_mapping_refinement[OF length_abs_get_suffix_types get_suffix_types_correct])
  apply (simp (no_asm_simp)
              del: List.list.size(4) 
              add: rename_list_length length_filter_lms)
  apply (metis get_suffix_types_correct get_suffix_types_eq is_lms_refinement 
               length_filter_lms length_get_suffix_types list.discI)
  done

lemma abs_sais_r0_to_r1:
  "sais_r1 T = sais_r0 T"
  apply (induct rule: sais_r0.induct[of _ T])
    apply simp
   apply simp
  apply (subst sais_r1.simps)
  apply (subst get_suffix_types_eq)
  apply (subst sais_r0.simps)
  apply (clarsimp simp only: Let_def split: if_splits)
  by presburger

lemma abs_sais_to_r1:
  "valid_list T  sais_r1 T = abs_sais T"
  by (simp add: abs_sais_r0_to_r1 abs_sais_to_r0)


section "Correctness"

interpretation sais: Suffix_Array_Restricted sais
  by (simp add: Suffix_Array_Restricted.intro Suffix_Array_Restricted.sa_r_permutation
                Suffix_Array_Restricted.sa_r_sorted abs_sais.Suffix_Array_Restricted_axioms abs_sais_to_r1)

interpretation abs_sais_ref_gen: Suffix_Array_General "sa_nat_wrapper map_to_nat sais"
  by (simp add: Suffix_Array_Restricted_imp_General sais.Suffix_Array_Restricted_axioms)

theorem sais_gen_is_Suffix_Array_General:
  "Suffix_Array_General sa  sa = sa_nat_wrapper map_to_nat sais"
  using Suffix_Array_General_determinism abs_sais_ref_gen.Suffix_Array_General_axioms by auto

end