Theory Rotated_Substring
theory Rotated_Substring
imports Nat_Mod_Helper
begin
section "Rotated Sublists"
definition is_sublist :: "'a list ⇒ 'a list ⇒ bool"
where
"is_sublist xs ys = (∃as bs. xs = as @ ys @ bs)"
definition is_rot_sublist :: "'a list ⇒ 'a list ⇒ bool"
where
"is_rot_sublist xs ys = (∃n. is_sublist (rotate n xs) ys)"
definition inc_one_bounded :: "nat ⇒ nat list ⇒ bool"
where
"inc_one_bounded n xs ≡
(∀i. Suc i < length xs ⟶ xs ! Suc i = Suc (xs ! i) mod n) ∧
(∀i < length xs. xs ! i < n)"
lemma inc_one_boundedD:
"⟦inc_one_bounded n xs; Suc i < length xs⟧ ⟹ xs ! Suc i = Suc (xs ! i) mod n"
"⟦inc_one_bounded n xs; i < length xs⟧ ⟹ xs ! i < n"
using inc_one_bounded_def by blast+
lemma inc_one_bounded_nth_plus:
"⟦inc_one_bounded n xs; i + k < length xs⟧ ⟹ xs ! (i + k) = (xs ! i + k) mod n"
proof (induct k)
case 0
then show ?case
by (simp add: inc_one_boundedD(2))
next
case (Suc k)
then show ?case
by (metis Suc_lessD add_Suc_right inc_one_bounded_def mod_Suc_eq)
qed
lemma inc_one_bounded_neq:
"⟦inc_one_bounded n xs; length xs ≤ n; i + k < length xs; k ≠ 0⟧ ⟹ xs ! (i + k) ≠ xs ! i"
using inc_one_bounded_nth_plus nat_mod_add_neq_self
by (simp add: inc_one_boundedD(2) linorder_not_le)
corollary inc_one_bounded_neq_nth:
assumes "inc_one_bounded n xs"
and "length xs ≤ n"
and "i < length xs"
and "j < length xs"
and "i ≠ j"
shows "xs ! i ≠ xs ! j"
proof (cases "i < j")
assume "i < j"
then show ?thesis
by (metis assms(1,2,4) canonically_ordered_monoid_add_class.lessE inc_one_bounded_neq)
next
assume "¬ i < j"
then show ?thesis
by (metis assms(1,2,3,5) canonically_ordered_monoid_add_class.lessE inc_one_bounded_neq
le_neq_implies_less linorder_not_le)
qed
lemma inc_one_bounded_distinct:
"⟦inc_one_bounded n xs; length xs ≤ n⟧ ⟹ distinct xs"
using distinct_conv_nth inc_one_bounded_neq_nth by blast
lemma inc_one_bounded_subset_upt:
"⟦inc_one_bounded n xs; length xs ≤ n⟧ ⟹ set xs ⊆ {0..<n}"
by (metis atLeastLessThan_iff in_set_conv_nth inc_one_boundedD(2) less_eq_nat.simps(1)
subset_code(1))
lemma inc_one_bounded_consD:
"inc_one_bounded n (x # xs) ⟹ inc_one_bounded n xs"
unfolding inc_one_bounded_def
using bot_nat_0.not_eq_extremum lessI less_zeroE mod_less_divisor by fastforce
lemma inc_one_bounded_nth:
"⟦inc_one_bounded n xs; i < length xs⟧ ⟹ xs ! i = ((λx. Suc x mod n)^^i) (xs ! 0)"
proof (induct i)
case 0
then show ?case
by simp
next
case (Suc i)
note IH = this
from IH
have "xs ! i = ((λx. Suc x mod n) ^^ i) (xs ! 0)"
by simp
hence "Suc (xs ! i) mod n = ((λx. Suc x mod n) ^^ Suc i) (xs ! 0)"
by force
moreover
from inc_one_boundedD(1)[OF IH(2,3)]
have "xs ! Suc i = Suc (xs ! i) mod n".
ultimately show ?case
by presburger
qed
lemma inc_one_bounded_nth_le:
"⟦inc_one_bounded n xs; i < length xs; (xs ! 0) + i < n⟧ ⟹
xs ! i = (xs ! 0) + i"
by (metis add_cancel_right_left inc_one_bounded_nth_plus mod_if)
lemma inc_one_bounded_upt1:
assumes "inc_one_bounded n xs"
and "length xs = Suc k"
and "Suc k ≤ n"
and "(xs ! 0) + k < n"
shows "xs = [xs ! 0..<(xs ! 0) + Suc k]"
proof (intro list_eq_iff_nth_eq[THEN iffD2] conjI impI allI)
show "length xs = length [xs ! 0..<xs ! 0 + Suc k]"
using assms(2) by force
next
fix i
assume "i < length xs"
hence "[xs ! 0..<xs ! 0 + Suc k] ! i = xs ! 0 + i"
by (metis add_less_cancel_left assms(2) nth_upt)
moreover
have "xs ! 0 + i < n"
using ‹i < length xs› assms(2,4) by linarith
with inc_one_bounded_nth_le[OF assms(1) ‹i < length xs›]
have "xs ! i = xs ! 0 + i"
by simp
ultimately show "xs ! i = [xs ! 0..<xs ! 0 + Suc k] ! i"
by presburger
qed
lemma inc_one_bounded_upt2:
assumes "inc_one_bounded n xs"
and "length xs = Suc k"
and "Suc k ≤ n"
and "n ≤ (xs ! 0) + k"
shows "xs = [xs ! 0..<n] @ [0..<(xs ! 0) + Suc k - n]"
proof (intro list_eq_iff_nth_eq[THEN iffD2] conjI impI allI)
show "length xs = length ([xs ! 0..<n] @ [0..<xs ! 0 + Suc k - n])"
using assms(1) assms(2) assms(4) inc_one_boundedD(2) less_or_eq_imp_le by auto
next
fix i
assume "i < length xs"
show "xs ! i = ([xs ! 0..<n] @ [0..<xs ! 0 + Suc k - n]) ! i"
proof (cases "i < length [xs ! 0..<n]")
assume "i < length [xs ! 0..<n]"
hence "([xs ! 0..<n] @ [0..<xs ! 0 + Suc k - n]) ! i = [xs ! 0..<n] ! i"
by (meson nth_append)
moreover
have "[xs ! 0..<n] ! i = xs ! 0 + i"
using ‹i < length [xs ! 0..<n]› by force
moreover
have "xs ! 0 + i < n"
using ‹i < length [xs ! 0..<n]› by auto
with inc_one_bounded_nth_le[OF assms(1) ‹i < length xs›]
have "xs ! i = xs ! 0 + i"
by blast
ultimately show "xs ! i = ([xs ! 0..<n] @ [0..<xs ! 0 + Suc k - n]) ! i"
by simp
next
assume "¬ i < length [xs ! 0..<n]"
hence "([xs ! 0..<n] @ [0..<xs ! 0 + Suc k - n]) ! i =
[0..<xs ! 0 + Suc k - n] ! (i - length [xs ! 0..<n] )"
by (meson nth_append)
moreover
have "[0..<xs ! 0 + Suc k - n] ! (i - length [xs ! 0..<n]) = i - (n - xs ! 0)"
using ‹i < length xs› add_0 assms(2) assms(4) by fastforce
moreover
{
have "i < n"
using ‹i < length xs› assms(2) assms(3) by linarith
moreover
from inc_one_boundedD(2)[OF assms(1), of 0]
have "xs ! 0 < n"
by (simp add: assms(2))
moreover
have "n - xs ! 0 ≤ i"
using ‹¬ i < length [xs ! 0..<n]› by force
ultimately have "xs ! i = i - (n - xs ! 0)"
using not_mod_a_pl_b_eq2[of n "xs ! 0" i]
inc_one_bounded_nth_plus[OF assms(1), of 0 i, simplified, OF ‹i < length xs›]
by presburger
}
ultimately show "xs ! i = ([xs ! 0..<n] @ [0..<xs ! 0 + Suc k - n]) ! i"
by argo
qed
qed
lemmas inc_one_bounded_upt = inc_one_bounded_upt1 inc_one_bounded_upt2
lemma is_rot_sublist_nil:
"is_rot_sublist xs []"
by (metis append_Nil is_rot_sublist_def is_sublist_def)
lemma rotate_upt:
"m ≤ n ⟹ rotate m [0..<n] = [m..<n] @ [0..<m]"
by (metis diff_zero le_Suc_ex length_upt rotate_append upt_add_eq_append zero_order(1))
lemma inc_one_bounded_is_rot_sublist:
assumes "inc_one_bounded n xs" "length xs ≤ n"
shows "is_rot_sublist [0..<n] xs"
unfolding is_rot_sublist_def is_sublist_def
proof (cases "length xs")
case 0
then show "∃na as bs. rotate na [0..<n] = as @ xs @ bs"
using append_Nil by blast
next
case (Suc k)
hence "Suc k ≤ n"
using assms(2) by auto
have "(xs ! 0) + k < n ⟹ ∃na as bs. rotate na [0..<n] = as @ xs @ bs"
proof -
assume "(xs ! 0) + k < n"
with inc_one_bounded_upt(1)[OF assms(1) Suc ‹Suc k ≤ n›]
have "xs = [xs ! 0..<xs ! 0 + Suc k]"
by blast
moreover
have "xs ! 0 + Suc k ≤ n"
by (simp add: Suc_leI ‹xs ! 0 + k < n›)
with upt_add_eq_append[of "xs ! 0" "xs ! 0 + Suc k" "n - (xs ! 0 + Suc k)"]
have "[xs ! 0..<n] = [xs ! 0..<xs ! 0 + Suc k] @ [xs ! 0 + Suc k..<n]"
by (metis le_add1 le_add_diff_inverse)
with upt_add_eq_append[of 0 "xs ! 0" "n - xs ! 0"]
have "[0..<n] = [0..<xs ! 0] @ [xs ! 0..<xs ! 0 + Suc k] @ [xs ! 0 + Suc k..<n]"
using ‹xs ! 0 + Suc k ≤ n› by fastforce
ultimately show ?thesis
by (metis append.right_neutral append_Nil rotate_append)
qed
moreover
have "¬ (xs ! 0) + k < n ⟹ ∃na as bs. rotate na [0..<n] = as @ xs @ bs"
proof -
assume "¬ (xs ! 0) + k < n"
hence "(xs ! 0) + k ≥ n"
by simp
with inc_one_bounded_upt(2)[OF assms(1) Suc ‹Suc k ≤ n›]
have "xs = [xs ! 0..<n] @ [0..<xs ! 0 + Suc k - n]"
by blast
moreover
from inc_one_boundedD(2)[OF assms(1), of 0]
have "xs ! 0 < n"
by (simp add: Suc)
with rotate_upt[of "xs ! 0" n]
have "rotate (xs ! 0) [0..<n] = [xs ! 0..<n] @ [0..<xs ! 0]"
by linarith
moreover
{
have "0 ≤ xs ! 0 + Suc k - n"
by simp
hence "[0..<xs ! 0 + Suc k - n + (n - Suc k)] =
[0..<xs ! 0 + Suc k - n] @ [xs ! 0 + Suc k - n..<xs ! 0 + Suc k - n + (n - Suc k)]"
using upt_add_eq_append[of 0 "xs ! 0 + Suc k - n" "n - Suc k"] by blast
moreover
have "xs ! 0 = xs ! 0 + Suc k - n + (n - Suc k)"
using ‹Suc k ≤ n› ‹n ≤ xs ! 0 + k› by auto
ultimately have "[0..<xs ! 0] = [0..<xs ! 0 + Suc k - n] @ [xs ! 0 + Suc k - n..<xs ! 0]"
by argo
}
ultimately show ?thesis
by (metis append.assoc append_Nil)
qed
ultimately show "∃na as bs. rotate na [0..<n] = as @ xs @ bs"
by blast
qed
lemma is_rot_sublist_idx:
"is_rot_sublist [0..<length xs] ys ⟹ is_rot_sublist xs (map ((!) xs) ys)"
unfolding is_rot_sublist_def is_sublist_def
proof (elim exE)
fix n as bs
assume "rotate n [0..<length xs] = as @ ys @ bs"
hence "rotate n xs = map ((!) xs) (as @ ys @ bs)"
by (metis map_nth rotate_map)
then show "∃n as bs. rotate n xs = as @ map ((!) xs) ys @ bs"
by auto
qed
lemma is_rot_sublist_upt_eq_upt_hd:
"⟦is_rot_sublist [0..<Suc n] ys; length ys = Suc n; ys ! 0 = 0⟧ ⟹ ys = [0..<Suc n]"
unfolding is_rot_sublist_def is_sublist_def
proof (elim exE)
fix m as bs
assume A: "length ys = Suc n" "ys ! 0 = 0" "rotate m [0..<Suc n] = as @ ys @ bs"
with rotate_conv_mod[of m "[0..<Suc n]"]
have "rotate (m mod length [0..<Suc n]) [0..<Suc n] = as @ ys @ bs"
by simp
with rotate_upt[of "m mod length [0..<Suc n]" "Suc n"]
have "[m mod length [0..<Suc n]..<Suc n] @ [0..<m mod length [0..<Suc n]] = as @ ys @ bs"
by (metis diff_zero le_Suc_eq length_upt mod_Suc_le_divisor)
hence "[m mod Suc n..<Suc n] @ [0..<m mod Suc n] = as @ ys @ bs"
by simp
moreover
have "as = []"
by (metis A(1) A(3) diff_zero length_append length_greater_0_conv length_rotate length_upt
less_add_same_cancel2 not_add_less1)
moreover
have "bs = []"
by (metis A(1) A(3) append.right_neutral append_eq_append_conv calculation(2) diff_zero
length_rotate length_upt self_append_conv2)
moreover
have "m mod Suc n = 0"
by (metis A add.right_neutral append.right_neutral calculation(2,3) diff_zero length_rotate
mod_less_divisor nth_rotate nth_upt self_append_conv2 zero_le zero_less_Suc
ordered_cancel_comm_monoid_diff_class.add_diff_inverse)
ultimately show "ys = [0..<Suc n]"
by simp
qed
lemma is_rot_sublist_upt_eq_upt_last:
"⟦is_rot_sublist [0..<Suc n] ys; length ys = Suc n; ys ! n = n⟧ ⟹ ys = [0..<Suc n]"
unfolding is_rot_sublist_def is_sublist_def
proof (elim exE)
fix m as bs
assume A: "length ys = Suc n" "ys ! n = n" "rotate m [0..<Suc n] = as @ ys @ bs"
with rotate_conv_mod[of m "[0..<Suc n]"]
have "rotate (m mod length [0..<Suc n]) [0..<Suc n] = as @ ys @ bs"
by simp
with rotate_upt[of "m mod length [0..<Suc n]" "Suc n"]
have "[m mod length [0..<Suc n]..<Suc n] @ [0..<m mod length [0..<Suc n]] = as @ ys @ bs"
by (metis diff_zero le_Suc_eq length_upt mod_Suc_le_divisor)
hence "[m mod Suc n..<Suc n] @ [0..<m mod Suc n] = as @ ys @ bs"
by simp
moreover
have "as = []"
by (metis A(1) A(3) diff_zero length_append length_greater_0_conv length_rotate length_upt
less_add_same_cancel2 not_add_less1)
moreover
have "bs = []"
by (metis A(1) A(3) append.right_neutral append_eq_append_conv calculation(2) diff_zero
length_rotate length_upt self_append_conv2)
moreover
from list_eq_iff_nth_eq[THEN iffD1, OF calculation(1), simplified,
simplified calculation(2,3), simplified]
have "Suc n = length ys" "∀i<Suc n. ([m mod Suc n..<n] @ n # [0..<m mod Suc n]) ! i = ys ! i"
by blast+
hence "([m mod Suc n..<n] @ n # [0..<m mod Suc n]) ! n = n"
by (simp add: A(2))
with nth_append[of "[m mod Suc n..<n]" "n # [0..<m mod Suc n]" n]
have "n < length [m mod Suc n..<n] ∨
(n # [0..<m mod Suc n]) ! (n - length [m mod Suc n..<n]) = n"
by argo
hence "m mod Suc n = 0"
proof
assume "n < length [m mod Suc n..<n]"
then show "m mod Suc n = 0"
by simp
next
assume B: "(n # [0..<m mod Suc n]) ! (n - length [m mod Suc n..<n]) = n"
show "m mod Suc n = 0"
proof (cases "n - length [m mod Suc n..<n]")
case 0
then show ?thesis
by simp
next
case (Suc x)
then show ?thesis
by (metis B One_nat_def add_Suc diff_diff_cancel length_upt lessI mod_Suc_le_divisor
mod_less_divisor nless_le nth_Cons_Suc nth_upt plus_1_eq_Suc zero_less_Suc)
qed
qed
ultimately show "ys = [0..<Suc n]"
by simp
qed
end