Theory Infinite_Sequence

section ‹ Infinite Sequences ›

theory Infinite_Sequence
imports
  HOL.Real
  List_Extra
  "HOL-Library.Sublist"
  "HOL-Library.Nat_Bijection"
begin

typedef 'a infseq = "UNIV :: (nat ⇒ 'a) set"
  by (auto)

setup_lifting type_definition_infseq

definition ssubstr :: "nat ⇒ nat ⇒ 'a infseq ⇒ 'a list" where
"ssubstr i j xs = map (Rep_infseq xs) [i ..< j]"

lift_definition nth_infseq :: "'a infseq ⇒ nat ⇒ 'a" (infixl "!s" 100)
is "λ f i. f i" .

abbreviation sinit :: "nat ⇒ 'a infseq ⇒ 'a list" where
"sinit i xs ≡ ssubstr 0 i xs"

lemma sinit_len [simp]:
  "length (sinit i xs) = i"
  by (simp add: ssubstr_def)

lemma sinit_0 [simp]: "sinit 0 xs = []"
  by (simp add: ssubstr_def)

lemma prefix_upt_0 [intro]:
  "i ≤ j ⟹ prefix [0..<i] [0..<j]"
  by (induct i, simp, metis append_prefixD le0 prefix_order.lift_Suc_mono_le prefix_order.order_refl upt_Suc)

lemma sinit_prefix:
  "i ≤ j ⟹ prefix (sinit i xs) (sinit j xs)"
  by (simp add: map_mono_prefix prefix_upt_0 ssubstr_def)

lemma sinit_strict_prefix:
  "i < j ⟹ strict_prefix (sinit i xs) (sinit j xs)"
  by (metis sinit_len sinit_prefix le_less nat_neq_iff prefix_order.dual_order.strict_iff_order)

lemma nth_sinit:
  "i < n ⟹ sinit n xs ! i = xs !s i"
  apply (unfold ssubstr_def)
  apply (transfer, auto)
  done

lemma sinit_append_split:
  assumes "i < j"
  shows "sinit j xs = sinit i xs @ ssubstr i j xs"
proof -
  have "[0..<i] @ [i..<j] = [0..<j]"
    by (metis assms le0 le_add_diff_inverse le_less upt_add_eq_append)
  thus ?thesis
    by (simp add: ssubstr_def, transfer, simp add: map_append[THEN sym])
qed

lemma sinit_linear_asym_lemma1:
  assumes "asym R" "i < j" "(sinit i xs, sinit i ys) ∈ lexord R" "(sinit j ys, sinit j xs) ∈ lexord R"
  shows False
proof -
  have sinit_xs: "sinit j xs = sinit i xs @ ssubstr i j xs"
    by (metis assms(2) sinit_append_split)
  have sinit_ys: "sinit j ys = sinit i ys @ ssubstr i j ys"
    by (metis assms(2) sinit_append_split)
  from sinit_xs sinit_ys assms(4)
  have "(sinit i ys, sinit i xs) ∈ lexord R ∨ (sinit i ys = sinit i xs ∧ (ssubstr i j ys, ssubstr i j xs) ∈ lexord R)"
    by (auto dest: lexord_append)
  with assms lexord_asymmetric show False
    by (force)
qed

lemma sinit_linear_asym_lemma2:
  assumes "asym R" "(sinit i xs, sinit i ys) ∈ lexord R" "(sinit j ys, sinit j xs) ∈ lexord R"
  shows False
proof (cases i j rule: linorder_cases)
  case less with assms show ?thesis
    by (auto dest: sinit_linear_asym_lemma1)
next
  case equal with assms show ?thesis
    by (simp add: lexord_asymmetric)
next
  case greater with assms show ?thesis
    by (auto dest: sinit_linear_asym_lemma1)
qed

lemma range_ext:
  assumes "∀i :: nat. ∀x∈{0..<i}. f(x) = g(x)"
  shows "f = g"
proof (rule ext)
  fix x :: nat
  obtain i :: nat where "i > x"
    by (metis lessI)
  with assms show "f(x) = g(x)"
    by (auto)
qed

lemma sinit_ext:
  "(∀ i. sinit i xs = sinit i ys) ⟹ xs = ys"
  by (simp add: ssubstr_def, transfer, auto intro: range_ext)

definition infseq_lexord :: "'a rel ⇒ ('a infseq) rel" where
"infseq_lexord R = {(xs, ys). (∃ i. (sinit i xs, sinit i ys) ∈ lexord R)}"

lemma infseq_lexord_irreflexive:
  "∀x. (x, x) ∉ R ⟹ (xs, xs) ∉ infseq_lexord R"
  by (auto dest: lexord_irreflexive simp add: irrefl_def infseq_lexord_def)

lemma infseq_lexord_irrefl:
  "irrefl R ⟹ irrefl (infseq_lexord R)"
  by (simp add: irrefl_def infseq_lexord_irreflexive)

lemma infseq_lexord_transitive:
  assumes "trans R"
  shows "trans (infseq_lexord R)"
unfolding infseq_lexord_def
proof (rule transI, clarify)
  fix xs ys zs :: "'a infseq" and m n :: nat
  assume las: "(sinit m xs, sinit m ys) ∈ lexord R" "(sinit n ys, sinit n zs) ∈ lexord R"
  hence inz: "m > 0"
    using gr0I by force
  from las(1) obtain i where sinitm: "(sinit m xs!i, sinit m ys!i) ∈ R" "i < m" "∀ j<i. sinit m xs!j = sinit m ys!j"
    using lexord_eq_length by force
  from las(2) obtain j where sinitn: "(sinit n ys!j, sinit n zs!j) ∈ R" "j < n" "∀ k<j. sinit n ys!k = sinit n zs!k"
    using lexord_eq_length by force
  show "∃i. (sinit i xs, sinit i zs) ∈ lexord R"
  proof (cases "i ≤ j")
    case True note lt = this
    with sinitm sinitn have "(sinit n xs!i, sinit n zs!i) ∈ R"
      by (metis assms le_eq_less_or_eq le_less_trans nth_sinit transD)
    moreover from lt sinitm sinitn have "∀ j<i. sinit m xs!j = sinit m zs!j"
      by (metis less_le_trans less_trans nth_sinit)
    ultimately have "(sinit n xs, sinit n zs) ∈ lexord R"
      by (metis assms las(1,2) lexord_append lexord_sufI lexord_trans linorder_le_cases
          linorder_less_linear sinit_append_split sinit_len)
    thus ?thesis by auto
  next
    case False
    then have ge: "i > j" by auto
    with assms sinitm sinitn have "(sinit n xs!j, sinit n zs!j) ∈ R"
      by (metis less_trans nth_sinit)
    moreover from ge sinitm sinitn have "∀ k<j. sinit m xs!k = sinit m zs!k"
      by (metis dual_order.strict_trans nth_sinit)
    moreover hence "∀k<j. sinit n xs ! k = sinit n zs ! k"
      by (metis dual_order.strict_trans ge nth_sinit sinitm(2) sinitn(2))
    ultimately have "(sinit n xs, sinit n zs) ∈ lexord R"
      by (metis lexord_intro_elems sinit_len sinitn(2))
    thus ?thesis by auto
  qed
qed

lemma infseq_lexord_trans:
  "⟦ (xs, ys) ∈ infseq_lexord R; (ys, zs) ∈ infseq_lexord R; trans R ⟧ ⟹ (xs, zs) ∈ infseq_lexord R"
  by (meson infseq_lexord_transitive transE)

lemma infseq_lexord_antisym:
  "⟦ asym R; (a, b) ∈ infseq_lexord R ⟧ ⟹ (b, a) ∉ infseq_lexord R"
  by (auto dest: sinit_linear_asym_lemma2 simp add: infseq_lexord_def)

lemma infseq_lexord_asym:
  assumes "asym R"
  shows "asym (infseq_lexord R)"
  by (simp add: assms asym_onI infseq_lexord_antisym)

lemma infseq_lexord_total:
  assumes "total R"
  shows "total (infseq_lexord R)"
  using assms by (simp add: total_on_def infseq_lexord_def, meson lexord_linear sinit_ext)

lemma infseq_lexord_strict_linear_order:
  assumes "strict_linear_order R"
  shows "strict_linear_order (infseq_lexord R)"
  using assms
  by (auto simp add: strict_linear_order_on_def partial_order_on_def preorder_on_def
           intro: infseq_lexord_transitive infseq_lexord_irrefl infseq_lexord_total)

lemma infseq_lexord_linear:
  assumes "(∀ a b. (a,b)∈ R ∨ a = b ∨ (b,a) ∈ R)"
  shows "(x,y) ∈ infseq_lexord R ∨ x = y ∨ (y,x) ∈ infseq_lexord R"
proof -
  have "total R"
    using assms total_on_def by blast
  hence "total (infseq_lexord R)"
    using infseq_lexord_total by blast
  thus ?thesis
    by (auto simp add: total_on_def)
qed

instantiation infseq :: (ord) ord
begin

definition less_infseq :: "'a infseq ⇒ 'a infseq ⇒ bool" where
"less_infseq xs ys ⟷ (xs, ys) ∈ infseq_lexord {(xs, ys). xs < ys}"

definition less_eq_infseq :: "'a infseq ⇒ 'a infseq ⇒ bool" where
"less_eq_infseq xs ys = (xs = ys ∨ xs < ys)"

instance ..

end

instance infseq :: (order) order
proof
  fix xs :: "'a infseq"
  show "xs ≤ xs" by (simp add: less_eq_infseq_def)
next
  fix xs ys zs :: "'a infseq"
  assume "xs ≤ ys" and "ys ≤ zs"
  then show "xs ≤ zs"
    by (force dest: infseq_lexord_trans simp add: less_eq_infseq_def less_infseq_def trans_def)
next
  fix xs ys :: "'a infseq"
  assume "xs ≤ ys" and "ys ≤ xs"
  then show "xs = ys"
    apply (simp_all add: less_eq_infseq_def less_infseq_def)
    apply safe
    apply (metis asym_onI case_prodD infseq_lexord_antisym mem_Collect_eq order_less_asym)
    done
next
  fix xs ys :: "'a infseq"
  show "xs < ys ⟷ xs ≤ ys ∧ ¬ ys ≤ xs"
    apply (simp_all add: less_infseq_def less_eq_infseq_def)
    apply safe
     apply (simp_all add: infseq_lexord_irreflexive)
    apply (metis asym_onI case_prodD infseq_lexord_antisym mem_Collect_eq order_less_imp_not_less)
    done
qed

instance infseq :: (linorder) linorder
proof
  fix xs ys :: "'a infseq"
  have "(xs, ys) ∈ infseq_lexord {(u, v). u < v} ∨ xs = ys ∨ (ys, xs) ∈ infseq_lexord {(u, v). u < v}"
    by (rule infseq_lexord_linear) auto
  then show "xs ≤ ys ∨ ys ≤ xs"
    by (auto simp add: less_eq_infseq_def less_infseq_def)
qed

lemma infseq_lexord_mono [mono]:
  "(⋀ x y. f x y ⟶ g x y) ⟹ (xs, ys) ∈ infseq_lexord {(x, y). f x y} ⟶ (xs, ys) ∈ infseq_lexord {(x, y). g x y}"
  apply (simp add: infseq_lexord_def)
  apply (metis case_prodD case_prodI lexord_take_index_conv mem_Collect_eq)
  done

fun insort_rel :: "'a rel ⇒ 'a ⇒ 'a list ⇒ 'a list" where
"insort_rel R x [] = [x]" |
"insort_rel R x (y # ys) = (if (x = y ∨ (x,y) ∈ R) then x # y # ys else y # insort_rel R x ys)"

inductive sorted_rel :: "'a rel ⇒ 'a list ⇒ bool" where
Nil_rel [iff]: "sorted_rel R []" |
Cons_rel: "∀ y ∈ set xs. (x = y ∨ (x, y) ∈ R) ⟹ sorted_rel R xs ⟹ sorted_rel R (x # xs)"

definition list_of_set :: "'a rel ⇒ 'a set ⇒ 'a list" where
"list_of_set R = folding_on.F (insort_rel R) []"

lift_definition infseq_inj :: "'a infseq infseq ⇒ 'a infseq" is
"λ f i. f (fst (prod_decode i)) (snd (prod_decode i))" .

lift_definition infseq_proj :: "'a infseq ⇒ 'a infseq infseq" is
"λ f i j. f (prod_encode (i, j))" .

lemma infseq_inj_inverse: "infseq_proj (infseq_inj x) = x"
  by (transfer, simp)

lemma infseq_proj_inverse: "infseq_inj (infseq_proj x) = x"
  by (transfer, simp)

lemma infseq_inj: "inj infseq_inj"
  by (metis injI infseq_inj_inverse)

lemma infseq_inj_surj: "bij infseq_inj"
  apply (rule bijI)
   apply (simp add: infseq_inj, safe, simp_all)
  apply (metis rangeI infseq_proj_inverse)
  done

end