From 6a5a473faa2f1ff3c0a5f6daf29c8d5fda72d3f6 Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Fri, 17 Oct 2025 15:40:04 +0200 Subject: [PATCH 01/21] Considering the transitively closed \tau relation --- Cslib/Foundations/Semantics/LTS/Basic.lean | 161 +++++++++++------- .../Semantics/LTS/Bisimulation.lean | 4 + 2 files changed, 108 insertions(+), 57 deletions(-) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index 2176a77d..f4151c97 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -77,7 +77,7 @@ inductive LTS.MTr (lts : LTS State Label) : State → List Label → State → P | refl {s : State} : lts.MTr s [] s | stepL {s1 : State} {μ : Label} {s2 : State} {μs : List Label} {s3 : State} : lts.Tr s1 μ s2 → lts.MTr s2 μs s3 → - lts.MTr s1 (μ :: μs) s3 + lts.MTr s1 (μ :: μs) s3 /-- Any transition is also a multi-step transition. -/ @[grind] @@ -416,10 +416,14 @@ section Weak class HasTau (Label : Type v) where τ : Label +/-- Saturated τ-transition relation. -/ +def LTS.τTr [HasTau Label] (lts : LTS State Label) : State → State → Prop := + Relation.ReflTransGen (fun s1 s2 => lts.Tr s1 HasTau.τ s2) + /-- Saturated transition relation. -/ inductive LTS.STr [HasTau Label] (lts : LTS State Label) : State → Label → State → Prop where | refl : lts.STr s HasTau.τ s -| tr : lts.STr s1 HasTau.τ s2 → lts.Tr s2 μ s3 → lts.STr s3 HasTau.τ s4 → lts.STr s1 μ s4 +| tr : lts.τTr s1 s2 → lts.Tr s2 μ s3 → lts.τTr s3 s4 → lts.STr s1 μ s4 /-- The `LTS` obtained by saturating the transition relation in `lts`. -/ @[grind =] @@ -430,21 +434,37 @@ def LTS.saturate [HasTau Label] (lts : LTS State Label) : LTS State Label where @[grind] theorem LTS.STr.single [HasTau Label] (lts : LTS State Label) : lts.Tr s μ s' → lts.STr s μ s' := by intro h - apply LTS.STr.tr LTS.STr.refl h LTS.STr.refl + apply LTS.STr.tr Relation.ReflTransGen.refl h Relation.ReflTransGen.refl + +/-- STr transitions labeled by HasTau.τ are exactly the τTr transitions. -/ +@[grind] +theorem LTS.STr_τTr [HasTau Label] (lts : LTS State Label) : + lts.STr s HasTau.τ s' ↔ lts.τTr s s' := by + apply Iff.intro <;> intro h + case mp => + cases h + case refl => exact Relation.ReflTransGen.refl + case tr _ _ h1 h2 h3 => + exact (Relation.ReflTransGen.trans h1 (Relation.ReflTransGen.head h2 h3)) + case mpr => + cases h + case refl => exact LTS.STr.refl + case tail _ h1 h2 => exact LTS.STr.tr h1 h2 Relation.ReflTransGen.refl + +/- Do we really need STrN? /-- As `LTS.str`, but counts the number of `τ`-transitions. This is convenient as induction metric. -/ -@[grind] inductive LTS.STrN [HasTau Label] (lts : LTS State Label) : ℕ → State → Label → State → Prop where | refl : lts.STrN 0 s HasTau.τ s | tr : - lts.STrN n s1 HasTau.τ s2 → + lts.τTrN n s1 s2 → lts.Tr s2 μ s3 → - lts.STrN m s3 HasTau.τ s4 → + lts.τTrN m s3 s4 → lts.STrN (n + m + 1) s1 μ s4 -/-- `LTS.str` and `LTS.strN` are equivalent. -/ +/-- `LTS.sTr` and `LTS.sTrN` are equivalent. -/ @[grind] theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : lts.STr s1 μ s2 ↔ ∃ n, lts.STrN n s1 μ s2 := by @@ -454,9 +474,9 @@ theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : case refl => exists 0 exact LTS.STrN.refl - case tr s1 sb μ sb' s2 hstr1 htr hstr2 ih1 ih2 => - obtain ⟨n1, ih1⟩ := ih1 - obtain ⟨n2, ih2⟩ := ih2 + case tr _ _ hτ1 htr hτ2 => + obtain ⟨n1, ih1⟩ := lts.τTr_imp_τTrN hτ1 + obtain ⟨n2, ih2⟩ := lts.τTr_imp_τTrN hτ2 exists (n1 + n2 + 1) apply LTS.STrN.tr ih1 htr ih2 case mpr => @@ -464,32 +484,40 @@ theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : induction h case refl => constructor - case tr n s1 sb μ sb' m s2 hstr1 htr hstr2 ih1 ih2 => - apply LTS.STr.tr ih1 htr ih2 + case tr m s1 s2 μ s3 k s4 hτ1 htr hτ2 => + apply LTS.STr.tr (lts.τTrN_imp_τTr hτ1) htr (lts.τTrN_imp_τTr hτ2) -/-- Saturated transitions labelled by τ can be composed (weighted version). -/ +/-- STrN transitions labeled by HasTau.τ are exactly the τTrN transitions. -/ @[grind] +theorem LTS.STrN_τTrN [HasTau Label] (lts : LTS State Label) : + lts.STrN n s HasTau.τ s' ↔ lts.τTrN n s s' := by + constructor <;> intro h + case mp => + cases h + case refl => exact LTS.τTrN.refl + case tr n' _ _ m' h1 h2 h3 => + have h4 := LTS.τTrN.tr h1 h2 + have h5 := LTS.τTrN.append lts h4 h3 + grind + case mpr => + cases h + case refl => exact LTS.STrN.refl + case tr n' s'' h1 h2 => exact LTS.STrN.tr h1 h2 LTS.τTrN.refl + +@[grind] +theorem LTS.τTr_imp_STrN_τ [HasTau Label] (lts : LTS State Label) : + lts.τTr s s' → ∃ n, lts.STrN n s HasTau.τ s' := by + intro h + obtain ⟨n, h⟩ := lts.τTr_imp_τTrN h + exists n + grind + +/-- Saturated transitions labelled by τ can be composed (weighted version). -/ theorem LTS.STrN.trans_τ [HasTau Label] (lts : LTS State Label) (h1 : lts.STrN n s1 HasTau.τ s2) (h2 : lts.STrN m s2 HasTau.τ s3) : - lts.STrN (n + m) s1 HasTau.τ s3 := by - cases h1 - case refl => grind - case tr n1 sb sb' n2 hstr1 htr hstr2 => - have ih := LTS.STrN.trans_τ lts hstr2 h2 - have conc := LTS.STrN.tr hstr1 htr ih - grind + lts.STrN (n + m) s1 HasTau.τ s3 := by grind -/-- Saturated transitions labelled by τ can be composed. -/ -@[grind] -theorem LTS.STr.trans_τ - [HasTau Label] (lts : LTS State Label) - (h1 : lts.STr s1 HasTau.τ s2) (h2 : lts.STr s2 HasTau.τ s3) : - lts.STr s1 HasTau.τ s3 := by - obtain ⟨n, h1N⟩ := (LTS.sTr_sTrN lts).1 h1 - obtain ⟨m, h2N⟩ := (LTS.sTr_sTrN lts).1 h2 - have concN := LTS.STrN.trans_τ lts h1N h2N - apply (LTS.sTr_sTrN lts).2 ⟨n + m, concN⟩ /-- Saturated transitions can be appended with τ-transitions (weighted version). -/ @[grind] @@ -498,13 +526,13 @@ theorem LTS.STrN.append (h1 : lts.STrN n1 s1 μ s2) (h2 : lts.STrN n2 s2 HasTau.τ s3) : lts.STrN (n1 + n2) s1 μ s3 := by + rw [STrN_τTrN lts] at h2 cases h1 case refl => grind - case tr n11 sb sb' n12 hstr1 htr hstr2 => - have hsuffix := LTS.STrN.trans_τ lts hstr2 h2 - have n_eq : n11 + (n12 + n2) + 1 = (n11 + n12 + 1 + n2) := by omega - rw [← n_eq] - apply LTS.STrN.tr hstr1 htr hsuffix + case tr _ _ _ _ h3 h4 h5 => + have h6 := LTS.τTrN.append lts h5 h2 + have h7 := LTS.STrN.tr h3 h4 h6 + grind /-- Saturated transitions can be composed (weighted version). -/ @[grind] @@ -514,13 +542,13 @@ theorem LTS.STrN.comp (h2 : lts.STrN n2 s2 μ s3) (h3 : lts.STrN n3 s3 HasTau.τ s4) : lts.STrN (n1 + n2 + n3) s1 μ s4 := by + rw [STrN_τTrN lts] at h1 h3 cases h2 - case refl => - apply LTS.STrN.trans_τ lts h1 h3 - case tr n21 sb sb' n22 hstr1 htr hstr2 => - have hprefix_τ := LTS.STrN.trans_τ lts h1 hstr1 - have hprefix := LTS.STrN.tr hprefix_τ htr hstr2 - have conc := LTS.STrN.append lts hprefix h3 + case refl => grind + case tr _ _ _ _ h4 h5 h6 => + have h7 := LTS.τTrN.append lts h1 h4 + have h8 := LTS.τTrN.append lts h6 h3 + have h9 := LTS.STrN.tr h7 h5 h8 grind /-- Saturated transitions can be composed. -/ @@ -531,16 +559,35 @@ theorem LTS.STr.comp (h2 : lts.STr s2 μ s3) (h3 : lts.STr s3 HasTau.τ s4) : lts.STr s1 μ s4 := by - obtain ⟨n1, h1N⟩ := (LTS.sTr_sTrN lts).1 h1 - obtain ⟨n2, h2N⟩ := (LTS.sTr_sTrN lts).1 h2 - obtain ⟨n3, h3N⟩ := (LTS.sTr_sTrN lts).1 h3 - have concN := LTS.STrN.comp lts h1N h2N h3N - apply (LTS.sTr_sTrN lts).2 ⟨n1 + n2 + n3, concN⟩ + rw [LTS.STr_τTr _] at h1 h3 + cases h2 + case refl => + rw [LTS.STr_τTr _] + apply Relation.ReflTransGen.trans h1 h3 + case tr _ _ hτ1 htr hτ2 => + exact LTS.STr.tr (Relation.ReflTransGen.trans h1 hτ1) htr (Relation.ReflTransGen.trans hτ2 h3) @[grind _=_] lemma LTS.saturate_tr_sTr [HasTau Label] (lts : LTS State Label) : lts.saturate.Tr s HasTau.τ = lts.STr s HasTau.τ := by simp [LTS.saturate] +/-- In a saturated LTS, the transition and saturated transition relations are the same. -/ +@[grind _=_] +theorem LTS.saturate_τTr_τTr [hHasTau : HasTau Label] (lts : LTS State Label) + : lts.saturate.τTr s = lts.τTr s := by + ext s'' + apply Iff.intro <;> intro h + case mp => + induction h + case refl => constructor + case tail _ _ _ h2 h3 => exact Relation.ReflTransGen.trans h3 ((LTS.STr_τTr _).mp h2) + case mpr => + cases h + case refl => constructor + case tail s' h2 h3 => + have h4 := LTS.STr.tr h2 h3 Relation.ReflTransGen.refl + exact Relation.ReflTransGen.single h4 + /-- In a saturated LTS, the transition and saturated transition relations are the same. -/ @[grind _=_] theorem LTS.saturate_sTr_tr [hHasTau : HasTau Label] (lts : LTS State Label) @@ -548,20 +595,20 @@ theorem LTS.saturate_sTr_tr [hHasTau : HasTau Label] (lts : LTS State Label) ext s' apply Iff.intro <;> intro h case mp => - induction h + cases h case refl => constructor - case tr s1 sb μ sb' s2 hstr1 htr hstr2 ih1 ih2 => - rw [hμ] at htr - apply LTS.STr.single at htr - rw [← LTS.saturate_tr_sTr] at htr - grind [LTS.STr.tr] + case tr hstr1 htr hstr2 => + apply LTS.STr.single + exact LTS.STr.tr hstr1 htr hstr2 case mpr => - induction h + cases h case refl => constructor - case tr s1 sb μ sb' s2 hstr1 htr hstr2 ih1 ih2 => - simp only [LTS.saturate] at ih1 htr ih2 - simp only [LTS.saturate] - grind + case tr hstr1 htr hstr2 => + rw [LTS.saturate_τTr_τTr lts] at hstr1 hstr2 + rw [←LTS.STr_τTr lts] at hstr1 hstr2 + exact LTS.STr.comp lts hstr1 htr hstr2 + +-/ /-- In a saturated LTS, every state is in its τ-image. -/ @[grind] diff --git a/Cslib/Foundations/Semantics/LTS/Bisimulation.lean b/Cslib/Foundations/Semantics/LTS/Bisimulation.lean index bcf40bae..c82f03db 100644 --- a/Cslib/Foundations/Semantics/LTS/Bisimulation.lean +++ b/Cslib/Foundations/Semantics/LTS/Bisimulation.lean @@ -809,6 +809,7 @@ theorem SWBisimulation.follow_internal_fst_n cases hstrN rename_i n1 sb sb' n2 hstrN1 htr hstrN2 let hswb_m := hswb + rw [←LTS.STrN_τTrN] at hstrN1 hstrN2 have ih1 := SWBisimulation.follow_internal_fst_n hswb hr hstrN1 obtain ⟨sb2, hstrs2, hrsb⟩ := ih1 have h := (hswb hrsb HasTau.τ).1 sb' htr @@ -836,6 +837,7 @@ theorem SWBisimulation.follow_internal_snd_n cases hstrN rename_i n1 sb sb' n2 hstrN1 htr hstrN2 let hswb_m := hswb + rw [←LTS.STrN_τTrN] at hstrN1 hstrN2 have ih1 := SWBisimulation.follow_internal_snd_n hswb hr hstrN1 obtain ⟨sb1, hstrs1, hrsb⟩ := ih1 have h := (hswb hrsb HasTau.τ).2 sb' htr @@ -897,6 +899,7 @@ theorem LTS.isWeakBisimulation_iff_isSWBisimulation constructor; constructor exact hr case tr sb sb' hstr1 htr hstr2 => + rw [←LTS.STr_τTr] at hstr1 hstr2 obtain ⟨sb2, hstr2b, hrb⟩ := SWBisimulation.follow_internal_fst h hr hstr1 obtain ⟨sb2', hstr2b', hrb'⟩ := (h hrb μ).1 _ htr obtain ⟨s2', hstr2', hrb2⟩ := SWBisimulation.follow_internal_fst h hrb' hstr2 @@ -912,6 +915,7 @@ theorem LTS.isWeakBisimulation_iff_isSWBisimulation constructor; constructor exact hr case tr sb sb' hstr1 htr hstr2 => + rw [←LTS.STr_τTr] at hstr1 hstr2 obtain ⟨sb1, hstr1b, hrb⟩ := SWBisimulation.follow_internal_snd h hr hstr1 obtain ⟨sb2', hstr1b', hrb'⟩ := (h hrb μ).2 _ htr obtain ⟨s1', hstr1', hrb2⟩ := SWBisimulation.follow_internal_snd h hrb' hstr2 From cd91c3518d14bbf0e9e4635c33f9cf5d8374b0db Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Fri, 17 Oct 2025 17:47:34 +0200 Subject: [PATCH 02/21] Completed introduction of tauTr, entire library builds correctly now. Removed some of the STrN theorems, as I think most of them are no longer necessary. Bisimulation theorems now complete using grind. --- Cslib/Foundations/Semantics/LTS/Basic.lean | 306 ++++++++---------- .../Semantics/LTS/Bisimulation.lean | 10 +- 2 files changed, 134 insertions(+), 182 deletions(-) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index f4151c97..2f25455f 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -145,6 +145,74 @@ def LTS.generatedBy (s : State) : LTS {s' : State // lts.CanReach s s'} Label wh end MultiStep +section Relation + +/-- Returns the relation that relates all states `s1` and `s2` via a fixed transition label `μ`. -/ +def LTS.Tr.toRelation (lts : LTS State Label) (μ : Label) : State → State → Prop := + fun s1 s2 => lts.Tr s1 μ s2 + +/-- Returns the relation that relates all states `s1` and `s2` via a fixed list of transition +labels `μs`. -/ +def LTS.MTr.toRelation (lts : LTS State Label) (μs : List Label) : State → State → Prop := + fun s1 s2 => lts.MTr s1 μs s2 + +/-- Any homogeneous relation can be seen as an LTS where all transitions have the same label. -/ +def Relation.toLTS [DecidableEq Label] (r : State → State → Prop) (μ : Label) : + LTS State Label where + Tr := fun s1 μ' s2 => if μ' = μ then r s1 s2 else False + +end Relation + +section Trans + +/-! ## Support for the calc tactic -/ + +/-- Transitions can be chained. -/ +instance (lts : LTS State Label) : + Trans + (LTS.Tr.toRelation lts μ1) + (LTS.Tr.toRelation lts μ2) + (LTS.MTr.toRelation lts [μ1, μ2]) where + trans := by + intro s1 s2 s3 htr1 htr2 + apply LTS.MTr.single at htr1 + apply LTS.MTr.single at htr2 + apply LTS.MTr.comp lts htr1 htr2 + +/-- Transitions can be chained with multi-step transitions. -/ +instance (lts : LTS State Label) : + Trans + (LTS.Tr.toRelation lts μ) + (LTS.MTr.toRelation lts μs) + (LTS.MTr.toRelation lts (μ :: μs)) where + trans := by + intro s1 s2 s3 htr1 hmtr2 + apply LTS.MTr.single at htr1 + apply LTS.MTr.comp lts htr1 hmtr2 + +/-- Multi-step transitions can be chained with transitions. -/ +instance (lts : LTS State Label) : + Trans + (LTS.MTr.toRelation lts μs) + (LTS.Tr.toRelation lts μ) + (LTS.MTr.toRelation lts (μs ++ [μ])) where + trans := by + intro s1 s2 s3 hmtr1 htr2 + apply LTS.MTr.single at htr2 + apply LTS.MTr.comp lts hmtr1 htr2 + +/-- Multi-step transitions can be chained. -/ +instance (lts : LTS State Label) : + Trans + (LTS.MTr.toRelation lts μs1) + (LTS.MTr.toRelation lts μs2) + (LTS.MTr.toRelation lts (μs1 ++ μs2)) where + trans := by + intro s1 s2 s3 hmtr1 hmtr2 + apply LTS.MTr.comp lts hmtr1 hmtr2 + +end Trans + section Termination /-! ## Definitions about termination -/ @@ -418,7 +486,7 @@ class HasTau (Label : Type v) where /-- Saturated τ-transition relation. -/ def LTS.τTr [HasTau Label] (lts : LTS State Label) : State → State → Prop := - Relation.ReflTransGen (fun s1 s2 => lts.Tr s1 HasTau.τ s2) + Relation.ReflTransGen (Tr.toRelation lts HasTau.τ) /-- Saturated transition relation. -/ inductive LTS.STr [HasTau Label] (lts : LTS State Label) : State → Label → State → Prop where @@ -434,7 +502,7 @@ def LTS.saturate [HasTau Label] (lts : LTS State Label) : LTS State Label where @[grind] theorem LTS.STr.single [HasTau Label] (lts : LTS State Label) : lts.Tr s μ s' → lts.STr s μ s' := by intro h - apply LTS.STr.tr Relation.ReflTransGen.refl h Relation.ReflTransGen.refl + apply LTS.STr.tr .refl h .refl /-- STr transitions labeled by HasTau.τ are exactly the τTr transitions. -/ @[grind] @@ -443,113 +511,13 @@ theorem LTS.STr_τTr [HasTau Label] (lts : LTS State Label) : apply Iff.intro <;> intro h case mp => cases h - case refl => exact Relation.ReflTransGen.refl + case refl => exact .refl case tr _ _ h1 h2 h3 => - exact (Relation.ReflTransGen.trans h1 (Relation.ReflTransGen.head h2 h3)) + exact (.trans h1 (.head h2 h3)) case mpr => cases h case refl => exact LTS.STr.refl - case tail _ h1 h2 => exact LTS.STr.tr h1 h2 Relation.ReflTransGen.refl - -/- Do we really need STrN? - -/-- As `LTS.str`, but counts the number of `τ`-transitions. This is convenient as induction -metric. -/ -inductive LTS.STrN [HasTau Label] (lts : LTS State Label) : - ℕ → State → Label → State → Prop where - | refl : lts.STrN 0 s HasTau.τ s - | tr : - lts.τTrN n s1 s2 → - lts.Tr s2 μ s3 → - lts.τTrN m s3 s4 → - lts.STrN (n + m + 1) s1 μ s4 - -/-- `LTS.sTr` and `LTS.sTrN` are equivalent. -/ -@[grind] -theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : - lts.STr s1 μ s2 ↔ ∃ n, lts.STrN n s1 μ s2 := by - apply Iff.intro <;> intro h - case mp => - induction h - case refl => - exists 0 - exact LTS.STrN.refl - case tr _ _ hτ1 htr hτ2 => - obtain ⟨n1, ih1⟩ := lts.τTr_imp_τTrN hτ1 - obtain ⟨n2, ih2⟩ := lts.τTr_imp_τTrN hτ2 - exists (n1 + n2 + 1) - apply LTS.STrN.tr ih1 htr ih2 - case mpr => - obtain ⟨n, h⟩ := h - induction h - case refl => - constructor - case tr m s1 s2 μ s3 k s4 hτ1 htr hτ2 => - apply LTS.STr.tr (lts.τTrN_imp_τTr hτ1) htr (lts.τTrN_imp_τTr hτ2) - -/-- STrN transitions labeled by HasTau.τ are exactly the τTrN transitions. -/ -@[grind] -theorem LTS.STrN_τTrN [HasTau Label] (lts : LTS State Label) : - lts.STrN n s HasTau.τ s' ↔ lts.τTrN n s s' := by - constructor <;> intro h - case mp => - cases h - case refl => exact LTS.τTrN.refl - case tr n' _ _ m' h1 h2 h3 => - have h4 := LTS.τTrN.tr h1 h2 - have h5 := LTS.τTrN.append lts h4 h3 - grind - case mpr => - cases h - case refl => exact LTS.STrN.refl - case tr n' s'' h1 h2 => exact LTS.STrN.tr h1 h2 LTS.τTrN.refl - -@[grind] -theorem LTS.τTr_imp_STrN_τ [HasTau Label] (lts : LTS State Label) : - lts.τTr s s' → ∃ n, lts.STrN n s HasTau.τ s' := by - intro h - obtain ⟨n, h⟩ := lts.τTr_imp_τTrN h - exists n - grind - -/-- Saturated transitions labelled by τ can be composed (weighted version). -/ -theorem LTS.STrN.trans_τ - [HasTau Label] (lts : LTS State Label) - (h1 : lts.STrN n s1 HasTau.τ s2) (h2 : lts.STrN m s2 HasTau.τ s3) : - lts.STrN (n + m) s1 HasTau.τ s3 := by grind - - -/-- Saturated transitions can be appended with τ-transitions (weighted version). -/ -@[grind] -theorem LTS.STrN.append - [HasTau Label] (lts : LTS State Label) - (h1 : lts.STrN n1 s1 μ s2) - (h2 : lts.STrN n2 s2 HasTau.τ s3) : - lts.STrN (n1 + n2) s1 μ s3 := by - rw [STrN_τTrN lts] at h2 - cases h1 - case refl => grind - case tr _ _ _ _ h3 h4 h5 => - have h6 := LTS.τTrN.append lts h5 h2 - have h7 := LTS.STrN.tr h3 h4 h6 - grind - -/-- Saturated transitions can be composed (weighted version). -/ -@[grind] -theorem LTS.STrN.comp - [HasTau Label] (lts : LTS State Label) - (h1 : lts.STrN n1 s1 HasTau.τ s2) - (h2 : lts.STrN n2 s2 μ s3) - (h3 : lts.STrN n3 s3 HasTau.τ s4) : - lts.STrN (n1 + n2 + n3) s1 μ s4 := by - rw [STrN_τTrN lts] at h1 h3 - cases h2 - case refl => grind - case tr _ _ _ _ h4 h5 h6 => - have h7 := LTS.τTrN.append lts h1 h4 - have h8 := LTS.τTrN.append lts h6 h3 - have h9 := LTS.STrN.tr h7 h5 h8 - grind + case tail _ h1 h2 => exact LTS.STr.tr h1 h2 .refl /-- Saturated transitions can be composed. -/ @[grind] @@ -608,8 +576,6 @@ theorem LTS.saturate_sTr_tr [hHasTau : HasTau Label] (lts : LTS State Label) rw [←LTS.STr_τTr lts] at hstr1 hstr2 exact LTS.STr.comp lts hstr1 htr hstr2 --/ - /-- In a saturated LTS, every state is in its τ-image. -/ @[grind] theorem LTS.mem_saturate_image_τ [HasTau Label] (lts : LTS State Label) : @@ -621,6 +587,65 @@ by performing only `τ`-transitions. -/ def LTS.τClosure [HasTau Label] (lts : LTS State Label) (S : Set State) : Set State := lts.saturate.setImage S HasTau.τ +/-- As `LTS.str`, but counts the number of `τ`-transitions. This is convenient as induction +metric. -/ +@[grind] +inductive LTS.STrN [HasTau Label] (lts : LTS State Label) : + ℕ → State → Label → State → Prop where + | refl : lts.STrN 0 s HasTau.τ s + | tr : + lts.STrN n s1 HasTau.τ s2 → + lts.Tr s2 μ s3 → + lts.STrN m s3 HasTau.τ s4 → + lts.STrN (n + m + 1) s1 μ s4 + +@[grind] +theorem LTS.τTr_imp_sTrN [HasTau Label] (lts : LTS State Label) : + lts.τTr s1 s2 → ∃ n, lts.STrN n s1 HasTau.τ s2 := by + intro h + induction h + case refl => + exists 0 + apply LTS.STrN.refl + case tail _ _ _ htr ih => + obtain ⟨n, hn⟩ := ih + exists (n + 1) + apply LTS.STrN.tr hn htr LTS.STrN.refl + +@[grind] +theorem LTS.sTrN_imp_τTr [HasTau Label] (lts : LTS State Label) : + lts.STrN n s1 HasTau.τ s2 → lts.τTr s1 s2 := by + intro h + cases h + case refl => exact Relation.ReflTransGen.refl + case tr m _ _ k hτ1 htr hτ2 => + have hτ1' := LTS.sTrN_imp_τTr lts hτ1 + have hτ3' := LTS.sTrN_imp_τTr lts hτ2 + exact Relation.ReflTransGen.trans hτ1' (Relation.ReflTransGen.head htr hτ3') + +/-- `LTS.str` and `LTS.strN` are equivalent. -/ +@[grind] +theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : + lts.STr s1 μ s2 ↔ ∃ n, lts.STrN n s1 μ s2 := by + apply Iff.intro <;> intro h + case mp => + induction h + case refl => + exists 0 + apply LTS.STrN.refl + case tr _ _ hτ1 htr hτ2 => + obtain ⟨n, hn⟩ := LTS.τTr_imp_sTrN lts hτ1 + obtain ⟨m, hm⟩ := LTS.τTr_imp_sTrN lts hτ2 + exists (n + m + 1) + apply LTS.STrN.tr hn htr hm + case mpr => + obtain ⟨n, hn⟩ := h + induction hn + case refl => + exact LTS.STr.refl + case tr _ _ _ _ _ _ h2 _ h1 h3 => + exact LTS.STr.comp lts h1 (LTS.STr.single lts h2) h3 + end Weak /-! ## Divergence -/ @@ -654,73 +679,6 @@ def LTS.DivergenceFree [HasTau Label] (lts : LTS State Label) : Prop := end Divergence -section Relation - -/-- Returns the relation that relates all states `s1` and `s2` via a fixed transition label `μ`. -/ -def LTS.Tr.toRelation (lts : LTS State Label) (μ : Label) : State → State → Prop := - fun s1 s2 => lts.Tr s1 μ s2 - -/-- Returns the relation that relates all states `s1` and `s2` via a fixed list of transition -labels `μs`. -/ -def LTS.MTr.toRelation (lts : LTS State Label) (μs : List Label) : State → State → Prop := - fun s1 s2 => lts.MTr s1 μs s2 - -/-- Any homogeneous relation can be seen as an LTS where all transitions have the same label. -/ -def Relation.toLTS [DecidableEq Label] (r : State → State → Prop) (μ : Label) : - LTS State Label where - Tr := fun s1 μ' s2 => if μ' = μ then r s1 s2 else False - -end Relation - -section Trans - -/-! ## Support for the calc tactic -/ - -/-- Transitions can be chained. -/ -instance (lts : LTS State Label) : - Trans - (LTS.Tr.toRelation lts μ1) - (LTS.Tr.toRelation lts μ2) - (LTS.MTr.toRelation lts [μ1, μ2]) where - trans := by - intro s1 s2 s3 htr1 htr2 - apply LTS.MTr.single at htr1 - apply LTS.MTr.single at htr2 - apply LTS.MTr.comp lts htr1 htr2 - -/-- Transitions can be chained with multi-step transitions. -/ -instance (lts : LTS State Label) : - Trans - (LTS.Tr.toRelation lts μ) - (LTS.MTr.toRelation lts μs) - (LTS.MTr.toRelation lts (μ :: μs)) where - trans := by - intro s1 s2 s3 htr1 hmtr2 - apply LTS.MTr.single at htr1 - apply LTS.MTr.comp lts htr1 hmtr2 - -/-- Multi-step transitions can be chained with transitions. -/ -instance (lts : LTS State Label) : - Trans - (LTS.MTr.toRelation lts μs) - (LTS.Tr.toRelation lts μ) - (LTS.MTr.toRelation lts (μs ++ [μ])) where - trans := by - intro s1 s2 s3 hmtr1 htr2 - apply LTS.MTr.single at htr2 - apply LTS.MTr.comp lts hmtr1 htr2 - -/-- Multi-step transitions can be chained. -/ -instance (lts : LTS State Label) : - Trans - (LTS.MTr.toRelation lts μs1) - (LTS.MTr.toRelation lts μs2) - (LTS.MTr.toRelation lts (μs1 ++ μs2)) where - trans := by - intro s1 s2 s3 hmtr1 hmtr2 - apply LTS.MTr.comp lts hmtr1 hmtr2 - -end Trans open Lean Elab Meta Command Term diff --git a/Cslib/Foundations/Semantics/LTS/Bisimulation.lean b/Cslib/Foundations/Semantics/LTS/Bisimulation.lean index c82f03db..0b09b456 100644 --- a/Cslib/Foundations/Semantics/LTS/Bisimulation.lean +++ b/Cslib/Foundations/Semantics/LTS/Bisimulation.lean @@ -809,7 +809,6 @@ theorem SWBisimulation.follow_internal_fst_n cases hstrN rename_i n1 sb sb' n2 hstrN1 htr hstrN2 let hswb_m := hswb - rw [←LTS.STrN_τTrN] at hstrN1 hstrN2 have ih1 := SWBisimulation.follow_internal_fst_n hswb hr hstrN1 obtain ⟨sb2, hstrs2, hrsb⟩ := ih1 have h := (hswb hrsb HasTau.τ).1 sb' htr @@ -817,9 +816,7 @@ theorem SWBisimulation.follow_internal_fst_n have ih2 := SWBisimulation.follow_internal_fst_n hswb hrsb2 hstrN2 obtain ⟨s2', hstrs2', hrs2⟩ := ih2 exists s2' - constructor - · apply LTS.STr.trans_τ lts (LTS.STr.trans_τ lts hstrs2 hstrsb2) hstrs2' - · exact hrs2 + grind /-- Utility theorem for 'following' internal transitions using an `SWBisimulation` (second component, weighted version). -/ @@ -837,7 +834,6 @@ theorem SWBisimulation.follow_internal_snd_n cases hstrN rename_i n1 sb sb' n2 hstrN1 htr hstrN2 let hswb_m := hswb - rw [←LTS.STrN_τTrN] at hstrN1 hstrN2 have ih1 := SWBisimulation.follow_internal_snd_n hswb hr hstrN1 obtain ⟨sb1, hstrs1, hrsb⟩ := ih1 have h := (hswb hrsb HasTau.τ).2 sb' htr @@ -845,9 +841,7 @@ theorem SWBisimulation.follow_internal_snd_n have ih2 := SWBisimulation.follow_internal_snd_n hswb hrsb2 hstrN2 obtain ⟨s2', hstrs2', hrs2⟩ := ih2 exists s2' - constructor - · apply LTS.STr.trans_τ lts (LTS.STr.trans_τ lts hstrs1 hstrsb2) hstrs2' - · exact hrs2 + grind /-- Utility theorem for 'following' internal transitions using an `SWBisimulation` (first component). -/ From 2092148e16f818d1b078277b0fd3a0dac77d3553 Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Fri, 17 Oct 2025 17:51:40 +0200 Subject: [PATCH 03/21] Perhaps keep those STrN theorems after all? --- Cslib/Foundations/Semantics/LTS/Basic.lean | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index 2f25455f..ee85d97f 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -623,6 +623,11 @@ theorem LTS.sTrN_imp_τTr [HasTau Label] (lts : LTS State Label) : have hτ3' := LTS.sTrN_imp_τTr lts hτ2 exact Relation.ReflTransGen.trans hτ1' (Relation.ReflTransGen.head htr hτ3') +@[grind] +theorem LTS.τTr_sTrN [HasTau Label] (lts : LTS State Label) : + lts.τTr s1 s2 ↔ ∃ n, lts.STrN n s1 HasTau.τ s2 := by + grind + /-- `LTS.str` and `LTS.strN` are equivalent. -/ @[grind] theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : @@ -646,6 +651,32 @@ theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : case tr _ _ _ _ _ _ h2 _ h1 h3 => exact LTS.STr.comp lts h1 (LTS.STr.single lts h2) h3 +/-- Saturated transitions labelled by τ can be composed (weighted version). -/ +theorem LTS.STrN.trans_τ + [HasTau Label] (lts : LTS State Label) + (h1 : lts.STrN n s1 HasTau.τ s2) (h2 : lts.STrN m s2 HasTau.τ s3) : + lts.STrN (n + m) s1 HasTau.τ s3 := by + sorry + +/-- Saturated transitions can be appended with τ-transitions (weighted version). -/ +@[grind] +theorem LTS.STrN.append + [HasTau Label] (lts : LTS State Label) + (h1 : lts.STrN n1 s1 μ s2) + (h2 : lts.STrN n2 s2 HasTau.τ s3) : + lts.STrN (n1 + n2) s1 μ s3 := by + sorry + +/-- Saturated transitions can be composed (weighted version). -/ +@[grind] +theorem LTS.STrN.comp + [HasTau Label] (lts : LTS State Label) + (h1 : lts.STrN n1 s1 HasTau.τ s2) + (h2 : lts.STrN n2 s2 μ s3) + (h3 : lts.STrN n3 s3 HasTau.τ s4) : + lts.STrN (n1 + n2 + n3) s1 μ s4 := by + sorry + end Weak /-! ## Divergence -/ From 43f9e97c337d69a273ac4b2b295818df55c34145 Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Mon, 15 Dec 2025 10:42:19 +0100 Subject: [PATCH 04/21] removed redundant code that accidentally stayed after merge --- Cslib/Foundations/Semantics/LTS/Basic.lean | 52 ---------------------- 1 file changed, 52 deletions(-) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index 1c5e22e0..40687dcb 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -497,10 +497,6 @@ theorem LTS.STr.comp case tr _ _ hτ1 htr hτ2 => exact LTS.STr.tr (Relation.ReflTransGen.trans h1 hτ1) htr (Relation.ReflTransGen.trans hτ2 h3) -@[grind _=_] -lemma LTS.saturate_tr_sTr [HasTau Label] (lts : LTS State Label) : - lts.saturate.Tr s HasTau.τ = lts.STr s HasTau.τ := by simp [LTS.saturate] - /-- In a saturated LTS, the transition and saturated transition relations are the same. -/ @[grind _=_] theorem LTS.saturate_τTr_τTr [hHasTau : HasTau Label] (lts : LTS State Label) @@ -663,54 +659,6 @@ theorem LTS.STrN.comp have conc := LTS.STrN.append lts hprefix h3 grind -/-- Saturated transitions can be composed. -/ -@[scoped grind <=] -theorem LTS.STr.comp - [HasTau Label] (lts : LTS State Label) - (h1 : lts.STr s1 HasTau.τ s2) - (h2 : lts.STr s2 μ s3) - (h3 : lts.STr s3 HasTau.τ s4) : - lts.STr s1 μ s4 := by - obtain ⟨n1, h1N⟩ := (LTS.sTr_sTrN lts).1 h1 - obtain ⟨n2, h2N⟩ := (LTS.sTr_sTrN lts).1 h2 - obtain ⟨n3, h3N⟩ := (LTS.sTr_sTrN lts).1 h3 - have concN := LTS.STrN.comp lts h1N h2N h3N - apply (LTS.sTr_sTrN lts).2 ⟨n1 + n2 + n3, concN⟩ - -open scoped LTS.STr in -/-- In a saturated LTS, the transition and saturated transition relations are the same. -/ -@[scoped grind _=_] -theorem LTS.saturate_sTr_tr [hHasTau : HasTau Label] (lts : LTS State Label) - (hμ : μ = hHasTau.τ) : lts.saturate.Tr s μ = lts.saturate.STr s μ := by - ext s' - apply Iff.intro <;> intro h - case mp => - induction h - case refl => constructor - case tr s1 sb μ sb' s2 hstr1 htr hstr2 ih1 ih2 => - rw [hμ] at htr - apply LTS.STr.single at htr - rw [← LTS.saturate_tr_sTr] at htr - grind [LTS.STr.tr] - case mpr => - induction h - case refl => constructor - case tr s1 sb μ sb' s2 hstr1 htr hstr2 ih1 ih2 => - simp only [LTS.saturate] at ih1 htr ih2 - simp only [LTS.saturate] - grind - -/-- In a saturated LTS, every state is in its τ-image. -/ -@[scoped grind .] -theorem LTS.mem_saturate_image_τ [HasTau Label] (lts : LTS State Label) : - s ∈ lts.saturate.image s HasTau.τ := LTS.STr.refl - -/-- The `τ`-closure of a set of states `S` is the set of states reachable by any state in `S` -by performing only `τ`-transitions. -/ -@[scoped grind =] -def LTS.τClosure [HasTau Label] (lts : LTS State Label) (S : Set State) : Set State := - lts.saturate.setImage S HasTau.τ - end Weak /-! ## Divergence -/ From 8edd9ad4de18ceee86fbb0faa28553e492ffdd8c Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Mon, 15 Dec 2025 11:17:53 +0100 Subject: [PATCH 05/21] Proved STrN.append --- Cslib/Foundations/Semantics/LTS/Basic.lean | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index 40687dcb..cf5d86fc 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -640,7 +640,11 @@ theorem LTS.STrN.append (h1 : lts.STrN n1 s1 μ s2) (h2 : lts.STrN n2 s2 HasTau.τ s3) : lts.STrN (n1 + n2) s1 μ s3 := by - sorry + induction h1 + case refl => grind + case tr hstr1 htr hstr2 ih1 ih2 => + have conc := LTS.STrN.tr hstr1 htr (ih2 h2) + grind /-- Saturated transitions can be composed (weighted version). -/ @[scoped grind <=] From 76de0ff86820523a0d8aa73715b988ce775eb167 Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Mon, 15 Dec 2025 11:46:06 +0100 Subject: [PATCH 06/21] Renamed \tauTr to \tauSTr --- Cslib/Foundations/Semantics/LTS/Basic.lean | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index cf5d86fc..88dad4be 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -442,13 +442,13 @@ class HasTau (Label : Type v) where τ : Label /-- Saturated τ-transition relation. -/ -def LTS.τTr [HasTau Label] (lts : LTS State Label) : State → State → Prop := +def LTS.τSTr [HasTau Label] (lts : LTS State Label) : State → State → Prop := Relation.ReflTransGen (Tr.toRelation lts HasTau.τ) /-- Saturated transition relation. -/ inductive LTS.STr [HasTau Label] (lts : LTS State Label) : State → Label → State → Prop where | refl : lts.STr s HasTau.τ s -| tr : lts.τTr s1 s2 → lts.Tr s2 μ s3 → lts.τTr s3 s4 → lts.STr s1 μ s4 +| tr : lts.τSTr s1 s2 → lts.Tr s2 μ s3 → lts.τSTr s3 s4 → lts.STr s1 μ s4 /-- The `LTS` obtained by saturating the transition relation in `lts`. -/ @[scoped grind =] @@ -469,7 +469,7 @@ theorem LTS.STr.single [HasTau Label] (lts : LTS State Label) : /-- STr transitions labeled by HasTau.τ are exactly the τTr transitions. -/ @[grind] theorem LTS.STr_τTr [HasTau Label] (lts : LTS State Label) : - lts.STr s HasTau.τ s' ↔ lts.τTr s s' := by + lts.STr s HasTau.τ s' ↔ lts.τSTr s s' := by apply Iff.intro <;> intro h case mp => cases h @@ -500,7 +500,7 @@ theorem LTS.STr.comp /-- In a saturated LTS, the transition and saturated transition relations are the same. -/ @[grind _=_] theorem LTS.saturate_τTr_τTr [hHasTau : HasTau Label] (lts : LTS State Label) - : lts.saturate.τTr s = lts.τTr s := by + : lts.saturate.τSTr s = lts.τSTr s := by ext s'' apply Iff.intro <;> intro h case mp => @@ -559,7 +559,7 @@ inductive LTS.STrN [HasTau Label] (lts : LTS State Label) : @[grind] theorem LTS.τTr_imp_sTrN [HasTau Label] (lts : LTS State Label) : - lts.τTr s1 s2 → ∃ n, lts.STrN n s1 HasTau.τ s2 := by + lts.τSTr s1 s2 → ∃ n, lts.STrN n s1 HasTau.τ s2 := by intro h induction h case refl => @@ -572,7 +572,7 @@ theorem LTS.τTr_imp_sTrN [HasTau Label] (lts : LTS State Label) : @[grind] theorem LTS.sTrN_imp_τTr [HasTau Label] (lts : LTS State Label) : - lts.STrN n s1 HasTau.τ s2 → lts.τTr s1 s2 := by + lts.STrN n s1 HasTau.τ s2 → lts.τSTr s1 s2 := by intro h cases h case refl => exact Relation.ReflTransGen.refl @@ -582,11 +582,11 @@ theorem LTS.sTrN_imp_τTr [HasTau Label] (lts : LTS State Label) : exact Relation.ReflTransGen.trans hτ1' (Relation.ReflTransGen.head htr hτ3') @[grind] -theorem LTS.τTr_sTrN [HasTau Label] (lts : LTS State Label) : - lts.τTr s1 s2 ↔ ∃ n, lts.STrN n s1 HasTau.τ s2 := by +theorem LTS.τSTr_sTrN [HasTau Label] (lts : LTS State Label) : + lts.τSTr s1 s2 ↔ ∃ n, lts.STrN n s1 HasTau.τ s2 := by grind -/-- `LTS.str` and `LTS.strN` are equivalent. -/ +/-- `LTS.sTr` and `LTS.sTrN` are equivalent. -/ @[scoped grind =] theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : lts.STr s1 μ s2 ↔ ∃ n, lts.STrN n s1 μ s2 := by From ea3b8a77baeb0144947be68cdfb3b4183221be58 Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Mon, 5 Jan 2026 14:41:00 +0100 Subject: [PATCH 07/21] Updated naming --- Cslib/Foundations/Semantics/LTS/Basic.lean | 54 +++++++++++----------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index be1ae944..edc7c88e 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -502,7 +502,7 @@ def LTS.saturate [HasTau Label] (lts : LTS State Label) : LTS State Label where Tr := lts.STr @[scoped grind _=_] -theorem LTS.saturate_tr_sTr [HasTau Label] {lts : LTS State Label} : +theorem LTS.saturate_tr_STr [HasTau Label] {lts : LTS State Label} : lts.saturate.Tr = lts.STr := by rfl /-- Any transition is also a saturated transition. -/ @@ -512,9 +512,9 @@ theorem LTS.STr.single [HasTau Label] (lts : LTS State Label) : intro h apply LTS.STr.tr .refl h .refl -/-- STr transitions labeled by HasTau.τ are exactly the τTr transitions. -/ -@[grind] -theorem LTS.STr_τTr [HasTau Label] (lts : LTS State Label) : +/-- STr transitions labeled by HasTau.τ are exactly the τSTr transitions. -/ +@[grind _=_] +theorem LTS.STr_τSTr [HasTau Label] (lts : LTS State Label) : lts.STr s HasTau.τ s' ↔ lts.τSTr s s' := by apply Iff.intro <;> intro h case mp => @@ -528,31 +528,31 @@ theorem LTS.STr_τTr [HasTau Label] (lts : LTS State Label) : case tail _ h1 h2 => exact LTS.STr.tr h1 h2 .refl /-- Saturated transitions can be composed. -/ -@[grind] +@[grind →] theorem LTS.STr.comp [HasTau Label] (lts : LTS State Label) (h1 : lts.STr s1 HasTau.τ s2) (h2 : lts.STr s2 μ s3) (h3 : lts.STr s3 HasTau.τ s4) : lts.STr s1 μ s4 := by - rw [LTS.STr_τTr _] at h1 h3 + rw [LTS.STr_τSTr _] at h1 h3 cases h2 case refl => - rw [LTS.STr_τTr _] + rw [LTS.STr_τSTr _] apply Relation.ReflTransGen.trans h1 h3 case tr _ _ hτ1 htr hτ2 => exact LTS.STr.tr (Relation.ReflTransGen.trans h1 hτ1) htr (Relation.ReflTransGen.trans hτ2 h3) /-- In a saturated LTS, the transition and saturated transition relations are the same. -/ @[grind _=_] -theorem LTS.saturate_τTr_τTr [hHasTau : HasTau Label] (lts : LTS State Label) +theorem LTS.saturate_τSTr_τSTr [hHasTau : HasTau Label] (lts : LTS State Label) : lts.saturate.τSTr s = lts.τSTr s := by ext s'' apply Iff.intro <;> intro h case mp => induction h case refl => constructor - case tail _ _ _ h2 h3 => exact Relation.ReflTransGen.trans h3 ((LTS.STr_τTr _).mp h2) + case tail _ _ _ h2 h3 => exact Relation.ReflTransGen.trans h3 ((LTS.STr_τSTr _).mp h2) case mpr => cases h case refl => constructor @@ -562,7 +562,7 @@ theorem LTS.saturate_τTr_τTr [hHasTau : HasTau Label] (lts : LTS State Label) /-- In a saturated LTS, the transition and saturated transition relations are the same. -/ @[grind _=_] -theorem LTS.saturate_sTr_tr [hHasTau : HasTau Label] (lts : LTS State Label) +theorem LTS.saturate_Tr_saturate_STr [hHasTau : HasTau Label] (lts : LTS State Label) (hμ : μ = hHasTau.τ) : lts.saturate.Tr s μ = lts.saturate.STr s μ := by ext s' apply Iff.intro <;> intro h @@ -576,12 +576,12 @@ theorem LTS.saturate_sTr_tr [hHasTau : HasTau Label] (lts : LTS State Label) cases h case refl => constructor case tr hstr1 htr hstr2 => - rw [LTS.saturate_τTr_τTr lts] at hstr1 hstr2 - rw [←LTS.STr_τTr lts] at hstr1 hstr2 + rw [LTS.saturate_τSTr_τSTr lts] at hstr1 hstr2 + rw [←LTS.STr_τSTr lts] at hstr1 hstr2 exact LTS.STr.comp lts hstr1 htr hstr2 /-- In a saturated LTS, every state is in its τ-image. -/ -@[grind] +@[grind .] theorem LTS.mem_saturate_image_τ [HasTau Label] (lts : LTS State Label) : s ∈ lts.saturate.image s HasTau.τ := LTS.STr.refl @@ -603,8 +603,8 @@ inductive LTS.STrN [HasTau Label] (lts : LTS State Label) : lts.STrN m s3 HasTau.τ s4 → lts.STrN (n + m + 1) s1 μ s4 -@[grind] -theorem LTS.τTr_imp_sTrN [HasTau Label] (lts : LTS State Label) : +@[grind .] +theorem LTS.τSTr_imp_STrN [HasTau Label] (lts : LTS State Label) : lts.τSTr s1 s2 → ∃ n, lts.STrN n s1 HasTau.τ s2 := by intro h induction h @@ -616,25 +616,25 @@ theorem LTS.τTr_imp_sTrN [HasTau Label] (lts : LTS State Label) : exists (n + 1) apply LTS.STrN.tr hn htr LTS.STrN.refl -@[grind] -theorem LTS.sTrN_imp_τTr [HasTau Label] (lts : LTS State Label) : +@[grind .] +theorem LTS.sTrN_imp_τSTr [HasTau Label] (lts : LTS State Label) : lts.STrN n s1 HasTau.τ s2 → lts.τSTr s1 s2 := by intro h cases h case refl => exact Relation.ReflTransGen.refl case tr m _ _ k hτ1 htr hτ2 => - have hτ1' := LTS.sTrN_imp_τTr lts hτ1 - have hτ3' := LTS.sTrN_imp_τTr lts hτ2 + have hτ1' := LTS.sTrN_imp_τSTr lts hτ1 + have hτ3' := LTS.sTrN_imp_τSTr lts hτ2 exact Relation.ReflTransGen.trans hτ1' (Relation.ReflTransGen.head htr hτ3') -@[grind] -theorem LTS.τSTr_sTrN [HasTau Label] (lts : LTS State Label) : +@[grind .] +theorem LTS.τSTr_STrN [HasTau Label] (lts : LTS State Label) : lts.τSTr s1 s2 ↔ ∃ n, lts.STrN n s1 HasTau.τ s2 := by grind /-- `LTS.sTr` and `LTS.sTrN` are equivalent. -/ @[scoped grind =] -theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : +theorem LTS.STr_STrN [HasTau Label] (lts : LTS State Label) : lts.STr s1 μ s2 ↔ ∃ n, lts.STrN n s1 μ s2 := by apply Iff.intro <;> intro h case mp => @@ -643,8 +643,8 @@ theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : exists 0 apply LTS.STrN.refl case tr _ _ hτ1 htr hτ2 => - obtain ⟨n, hn⟩ := LTS.τTr_imp_sTrN lts hτ1 - obtain ⟨m, hm⟩ := LTS.τTr_imp_sTrN lts hτ2 + obtain ⟨n, hn⟩ := LTS.τSTr_imp_STrN lts hτ1 + obtain ⟨m, hm⟩ := LTS.τSTr_imp_STrN lts hτ2 exists (n + m + 1) apply LTS.STrN.tr hn htr hm case mpr => @@ -674,10 +674,10 @@ theorem LTS.STr.trans_τ [HasTau Label] (lts : LTS State Label) (h1 : lts.STr s1 HasTau.τ s2) (h2 : lts.STr s2 HasTau.τ s3) : lts.STr s1 HasTau.τ s3 := by - obtain ⟨n, h1N⟩ := (LTS.sTr_sTrN lts).1 h1 - obtain ⟨m, h2N⟩ := (LTS.sTr_sTrN lts).1 h2 + obtain ⟨n, h1N⟩ := (LTS.STr_STrN lts).1 h1 + obtain ⟨m, h2N⟩ := (LTS.STr_STrN lts).1 h2 have concN := LTS.STrN.trans_τ lts h1N h2N - apply (LTS.sTr_sTrN lts).2 ⟨n + m, concN⟩ + apply (LTS.STr_STrN lts).2 ⟨n + m, concN⟩ /-- Saturated transitions can be appended with τ-transitions (weighted version). -/ @[scoped grind <=] From f85abc22e5c509d898e797b55d304c49c742c27e Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Mon, 5 Jan 2026 15:01:02 +0100 Subject: [PATCH 08/21] Staying closer to original --- Cslib/Foundations/Semantics/LTS/Basic.lean | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index edc7c88e..17ce3e24 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -87,7 +87,7 @@ inductive LTS.MTr (lts : LTS State Label) : State → List Label → State → P | refl {s : State} : lts.MTr s [] s | stepL {s1 : State} {μ : Label} {s2 : State} {μs : List Label} {s3 : State} : lts.Tr s1 μ s2 → lts.MTr s2 μs s3 → - lts.MTr s1 (μ :: μs) s3 + lts.MTr s1 (μ :: μs) s3 /-- Any transition is also a multistep transition. -/ @[scoped grind →] @@ -502,7 +502,7 @@ def LTS.saturate [HasTau Label] (lts : LTS State Label) : LTS State Label where Tr := lts.STr @[scoped grind _=_] -theorem LTS.saturate_tr_STr [HasTau Label] {lts : LTS State Label} : +theorem LTS.saturate_tr_sTr [HasTau Label] {lts : LTS State Label} : lts.saturate.Tr = lts.STr := by rfl /-- Any transition is also a saturated transition. -/ @@ -514,7 +514,7 @@ theorem LTS.STr.single [HasTau Label] (lts : LTS State Label) : /-- STr transitions labeled by HasTau.τ are exactly the τSTr transitions. -/ @[grind _=_] -theorem LTS.STr_τSTr [HasTau Label] (lts : LTS State Label) : +theorem LTS.sTr_eq_τSTr [HasTau Label] (lts : LTS State Label) : lts.STr s HasTau.τ s' ↔ lts.τSTr s s' := by apply Iff.intro <;> intro h case mp => @@ -535,10 +535,10 @@ theorem LTS.STr.comp (h2 : lts.STr s2 μ s3) (h3 : lts.STr s3 HasTau.τ s4) : lts.STr s1 μ s4 := by - rw [LTS.STr_τSTr _] at h1 h3 + rw [LTS.sTr_eq_τSTr _] at h1 h3 cases h2 case refl => - rw [LTS.STr_τSTr _] + rw [LTS.sTr_eq_τSTr _] apply Relation.ReflTransGen.trans h1 h3 case tr _ _ hτ1 htr hτ2 => exact LTS.STr.tr (Relation.ReflTransGen.trans h1 hτ1) htr (Relation.ReflTransGen.trans hτ2 h3) @@ -552,7 +552,7 @@ theorem LTS.saturate_τSTr_τSTr [hHasTau : HasTau Label] (lts : LTS State Label case mp => induction h case refl => constructor - case tail _ _ _ h2 h3 => exact Relation.ReflTransGen.trans h3 ((LTS.STr_τSTr _).mp h2) + case tail _ _ _ h2 h3 => exact Relation.ReflTransGen.trans h3 ((LTS.sTr_eq_τSTr _).mp h2) case mpr => cases h case refl => constructor @@ -562,7 +562,7 @@ theorem LTS.saturate_τSTr_τSTr [hHasTau : HasTau Label] (lts : LTS State Label /-- In a saturated LTS, the transition and saturated transition relations are the same. -/ @[grind _=_] -theorem LTS.saturate_Tr_saturate_STr [hHasTau : HasTau Label] (lts : LTS State Label) +theorem LTS.saturate_tr_saturate_sTr [hHasTau : HasTau Label] (lts : LTS State Label) (hμ : μ = hHasTau.τ) : lts.saturate.Tr s μ = lts.saturate.STr s μ := by ext s' apply Iff.intro <;> intro h @@ -577,7 +577,7 @@ theorem LTS.saturate_Tr_saturate_STr [hHasTau : HasTau Label] (lts : LTS State L case refl => constructor case tr hstr1 htr hstr2 => rw [LTS.saturate_τSTr_τSTr lts] at hstr1 hstr2 - rw [←LTS.STr_τSTr lts] at hstr1 hstr2 + rw [←LTS.sTr_eq_τSTr lts] at hstr1 hstr2 exact LTS.STr.comp lts hstr1 htr hstr2 /-- In a saturated LTS, every state is in its τ-image. -/ @@ -604,7 +604,7 @@ inductive LTS.STrN [HasTau Label] (lts : LTS State Label) : lts.STrN (n + m + 1) s1 μ s4 @[grind .] -theorem LTS.τSTr_imp_STrN [HasTau Label] (lts : LTS State Label) : +theorem LTS.τSTr_imp_sTrN [HasTau Label] (lts : LTS State Label) : lts.τSTr s1 s2 → ∃ n, lts.STrN n s1 HasTau.τ s2 := by intro h induction h @@ -628,13 +628,13 @@ theorem LTS.sTrN_imp_τSTr [HasTau Label] (lts : LTS State Label) : exact Relation.ReflTransGen.trans hτ1' (Relation.ReflTransGen.head htr hτ3') @[grind .] -theorem LTS.τSTr_STrN [HasTau Label] (lts : LTS State Label) : +theorem LTS.τSTr_eq_sTrN [HasTau Label] (lts : LTS State Label) : lts.τSTr s1 s2 ↔ ∃ n, lts.STrN n s1 HasTau.τ s2 := by grind /-- `LTS.sTr` and `LTS.sTrN` are equivalent. -/ @[scoped grind =] -theorem LTS.STr_STrN [HasTau Label] (lts : LTS State Label) : +theorem LTS.sTr_eq_sTrN [HasTau Label] (lts : LTS State Label) : lts.STr s1 μ s2 ↔ ∃ n, lts.STrN n s1 μ s2 := by apply Iff.intro <;> intro h case mp => @@ -643,8 +643,8 @@ theorem LTS.STr_STrN [HasTau Label] (lts : LTS State Label) : exists 0 apply LTS.STrN.refl case tr _ _ hτ1 htr hτ2 => - obtain ⟨n, hn⟩ := LTS.τSTr_imp_STrN lts hτ1 - obtain ⟨m, hm⟩ := LTS.τSTr_imp_STrN lts hτ2 + obtain ⟨n, hn⟩ := LTS.τSTr_imp_sTrN lts hτ1 + obtain ⟨m, hm⟩ := LTS.τSTr_imp_sTrN lts hτ2 exists (n + m + 1) apply LTS.STrN.tr hn htr hm case mpr => @@ -674,10 +674,10 @@ theorem LTS.STr.trans_τ [HasTau Label] (lts : LTS State Label) (h1 : lts.STr s1 HasTau.τ s2) (h2 : lts.STr s2 HasTau.τ s3) : lts.STr s1 HasTau.τ s3 := by - obtain ⟨n, h1N⟩ := (LTS.STr_STrN lts).1 h1 - obtain ⟨m, h2N⟩ := (LTS.STr_STrN lts).1 h2 + obtain ⟨n, h1N⟩ := (LTS.sTr_eq_sTrN lts).1 h1 + obtain ⟨m, h2N⟩ := (LTS.sTr_eq_sTrN lts).1 h2 have concN := LTS.STrN.trans_τ lts h1N h2N - apply (LTS.STr_STrN lts).2 ⟨n + m, concN⟩ + apply (LTS.sTr_eq_sTrN lts).2 ⟨n + m, concN⟩ /-- Saturated transitions can be appended with τ-transitions (weighted version). -/ @[scoped grind <=] From ca153219dd5c6ee0906b728f0ecfaa6f068b659b Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Mon, 5 Jan 2026 15:04:32 +0100 Subject: [PATCH 09/21] Minor edits, changing back to old namings --- Cslib/Foundations/Semantics/LTS/Basic.lean | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index 17ce3e24..a3fe1bb5 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -628,13 +628,13 @@ theorem LTS.sTrN_imp_τSTr [HasTau Label] (lts : LTS State Label) : exact Relation.ReflTransGen.trans hτ1' (Relation.ReflTransGen.head htr hτ3') @[grind .] -theorem LTS.τSTr_eq_sTrN [HasTau Label] (lts : LTS State Label) : +theorem LTS.τSTr_sTrN [HasTau Label] (lts : LTS State Label) : lts.τSTr s1 s2 ↔ ∃ n, lts.STrN n s1 HasTau.τ s2 := by grind -/-- `LTS.sTr` and `LTS.sTrN` are equivalent. -/ +/-- `LTS.str` and `LTS.strN` are equivalent. -/ @[scoped grind =] -theorem LTS.sTr_eq_sTrN [HasTau Label] (lts : LTS State Label) : +theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : lts.STr s1 μ s2 ↔ ∃ n, lts.STrN n s1 μ s2 := by apply Iff.intro <;> intro h case mp => @@ -674,10 +674,10 @@ theorem LTS.STr.trans_τ [HasTau Label] (lts : LTS State Label) (h1 : lts.STr s1 HasTau.τ s2) (h2 : lts.STr s2 HasTau.τ s3) : lts.STr s1 HasTau.τ s3 := by - obtain ⟨n, h1N⟩ := (LTS.sTr_eq_sTrN lts).1 h1 - obtain ⟨m, h2N⟩ := (LTS.sTr_eq_sTrN lts).1 h2 + obtain ⟨n, h1N⟩ := (LTS.sTr_sTrN lts).1 h1 + obtain ⟨m, h2N⟩ := (LTS.sTr_sTrN lts).1 h2 have concN := LTS.STrN.trans_τ lts h1N h2N - apply (LTS.sTr_eq_sTrN lts).2 ⟨n + m, concN⟩ + apply (LTS.sTr_sTrN lts).2 ⟨n + m, concN⟩ /-- Saturated transitions can be appended with τ-transitions (weighted version). -/ @[scoped grind <=] From dcceb8ffa529fa7c0453a7f5087c14a678040a5b Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Mon, 5 Jan 2026 15:08:23 +0100 Subject: [PATCH 10/21] Final reverts to original. Now PR only contains essential changes. --- Cslib/Foundations/Semantics/LTS/Basic.lean | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index a3fe1bb5..52250938 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -682,10 +682,10 @@ theorem LTS.STr.trans_τ /-- Saturated transitions can be appended with τ-transitions (weighted version). -/ @[scoped grind <=] theorem LTS.STrN.append - [HasTau Label] (lts : LTS State Label) - (h1 : lts.STrN n1 s1 μ s2) - (h2 : lts.STrN n2 s2 HasTau.τ s3) : - lts.STrN (n1 + n2) s1 μ s3 := by + [HasTau Label] (lts : LTS State Label) + (h1 : lts.STrN n1 s1 μ s2) + (h2 : lts.STrN n2 s2 HasTau.τ s3) : + lts.STrN (n1 + n2) s1 μ s3 := by induction h1 case refl => grind case tr hstr1 htr hstr2 ih1 ih2 => @@ -739,7 +739,6 @@ class LTS.DivergenceFree [HasTau Label] (lts : LTS State Label) where end Divergence - open Lean Elab Meta Command Term /-- A command to create an `LTS` from a labelled transition `α → β → α → Prop`, robust to use of From eeb8bfc5e2536659f994d1a58a8eed31001cca88 Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Mon, 5 Jan 2026 15:34:47 +0100 Subject: [PATCH 11/21] Moving definition STrN up --- Cslib/Foundations/Semantics/LTS/Basic.lean | 76 ++++------------------ 1 file changed, 13 insertions(+), 63 deletions(-) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index 52250938..2708d993 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -496,6 +496,18 @@ inductive LTS.STr [HasTau Label] (lts : LTS State Label) : State → Label → S | refl : lts.STr s HasTau.τ s | tr : lts.τSTr s1 s2 → lts.Tr s2 μ s3 → lts.τSTr s3 s4 → lts.STr s1 μ s4 +/-- As `LTS.str`, but counts the number of `τ`-transitions. This is convenient as induction +metric. -/ +@[scoped grind] +inductive LTS.STrN [HasTau Label] (lts : LTS State Label) : + ℕ → State → Label → State → Prop where + | refl : lts.STrN 0 s HasTau.τ s + | tr : + lts.STrN n s1 HasTau.τ s2 → + lts.Tr s2 μ s3 → + lts.STrN m s3 HasTau.τ s4 → + lts.STrN (n + m + 1) s1 μ s4 + /-- The `LTS` obtained by saturating the transition relation in `lts`. -/ @[scoped grind =] def LTS.saturate [HasTau Label] (lts : LTS State Label) : LTS State Label where @@ -512,6 +524,7 @@ theorem LTS.STr.single [HasTau Label] (lts : LTS State Label) : intro h apply LTS.STr.tr .refl h .refl + /-- STr transitions labeled by HasTau.τ are exactly the τSTr transitions. -/ @[grind _=_] theorem LTS.sTr_eq_τSTr [HasTau Label] (lts : LTS State Label) : @@ -591,69 +604,6 @@ by performing only `τ`-transitions. -/ def LTS.τClosure [HasTau Label] (lts : LTS State Label) (S : Set State) : Set State := lts.saturate.setImage S HasTau.τ -/-- As `LTS.str`, but counts the number of `τ`-transitions. This is convenient as induction -metric. -/ -@[scoped grind] -inductive LTS.STrN [HasTau Label] (lts : LTS State Label) : - ℕ → State → Label → State → Prop where - | refl : lts.STrN 0 s HasTau.τ s - | tr : - lts.STrN n s1 HasTau.τ s2 → - lts.Tr s2 μ s3 → - lts.STrN m s3 HasTau.τ s4 → - lts.STrN (n + m + 1) s1 μ s4 - -@[grind .] -theorem LTS.τSTr_imp_sTrN [HasTau Label] (lts : LTS State Label) : - lts.τSTr s1 s2 → ∃ n, lts.STrN n s1 HasTau.τ s2 := by - intro h - induction h - case refl => - exists 0 - apply LTS.STrN.refl - case tail _ _ _ htr ih => - obtain ⟨n, hn⟩ := ih - exists (n + 1) - apply LTS.STrN.tr hn htr LTS.STrN.refl - -@[grind .] -theorem LTS.sTrN_imp_τSTr [HasTau Label] (lts : LTS State Label) : - lts.STrN n s1 HasTau.τ s2 → lts.τSTr s1 s2 := by - intro h - cases h - case refl => exact Relation.ReflTransGen.refl - case tr m _ _ k hτ1 htr hτ2 => - have hτ1' := LTS.sTrN_imp_τSTr lts hτ1 - have hτ3' := LTS.sTrN_imp_τSTr lts hτ2 - exact Relation.ReflTransGen.trans hτ1' (Relation.ReflTransGen.head htr hτ3') - -@[grind .] -theorem LTS.τSTr_sTrN [HasTau Label] (lts : LTS State Label) : - lts.τSTr s1 s2 ↔ ∃ n, lts.STrN n s1 HasTau.τ s2 := by - grind - -/-- `LTS.str` and `LTS.strN` are equivalent. -/ -@[scoped grind =] -theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : - lts.STr s1 μ s2 ↔ ∃ n, lts.STrN n s1 μ s2 := by - apply Iff.intro <;> intro h - case mp => - induction h - case refl => - exists 0 - apply LTS.STrN.refl - case tr _ _ hτ1 htr hτ2 => - obtain ⟨n, hn⟩ := LTS.τSTr_imp_sTrN lts hτ1 - obtain ⟨m, hm⟩ := LTS.τSTr_imp_sTrN lts hτ2 - exists (n + m + 1) - apply LTS.STrN.tr hn htr hm - case mpr => - obtain ⟨n, hn⟩ := h - induction hn - case refl => - exact LTS.STr.refl - case tr _ _ _ _ _ _ h2 _ h1 h3 => - exact LTS.STr.comp lts h1 (LTS.STr.single lts h2) h3 /-- Saturated transitions labelled by τ can be composed (weighted version). -/ @[scoped grind →] From b091047d59197cad4549f0f3565117a3e04e7d54 Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Mon, 5 Jan 2026 15:38:42 +0100 Subject: [PATCH 12/21] One more move --- Cslib/Foundations/Semantics/LTS/Basic.lean | 23 +++++++++++----------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index 2708d993..627e74c4 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -496,18 +496,6 @@ inductive LTS.STr [HasTau Label] (lts : LTS State Label) : State → Label → S | refl : lts.STr s HasTau.τ s | tr : lts.τSTr s1 s2 → lts.Tr s2 μ s3 → lts.τSTr s3 s4 → lts.STr s1 μ s4 -/-- As `LTS.str`, but counts the number of `τ`-transitions. This is convenient as induction -metric. -/ -@[scoped grind] -inductive LTS.STrN [HasTau Label] (lts : LTS State Label) : - ℕ → State → Label → State → Prop where - | refl : lts.STrN 0 s HasTau.τ s - | tr : - lts.STrN n s1 HasTau.τ s2 → - lts.Tr s2 μ s3 → - lts.STrN m s3 HasTau.τ s4 → - lts.STrN (n + m + 1) s1 μ s4 - /-- The `LTS` obtained by saturating the transition relation in `lts`. -/ @[scoped grind =] def LTS.saturate [HasTau Label] (lts : LTS State Label) : LTS State Label where @@ -524,6 +512,17 @@ theorem LTS.STr.single [HasTau Label] (lts : LTS State Label) : intro h apply LTS.STr.tr .refl h .refl +/-- As `LTS.str`, but counts the number of `τ`-transitions. This is convenient as induction +metric. -/ +@[scoped grind] +inductive LTS.STrN [HasTau Label] (lts : LTS State Label) : + ℕ → State → Label → State → Prop where + | refl : lts.STrN 0 s HasTau.τ s + | tr : + lts.STrN n s1 HasTau.τ s2 → + lts.Tr s2 μ s3 → + lts.STrN m s3 HasTau.τ s4 → + lts.STrN (n + m + 1) s1 μ s4 /-- STr transitions labeled by HasTau.τ are exactly the τSTr transitions. -/ @[grind _=_] From 87ce4910dd45d14c0dfde870388d688e1255aeb9 Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Mon, 5 Jan 2026 15:43:33 +0100 Subject: [PATCH 13/21] Move some more --- Cslib/Foundations/Semantics/LTS/Basic.lean | 51 ++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index 627e74c4..dabcdb3b 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -603,6 +603,57 @@ by performing only `τ`-transitions. -/ def LTS.τClosure [HasTau Label] (lts : LTS State Label) (S : Set State) : Set State := lts.saturate.setImage S HasTau.τ +@[grind .] +theorem LTS.τSTr_imp_sTrN [HasTau Label] (lts : LTS State Label) : + lts.τSTr s1 s2 → ∃ n, lts.STrN n s1 HasTau.τ s2 := by + intro h + induction h + case refl => + exists 0 + apply LTS.STrN.refl + case tail _ _ _ htr ih => + obtain ⟨n, hn⟩ := ih + exists (n + 1) + apply LTS.STrN.tr hn htr LTS.STrN.refl + +@[grind .] +theorem LTS.sTrN_imp_τSTr [HasTau Label] (lts : LTS State Label) : + lts.STrN n s1 HasTau.τ s2 → lts.τSTr s1 s2 := by + intro h + cases h + case refl => exact Relation.ReflTransGen.refl + case tr m _ _ k hτ1 htr hτ2 => + have hτ1' := LTS.sTrN_imp_τSTr lts hτ1 + have hτ3' := LTS.sTrN_imp_τSTr lts hτ2 + exact Relation.ReflTransGen.trans hτ1' (Relation.ReflTransGen.head htr hτ3') + +@[grind .] +theorem LTS.τSTr_sTrN [HasTau Label] (lts : LTS State Label) : + lts.τSTr s1 s2 ↔ ∃ n, lts.STrN n s1 HasTau.τ s2 := by + grind + +/-- `LTS.str` and `LTS.strN` are equivalent. -/ +@[scoped grind =] +theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : + lts.STr s1 μ s2 ↔ ∃ n, lts.STrN n s1 μ s2 := by + apply Iff.intro <;> intro h + case mp => + induction h + case refl => + exists 0 + apply LTS.STrN.refl + case tr _ _ hτ1 htr hτ2 => + obtain ⟨n, hn⟩ := LTS.τSTr_imp_sTrN lts hτ1 + obtain ⟨m, hm⟩ := LTS.τSTr_imp_sTrN lts hτ2 + exists (n + m + 1) + apply LTS.STrN.tr hn htr hm + case mpr => + obtain ⟨n, hn⟩ := h + induction hn + case refl => + exact LTS.STr.refl + case tr _ _ _ _ _ _ h2 _ h1 h3 => + exact LTS.STr.comp lts h1 (LTS.STr.single lts h2) h3 /-- Saturated transitions labelled by τ can be composed (weighted version). -/ @[scoped grind →] From 03b9c262a5055bb9c70ff06344cad453198bc936 Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Mon, 5 Jan 2026 15:47:08 +0100 Subject: [PATCH 14/21] Some more moves --- Cslib/Foundations/Semantics/LTS/Basic.lean | 139 +++++++++++---------- 1 file changed, 71 insertions(+), 68 deletions(-) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index dabcdb3b..9412e738 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -539,22 +539,6 @@ theorem LTS.sTr_eq_τSTr [HasTau Label] (lts : LTS State Label) : case refl => exact LTS.STr.refl case tail _ h1 h2 => exact LTS.STr.tr h1 h2 .refl -/-- Saturated transitions can be composed. -/ -@[grind →] -theorem LTS.STr.comp - [HasTau Label] (lts : LTS State Label) - (h1 : lts.STr s1 HasTau.τ s2) - (h2 : lts.STr s2 μ s3) - (h3 : lts.STr s3 HasTau.τ s4) : - lts.STr s1 μ s4 := by - rw [LTS.sTr_eq_τSTr _] at h1 h3 - cases h2 - case refl => - rw [LTS.sTr_eq_τSTr _] - apply Relation.ReflTransGen.trans h1 h3 - case tr _ _ hτ1 htr hτ2 => - exact LTS.STr.tr (Relation.ReflTransGen.trans h1 hτ1) htr (Relation.ReflTransGen.trans hτ2 h3) - /-- In a saturated LTS, the transition and saturated transition relations are the same. -/ @[grind _=_] theorem LTS.saturate_τSTr_τSTr [hHasTau : HasTau Label] (lts : LTS State Label) @@ -572,25 +556,6 @@ theorem LTS.saturate_τSTr_τSTr [hHasTau : HasTau Label] (lts : LTS State Label have h4 := LTS.STr.tr h2 h3 Relation.ReflTransGen.refl exact Relation.ReflTransGen.single h4 -/-- In a saturated LTS, the transition and saturated transition relations are the same. -/ -@[grind _=_] -theorem LTS.saturate_tr_saturate_sTr [hHasTau : HasTau Label] (lts : LTS State Label) - (hμ : μ = hHasTau.τ) : lts.saturate.Tr s μ = lts.saturate.STr s μ := by - ext s' - apply Iff.intro <;> intro h - case mp => - cases h - case refl => constructor - case tr hstr1 htr hstr2 => - apply LTS.STr.single - exact LTS.STr.tr hstr1 htr hstr2 - case mpr => - cases h - case refl => constructor - case tr hstr1 htr hstr2 => - rw [LTS.saturate_τSTr_τSTr lts] at hstr1 hstr2 - rw [←LTS.sTr_eq_τSTr lts] at hstr1 hstr2 - exact LTS.STr.comp lts hstr1 htr hstr2 /-- In a saturated LTS, every state is in its τ-image. -/ @[grind .] @@ -632,28 +597,6 @@ theorem LTS.τSTr_sTrN [HasTau Label] (lts : LTS State Label) : lts.τSTr s1 s2 ↔ ∃ n, lts.STrN n s1 HasTau.τ s2 := by grind -/-- `LTS.str` and `LTS.strN` are equivalent. -/ -@[scoped grind =] -theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : - lts.STr s1 μ s2 ↔ ∃ n, lts.STrN n s1 μ s2 := by - apply Iff.intro <;> intro h - case mp => - induction h - case refl => - exists 0 - apply LTS.STrN.refl - case tr _ _ hτ1 htr hτ2 => - obtain ⟨n, hn⟩ := LTS.τSTr_imp_sTrN lts hτ1 - obtain ⟨m, hm⟩ := LTS.τSTr_imp_sTrN lts hτ2 - exists (n + m + 1) - apply LTS.STrN.tr hn htr hm - case mpr => - obtain ⟨n, hn⟩ := h - induction hn - case refl => - exact LTS.STr.refl - case tr _ _ _ _ _ _ h2 _ h1 h3 => - exact LTS.STr.comp lts h1 (LTS.STr.single lts h2) h3 /-- Saturated transitions labelled by τ can be composed (weighted version). -/ @[scoped grind →] @@ -668,17 +611,6 @@ theorem LTS.STrN.trans_τ have conc := LTS.STrN.tr hstr1 htr ih grind -/-- Saturated transitions labelled by τ can be composed. -/ -@[scoped grind →] -theorem LTS.STr.trans_τ - [HasTau Label] (lts : LTS State Label) - (h1 : lts.STr s1 HasTau.τ s2) (h2 : lts.STr s2 HasTau.τ s3) : - lts.STr s1 HasTau.τ s3 := by - obtain ⟨n, h1N⟩ := (LTS.sTr_sTrN lts).1 h1 - obtain ⟨m, h2N⟩ := (LTS.sTr_sTrN lts).1 h2 - have concN := LTS.STrN.trans_τ lts h1N h2N - apply (LTS.sTr_sTrN lts).2 ⟨n + m, concN⟩ - /-- Saturated transitions can be appended with τ-transitions (weighted version). -/ @[scoped grind <=] theorem LTS.STrN.append @@ -709,6 +641,77 @@ theorem LTS.STrN.comp have conc := LTS.STrN.append lts hprefix h3 grind +/-- Saturated transitions can be composed. -/ +@[grind →] +theorem LTS.STr.comp + [HasTau Label] (lts : LTS State Label) + (h1 : lts.STr s1 HasTau.τ s2) + (h2 : lts.STr s2 μ s3) + (h3 : lts.STr s3 HasTau.τ s4) : + lts.STr s1 μ s4 := by + rw [LTS.sTr_eq_τSTr _] at h1 h3 + cases h2 + case refl => + rw [LTS.sTr_eq_τSTr _] + apply Relation.ReflTransGen.trans h1 h3 + case tr _ _ hτ1 htr hτ2 => + exact LTS.STr.tr (Relation.ReflTransGen.trans h1 hτ1) htr (Relation.ReflTransGen.trans hτ2 h3) + +/-- `LTS.str` and `LTS.strN` are equivalent. -/ +@[scoped grind =] +theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : + lts.STr s1 μ s2 ↔ ∃ n, lts.STrN n s1 μ s2 := by + apply Iff.intro <;> intro h + case mp => + induction h + case refl => + exists 0 + apply LTS.STrN.refl + case tr _ _ hτ1 htr hτ2 => + obtain ⟨n, hn⟩ := LTS.τSTr_imp_sTrN lts hτ1 + obtain ⟨m, hm⟩ := LTS.τSTr_imp_sTrN lts hτ2 + exists (n + m + 1) + apply LTS.STrN.tr hn htr hm + case mpr => + obtain ⟨n, hn⟩ := h + induction hn + case refl => + exact LTS.STr.refl + case tr _ _ _ _ _ _ h2 _ h1 h3 => + exact LTS.STr.comp lts h1 (LTS.STr.single lts h2) h3 + +/-- Saturated transitions labelled by τ can be composed. -/ +@[scoped grind →] +theorem LTS.STr.trans_τ + [HasTau Label] (lts : LTS State Label) + (h1 : lts.STr s1 HasTau.τ s2) (h2 : lts.STr s2 HasTau.τ s3) : + lts.STr s1 HasTau.τ s3 := by + obtain ⟨n, h1N⟩ := (LTS.sTr_sTrN lts).1 h1 + obtain ⟨m, h2N⟩ := (LTS.sTr_sTrN lts).1 h2 + have concN := LTS.STrN.trans_τ lts h1N h2N + apply (LTS.sTr_sTrN lts).2 ⟨n + m, concN⟩ + +/-- In a saturated LTS, the transition and saturated transition relations are the same. -/ +@[grind _=_] +theorem LTS.saturate_tr_saturate_sTr [hHasTau : HasTau Label] (lts : LTS State Label) + (hμ : μ = hHasTau.τ) : lts.saturate.Tr s μ = lts.saturate.STr s μ := by + ext s' + apply Iff.intro <;> intro h + case mp => + cases h + case refl => constructor + case tr hstr1 htr hstr2 => + apply LTS.STr.single + exact LTS.STr.tr hstr1 htr hstr2 + case mpr => + cases h + case refl => constructor + case tr hstr1 htr hstr2 => + rw [LTS.saturate_τSTr_τSTr lts] at hstr1 hstr2 + rw [←LTS.sTr_eq_τSTr lts] at hstr1 hstr2 + exact LTS.STr.comp lts hstr1 htr hstr2 + + end Weak /-! ## Divergence -/ From b25960824fa057a3ec49dbac9b1b59d18b57376a Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Mon, 5 Jan 2026 15:53:20 +0100 Subject: [PATCH 15/21] Revert "Final reverts to original. Now PR only contains essential changes." This reverts commit dcceb8ffa529fa7c0453a7f5087c14a678040a5b. --- Cslib/Foundations/Semantics/LTS/Basic.lean | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index 9412e738..4422160c 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -614,10 +614,10 @@ theorem LTS.STrN.trans_τ /-- Saturated transitions can be appended with τ-transitions (weighted version). -/ @[scoped grind <=] theorem LTS.STrN.append - [HasTau Label] (lts : LTS State Label) - (h1 : lts.STrN n1 s1 μ s2) - (h2 : lts.STrN n2 s2 HasTau.τ s3) : - lts.STrN (n1 + n2) s1 μ s3 := by + [HasTau Label] (lts : LTS State Label) + (h1 : lts.STrN n1 s1 μ s2) + (h2 : lts.STrN n2 s2 HasTau.τ s3) : + lts.STrN (n1 + n2) s1 μ s3 := by induction h1 case refl => grind case tr hstr1 htr hstr2 ih1 ih2 => @@ -742,6 +742,7 @@ class LTS.DivergenceFree [HasTau Label] (lts : LTS State Label) where end Divergence + open Lean Elab Meta Command Term /-- A command to create an `LTS` from a labelled transition `α → β → α → Prop`, robust to use of From b4ed3c80fa0a422d47eeb1de92b02f5b4eb4247e Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Mon, 5 Jan 2026 16:14:32 +0100 Subject: [PATCH 16/21] naming convention: _eq_ left out --- Cslib/Foundations/Semantics/LTS/Basic.lean | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index 4422160c..7a979a7e 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -525,8 +525,8 @@ inductive LTS.STrN [HasTau Label] (lts : LTS State Label) : lts.STrN (n + m + 1) s1 μ s4 /-- STr transitions labeled by HasTau.τ are exactly the τSTr transitions. -/ -@[grind _=_] -theorem LTS.sTr_eq_τSTr [HasTau Label] (lts : LTS State Label) : +@[scoped grind _=_] +theorem LTS.sTr_τSTr [HasTau Label] (lts : LTS State Label) : lts.STr s HasTau.τ s' ↔ lts.τSTr s s' := by apply Iff.intro <;> intro h case mp => @@ -540,7 +540,7 @@ theorem LTS.sTr_eq_τSTr [HasTau Label] (lts : LTS State Label) : case tail _ h1 h2 => exact LTS.STr.tr h1 h2 .refl /-- In a saturated LTS, the transition and saturated transition relations are the same. -/ -@[grind _=_] +@[scoped grind _=_] theorem LTS.saturate_τSTr_τSTr [hHasTau : HasTau Label] (lts : LTS State Label) : lts.saturate.τSTr s = lts.τSTr s := by ext s'' @@ -548,7 +548,7 @@ theorem LTS.saturate_τSTr_τSTr [hHasTau : HasTau Label] (lts : LTS State Label case mp => induction h case refl => constructor - case tail _ _ _ h2 h3 => exact Relation.ReflTransGen.trans h3 ((LTS.sTr_eq_τSTr _).mp h2) + case tail _ _ _ h2 h3 => exact Relation.ReflTransGen.trans h3 ((LTS.sTr_τSTr _).mp h2) case mpr => cases h case refl => constructor @@ -558,17 +558,17 @@ theorem LTS.saturate_τSTr_τSTr [hHasTau : HasTau Label] (lts : LTS State Label /-- In a saturated LTS, every state is in its τ-image. -/ -@[grind .] +@[scoped grind .] theorem LTS.mem_saturate_image_τ [HasTau Label] (lts : LTS State Label) : s ∈ lts.saturate.image s HasTau.τ := LTS.STr.refl /-- The `τ`-closure of a set of states `S` is the set of states reachable by any state in `S` by performing only `τ`-transitions. -/ -@[grind =] +@[scoped grind =] def LTS.τClosure [HasTau Label] (lts : LTS State Label) (S : Set State) : Set State := lts.saturate.setImage S HasTau.τ -@[grind .] +@[scoped grind .] theorem LTS.τSTr_imp_sTrN [HasTau Label] (lts : LTS State Label) : lts.τSTr s1 s2 → ∃ n, lts.STrN n s1 HasTau.τ s2 := by intro h @@ -581,7 +581,7 @@ theorem LTS.τSTr_imp_sTrN [HasTau Label] (lts : LTS State Label) : exists (n + 1) apply LTS.STrN.tr hn htr LTS.STrN.refl -@[grind .] +@[scoped grind .] theorem LTS.sTrN_imp_τSTr [HasTau Label] (lts : LTS State Label) : lts.STrN n s1 HasTau.τ s2 → lts.τSTr s1 s2 := by intro h @@ -592,7 +592,7 @@ theorem LTS.sTrN_imp_τSTr [HasTau Label] (lts : LTS State Label) : have hτ3' := LTS.sTrN_imp_τSTr lts hτ2 exact Relation.ReflTransGen.trans hτ1' (Relation.ReflTransGen.head htr hτ3') -@[grind .] +@[scoped grind .] theorem LTS.τSTr_sTrN [HasTau Label] (lts : LTS State Label) : lts.τSTr s1 s2 ↔ ∃ n, lts.STrN n s1 HasTau.τ s2 := by grind @@ -649,10 +649,10 @@ theorem LTS.STr.comp (h2 : lts.STr s2 μ s3) (h3 : lts.STr s3 HasTau.τ s4) : lts.STr s1 μ s4 := by - rw [LTS.sTr_eq_τSTr _] at h1 h3 + rw [LTS.sTr_τSTr _] at h1 h3 cases h2 case refl => - rw [LTS.sTr_eq_τSTr _] + rw [LTS.sTr_τSTr _] apply Relation.ReflTransGen.trans h1 h3 case tr _ _ hτ1 htr hτ2 => exact LTS.STr.tr (Relation.ReflTransGen.trans h1 hτ1) htr (Relation.ReflTransGen.trans hτ2 h3) @@ -708,7 +708,7 @@ theorem LTS.saturate_tr_saturate_sTr [hHasTau : HasTau Label] (lts : LTS State L case refl => constructor case tr hstr1 htr hstr2 => rw [LTS.saturate_τSTr_τSTr lts] at hstr1 hstr2 - rw [←LTS.sTr_eq_τSTr lts] at hstr1 hstr2 + rw [←LTS.sTr_τSTr lts] at hstr1 hstr2 exact LTS.STr.comp lts hstr1 htr hstr2 From 48188337e0bb144304fea24d6e89a24ce91922c9 Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Mon, 5 Jan 2026 16:22:59 +0100 Subject: [PATCH 17/21] Guesses regarding grind --- Cslib/Foundations/Semantics/LTS/Basic.lean | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index 7a979a7e..6bc7d73c 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -497,7 +497,7 @@ inductive LTS.STr [HasTau Label] (lts : LTS State Label) : State → Label → S | tr : lts.τSTr s1 s2 → lts.Tr s2 μ s3 → lts.τSTr s3 s4 → lts.STr s1 μ s4 /-- The `LTS` obtained by saturating the transition relation in `lts`. -/ -@[scoped grind =] +@[scoped grind] def LTS.saturate [HasTau Label] (lts : LTS State Label) : LTS State Label where Tr := lts.STr @@ -556,7 +556,6 @@ theorem LTS.saturate_τSTr_τSTr [hHasTau : HasTau Label] (lts : LTS State Label have h4 := LTS.STr.tr h2 h3 Relation.ReflTransGen.refl exact Relation.ReflTransGen.single h4 - /-- In a saturated LTS, every state is in its τ-image. -/ @[scoped grind .] theorem LTS.mem_saturate_image_τ [HasTau Label] (lts : LTS State Label) : @@ -564,7 +563,7 @@ theorem LTS.mem_saturate_image_τ [HasTau Label] (lts : LTS State Label) : /-- The `τ`-closure of a set of states `S` is the set of states reachable by any state in `S` by performing only `τ`-transitions. -/ -@[scoped grind =] +@[scoped grind] def LTS.τClosure [HasTau Label] (lts : LTS State Label) (S : Set State) : Set State := lts.saturate.setImage S HasTau.τ @@ -599,7 +598,7 @@ theorem LTS.τSTr_sTrN [HasTau Label] (lts : LTS State Label) : /-- Saturated transitions labelled by τ can be composed (weighted version). -/ -@[scoped grind →] +@[scoped grind <=] theorem LTS.STrN.trans_τ [HasTau Label] (lts : LTS State Label) (h1 : lts.STrN n s1 HasTau.τ s2) (h2 : lts.STrN m s2 HasTau.τ s3) : @@ -642,7 +641,7 @@ theorem LTS.STrN.comp grind /-- Saturated transitions can be composed. -/ -@[grind →] +@[scoped grind <=] theorem LTS.STr.comp [HasTau Label] (lts : LTS State Label) (h1 : lts.STr s1 HasTau.τ s2) @@ -681,7 +680,7 @@ theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : exact LTS.STr.comp lts h1 (LTS.STr.single lts h2) h3 /-- Saturated transitions labelled by τ can be composed. -/ -@[scoped grind →] +@[scoped grind <=] theorem LTS.STr.trans_τ [HasTau Label] (lts : LTS State Label) (h1 : lts.STr s1 HasTau.τ s2) (h2 : lts.STr s2 HasTau.τ s3) : @@ -711,7 +710,6 @@ theorem LTS.saturate_tr_saturate_sTr [hHasTau : HasTau Label] (lts : LTS State L rw [←LTS.sTr_τSTr lts] at hstr1 hstr2 exact LTS.STr.comp lts hstr1 htr hstr2 - end Weak /-! ## Divergence -/ From 091bdc4a84ae3307ccee9c8c24c1eae36147dc55 Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Mon, 5 Jan 2026 16:33:48 +0100 Subject: [PATCH 18/21] Fixed Weak Bisimulation proofs (open LTS.STr due to scoped grind, and updated renamings) --- Cslib/Foundations/Semantics/LTS/Basic.lean | 30 +++++++++---------- .../Semantics/LTS/Bisimulation.lean | 6 ++-- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index 6bc7d73c..40abb55e 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -501,12 +501,12 @@ inductive LTS.STr [HasTau Label] (lts : LTS State Label) : State → Label → S def LTS.saturate [HasTau Label] (lts : LTS State Label) : LTS State Label where Tr := lts.STr -@[scoped grind _=_] +@[scoped grind] theorem LTS.saturate_tr_sTr [HasTau Label] {lts : LTS State Label} : lts.saturate.Tr = lts.STr := by rfl /-- Any transition is also a saturated transition. -/ -@[scoped grind →] +@[scoped grind] theorem LTS.STr.single [HasTau Label] (lts : LTS State Label) : lts.Tr s μ s' → lts.STr s μ s' := by intro h @@ -525,7 +525,7 @@ inductive LTS.STrN [HasTau Label] (lts : LTS State Label) : lts.STrN (n + m + 1) s1 μ s4 /-- STr transitions labeled by HasTau.τ are exactly the τSTr transitions. -/ -@[scoped grind _=_] +@[scoped grind] theorem LTS.sTr_τSTr [HasTau Label] (lts : LTS State Label) : lts.STr s HasTau.τ s' ↔ lts.τSTr s s' := by apply Iff.intro <;> intro h @@ -540,7 +540,7 @@ theorem LTS.sTr_τSTr [HasTau Label] (lts : LTS State Label) : case tail _ h1 h2 => exact LTS.STr.tr h1 h2 .refl /-- In a saturated LTS, the transition and saturated transition relations are the same. -/ -@[scoped grind _=_] +@[scoped grind] theorem LTS.saturate_τSTr_τSTr [hHasTau : HasTau Label] (lts : LTS State Label) : lts.saturate.τSTr s = lts.τSTr s := by ext s'' @@ -557,7 +557,7 @@ theorem LTS.saturate_τSTr_τSTr [hHasTau : HasTau Label] (lts : LTS State Label exact Relation.ReflTransGen.single h4 /-- In a saturated LTS, every state is in its τ-image. -/ -@[scoped grind .] +@[scoped grind] theorem LTS.mem_saturate_image_τ [HasTau Label] (lts : LTS State Label) : s ∈ lts.saturate.image s HasTau.τ := LTS.STr.refl @@ -567,7 +567,7 @@ by performing only `τ`-transitions. -/ def LTS.τClosure [HasTau Label] (lts : LTS State Label) (S : Set State) : Set State := lts.saturate.setImage S HasTau.τ -@[scoped grind .] +@[scoped grind] theorem LTS.τSTr_imp_sTrN [HasTau Label] (lts : LTS State Label) : lts.τSTr s1 s2 → ∃ n, lts.STrN n s1 HasTau.τ s2 := by intro h @@ -580,7 +580,7 @@ theorem LTS.τSTr_imp_sTrN [HasTau Label] (lts : LTS State Label) : exists (n + 1) apply LTS.STrN.tr hn htr LTS.STrN.refl -@[scoped grind .] +@[scoped grind] theorem LTS.sTrN_imp_τSTr [HasTau Label] (lts : LTS State Label) : lts.STrN n s1 HasTau.τ s2 → lts.τSTr s1 s2 := by intro h @@ -591,14 +591,14 @@ theorem LTS.sTrN_imp_τSTr [HasTau Label] (lts : LTS State Label) : have hτ3' := LTS.sTrN_imp_τSTr lts hτ2 exact Relation.ReflTransGen.trans hτ1' (Relation.ReflTransGen.head htr hτ3') -@[scoped grind .] +@[scoped grind] theorem LTS.τSTr_sTrN [HasTau Label] (lts : LTS State Label) : lts.τSTr s1 s2 ↔ ∃ n, lts.STrN n s1 HasTau.τ s2 := by grind /-- Saturated transitions labelled by τ can be composed (weighted version). -/ -@[scoped grind <=] +@[scoped grind] theorem LTS.STrN.trans_τ [HasTau Label] (lts : LTS State Label) (h1 : lts.STrN n s1 HasTau.τ s2) (h2 : lts.STrN m s2 HasTau.τ s3) : @@ -611,7 +611,7 @@ theorem LTS.STrN.trans_τ grind /-- Saturated transitions can be appended with τ-transitions (weighted version). -/ -@[scoped grind <=] +@[scoped grind] theorem LTS.STrN.append [HasTau Label] (lts : LTS State Label) (h1 : lts.STrN n1 s1 μ s2) @@ -624,7 +624,7 @@ theorem LTS.STrN.append grind /-- Saturated transitions can be composed (weighted version). -/ -@[scoped grind <=] +@[scoped grind] theorem LTS.STrN.comp [HasTau Label] (lts : LTS State Label) (h1 : lts.STrN n1 s1 HasTau.τ s2) @@ -641,7 +641,7 @@ theorem LTS.STrN.comp grind /-- Saturated transitions can be composed. -/ -@[scoped grind <=] +@[scoped grind] theorem LTS.STr.comp [HasTau Label] (lts : LTS State Label) (h1 : lts.STr s1 HasTau.τ s2) @@ -657,7 +657,7 @@ theorem LTS.STr.comp exact LTS.STr.tr (Relation.ReflTransGen.trans h1 hτ1) htr (Relation.ReflTransGen.trans hτ2 h3) /-- `LTS.str` and `LTS.strN` are equivalent. -/ -@[scoped grind =] +@[scoped grind] theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : lts.STr s1 μ s2 ↔ ∃ n, lts.STrN n s1 μ s2 := by apply Iff.intro <;> intro h @@ -680,7 +680,7 @@ theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : exact LTS.STr.comp lts h1 (LTS.STr.single lts h2) h3 /-- Saturated transitions labelled by τ can be composed. -/ -@[scoped grind <=] +@[scoped grind] theorem LTS.STr.trans_τ [HasTau Label] (lts : LTS State Label) (h1 : lts.STr s1 HasTau.τ s2) (h2 : lts.STr s2 HasTau.τ s3) : @@ -691,7 +691,7 @@ theorem LTS.STr.trans_τ apply (LTS.sTr_sTrN lts).2 ⟨n + m, concN⟩ /-- In a saturated LTS, the transition and saturated transition relations are the same. -/ -@[grind _=_] +@[grind] theorem LTS.saturate_tr_saturate_sTr [hHasTau : HasTau Label] (lts : LTS State Label) (hμ : μ = hHasTau.τ) : lts.saturate.Tr s μ = lts.saturate.STr s μ := by ext s' diff --git a/Cslib/Foundations/Semantics/LTS/Bisimulation.lean b/Cslib/Foundations/Semantics/LTS/Bisimulation.lean index 19d95043..28f0b87a 100644 --- a/Cslib/Foundations/Semantics/LTS/Bisimulation.lean +++ b/Cslib/Foundations/Semantics/LTS/Bisimulation.lean @@ -756,6 +756,8 @@ end Bisimulation section WeakBisimulation +open LTS.STr + /-! ## Weak bisimulation and weak bisimilarity -/ /-- A weak bisimulation is similar to a `Bisimulation`, but allows for the related processes to do @@ -890,7 +892,7 @@ theorem LTS.isWeakBisimulation_iff_isSWBisimulation constructor; constructor exact hr case tr sb sb' hstr1 htr hstr2 => - rw [←LTS.STr_τTr] at hstr1 hstr2 + rw [←LTS.sTr_τSTr] at hstr1 hstr2 obtain ⟨sb2, hstr2b, hrb⟩ := SWBisimulation.follow_internal_fst h hr hstr1 obtain ⟨sb2', hstr2b', hrb'⟩ := (h hrb μ).1 _ htr obtain ⟨s2', hstr2', hrb2⟩ := SWBisimulation.follow_internal_fst h hrb' hstr2 @@ -906,7 +908,7 @@ theorem LTS.isWeakBisimulation_iff_isSWBisimulation constructor; constructor exact hr case tr sb sb' hstr1 htr hstr2 => - rw [←LTS.STr_τTr] at hstr1 hstr2 + rw [←LTS.sTr_τSTr] at hstr1 hstr2 obtain ⟨sb1, hstr1b, hrb⟩ := SWBisimulation.follow_internal_snd h hr hstr1 obtain ⟨sb2', hstr1b', hrb'⟩ := (h hrb μ).2 _ htr obtain ⟨s1', hstr1', hrb2⟩ := SWBisimulation.follow_internal_snd h hrb' hstr2 From e0a5a54afa5012311952fc9c9584980af6395901 Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Mon, 5 Jan 2026 16:40:29 +0100 Subject: [PATCH 19/21] Better understanding of @[grind] options, I hope. --- Cslib/Foundations/Semantics/LTS/Basic.lean | 31 +++++++++++----------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index 40abb55e..1c2fb255 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -501,12 +501,12 @@ inductive LTS.STr [HasTau Label] (lts : LTS State Label) : State → Label → S def LTS.saturate [HasTau Label] (lts : LTS State Label) : LTS State Label where Tr := lts.STr -@[scoped grind] +@[scoped grind _=_] theorem LTS.saturate_tr_sTr [HasTau Label] {lts : LTS State Label} : lts.saturate.Tr = lts.STr := by rfl /-- Any transition is also a saturated transition. -/ -@[scoped grind] +@[scoped grind .] theorem LTS.STr.single [HasTau Label] (lts : LTS State Label) : lts.Tr s μ s' → lts.STr s μ s' := by intro h @@ -525,7 +525,7 @@ inductive LTS.STrN [HasTau Label] (lts : LTS State Label) : lts.STrN (n + m + 1) s1 μ s4 /-- STr transitions labeled by HasTau.τ are exactly the τSTr transitions. -/ -@[scoped grind] +@[scoped grind _=_] theorem LTS.sTr_τSTr [HasTau Label] (lts : LTS State Label) : lts.STr s HasTau.τ s' ↔ lts.τSTr s s' := by apply Iff.intro <;> intro h @@ -540,7 +540,7 @@ theorem LTS.sTr_τSTr [HasTau Label] (lts : LTS State Label) : case tail _ h1 h2 => exact LTS.STr.tr h1 h2 .refl /-- In a saturated LTS, the transition and saturated transition relations are the same. -/ -@[scoped grind] +@[scoped grind _=_] theorem LTS.saturate_τSTr_τSTr [hHasTau : HasTau Label] (lts : LTS State Label) : lts.saturate.τSTr s = lts.τSTr s := by ext s'' @@ -557,7 +557,7 @@ theorem LTS.saturate_τSTr_τSTr [hHasTau : HasTau Label] (lts : LTS State Label exact Relation.ReflTransGen.single h4 /-- In a saturated LTS, every state is in its τ-image. -/ -@[scoped grind] +@[scoped grind .] theorem LTS.mem_saturate_image_τ [HasTau Label] (lts : LTS State Label) : s ∈ lts.saturate.image s HasTau.τ := LTS.STr.refl @@ -567,7 +567,7 @@ by performing only `τ`-transitions. -/ def LTS.τClosure [HasTau Label] (lts : LTS State Label) (S : Set State) : Set State := lts.saturate.setImage S HasTau.τ -@[scoped grind] +@[scoped grind .] theorem LTS.τSTr_imp_sTrN [HasTau Label] (lts : LTS State Label) : lts.τSTr s1 s2 → ∃ n, lts.STrN n s1 HasTau.τ s2 := by intro h @@ -580,7 +580,7 @@ theorem LTS.τSTr_imp_sTrN [HasTau Label] (lts : LTS State Label) : exists (n + 1) apply LTS.STrN.tr hn htr LTS.STrN.refl -@[scoped grind] +@[scoped grind →] theorem LTS.sTrN_imp_τSTr [HasTau Label] (lts : LTS State Label) : lts.STrN n s1 HasTau.τ s2 → lts.τSTr s1 s2 := by intro h @@ -591,14 +591,13 @@ theorem LTS.sTrN_imp_τSTr [HasTau Label] (lts : LTS State Label) : have hτ3' := LTS.sTrN_imp_τSTr lts hτ2 exact Relation.ReflTransGen.trans hτ1' (Relation.ReflTransGen.head htr hτ3') -@[scoped grind] +@[scoped grind =] theorem LTS.τSTr_sTrN [HasTau Label] (lts : LTS State Label) : lts.τSTr s1 s2 ↔ ∃ n, lts.STrN n s1 HasTau.τ s2 := by grind - /-- Saturated transitions labelled by τ can be composed (weighted version). -/ -@[scoped grind] +@[scoped grind .] theorem LTS.STrN.trans_τ [HasTau Label] (lts : LTS State Label) (h1 : lts.STrN n s1 HasTau.τ s2) (h2 : lts.STrN m s2 HasTau.τ s3) : @@ -611,7 +610,7 @@ theorem LTS.STrN.trans_τ grind /-- Saturated transitions can be appended with τ-transitions (weighted version). -/ -@[scoped grind] +@[scoped grind .] theorem LTS.STrN.append [HasTau Label] (lts : LTS State Label) (h1 : lts.STrN n1 s1 μ s2) @@ -624,7 +623,7 @@ theorem LTS.STrN.append grind /-- Saturated transitions can be composed (weighted version). -/ -@[scoped grind] +@[scoped grind <=] theorem LTS.STrN.comp [HasTau Label] (lts : LTS State Label) (h1 : lts.STrN n1 s1 HasTau.τ s2) @@ -641,7 +640,7 @@ theorem LTS.STrN.comp grind /-- Saturated transitions can be composed. -/ -@[scoped grind] +@[scoped grind <=] theorem LTS.STr.comp [HasTau Label] (lts : LTS State Label) (h1 : lts.STr s1 HasTau.τ s2) @@ -657,7 +656,7 @@ theorem LTS.STr.comp exact LTS.STr.tr (Relation.ReflTransGen.trans h1 hτ1) htr (Relation.ReflTransGen.trans hτ2 h3) /-- `LTS.str` and `LTS.strN` are equivalent. -/ -@[scoped grind] +@[scoped grind =] theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : lts.STr s1 μ s2 ↔ ∃ n, lts.STrN n s1 μ s2 := by apply Iff.intro <;> intro h @@ -680,7 +679,7 @@ theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : exact LTS.STr.comp lts h1 (LTS.STr.single lts h2) h3 /-- Saturated transitions labelled by τ can be composed. -/ -@[scoped grind] +@[scoped grind <=] theorem LTS.STr.trans_τ [HasTau Label] (lts : LTS State Label) (h1 : lts.STr s1 HasTau.τ s2) (h2 : lts.STr s2 HasTau.τ s3) : @@ -691,7 +690,7 @@ theorem LTS.STr.trans_τ apply (LTS.sTr_sTrN lts).2 ⟨n + m, concN⟩ /-- In a saturated LTS, the transition and saturated transition relations are the same. -/ -@[grind] +@[scoped grind _=_] theorem LTS.saturate_tr_saturate_sTr [hHasTau : HasTau Label] (lts : LTS State Label) (hμ : μ = hHasTau.τ) : lts.saturate.Tr s μ = lts.saturate.STr s μ := by ext s' From 12de94f7fb6b3a0247d91da85a06cd493fd70fd7 Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Mon, 5 Jan 2026 17:13:26 +0100 Subject: [PATCH 20/21] CI complained about gind in LTS.STrN.trans_\tau, not sure why. Trying a different modifier. --- Cslib/Foundations/Semantics/LTS/Basic.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index 1c2fb255..6eef21e1 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -597,7 +597,7 @@ theorem LTS.τSTr_sTrN [HasTau Label] (lts : LTS State Label) : grind /-- Saturated transitions labelled by τ can be composed (weighted version). -/ -@[scoped grind .] +@[scoped grind →] theorem LTS.STrN.trans_τ [HasTau Label] (lts : LTS State Label) (h1 : lts.STrN n s1 HasTau.τ s2) (h2 : lts.STrN m s2 HasTau.τ s3) : @@ -679,7 +679,7 @@ theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : exact LTS.STr.comp lts h1 (LTS.STr.single lts h2) h3 /-- Saturated transitions labelled by τ can be composed. -/ -@[scoped grind <=] +@[scoped grind →] theorem LTS.STr.trans_τ [HasTau Label] (lts : LTS State Label) (h1 : lts.STr s1 HasTau.τ s2) (h2 : lts.STr s2 HasTau.τ s3) : From 462e8d4318d04075dde65f8069f516c491c2a8b0 Mon Sep 17 00:00:00 2001 From: "Cuijpers, Pieter" Date: Thu, 8 Jan 2026 11:09:03 +0100 Subject: [PATCH 21/21] Removed STrN as it is no longer needed --- Cslib/Foundations/Semantics/LTS/Basic.lean | 114 +-------------------- 1 file changed, 3 insertions(+), 111 deletions(-) diff --git a/Cslib/Foundations/Semantics/LTS/Basic.lean b/Cslib/Foundations/Semantics/LTS/Basic.lean index 6eef21e1..d23fafcb 100644 --- a/Cslib/Foundations/Semantics/LTS/Basic.lean +++ b/Cslib/Foundations/Semantics/LTS/Basic.lean @@ -512,18 +512,6 @@ theorem LTS.STr.single [HasTau Label] (lts : LTS State Label) : intro h apply LTS.STr.tr .refl h .refl -/-- As `LTS.str`, but counts the number of `τ`-transitions. This is convenient as induction -metric. -/ -@[scoped grind] -inductive LTS.STrN [HasTau Label] (lts : LTS State Label) : - ℕ → State → Label → State → Prop where - | refl : lts.STrN 0 s HasTau.τ s - | tr : - lts.STrN n s1 HasTau.τ s2 → - lts.Tr s2 μ s3 → - lts.STrN m s3 HasTau.τ s4 → - lts.STrN (n + m + 1) s1 μ s4 - /-- STr transitions labeled by HasTau.τ are exactly the τSTr transitions. -/ @[scoped grind _=_] theorem LTS.sTr_τSTr [HasTau Label] (lts : LTS State Label) : @@ -567,78 +555,6 @@ by performing only `τ`-transitions. -/ def LTS.τClosure [HasTau Label] (lts : LTS State Label) (S : Set State) : Set State := lts.saturate.setImage S HasTau.τ -@[scoped grind .] -theorem LTS.τSTr_imp_sTrN [HasTau Label] (lts : LTS State Label) : - lts.τSTr s1 s2 → ∃ n, lts.STrN n s1 HasTau.τ s2 := by - intro h - induction h - case refl => - exists 0 - apply LTS.STrN.refl - case tail _ _ _ htr ih => - obtain ⟨n, hn⟩ := ih - exists (n + 1) - apply LTS.STrN.tr hn htr LTS.STrN.refl - -@[scoped grind →] -theorem LTS.sTrN_imp_τSTr [HasTau Label] (lts : LTS State Label) : - lts.STrN n s1 HasTau.τ s2 → lts.τSTr s1 s2 := by - intro h - cases h - case refl => exact Relation.ReflTransGen.refl - case tr m _ _ k hτ1 htr hτ2 => - have hτ1' := LTS.sTrN_imp_τSTr lts hτ1 - have hτ3' := LTS.sTrN_imp_τSTr lts hτ2 - exact Relation.ReflTransGen.trans hτ1' (Relation.ReflTransGen.head htr hτ3') - -@[scoped grind =] -theorem LTS.τSTr_sTrN [HasTau Label] (lts : LTS State Label) : - lts.τSTr s1 s2 ↔ ∃ n, lts.STrN n s1 HasTau.τ s2 := by - grind - -/-- Saturated transitions labelled by τ can be composed (weighted version). -/ -@[scoped grind →] -theorem LTS.STrN.trans_τ - [HasTau Label] (lts : LTS State Label) - (h1 : lts.STrN n s1 HasTau.τ s2) (h2 : lts.STrN m s2 HasTau.τ s3) : - lts.STrN (n + m) s1 HasTau.τ s3 := by - cases h1 - case refl => grind - case tr n1 sb sb' n2 hstr1 htr hstr2 => - have ih := LTS.STrN.trans_τ lts hstr2 h2 - have conc := LTS.STrN.tr hstr1 htr ih - grind - -/-- Saturated transitions can be appended with τ-transitions (weighted version). -/ -@[scoped grind .] -theorem LTS.STrN.append - [HasTau Label] (lts : LTS State Label) - (h1 : lts.STrN n1 s1 μ s2) - (h2 : lts.STrN n2 s2 HasTau.τ s3) : - lts.STrN (n1 + n2) s1 μ s3 := by - induction h1 - case refl => grind - case tr hstr1 htr hstr2 ih1 ih2 => - have conc := LTS.STrN.tr hstr1 htr (ih2 h2) - grind - -/-- Saturated transitions can be composed (weighted version). -/ -@[scoped grind <=] -theorem LTS.STrN.comp - [HasTau Label] (lts : LTS State Label) - (h1 : lts.STrN n1 s1 HasTau.τ s2) - (h2 : lts.STrN n2 s2 μ s3) - (h3 : lts.STrN n3 s3 HasTau.τ s4) : - lts.STrN (n1 + n2 + n3) s1 μ s4 := by - cases h2 - case refl => - apply LTS.STrN.trans_τ lts h1 h3 - case tr n21 sb sb' n22 hstr1 htr hstr2 => - have hprefix_τ := LTS.STrN.trans_τ lts h1 hstr1 - have hprefix := LTS.STrN.tr hprefix_τ htr hstr2 - have conc := LTS.STrN.append lts hprefix h3 - grind - /-- Saturated transitions can be composed. -/ @[scoped grind <=] theorem LTS.STr.comp @@ -655,39 +571,15 @@ theorem LTS.STr.comp case tr _ _ hτ1 htr hτ2 => exact LTS.STr.tr (Relation.ReflTransGen.trans h1 hτ1) htr (Relation.ReflTransGen.trans hτ2 h3) -/-- `LTS.str` and `LTS.strN` are equivalent. -/ -@[scoped grind =] -theorem LTS.sTr_sTrN [HasTau Label] (lts : LTS State Label) : - lts.STr s1 μ s2 ↔ ∃ n, lts.STrN n s1 μ s2 := by - apply Iff.intro <;> intro h - case mp => - induction h - case refl => - exists 0 - apply LTS.STrN.refl - case tr _ _ hτ1 htr hτ2 => - obtain ⟨n, hn⟩ := LTS.τSTr_imp_sTrN lts hτ1 - obtain ⟨m, hm⟩ := LTS.τSTr_imp_sTrN lts hτ2 - exists (n + m + 1) - apply LTS.STrN.tr hn htr hm - case mpr => - obtain ⟨n, hn⟩ := h - induction hn - case refl => - exact LTS.STr.refl - case tr _ _ _ _ _ _ h2 _ h1 h3 => - exact LTS.STr.comp lts h1 (LTS.STr.single lts h2) h3 - /-- Saturated transitions labelled by τ can be composed. -/ @[scoped grind →] theorem LTS.STr.trans_τ [HasTau Label] (lts : LTS State Label) (h1 : lts.STr s1 HasTau.τ s2) (h2 : lts.STr s2 HasTau.τ s3) : lts.STr s1 HasTau.τ s3 := by - obtain ⟨n, h1N⟩ := (LTS.sTr_sTrN lts).1 h1 - obtain ⟨m, h2N⟩ := (LTS.sTr_sTrN lts).1 h2 - have concN := LTS.STrN.trans_τ lts h1N h2N - apply (LTS.sTr_sTrN lts).2 ⟨n + m, concN⟩ + rw [LTS.sTr_τSTr _] at h1 h2 + rw [LTS.sTr_τSTr _] + apply Relation.ReflTransGen.trans h1 h2 /-- In a saturated LTS, the transition and saturated transition relations are the same. -/ @[scoped grind _=_]