Theory Sequence_Toolkit

section ‹ Sequence Toolkit ›

theory Sequence_Toolkit
  imports Number_Toolkit
begin

subsection ‹ Conversion ›

text ‹ We define a number of coercions for mapping a list to finite function. ›

abbreviation rel_of_list :: "'a list ⇒ nat ↔ 'a" ("[_]s") where
"rel_of_list xs ≡ [list_pfun xs]⇸"

abbreviation seq_nth ("_'(_')s" [999,0] 999) where
"seq_nth xs i ≡ xs ! (i - 1)"

declare [[coercion list_ffun]]
declare [[coercion list_pfun]]
declare [[coercion rel_of_list]]
declare [[coercion seq_nth]]

subsection ‹ Number range›

lemma number_range: "{i..j} = {k :: ℤ. i ≤ k ∧ k ≤ j}"
  by (auto)

text ‹ The number range from $i$ to $j$ is the set of all integers greater than or equal to $i$, 
  which are also less than or equal to $j$.›

subsection ‹ Iteration ›

definition iter :: "ℤ ⇒ ('X ↔ 'X) ⇒ ('X ↔ 'X)" where
"iter n R = (if (n ≥ 0) then R ^^ (nat n) else (R∼) ^^ (nat n))"

lemma iter_eqs:
  "iter 0 r = Id"
  "n ≥ 0 ⟹ iter (n + 1) r = r ; (iter n r)"
  "n < 0 ⟹ iter (n + 1) r = iter n (r∼)"
  by (simp_all add: iter_def, metis Suc_nat_eq_nat_zadd1 add.commute relpow.simps(2) relpow_commute)

subsection ‹ Number of members of a set ›

lemma size_rel_of_list: 
  "#xs = length xs" 
  by simp

subsection ‹ Minimum ›

text ‹ Implemented by the function @{const Min}. ›

subsection ‹ Maximum ›

text ‹ Implemented by the function @{const Max}. ›

subsection ‹ Finite sequences ›

definition "seq A = lists A"

lemma seq_iff [simp]: "xs ∈ seq A ⟷ set xs ⊆ A"
  by (simp add: in_lists_conv_set seq_def subset_code(1))
  
lemma seq_ffun_set: "range list_ffun = {f :: ℕ ⇻ 'X. dom(f) = {1..#f}}"
  by (simp add: range_list_ffun, force)

subsection ‹ Non-empty finite sequences ›

definition "seq1 A = seq A - {[]}"

lemma seq1_iff [simp]: "xs ∈ seq1(A) ⟷ (xs ∈ seq A ∧ #xs > 0)"
  by (simp add: seq1_def)

subsection ‹ Injective sequences ›

definition "iseq A = seq A ∩ Collect distinct"

lemma iseq_iff [simp]: "xs ∈ iseq(A) ⟷ (xs ∈ seq A ∧ distinct xs)"
  by (simp add: iseq_def)

subsection ‹ Bounded sequences ›

definition bseq :: "ℕ ⇒ 'a set ⇒ 'a list set" ("bseq[_]") where
"bseq n A = bounded_lists n A"

(* Proof that this corresponds to the Z definition required *)

subsection ‹ Sequence brackets ›

text ‹ Provided by the HOL list notation @{term "[x, y, z]"}. ›

subsection ‹ Concatenation ›

text ‹ Provided by the HOL concatenation operator @{term "(@)"}. ›

subsection ‹ Reverse ›

text ‹ Provided by the HOL function @{const rev}. ›

subsection ‹ Head of a sequence ›

definition head :: "'a list ⇸ 'a" where
"head = (λ xs :: 'a list | #xs > 0 ∙ hd xs)"

lemma dom_head: "dom head = {xs. #xs > 0}"
  by (simp add: head_def)

lemma head_app: "#xs > 0 ⟹ head xs = hd xs"
  by (simp add: head_def)

lemma head_z_def: "xs ∈ seq1(A) ⟹ head xs = xs 1"
  by (simp add: hd_conv_nth head_app seq1_def)

subsection ‹ Last of a sequence ›

definition slast :: "'a list ⇸ 'a" where
"slast = (λ xs :: 'a list | #xs > 0 ∙ List.last xs)"

lemma dom_last: "dom slast = {xs. #xs > 0}"
  by (simp add: slast_def)

lemma slast_app: "#xs > 0 ⟹ slast xs = last xs"
  by (simp add: slast_def)

lemma slast_eq: "#s > 0 ⟹ last s = s (#s)"
  by (simp add: slast_app last_conv_nth)

subsection ‹ Tail of a sequence ›

definition tail :: "'a list ⇸ 'a list" where
"tail = (λ xs :: 'a list | #xs > 0 ∙ tl xs)"

lemma dom_tail: "dom tail = {xs. #xs > 0}"
  by (simp add: tail_def)

lemma tail_app: "#xs > 0 ⟹ tail xs = tl xs"
  by (simp add: tail_def)

subsection ‹ Domain ›

definition dom_seq :: "'a list ⇒ ℕ set" where
[simp]: "dom_seq xs = {0..<#xs}"

adhoc_overloading dom ⇌ dom_seq

subsection ‹ Range ›

definition ran_seq :: "'a list ⇒ 'a set" where
[simp]: "ran_seq xs = set xs"

adhoc_overloading ran ⇌ ran_seq

subsection ‹ Filter ›

notation seq_filter (infix "↾" 80)

lemma seq_filter_Nil: "[] ↾ V = []" by simp

lemma seq_filter_append: "(s @ t) ↾ V = (s ↾ V) @ (t ↾ V)" 
  by (simp add: seq_filter_append)

lemma seq_filter_subset_iff: "ran s ⊆ V ⟷ (s ↾ V = s)"
  by (auto simp add: seq_filter_def subsetD, meson filter_id_conv)

lemma seq_filter_empty: "s ↾ {} = []" by simp

lemma seq_filter_size: "#(s ↾ V) ≤ #s"
  by (simp add: seq_filter_def)

lemma seq_filter_twice: "(s ↾ V) ↾ W = s ↾ (V ∩ W)" by simp

subsection ‹ Examples ›

lemma "([1,2,3] ; (λ x ∙ x + 1)) 1 = 2"
  by (simp add: pfun_graph_comp[THEN sym] list_pfun_def pcomp_pabs)

end