88
99public import Cslib.Computability.Automata.NA.Pair
1010public import Cslib.Computability.Languages.Congruences.RightCongruence
11+ public import Cslib.Computability.Languages.OmegaLanguage
12+ public import Cslib.Foundations.Data.Set.Saturation
1113
1214@[expose] public section
1315
@@ -20,7 +22,7 @@ of ω-regular languages under complementation.
2022
2123namespace Cslib.Automata.NA.Buchi
2224
23- open Function
25+ open Function Set Filter ωAcceptor ωLanguage ωSequence
2426
2527variable {Symbol : Type *} {State : Type }
2628
@@ -32,7 +34,7 @@ following two conditions hold:
3234from `s` to `t` via an acceptingg states. -/
3335def BuchiCongruence (na : Buchi State Symbol) : RightCongruence Symbol where
3436 eq.r u v :=
35- ∀ { s t} , (u ∈ na.pairLang s t ↔ v ∈ na.pairLang s t) ∧
37+ ∀ s t, (u ∈ na.pairLang s t ↔ v ∈ na.pairLang s t) ∧
3638 (u ∈ na.pairViaLang na.accept s t ↔ v ∈ na.pairViaLang na.accept s t)
3739 eq.iseqv.refl := by grind
3840 eq.iseqv.symm := by grind
@@ -72,4 +74,128 @@ lemma buchiCongrParam_surjective : Surjective na.BuchiCongrParam := by
7274theorem buchiCongruence_fin_index [Finite State] : Finite (Quotient na.BuchiCongruence.eq) :=
7375 Finite.of_surjective na.BuchiCongrParam buchiCongrParam_surjective
7476
77+ /-- If `xl` and `yl` belong to the same equivalence class of `na.BuchiCongruence`
78+ and `xl` can move `na` from state `s` to state `t`, then so can `yl` and, furthermore,
79+ if `xl` makes `na` go through an accepting state of `na`, then so can `yl`. -/
80+ lemma buchiCongruence_transfer
81+ {a : Quotient na.BuchiCongruence.eq} {xl yl : List Symbol} {s t : State}
82+ (hc : xl ∈ na.BuchiCongruence.eqvCls a) (hc' : yl ∈ na.BuchiCongruence.eqvCls a)
83+ (hp : xl ∈ na.pairLang s t) : ∃ sl, na.IsExecution s yl t sl ∧
84+ ( xl ∈ na.pairViaLang na.accept s t → ∃ r ∈ na.accept, r ∈ sl ) := by
85+ have h_eq : na.BuchiCongruence.eq xl yl := by
86+ apply Quotient.exact
87+ grind
88+ have := h_eq s t
89+ by_cases h_xl : xl ∈ na.pairViaLang na.accept s t
90+ · have h_yl : yl ∈ na.pairViaLang na.accept s t := by grind
91+ obtain ⟨r, _, yl1, yl2, h_yl1, h_yl2, rfl⟩ := LTS.mem_pairViaLang.mp h_yl
92+ obtain ⟨sl1, h_yl1⟩ := LTS.mTr_isExecution h_yl1
93+ obtain ⟨sl2, h_yl2⟩ := LTS.mTr_isExecution h_yl2
94+ have := LTS.IsExecution.comp h_yl1 h_yl2
95+ grind [LTS.IsExecution]
96+ · have h_yl : yl ∈ na.pairLang s t := by grind
97+ grind [LTS.mTr_isExecution h_yl]
98+
99+ /-- `na.buchiFamily` is a family of ω-languages indexed by a pair of equivalence classes
100+ of `na.BuchiCongruence` which will turn out to saturate the ω-language accepted by `na`
101+ and cover all possible ω-sequences. -/
102+ def buchiFamily [Inhabited Symbol] (na : Buchi State Symbol) :
103+ Quotient na.BuchiCongruence.eq × Quotient na.BuchiCongruence.eq → ωLanguage Symbol
104+ | (a, b) => na.BuchiCongruence.eqvCls a * (na.BuchiCongruence.eqvCls b)^ω
105+
106+ theorem mem_buchiFamily [Inhabited Symbol]
107+ {xs : ωSequence Symbol} {a b : Quotient na.BuchiCongruence.eq} :
108+ xs ∈ na.buchiFamily (a, b) ↔ ∃ xl, ∃ xls : ωSequence (List Symbol),
109+ xl ∈ na.BuchiCongruence.eqvCls a ∧ (∀ k, xls k ∈ na.BuchiCongruence.eqvCls b - 1 ) ∧
110+ xl ++ω xls.flatten = xs := by
111+ grind [buchiFamily]
112+
113+ -- This intermediate result is split out of the proof of `buchiCongruence_saturation` below
114+ -- because that proof was too big and kept exceeding the default `maxHeartbeats`.
115+ private lemma frequently_via_accept [Inhabited Symbol]
116+ {xl : List Symbol} {xls : ωSequence (List Symbol)} {ss : ωSequence State}
117+ (h_acc : ∃ᶠ (k : ℕ) in atTop, ss k ∈ na.accept) (h_exec : na.ωTr ss (xl ++ω xls.flatten))
118+ (h_xls_p : ∀ (k : ℕ), (xls k).length > 0 )
119+ (f : ℕ → ℕ) (h_f : f = fun k => xl.length + xls.cumLen k)
120+ (ts : ωSequence State) (h_ts : ts = ωSequence.mk (fun k ↦ ss (f k))) :
121+ ∃ᶠ (k : ℕ) in atTop, xls k ∈ na.pairViaLang na.accept (ts k) (ts (k + 1 )) := by
122+ have hm : StrictMono f := by
123+ intro m n h_mn
124+ grind [cumLen_strictMono h_xls_p h_mn]
125+ apply Frequently.mono <| frequently_in_strictMono hm h_acc
126+ rintro n ⟨k, _, _⟩
127+ apply LTS.mem_pairViaLang.mpr
128+ use ss (f n + k), by grind
129+ use (xls n).take k, (xls n).drop k
130+ split_ands
131+ · have := LTS.isExecution_mTr na.toLTS <|
132+ LTS.ωTr_isExecution h_exec (show f n ≤ f n + k by grind)
133+ suffices (xl ++ω xls.flatten).extract (f n) (f n + k) = (xls n).take k by grind
134+ have : xls.flatten.extract (xls.cumLen n) (xls.cumLen n + k) = (xls n).take k := by
135+ grind [extract_flatten h_xls_p n]
136+ grind only [extract_apppend_right_right]
137+ · have := LTS.isExecution_mTr na.toLTS <|
138+ LTS.ωTr_isExecution h_exec (show f n + k ≤ f (n + 1 ) by grind)
139+ suffices (xl ++ω xls.flatten).extract (f n + k) (f (n + 1 )) = (xls n).drop k by grind
140+ have : xls.flatten.extract (xls.cumLen n + k) (xls.cumLen (n + 1 )) = (xls n).drop k := by
141+ grind [extract_flatten h_xls_p n]
142+ grind only [= cumLen_succ, extract_apppend_right_right]
143+ · grind only [!List.take_append_drop]
144+
145+ /-- `na.buchiFamily` saturates the ω-language accepted by `na`. -/
146+ theorem buchiCongruence_saturation [Inhabited Symbol] :
147+ Saturates na.buchiFamily (language na) := by
148+ rintro ⟨a, b⟩ ⟨xs, h_xs, h_lang⟩ ys h_ys
149+ obtain ⟨xl, xls, h_xl_c, h_xls_c, rfl⟩ := mem_buchiFamily.mp h_xs
150+ obtain ⟨yl, yls, h_yl_c, h_yls_c, rfl⟩ := mem_buchiFamily.mp h_ys
151+ obtain ⟨ss, ⟨h_init, h_exec⟩, h_acc⟩ := h_lang
152+ have h_xls_p (k : ℕ) : (xls k).length > 0 := by
153+ grind [Language.mem_sub_one, List.ne_nil_iff_length_pos]
154+ have h_yls_p (k : ℕ) : (yls k).length > 0 := by
155+ grind [Language.mem_sub_one, List.ne_nil_iff_length_pos]
156+ let f (k : ℕ) := xl.length + xls.cumLen k
157+ let ts := ωSequence.mk (fun k ↦ ss (f k))
158+ have h_xl_e : xl ∈ na.pairLang (ss 0 ) (ts 0 ) := by
159+ have := LTS.ωTr_mTr h_exec (show 0 ≤ xl.length by grind)
160+ grind [extract_append_zero_right, LTS.mem_pairLang]
161+ have h_xls_e (k : ℕ) : (xls k) ∈ na.pairLang (ts k) (ts (k + 1 )) := by
162+ have := LTS.ωTr_mTr h_exec (show f k ≤ f (k + 1 ) by grind)
163+ suffices (xl ++ω xls.flatten).extract (f k) (f (k + 1 )) = xls k by grind [LTS.mem_pairLang]
164+ simp (disch := grind) [extract_apppend_right_right, f]
165+ have h_yl_e : yl ∈ na.pairLang (ss 0 ) (ts 0 ) := by
166+ obtain ⟨sl, h_e, _⟩ := buchiCongruence_transfer h_xl_c h_yl_c h_xl_e
167+ grind [LTS.mem_pairLang, LTS.isExecution_mTr (lts := na.toLTS) h_e]
168+ have h_yls (k : ℕ) : ∃ sl, na.IsExecution (ts k) (yls k) (ts (k + 1 )) sl ∧
169+ ( (xls k) ∈ na.pairViaLang na.accept (ts k) (ts (k + 1 )) → ∃ s ∈ na.accept, s ∈ sl ) := by
170+ exact buchiCongruence_transfer ((h_xls_c k).left) ((h_yls_c k).left) (h_xls_e k)
171+ choose sls h_yls_e h_yls_a using h_yls
172+ obtain ⟨ss1, h_ss1_run, h_ss1_seg⟩ := LTS.IsExecution.flatten h_yls_e h_yls_p
173+ obtain ⟨ss2, _, _, _, _⟩ := LTS.ωTr.append h_yl_e h_ss1_run (by
174+ have : ss1 0 = (sls 0 )[0 ]'(by grind) := by
175+ grind [get_extract (xs := ss1) (show 0 < yls.cumLen 1 - yls.cumLen 0 by grind)]
176+ have : ts 0 = (sls 0 )[0 ]'(by grind) := by grind [LTS.IsExecution]
177+ grind)
178+ use ss2, by grind [Run.mk]
179+ suffices ∃ᶠ (k : ℕ) in Filter.atTop, ss1 k ∈ na.accept by
180+ apply (drop_frequently_iff_frequently yl.length).mp
181+ grind
182+ have h_acc' := frequently_via_accept h_acc h_exec h_xls_p f rfl ts rfl
183+ have h_mono : StrictMono yls.cumLen := cumLen_strictMono h_yls_p
184+ apply frequently_atTop.mpr
185+ intro n
186+ obtain ⟨m, _, s, _, h_mem⟩ := frequently_atTop.mp (Frequently.mono h_acc' h_yls_a) n
187+ have : m ≤ yls.cumLen m := by grind [StrictMono.add_le_nat h_mono m 0 ]
188+ obtain ⟨k, _, _⟩ := List.mem_iff_getElem.mp h_mem
189+ use yls.cumLen m + k, by grind
190+ suffices ss1 (yls.cumLen m + k) = (sls m)[k] by grind
191+ by_cases k < (yls m).length
192+ · have h1 : k < yls.cumLen (m + 1 ) - yls.cumLen m := by grind only [= cumLen_succ]
193+ simp [← get_extract (xs := ss1) h1, h_ss1_seg m]
194+ · obtain ⟨_, _, _, _⟩ := h_yls_e m
195+ obtain ⟨_, _, _, _⟩ := h_yls_e (m + 1 )
196+ have := h_mono (show m + 1 < m + 2 by omega)
197+ have h1 : 0 < yls.cumLen (m + 2 ) - yls.cumLen (m + 1 ) := by omega
198+ have h2 := get_extract (xs := ss1) h1
199+ grind only [= cumLen_succ, = get_fun, = List.getElem_take]
200+
75201end Cslib.Automata.NA.Buchi
0 commit comments