Theory Border_Array
theory Border_Array
imports
CoWBasic
begin
subsection ‹Auxiliary lemmas on suffix and border extension›
lemma border_ConsD: assumes "b#x ≤b a#w"
shows "a = b" and
"x ≠ ε ⟹ x ≤b w" and
border_ConsD_neq: "x ≠ w" and
border_ConsD_pref: "x ≤p w" and
border_ConsD_suf: "x ≤s w"
proof-
show "a = b"
using borderD_pref[OF assms] by force
show "x ≠ w" and "x ≤p w" and "x ≤s w"
using borderD_neq[OF assms, unfolded ‹a = b›]
borderD_pref[OF assms, unfolded Cons_prefix_Cons]
suffix_ConsD2[OF borderD_suf[OF assms]] by force+
thus "x ≠ ε ⟹ x ≤b w"
unfolding border_def by blast
qed
lemma ext_suf_Cons:
"Suc i + ❙|u❙| = ❙|w❙| ⟹ u ≤s w ⟹ (w!i)#u ≤s (w!i)#w"
proof-
assume "Suc i + ❙|u❙| = ❙|w❙|" and "u ≤s w"
hence "u = drop (Suc i) w"
unfolding suffix_def using ‹Suc i + ❙|u❙| = ❙|w❙|› by auto
have "i < ❙|w❙|"
using ‹Suc i + ❙|u❙| = ❙|w❙|› by auto
from id_take_nth_drop[OF this, folded ‹u = drop (Suc i) w›]
show "w ! i # u ≤s w ! i # w"
using suffix_ConsI triv_suf by metis
qed
lemma ext_suf_Cons_take_drop: assumes "take k (drop (Suc i) w) ≤s drop (Suc i) w" and "w ! i = w ! (❙|w❙| - Suc k)"
shows "take (Suc k) (drop i w) ≤s drop i w"
proof (cases "(Suc k) + i < ❙|w❙|", simp_all)
assume "Suc (k + i) < ❙|w❙|"
hence "i < ❙|w❙|"
by simp
have "Suc (❙|w❙| - Suc i - Suc k) = ❙|w❙| - Suc(i+k)"
using Suc_diff_Suc ‹Suc (k + i) < ❙|w❙|›
by (simp add: Suc_diff_Suc)
have "❙|take k (drop (Suc i) w)❙| = k"
using ‹Suc (k + i) < ❙|w❙|› by fastforce
have "Suc (❙|w❙| - Suc i - Suc k) + ❙|take k (drop (Suc i) w)❙| = ❙|drop (Suc i) w❙|"
unfolding ‹❙|take k (drop (Suc i) w)❙| = k› ‹Suc (❙|w❙| - Suc i - Suc k) = ❙|w❙| - Suc(i+k)›
using ‹Suc (k + i) < ❙|w❙|› by simp
hence "❙|drop (Suc (❙|w❙| - Suc i - k)) (drop i w)❙| = k"
using ‹i < ❙|w❙|› by fastforce
have "❙|w❙| - Suc i - k < ❙|drop i w❙|"
by (metis Suc_diff_Suc ‹i < ❙|w❙|› diff_less_Suc length_drop)
have "(drop i w)!(❙|w❙| - Suc i - k) = w ! i"
using ‹Suc (k + i) < ❙|w❙|› ‹w ! i = w ! (❙|w❙| - Suc k)› by auto
have "take (Suc k) (drop i w) = w!i#take k (drop (Suc i) w)"
using Cons_nth_drop_Suc[OF ‹i < ❙|w❙|›] take_Suc_Cons[of k "w!i" "drop (Suc i) w"] by argo
have "drop (Suc (❙|w❙| - Suc i - k)) (drop i w) = drop (❙|w❙| - Suc i - k) (drop (Suc i) w)"
by auto
hence "drop (Suc (❙|w❙| - Suc i - k)) (drop i w) = take k (drop (Suc i) w)"
using ‹❙|take k (drop (Suc i) w)❙| = k›
‹take k (drop (Suc i) w) ≤s drop (Suc i) w› suf_drop_conv length_drop by metis
with
id_take_nth_drop[OF ‹❙|w❙| - Suc i - k < ❙|drop i w❙|›]
show ?thesis
unfolding ‹(drop i w)!(❙|w❙| - Suc i - k) = w ! i›
‹take (Suc k) (drop i w) = w!i#take k (drop (Suc i) w)›
unfolding suffix_def by auto
qed
lemma ext_border_Cons:
"Suc i + ❙|u❙| = ❙|w❙| ⟹ u ≤b w ⟹ (w!i)#u ≤b (w!i)#w"
unfolding border_def using ext_suf_Cons Cons_prefix_Cons list.discI list.inject by metis
lemma border_add_Cons_len: assumes "max_borderP u w" and "v ≤b (a#w)" shows "❙|v❙| ≤ Suc ❙|u❙|"
proof-
have "v ≠ ε"
using ‹v ≤b (a#w)› by simp
then obtain v' where "v = a#v'"
using borderD_pref[OF ‹v ≤b (a#w)›, unfolded prefix_Cons] by blast
show "❙|v❙| ≤ Suc ❙|u❙|"
proof (cases "v' = ε")
assume "v' ≠ ε"
have "w ≠ ε"
using borderedI[OF ‹v ≤b (a#w)›] sing_not_bordered[of a] by blast
have "v' ≤b w"
using border_ConsD(2)[OF ‹v ≤b (a#w)›[unfolded ‹v = a # v'›] ‹v' ≠ ε›].
thus "❙|v❙| ≤ Suc ❙|u❙|"
unfolding ‹v = a # v'› length_Cons Suc_le_mono
using ‹max_borderP u w›[unfolded max_borderP_def]
prefix_length_le by blast
qed (simp add: ‹v = a#v'›)
qed
section ‹Computing the Border Array›
text‹The computation is a special case of the Knuth-Morris-Pratt algorithm.›
text‹
▪ KMP w arr bord pos
▪ w: processed word does not change; it is processed starting from the last letter
▪ pos: actually examined pos-th letter; that is, it is w!(pos-1)
▪ arr: already calculated suffix-border-array of w;
that is, the length of array is (|w| - pos)
and arr!(|w| - pos - bord) is the max border length of the suffix of w of length bord
▪ bord: length of the current max border length candidate
to see whether it can be extended we compare: w!(pos-1) ?= w!(|w| - (Suc bord));
(Suc bord) is the length of the max border if the comparison is succesful
▪ if the comparison fails we move to the max border of the suffix of length bord;
its max border length is stored in arr!(|w| - pos - bord)
▪ if bord was 0 and the comparison failed, the word is unbordered
›
fun KMP_arr :: "'a list ⇒ nat list ⇒ nat ⇒ nat ⇒ nat list"
where "KMP_arr _ arr _ 0 = arr" |
"KMP_arr w arr bord (Suc i) =
(if w!i = w!(❙|w❙| - (Suc bord))
then (Suc bord) # arr
else (if bord = 0
then 0#arr
else (if (arr!(❙|w❙| - (Suc i) - bord)) < bord
then arr
else undefined#arr
)
)
)"
fun KMP_bord :: "'a list ⇒ nat list ⇒ nat ⇒ nat ⇒ nat"
where "KMP_bord _ _ bord 0 = bord" |
"KMP_bord w arr bord (Suc i) =
(if w!i = w!(❙|w❙| - (Suc bord))
then Suc bord
else (if bord = 0
then 0
else (if (arr!(❙|w❙| - (Suc i) - bord)) < bord
then arr!(❙|w❙| - (Suc i) - bord)
else 0
)
)
)"
fun KMP_pos :: "'a list ⇒ nat list ⇒ nat ⇒ nat ⇒ nat"
where
"KMP_pos _ _ _ 0 = 0" |
"KMP_pos w arr bord (Suc i) =
(if w!i = w!(❙|w❙| - (Suc bord))
then i
else (if bord = 0
then i
else (if (arr!(❙|w❙| - (Suc i) - bord)) < bord
then Suc i
else i
)
)
)"
thm prod_cases
nat.exhaust
prod.exhaust
prod_cases3
function KMP :: "'a list ⇒ nat list ⇒ nat ⇒ nat ⇒ nat list" where
"KMP w arr bord 0 = arr" |
"KMP w arr bord (Suc i) = KMP w (KMP_arr w arr bord (Suc i)) (KMP_bord w arr bord (Suc i)) (KMP_pos w arr bord (Suc i))"
using not0_implies_Suc by (force+)
termination
by (relation "measures [λ(_, _ , compar, pos). pos,λ(_, _ , compar, pos). compar]", simp_all)
lemma KMP_len: "❙|KMP w arr bord pos❙| = ❙|arr❙| + pos"
by (induct w arr bord pos rule: KMP.induct, auto)
value[nbe] "KMP [a] [0] 0 0"
value "KMP [ 0::nat] [0] 0 0"
value "KMP [5,4,5,3,5,5::nat] [0] 0 5"
value "KMP [5,4::nat,5,3,5,5] [1,0] 1 4"
value "KMP [0,1,1,0::nat,0,0,1,1,1] [0] 0 8"
value "KMP [0::nat,1] [0] 0 1"
subsection ‹Verification of the computation›
definition KMP_valid :: "'a list ⇒ nat list ⇒ nat ⇒ nat ⇒ bool"
where "KMP_valid w arr bord pos = (❙|arr❙| + pos = ❙|w❙| ∧
pos + bord < ❙|w❙| ∧
take bord (drop pos w) ≤p (drop pos w) ∧
take bord (drop pos w) ≤s (drop pos w) ∧
(∀ v. v ≤b w!(pos - 1)#(drop pos w) ⟶ ❙|v❙| ≤ Suc bord) ∧
(∀ k < ❙|arr❙|. max_borderP (take (arr!k) (drop (pos + k) w)) (drop (pos + k) w))
)"
lemma " KMP_valid w arr bord pos ⟹ w ≠ ε"
unfolding KMP_valid_def
using le_antisym less_imp_le_nat less_not_refl2 take_Nil take_all_iff by metis
lemma KMP_valid_base: assumes "w ≠ ε" shows "KMP_valid w [0] 0 (❙|w❙|-1)"
proof (unfold KMP_valid_def, intro conjI)
show "❙|[0]❙| + (❙|w❙| - 1) = ❙|w❙|"
by (simp add: assms)
show "❙|w❙| - 1 + 0 < ❙|w❙|"
using ‹w ≠ ε› by simp
show "take 0 (drop (❙|w❙| - 1) w) ≤p drop (❙|w❙| - 1) w"
by simp
show "take 0 (drop (❙|w❙| - 1) w) ≤s drop (❙|w❙| - 1) w"
by simp
show "∀v. v ≤b w ! (❙|w❙| - 1 - 1) # drop (❙|w❙| - 1) w ⟶ ❙|v❙| ≤ Suc 0"
proof (rule allI, rule impI)
fix v assume b: "v ≤b w ! (❙|w❙| - 1 - 1) # drop (❙|w❙| - 1) w"
have "❙|w ! (❙|w❙| - 1 - 1) # drop (❙|w❙| - 1) w❙| = Suc (Suc 0)"
using ‹❙|[0]❙| + (❙|w❙| - 1) = ❙|w❙|› by auto
from border_len(3)[OF b, unfolded this]
show "❙|v❙| ≤ Suc 0"
using border_len(3)[OF b] by simp
qed
have "❙|w❙| - Suc 0 = ❙|butlast w❙|"
by simp
have all: "∀v. v ≤b [last w] ⟶ v ≤p ε"
by (meson borderedI sing_not_bordered)
have "butlast w ⋅ [last w] = w"
by (simp add: assms)
hence last: "drop (❙|w❙| - Suc 0) w = [last w]"
unfolding ‹❙|w❙| - Suc 0 = ❙|butlast w❙|› using drop_pref by metis
hence "max_borderP ε (drop (❙|w❙| - Suc 0) w)"
unfolding max_borderP_def using all by simp
thus "∀k<❙|[0]❙|. max_borderP (take ([0] ! k) (drop (❙|w❙| - 1 + k) w)) (drop (❙|w❙| - 1 + k) w)"
by simp
qed
lemma KMP_valid_step: assumes "KMP_valid w arr bord (Suc i)"
shows "KMP_valid w (KMP_arr w arr bord (Suc i)) (KMP_bord w arr bord (Suc i)) (KMP_pos w arr bord (Suc i))"
proof-
have all_k: "∀k<❙|arr❙|. max_borderP (take (arr ! k) (drop (Suc i + k) w)) (drop (Suc i + k) w)"
using assms[unfolded KMP_valid_def] by blast
have "❙|arr❙| + Suc i = ❙|w❙|" and
"Suc i + bord < ❙|w❙|" and
bord_pref: "take bord (drop (Suc i) w) ≤p drop (Suc i) w" and
bord_suf: "take bord (drop (Suc i) w) ≤s drop (Suc i) w" and
up_bord: "⋀ v. v ≤b w!i#(drop (Suc i) w) ⟹ ❙|v❙| ≤ Suc bord" and
all_k_neq0: "⋀ k. k < ❙|arr❙| ⟹ take (arr ! k) (drop (Suc i + k) w) = drop (Suc i + k) w ⟶ drop (Suc i + k) w = ε" and
all_k_pref: "⋀ k. k < ❙|arr❙| ⟹ take (arr ! k) (drop (Suc i + k) w) ≤p drop (Suc i + k) w" and
all_k_suf: "⋀ k. k < ❙|arr❙| ⟹ take (arr ! k) (drop (Suc i + k) w) ≤s drop (Suc i + k) w" and
all_k_v: "⋀ k v. k < ❙|arr❙| ⟹ v ≤b drop (Suc i + k) w ⟹ v ≤p take (arr ! k) (drop (Suc i + k) w)"
using assms[unfolded KMP_valid_def max_borderP_def diff_Suc_1] by blast+
have all_k_neq: "⋀ k. k < ❙|arr❙| ⟹ take (arr ! k) (drop (Suc i + k) w) ≠ drop (Suc i + k) w"
using ‹Suc i + bord < ❙|w❙|› ‹❙|arr❙| + Suc i = ❙|w❙|› all_k_neq0
add.commute add_le_imp_le_left drop_all_iff le_antisym less_imp_le_nat less_not_refl2 by metis
have "w ≠ ε"
using ‹❙|arr❙| + Suc i = ❙|w❙|› by auto
have "Suc i < ❙|w❙|"
using ‹Suc i + bord < ❙|w❙|› by simp
have pop_i: "drop i w = (w!i)# (drop (Suc i) w)"
by (simp add: Cons_nth_drop_Suc Suc_lessD ‹Suc i < ❙|w❙|›)
have "drop (Suc i) w ≠ ε"
using ‹Suc i < ❙|w❙|› by fastforce
have "Suc i + (❙|w❙| - Suc i - bord) = ❙|w❙| - bord"
unfolding diff_right_commute[of _ _ bord] using ‹Suc i + bord < ❙|w❙|› by linarith
show "KMP_valid w (KMP_arr w arr bord (Suc i)) (KMP_bord w arr bord (Suc i)) (KMP_pos w arr bord (Suc i))"
proof (cases "w ! i = w ! (❙|w❙| - Suc bord)")
assume match: "w ! i = w ! (❙|w❙| - Suc bord)"
show ?thesis
proof (unfold KMP_valid_def KMP_arr.simps KMP_bord.simps KMP_pos.simps if_P[OF match], intro conjI)
show "❙|Suc bord # arr❙| + i = ❙|w❙|"
using ‹❙|arr❙| + Suc i = ❙|w❙|› by auto
show "i + Suc bord < ❙|w❙|"
using ‹Suc i + bord < ❙|w❙|› by auto
show "take (Suc bord) (drop i w) ≤p drop i w"
using take_is_prefix by auto
show "take (Suc bord) (drop i w) ≤s drop i w"
using ‹take bord (drop (Suc i) w) ≤s drop (Suc i) w› ext_suf_Cons_take_drop match by blast
show all_k_new: "∀k<❙|Suc bord # arr❙|. max_borderP (take ((Suc bord # arr) ! k) (drop (i + k) w)) (drop (i + k) w)"
proof (rule allI, rule impI)
fix k assume "k < ❙|Suc bord # arr❙|"
show "max_borderP (take ((Suc bord # arr) ! k) (drop (i + k) w)) (drop (i + k) w)"
proof (cases "0 < k")
assume "0 < k"
thus ?thesis using all_k
by (metis Suc_less_eq ‹k < ❙|Suc bord # arr❙|› add.right_neutral add_Suc_shift gr0_implies_Suc list.size(4) nth_Cons_Suc)
next
assume "¬ 0 < k" hence "k = 0" by simp
show ?thesis
unfolding max_borderP_def ‹k = 0›
proof (intro conjI)
show "take ((Suc bord # arr) ! 0) (drop (i + 0) w) = drop (i + 0) w ⟶ drop (i + 0) w = ε"
using ‹i + Suc bord < ❙|w❙|› by fastforce
show "take ((Suc bord # arr) ! 0) (drop (i + 0) w) ≤p drop (i + 0) w"
using ‹take (Suc bord) (drop i w) ≤p drop i w› by auto
show "take ((Suc bord # arr) ! 0) (drop (i + 0) w) ≤s drop (i + 0) w"
by simp fact
show "∀v. v ≤b drop (i + 0) w ⟶ v ≤p take ((Suc bord # arr) ! 0) (drop (i + 0) w)"
proof (rule allI, rule impI)
fix v assume "v ≤b drop (i + 0) w" hence "v ≤b drop i w" by simp
from borderD_pref[OF this] up_bord[OF this[unfolded pop_i]]
show "v ≤p take ((Suc bord # arr) ! 0) (drop (i + 0) w)"
unfolding prefix_def by force
qed
qed
qed
qed
have "max_borderP (take (Suc bord) (drop i w)) (drop i w)"
using all_k_new[rule_format, of 0, unfolded length_Cons nth_Cons_0 add_0_right, OF zero_less_Suc].
from border_add_Cons_len[OF this] max_borderP_D_max[OF this] max_borderP_D_neq[OF _ this]
show "∀v. v ≤b w ! (i - 1) # drop i w ⟶ ❙|v❙| ≤ Suc (Suc bord)"
using nat_le_linear take_all take_len list.discI pop_i by metis
qed
next
assume mismatch: "w ! i ≠ w ! (❙|w❙| - Suc bord)"
show ?thesis
proof (cases "bord = 0")
assume "bord ≠ 0"
let ?k = "❙|w❙| - Suc i - bord" and
?w' = "drop (Suc i) w"
have "?k < ❙|arr❙|"
using ‹Suc i + bord < ❙|w❙|› ‹❙|arr❙| + Suc i = ❙|w❙|› ‹bord ≠ 0› by linarith
from all_k_neq[OF this]
have "arr ! ?k < bord"
by (simp add: ‹take (arr ! ?k) (drop (Suc i + ?k) w) ≠ drop (Suc i + ?k) w› ‹Suc i + ?k = ❙|w❙| - bord› ‹Suc i + bord < ❙|w❙|› add_diff_inverse_nat diff_add_inverse2 gr0I less_diff_conv nat_diff_split_asm )
let ?old_pref = "take bord ?w'" and
?old_suf = "drop (❙|w❙| - bord) w" and
?new_pref = "take (arr ! ?k) ?w'"
show ?thesis
proof (unfold KMP_valid_def KMP_arr.simps KMP_bord.simps KMP_pos.simps if_not_P[OF mismatch] if_not_P[OF ‹bord ≠ 0›] if_P[OF ‹arr ! ?k < bord›] diff_Suc_1, intro conjI)
show "❙|arr❙| + Suc i = ❙|w❙|"
using ‹❙|arr❙| + Suc i = ❙|w❙|› by auto
show "Suc i + arr ! ?k < ❙|w❙|"
using ‹Suc i + bord < ❙|w❙|› ‹arr ! ?k < bord› by linarith
show "take (arr ! ?k) (drop (Suc i) w) ≤p drop (Suc i) w"
using take_is_prefix by blast
have "?old_suf ≤s ?w'"
by (meson ‹Suc i + bord < ❙|w❙|› le_suf_drop less_diff_conv nat_less_le)
have "❙|?old_pref❙| = bord"
using ‹Suc i + bord < ❙|w❙|› take_len len_after_drop nat_less_le by blast
also have "... = ❙|?old_suf❙|"
using ‹Suc i + bord < ❙|w❙|› by simp
ultimately have eq1: "?old_pref = ?old_suf"
using ‹take bord (drop (Suc i) w) ≤s drop (Suc i) w› ‹drop (❙|w❙| - bord) w ≤s drop (Suc i) w› suf_ruler_eq_len by metis
have "❙|?new_pref❙| = arr!?k"
using take_len ‹Suc i + bord < ❙|w❙|› ‹arr ! ?k < bord› diff_diff_left by force
have "take (arr ! ?k) ?old_suf ≤p ?old_pref"
using take_is_prefix ‹?old_pref = ?old_suf› by metis
from pref_take[OF pref_trans[OF this take_is_prefix], unfolded ‹❙|?new_pref❙| = arr!?k›, symmetric]
have "take (arr ! ?k) ?old_suf = take (arr ! ?k) ?w'"
using take_len ‹arr ! ?k < bord› ‹bord = ❙|drop (❙|w❙| - bord) w❙|› less_imp_le_nat by metis
from all_k_suf[OF ‹?k < ❙|arr❙|›, unfolded ‹Suc i + ?k = ❙|w❙| - bord›] this
have "take (arr ! ?k) ?w' ≤s ?old_suf" by simp
with ‹?old_pref ≤s ?w'›[unfolded ‹?old_pref = ?old_suf›]
show "take (arr ! ?k) ?w' ≤s ?w'"
using suf_trans by blast
have "?old_pref ≠ ε"
using ‹bord ≠ 0› ‹❙|?old_pref❙| = bord› by force
moreover have "?old_pref ≠ ?w'"
using ‹Suc i + bord < ❙|w❙|›
by (intro lenarg_not, unfold length_drop ‹❙|take bord ?w'❙| = bord›, linarith)
ultimately have "?old_pref ≤b ?w'"
by (intro borderI[OF bord_pref bord_suf])
show "∀v. v ≤b w !i # ?w' ⟶ ❙|v❙| ≤ Suc (arr ! ?k)"
proof (rule allI,rule impI)
have extendable: "w ! i # v' ≤b w ! i # ?w' ⟹ v' ≠ ε ⟹ ❙|v'❙| ≤ arr ! ?k" for v'
proof-
assume "w!i # v' ≤b w!i # ?w'" and "v' ≠ ε"
from suf_trans[OF borderD_suf[OF ‹w!i # v' ≤b w ! i # ?w'›, folded pop_i] suffix_drop]
have "w!i # v' ≤s w".
from this[unfolded suf_drop_conv, THEN nth_via_drop] mismatch
have "❙|w!i # v'❙| ≠ Suc bord"
by force
with up_bord[OF ‹w!i # v' ≤b w ! i # ?w'›]
have "❙|v'❙| < bord"
by simp
from border_ConsD(2)[OF ‹w!i # v' ≤b w ! i # ?w'› ‹v' ≠ ε›]
have "v' ≤b ?w'".
from borders_compare[OF ‹?old_pref ≤b ?w'› this, unfolded ‹❙|?old_pref❙| = bord›, unfolded ‹?old_pref = ?old_suf›, OF ‹❙|v'❙| < bord›]
have "v' ≤b ?old_suf".
from prefix_length_le[OF max_borderP_D_max[OF all_k[rule_format, OF ‹?k < ❙|arr❙|›], unfolded ‹Suc i + ?k = ❙|w❙| - bord›, OF this]]
show "❙|v'❙| ≤ arr!?k"
using len_take1[of "arr!?k", of w] by simp
qed
fix v assume "v ≤b w!i # ?w'"
show "❙|v❙| ≤ Suc (arr ! ?k)"
proof (cases "❙|v❙| ≤ Suc 0")
assume "¬ ❙|v❙| ≤ Suc 0" hence "Suc 0 < ❙|v❙|" by simp
from hd_tl_longE[OF this]
obtain a v' where "v = a#v'" and "v' ≠ ε"
by blast
with borderD_pref[OF ‹v ≤b w!i # ?w'›, unfolded prefix_Cons]
have "v = w!i#v'"
by simp
from extendable[OF ‹v ≤b w!i # ?w'›[unfolded ‹v = w!i#v'›] ‹v' ≠ ε›]
show ?thesis
by (simp add: ‹v = a # v'›)
qed simp
qed
show " ∀k<❙|arr❙|. max_borderP (take (arr ! k) (drop (Suc i + k) w)) (drop (Suc i + k) w)"
using all_k by blast
qed
next
assume "bord = 0"
show ?thesis
proof (unfold KMP_valid_def KMP_arr.simps KMP_bord.simps KMP_pos.simps if_not_P[OF mismatch] if_P[OF ‹bord = 0›], intro conjI)
show "❙|0 # arr❙| + i = ❙|w❙|"
using ‹❙|arr❙| + Suc i = ❙|w❙|› by auto
show "i + 0 < ❙|w❙|"
by (simp add: Suc_lessD ‹Suc i < ❙|w❙|›)
show "take 0 (drop i w) ≤p drop i w"
by simp
show "take 0 (drop i w) ≤s drop i w"
using ext_suf_Cons_take_drop by simp
have "max_borderP ε (drop i w)"
proof(rule ccontr)
assume "¬ max_borderP ε (drop i w)"
then obtain a t where "max_borderP (a#t) (drop i w)"
unfolding pop_i using max_border_ex[of "w ! i # drop (Suc i) w"] neq_Nil_conv by metis
from up_bord[OF max_borderP_border[OF this list.simps(3), unfolded pop_i], unfolded ‹bord = 0›]
have "t = ε" by simp
from max_borderP_border[OF ‹max_borderP (a#t) (drop i w)›[unfolded this] list.simps(3)]
have "[a] ≤b drop i w".
from borderD_pref[OF this]
have "w!i = a"
by (simp add: pop_i)
moreover have "w!(❙|w❙| - 1) = a"
using borderD_suf[OF ‹[a] ≤b drop i w›] nth_via_drop sing_len suf_drop_conv suf_share_take suffix_drop suffix_length_le by metis
ultimately show False
using mismatch[unfolded ‹bord = 0›] by simp
qed
thus "∀v. v ≤b w ! (i - 1) # drop i w ⟶ ❙|v❙| ≤ Suc 0"
by (metis border_add_Cons_len list.size(3))
show "∀k<❙|0 # arr❙|. max_borderP (take ((0 # arr) ! k) (drop (i + k) w)) (drop (i + k) w)"
proof (rule allI, rule impI)
fix k assume "k < ❙|0 # arr❙|"
show "max_borderP (take ((0 # arr) ! k) (drop (i + k) w)) (drop (i + k) w)"
proof (cases "0 < k")
assume "0 < k"
thus ?thesis using all_k
by (metis Suc_less_eq ‹k < ❙|0 # arr❙|› add.right_neutral add_Suc_shift gr0_implies_Suc list.size(4) nth_Cons_Suc)
next
assume "¬ 0 < k" hence "k = 0" by simp
thus ?thesis
using ‹max_borderP ε (drop i w)› by auto
qed
qed
qed
qed
qed
qed
lemma KMP_valid_max: assumes "KMP_valid w arr bord pos" "k < ❙|w❙|"
shows "max_borderP (take ((KMP w arr bord pos)!k) (drop k w)) (drop k w)"
using assms
proof (induct w arr bord pos arbitrary: k rule: KMP.induct)
case (2 w arr bord i)
then show ?case
unfolding KMP.simps using KMP_valid_step by blast
qed (simp add: KMP_valid_def)
section ‹Border array›
fun border_array :: "'a list ⇒ nat list" where
"border_array ε = ε"
| "border_array (a#w) = rev (KMP (rev (a#w)) [0] 0 (❙|a#w❙|-1))"
lemma border_array_len: "❙|border_array w❙| = ❙|w❙|"
by (induct w, simp_all add: KMP_len)
theorem bord_array: assumes "Suc k ≤ ❙|w❙|" shows "(border_array w)!k = ❙|max_border (take (Suc k) w)❙|"
proof-
define m where "m = ❙|w❙| - Suc k"
hence "m < ❙|rev w❙|"
by (simp add: Suc_diff_Suc assms less_eq_Suc_le)
have "rev w ≠ ε" and "k < ❙|rev w❙|"
using ‹Suc k ≤ ❙|w❙|› by auto
hence "w = hd w#tl w"
by simp
from arg_cong[OF border_array.simps(2)[of "hd w" "tl w", folded this], of rev, unfolded rev_rev_ident]
have "rev (border_array w) = (KMP (rev w) [0] 0 (❙|w❙|-1))".
hence "max_borderP (take (rev (border_array w)!m) (drop m (rev w))) (drop m (rev w))"
using KMP_valid_max[rule_format, OF KMP_valid_base[OF ‹rev w ≠ ε›] ‹m < ❙|rev w❙|›] by simp
hence "max_border (drop m (rev w)) = take (rev (border_array w)!m) (drop m (rev w))"
using max_borderP_max_border by blast
hence "❙|max_border (drop m (rev w))❙| = rev (border_array w)!m"
by (metis ‹m < ❙|rev w❙|› drop_all_iff leD max_border_nemp_neq nat_le_linear take_all take_len)
thus ?thesis
using m_def
by (metis Suc_diff_Suc ‹k < ❙|rev w❙|› ‹m < ❙|rev w❙|› border_array_len diff_diff_cancel drop_rev length_rev less_imp_le_nat max_border_len_rev rev_nth)
qed
lemma max_border_comp [code]: "max_border w = take ((border_array w)!(❙|w❙|-1)) w"
proof (cases "w = ε")
assume "w = ε"
thus "max_border w = take ((border_array w)!(❙|w❙|-1)) w"
using max_bord_take take_Nil by metis
next
assume "w ≠ ε"
hence "Suc (❙|w❙| - 1) ≤ ❙|w❙|" by simp
from bord_array[OF this]
have "(border_array w)!(❙|w❙|-1) = ❙|max_border w❙|"
by (simp add: ‹w ≠ ε›)
thus "max_border w = take ((border_array w)!(❙|w❙|-1)) w"
using max_bord_take by auto
qed
value[nbe] "primitive [a,b,a]"
value "primitive [0,1,0::nat]"
value "border_array [5,4,5,3,5,5,5,4,5::nat]"
value "primitive [5,4,5,3,5,5,5,4,5::nat]"
value "primitive [5,4,5,3,5,5,5,4,5::nat]"
value[nbe] "bordered []"
value "border_array [0,1,1,0,0,0,1,1,1,1,1,0,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1,1,1,0,0,0,1,1,1,0,1,1,0,0,0,1,1,1,0,1,1,0,0,0,1,1,1,0,0,1,0::nat]"
value[nbe] "border_array ε"
value "border_array [1,0,1,0,1,1,0,0::nat]"
value "max_border [1,0,1,0,1,1,0,0,1,0,1,1,0,1,0,1,1,0,0,1,0,1,1,0,1,0,1,1,0,0,1,0,1,0,0,1::nat]"
thm max_border_comp
value "bordered [1,0::nat,1,0,1,1,0,1]"
value "π [1::nat,0,1,0,1,1,0,1]"
thm min_per_root_take
value "❙|π [1::nat,0,1,0,1,1,0,1]❙|"
value "ρ [1::nat,0,1,1,0,1,1,0,1]"
thm primroot_code
value "ρ [1::nat,0,1,1,0,1,1,0]"
value[nbe] "π ε"
end