# Theory Fstreams

theory Fstreams
imports Stream
```(*  Title:      HOL/HOLCF/FOCUS/Fstreams.thy
Author:     Borislav Gajanovic

FOCUS flat streams (with lifted elements).

TODO: integrate this with Fstream.
*)

theory Fstreams
imports "HOLCF-Library.Stream"
begin

default_sort type

type_synonym 'a fstream = "('a lift) stream"

definition
fsingleton    :: "'a => 'a fstream"  ("<_>" [1000] 999) where
fsingleton_def2: "fsingleton = (%a. Def a && UU)"

definition
fsfilter      :: "'a set ⇒ 'a fstream → 'a fstream" where
"fsfilter A = sfilter⋅(flift2 (λx. x∈A))"

definition
fsmap         :: "('a => 'b) => 'a fstream -> 'b fstream" where
"fsmap f = smap⋅(flift2 f)"

definition
jth           :: "nat => 'a fstream => 'a" where
"jth = (%n s. if enat n < #s then THE a. i_th n s = Def a else undefined)"

definition
first         :: "'a fstream => 'a" where
"first = (%s. jth 0 s)"

definition
last          :: "'a fstream => 'a" where
"last = (%s. case #s of enat n => (if n~=0 then jth (THE k. Suc k = n) s else undefined))"

abbreviation
emptystream :: "'a fstream"  ("<>") where
"<> == ⊥"

abbreviation
fsfilter' :: "'a set ⇒ 'a fstream ⇒ 'a fstream"       ("(_©_)" [64,63] 63) where

notation (ASCII)
fsfilter'  ("(_'(C')_)" [64,63] 63)

lemma ft_fsingleton[simp]: "ft⋅(<a>) = Def a"

lemma slen_fsingleton[simp]: "#(<a>) = enat 1"

lemma slen_fstreams[simp]: "#(<a> ooo s) = eSuc (#s)"

lemma slen_fstreams2[simp]: "#(s ooo <a>) = eSuc (#s)"
apply (cases "#s")
apply (insert slen_sconc [of _ s "Suc 0" "<a>"], auto)
done

lemma j_th_0_fsingleton[simp]:"jth 0 (<a>) = a"
done

lemma jth_0[simp]: "jth 0 (<a> ooo s) = a"
done

lemma first_sconc[simp]: "first (<a> ooo s) = a"

lemma first_fsingleton[simp]: "first (<a>) = a"

lemma jth_n[simp]: "enat n = #s ==> jth n (s ooo <a>) = a"
apply (simp add: enat_defs split: enat.splits)
done

lemma last_sconc[simp]: "enat n = #s ==> last (s ooo <a>) = a"
apply (drule sym, auto)
done

lemma last_fsingleton[simp]: "last (<a>) = a"

lemma first_UU[simp]: "first UU = undefined"

lemma last_UU[simp]:"last UU = undefined"
by (simp add: last_def jth_def enat_defs)

lemma last_infinite[simp]:"#s = ∞ ⟹ last s = undefined"

lemma jth_slen_lemma1:"n ≤ k ∧ enat n = #s ⟹ jth k s = undefined"
by (simp add: jth_def enat_defs split:enat.splits, auto)

lemma jth_UU[simp]:"jth n UU = undefined"

lemma ext_last:"⟦s ≠ UU; enat (Suc n) = #s⟧ ⟹ (stream_take n⋅s) ooo <(last s)> = s"
apply (case_tac "#s", auto)
apply (subgoal_tac "Def (jth n s) = i_th n s")
apply (drule slen_take_lemma1, auto)
apply (case_tac "i_th n s = UU")
apply auto
apply (case_tac "i_rt n s = UU", auto)
apply (drule i_rt_slen [THEN iffD1])
apply (drule slen_take_eq_rev [rule_format, THEN iffD2],auto)
apply (drule not_Undef_is_Def [THEN iffD1], auto)
done

lemma fsingleton_lemma1[simp]: "(<a> = <b>) = (a=b)"

lemma fsingleton_lemma2[simp]: "<a> ~= <>"

lemma fsingleton_sconc:"<a> ooo s = Def a && s"

lemma fstreams_ind:
"[| adm P; P <>; !!a s. P s ==> P (<a> ooo s) |] ==> P x"
apply (rule stream.induct, auto)
apply (drule not_Undef_is_Def [THEN iffD1], auto)
done

lemma fstreams_ind2:
"[| adm P; P <>; !!a. P (<a>); !!a b s. P s ==> P (<a> ooo <b> ooo s) |] ==> P x"
apply (rule stream_ind2, auto)
apply (drule not_Undef_is_Def [THEN iffD1], auto)+
done

lemma fstreams_take_Suc[simp]: "stream_take (Suc n)⋅(<a> ooo s) = <a> ooo stream_take n⋅s"

lemma fstreams_not_empty[simp]: "<a> ooo s ≠ <>"

lemma fstreams_not_empty2[simp]: "s ooo <a> ≠ <>"
by (case_tac "s=UU", auto)

lemma fstreams_exhaust: "x = UU ∨ (∃a s. x = <a> ooo s)"
apply (erule contrapos_pp, auto)
apply (drule stream_exhaust_eq [THEN iffD1], auto)
apply (drule not_Undef_is_Def [THEN iffD1], auto)
done

lemma fstreams_cases: "⟦x = UU ⟹ P; ⋀a y. x = <a> ooo y ⟹ P⟧ ⟹ P"
by (insert fstreams_exhaust [of x], auto)

lemma fstreams_exhaust_eq: "x ≠ UU ⟷ (∃a y. x = <a> ooo y)"
apply (drule stream_exhaust_eq [THEN iffD1], auto)
apply (drule not_Undef_is_Def [THEN iffD1], auto)
done

lemma fstreams_inject: "<a> ooo s = <b> ooo t ⟷ a = b ∧ s = t"

lemma fstreams_prefix: "<a> ooo s << t ⟹ ∃tt. t = <a> ooo tt ∧ s << tt"
apply (insert stream_prefix [of "Def a" s t], auto)
done

lemma fstreams_prefix': "x << <a> ooo z ⟷ x = <> ∨ (∃y. x = <a> ooo y ∧ y << z)"
apply (auto, case_tac "x=UU", auto)
apply (drule stream_exhaust_eq [THEN iffD1], auto)
apply (drule ax_flat, simp)
apply (erule sconc_mono)
done

lemma ft_fstreams[simp]: "ft⋅(<a> ooo s) = Def a"

lemma rt_fstreams[simp]: "rt⋅(<a> ooo s) = s"

lemma ft_eq[simp]: "ft⋅s = Def a ⟷ (∃t. s = <a> ooo t)"
apply (cases s, auto)
done

lemma surjective_fstreams: "<d> ooo y = x ⟷ (ft⋅x = Def d ∧ rt⋅x = y)"
by auto

lemma fstreams_mono: "<a> ooo b << <a> ooo c ⟹ b << c"

lemma fsmap_UU[simp]: "fsmap f⋅UU = UU"

lemma fsmap_fsingleton_sconc: "fsmap f⋅(<x> ooo xs) = <(f x)> ooo (fsmap f⋅xs)"
by (simp add: fsmap_def fsingleton_def2 flift2_def)

lemma fsmap_fsingleton[simp]: "fsmap f⋅(<x>) = <(f x)>"
by (simp add: fsmap_def fsingleton_def2 flift2_def)

lemma fstreams_chain_lemma[rule_format]:
"∀s x y. stream_take n⋅(s::'a fstream) << x ∧ x << y ∧ y << s ∧ x ≠ y ⟶ stream_take (Suc n)⋅s << y"
apply (induct_tac n, auto)
apply (case_tac "s=UU", auto)
apply (drule stream_exhaust_eq [THEN iffD1], auto)
apply (case_tac "y=UU", auto)
apply (drule stream_exhaust_eq [THEN iffD1], auto)
apply (case_tac "s=UU", auto)
apply (drule stream_exhaust_eq [THEN iffD1], auto)
apply (erule_tac x="ya" in allE)
apply (drule stream_prefix, auto)
apply (case_tac "y=UU",auto)
apply (drule stream_exhaust_eq [THEN iffD1], clarsimp)
apply auto
apply (erule_tac x="tt" in allE)
apply (erule_tac x="yb" in allE, auto)
done

lemma fstreams_lub_lemma1: "⟦chain Y; (LUB i. Y i) = <a> ooo s⟧ ⟹ ∃j t. Y j = <a> ooo t"
apply (subgoal_tac "(LUB i. Y i) ~= UU")
apply (frule lub_eq_bottom_iff, auto)
apply (drule_tac x="i" in is_ub_thelub, auto)
apply (drule fstreams_prefix' [THEN iffD1], auto)
done

lemma fstreams_lub1:
"⟦chain Y; (LUB i. Y i) = <a> ooo s⟧
⟹ (∃j t. Y j = <a> ooo t) ∧ (∃X. chain X ∧ (∀i. ∃j. <a> ooo X i << Y j) ∧ (LUB i. X i) = s)"
apply (rule_tac x="λn. stream_take n⋅s" in exI, auto)
apply (induct_tac i, auto)
apply (drule fstreams_lub_lemma1, auto)
apply (rule_tac x="j" in exI, auto)
apply (case_tac "max_in_chain j Y")
apply (frule lub_finch1 [THEN lub_eqI], auto)
apply (rule_tac x="j" in exI)
apply (erule subst) back back
apply (rule_tac x="ja" in exI)
apply (subgoal_tac "Y j << Y ja")
apply (drule fstreams_prefix, auto)+
apply (rule sconc_mono)
apply (rule fstreams_chain_lemma, auto)
apply (subgoal_tac "Y ja << (LUB i. (Y i))", clarsimp)
apply (drule fstreams_mono, simp)
apply (rule is_ub_thelub, simp)
apply (blast intro: chain_mono)
by (rule stream_reach2)

lemma lub_Pair_not_UU_lemma:
"⟦chain Y; (LUB i. Y i) = ((a::'a::flat), b); a ≠ UU; b ≠ UU⟧
⟹ ∃j c d. Y j = (c, d) ∧ c ≠ UU ∧ d ≠ UU"
apply (frule lub_prod, clarsimp)
apply (clarsimp simp add: lub_eq_bottom_iff [where Y="λi. fst (Y i)"])
apply (case_tac "Y i", clarsimp)
apply (case_tac "max_in_chain i Y")
apply (drule maxinch_is_thelub, auto)
apply (rule_tac x="i" in exI, auto)
apply (subgoal_tac "Y i << Y j",auto)
apply (drule ax_flat, auto)
apply (case_tac "snd (Y j) = UU",auto)
apply (case_tac "Y j", auto)
apply (rule_tac x="j" in exI)
apply (case_tac "Y j",auto)
apply (drule chain_mono, auto)
done

lemma fstreams_lub_lemma2:
"⟦chain Y; (LUB i. Y i) = (a, <m> ooo ms); (a::'a::flat) ≠ UU⟧ ⟹ ∃j t. Y j = (a, <m> ooo t)"
apply (frule lub_Pair_not_UU_lemma, auto)
apply (drule_tac x="j" in is_ub_thelub, auto)
apply (drule ax_flat, clarsimp)
apply (drule fstreams_prefix' [THEN iffD1], auto)
done

lemma fstreams_lub2:
"⟦chain Y; (LUB i. Y i) = (a, <m> ooo ms); (a::'a::flat) ≠ UU⟧
⟹ (∃j t. Y j = (a, <m> ooo t)) ∧ (∃X. chain X ∧ (∀i. ∃j. (a, <m> ooo X i) << Y j) ∧ (LUB i. X i) = ms)"
apply (rule_tac x="λn. stream_take n⋅ms" in exI, auto)
apply (induct_tac i, auto)
apply (drule fstreams_lub_lemma2, auto)
apply (rule_tac x="j" in exI, auto)
apply (case_tac "max_in_chain j Y")
apply (frule lub_finch1 [THEN lub_eqI], auto)
apply (rule_tac x="j" in exI)
apply (erule subst) back back
apply (rule_tac x="ja" in exI)
apply (subgoal_tac "Y j << Y ja")
apply (drule below_trans)
apply (drule fstreams_prefix, auto)+
apply (rule sconc_mono)
apply (subgoal_tac "tt ≠ tta" "tta << ms")
apply (blast intro: fstreams_chain_lemma)
apply (frule lub_prod, auto)
apply (subgoal_tac "snd (Y ja) << (LUB i. snd (Y i))", clarsimp)
apply (drule fstreams_mono, simp)
apply (rule is_ub_thelub chainI)
apply (subgoal_tac "fst (Y j) ≠ fst (Y ja) ∨ snd (Y j) ≠ snd (Y ja)", simp)
apply (drule ax_flat, simp)+
apply (drule prod_eqI, auto)