# Theory Sequence_LTL

```section ‹Linear Temporal Logic on Streams›

theory Sequence_LTL
imports
"Sequence"
"HOL-Library.Linear_Temporal_Logic_on_Streams"
begin

subsection ‹Basics›

text ‹Avoid destroying the constant @{const holds} prematurely.›
lemmas [simp del] = holds.simps holds_eq1 holds_eq2 not_holds_eq

(* TODO: these cannot be applied successively to simplify infs due to introduction of ∘
avoid or add extra simplification rules for infs *)
lemma ev_smap[iff]: "ev P (smap f w) ⟷ ev (P ∘ smap f) w" using ev_smap unfolding comp_apply by this
lemma alw_smap[iff]: "alw P (smap f w) ⟷ alw (P ∘ smap f) w" using alw_smap unfolding comp_apply by this
lemma holds_smap[iff]: "holds P (smap f w) ⟷ holds (P ∘ f) w" unfolding holds.simps by simp

lemmas [iff] = ev_sconst alw_sconst hld_smap'

lemmas [iff] = alw_ev_stl
lemma alw_ev_sdrop[iff]: "alw (ev P) (sdrop n w) ⟷ alw (ev P) w"
using alw_ev_sdrop alw_sdrop by blast
lemma alw_ev_scons[iff]: "alw (ev P) (a ## w) ⟷ alw (ev P) w" by (metis alw_ev_stl stream.sel(2))
lemma alw_ev_shift[iff]: "alw (ev P) (u @- v) ⟷ alw (ev P) v" by (induct u) (auto)

lemmas [simp del, iff] = ev_alw_stl
lemma ev_alw_sdrop[iff]: "ev (alw P) (sdrop n w) ⟷ ev (alw P) w"
using alwD alw_alw alw_sdrop ev_alw_imp_alw_ev not_ev_iff by metis
lemma ev_alw_scons[iff]: "ev (alw P) (a ## w) ⟷ ev (alw P) w" by (metis ev_alw_stl stream.sel(2))
lemma ev_alw_shift[iff]: "ev (alw P) (u @- v) ⟷ ev (alw P) v" by (induct u) (auto)

lemma holds_sconst[iff]: "holds P (sconst a) ⟷ P a" unfolding holds.simps by simp
lemma HLD_sconst[iff]: "HLD A (sconst a) ⟷ a ∈ A" unfolding HLD_def holds.simps by simp

lemma ev_alt_def: "ev φ w ⟷ (∃ u v. w = u @- v ∧ φ v)"
using ev.base ev_shift ev_imp_shift by metis
lemma ev_stl_alt_def: "ev φ (stl w) ⟷ (∃ u v. w = u @- v ∧ u ≠ [] ∧ φ v)"
unfolding ev_alt_def by (cases w) (force simp: scons_eq)

lemma ev_HLD_sset: "ev (HLD A) w ⟷ sset w ∩ A ≠ {}" unfolding HLD_def ev_holds_sset by auto

lemma alw_ev_coinduct[case_names alw_ev, consumes 1]:
assumes "R w"
assumes "⋀ w. R w ⟹ ev φ w ∧ ev R (stl w)"
shows "alw (ev φ) w"
proof -
have "ev R w" using assms(1) by rule
then show ?thesis using assms(2) by (coinduct) (metis alw_sdrop not_ev_iff sdrop_stl sdrop_wait)
qed

subsection ‹Infinite Occurrence›

abbreviation "infs P w ≡ alw (ev (holds P)) w"
abbreviation "fins P w ≡ ¬ infs P w"

lemma infs_suffix: "infs P w ⟷ (∀ u v. w = u @- v ⟶ Bex (sset v) P)"
using alwD alw_iff_sdrop alw_shift ev_holds_sset stake_sdrop by (metis (mono_tags, opaque_lifting))
lemma infs_snth: "infs P w ⟷ (∀ n. ∃ k ≥ n. P (w !! k))"
by (auto simp: alw_iff_sdrop ev_iff_sdrop holds.simps intro: le_add1 dest: le_Suc_ex)
lemma infs_infm: "infs P w ⟷ (∃⇩∞ i. P (w !! i))"
unfolding infs_snth INFM_nat_le by rule

lemma infs_coinduct[case_names infs, coinduct pred: infs]:
assumes "R w"
assumes "⋀ w. R w ⟹ Bex (sset w) P ∧ ev R (stl w)"
shows "infs P w"
using assms by (coinduct rule: alw_ev_coinduct) (auto simp: ev_holds_sset)
lemma infs_coinduct_shift[case_names infs, consumes 1]:
assumes "R w"
assumes "⋀ w. R w ⟹ ∃ u v. w = u @- v ∧ Bex (set u) P ∧ R v"
shows "infs P w"
using assms by (coinduct) (force simp: ev_stl_alt_def)
lemma infs_flat_coinduct[case_names infs_flat, consumes 1]:
assumes "R w"
assumes "⋀ u v. R (u ## v) ⟹ Bex (set u) P ∧ R v"
shows "infs P (flat w)"
using assms by (coinduction arbitrary: w rule: infs_coinduct_shift)
(metis empty_iff flat_Stream list.set(1) stream.exhaust)
lemma infs_sscan_coinduct[case_names infs_sscan, consumes 1]:
assumes "R w a"
assumes "⋀ w a. R w a ⟹ P a ∧ (∃ u v. w = u @- v ∧ u ≠ [] ∧ R v (fold f u a))"
shows "infs P (a ## sscan f w a)"
using assms(1)
proof (coinduction arbitrary: w a rule: infs_coinduct_shift)
case (infs w a)
obtain u v where 1: "P a" "w = u @- v" "u ≠ []" "R v (fold f u a)" using infs assms(2) by blast
show ?case
proof (intro exI conjI bexI)
have "sscan f w a = scan f u a @- sscan f v (fold f u a)" unfolding 1(2) by simp
also have "scan f u a = butlast (scan f u a) @ [fold f u a]"
using 1(3) by (metis last_ConsR scan_eq_nil scan_last snoc_eq_iff_butlast)
also have "a ## … @- sscan f v (fold f u a) =
(a # butlast (scan f u a)) @- fold f u a ## sscan f v (fold f u a)" by simp
finally show "a ## sscan f w a = (a # butlast (scan f u a)) @- fold f u a ## sscan f v (fold f u a)" by this
show "P a" using 1(1) by this
show "a ∈ set (a # butlast (scan f u a))" by simp
show "R v (fold f u a)" using 1(4) by this
qed rule
qed

lemma infs_mono: "(⋀ a. a ∈ sset w ⟹ P a ⟹ Q a) ⟹ infs P w ⟹ infs Q w"
unfolding infs_snth by force
lemma infs_mono_strong: "stream_all2 (λ a b. P a ⟶ Q b) u v ⟹ infs P u ⟹ infs Q v"
unfolding stream_rel_snth infs_snth by blast

lemma infs_all: "Ball (sset w) P ⟹ infs P w" unfolding infs_snth by auto
lemma infs_any: "infs P w ⟹ Bex (sset w) P" unfolding ev_holds_sset by auto

lemma infs_bot[iff]: "infs bot w ⟷ False" using infs_any by auto
lemma infs_top[iff]: "infs top w ⟷ True" by (simp add: infs_all)
lemma infs_disj[iff]: "infs (λ a. P a ∨ Q a) w ⟷ infs P w ∨ infs Q w"
unfolding infs_snth using le_trans le_cases by metis
lemma infs_bex[iff]:
assumes "finite S"
shows "infs (λ a. ∃ x ∈ S. P x a) w ⟷ (∃ x ∈ S. infs (P x) w)"
using assms infs_any by induct auto
lemma infs_bex_le_nat[iff]: "infs (λ a. ∃ k < n :: nat. P k a) w ⟷ (∃ k < n. infs (P k) w)"
proof -
have "infs (λ a. ∃ k < n. P k a) w ⟷ infs (λ a. ∃ k ∈ {k. k < n}. P k a) w" by simp
also have "… ⟷ (∃ k ∈ {k. k < n}. infs (P k) w)" by blast
also have "… ⟷ (∃ k < n. infs (P k) w)" by simp
finally show ?thesis by this
qed

lemma infs_cycle[iff]:
assumes "w ≠ []"
shows "infs P (cycle w) ⟷ Bex (set w) P"
proof
show "infs P (cycle w) ⟹ Bex (set w) P"
using assms by (auto simp: ev_holds_sset dest: alwD)
show "Bex (set w) P ⟹ infs P (cycle w)"
using assms by (coinduction rule: infs_coinduct_shift) (blast dest: cycle_decomp)
qed

end```