Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 167 additions & 0 deletions Cslib/Logics/LTL/Basic.Lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/-
Copyright (c) 2026 Fabrizio Montesi. All rights reserved.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can put your name here.

Released under Apache 2.0 license as described in the file LICENSE.
Authors: Lorenzo Pace
-/

module

public import Cslib.Foundations.Semantics.LTS.Bisimulation
public import Cslib.Foundations.Data.OmegaSequence.Defs

@[expose] public section

/-! # Linear Temporal Logic

Linear Temporal Logic (LTL) is a logic for reasoning about the validity of propositional atoms
in non-branching time.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

non-branching -> linear.


## Main definitions

- `Proposition`: the language of propositions, parametrized on the type of atoms.
- `Satisfies ls φ`: the ω-sequence `ls` satisfies proposition `p`.
- `Proposition.equiv`: equivalence of two propositions modulo `Satisfies`.

## Main statements

- `next_self_dual`: Negation can be brought inside the `next` operator.
- `distrib_eventually_or`: the `eventually` operator distributes on disjunction.
- `expansion_until`: expansion rule for the `until` operator
- `expansion_eventually`: expansion rule for the `eventually` operator

## References
Course slides, University of Pisa: https://pages.di.unipi.it/gadducci/SVV-24/slideB/svv_b_01.pdf
-/

namespace Cslib.Logic.LTL

/-- Propositions, where `T` is the type of atoms. -/
inductive Proposition (T : Type) : Type u where
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
inductive Proposition (T : Type) : Type u where
inductive Proposition (T : Type u) : Type u where

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason implies and leads_to are not among the operators? Alternatively, can we take seriously the idea that (for example) always and eventuallycan be defined as derived operators and reduce this inductive definition to a minimal set of operators?

| true
| false
| not (φ₁ : Proposition T)
| and (φ₁ φ₂ : Proposition T)
| or (φ₁ φ₂ : Proposition T)
| next (φ : Proposition T)
| eventually (φ : Proposition T)
| always (φ : Proposition T)
| until_op (φ : Proposition T) (φ : Proposition T)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure until doesn't work here? I played with it a little bit and it seems to work. These operators are never used "nakedly" and always appears as part of dot-notations.

| atom (p : T)
Comment on lines +39 to +51
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of trying to anticipate and enumerate all propositional operators you will ever need, I wonder if it is better to limit yourself to a minimal set of operators in terms of which other operators can be defined. For example, even with the expanded set of operators given above, you still miss one important operator:

def Proposition.leadsTo (φ₁ φ₂ : Proposition T) : Proposition T :=
  (φ₁.implies φ₂.eventually).always

variable (φ₁ φ₂ : Proposition T)
#check (φ₁.leadsTo φ₂)

As you can see, the dot-notation enables the new operator to be written and used pretty much like those in the original inductive definition. By limiting yourself to a minimal set of core operators which will likely stay stable, you will have fewer operators to deal with if you ever want to develop any proof theory for LTL.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes a lot of sense. On it 👍


/-- Satisfaction relation for ω-sequences of atom valuations. -/
@[simp, scoped grind =]
def Satisfies (ls : ωSequence (Set T)) (φ : Proposition T) := match φ with
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def Satisfies (ls : ωSequence (Set T)) : Proposition T) := match φ with
def Satisfies (ls : ωSequence (Set T)) : Proposition TProp

| .true => True
| .false => False
| .and φ₁ φ₂ => Satisfies ls φ₁ ∧ Satisfies ls φ₂
| .or φ₁ φ₂ => Satisfies ls φ₁ ∨ Satisfies ls φ₂
| .atom (p) => p ∈ ls 0
| .not φ => ¬ (Satisfies ls φ)
| .next φ => Satisfies (ωSequence.drop 1 ls) φ
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| .next φ => Satisfies (ωSequence.drop 1 ls) φ
| .next φ => Satisfies (ls.drop 1) φ

etc

| .eventually φ => ∃ k : ℕ, Satisfies (ωSequence.drop k ls) φ
| .always φ => ∀ k : ℕ , Satisfies (ωSequence.drop k ls) φ
| .until_op φ₁ φ₂ => ∃ k : ℕ,
Satisfies (ωSequence.drop k ls) φ₂ ∧
∀ i : ℕ, i < k →
Satisfies (ωSequence.drop i ls) φ₁

notation:50 ls " ⊧ " φ => Satisfies ls φ

/-- Equivalence of LTL propositions on ω-sequences. -/
@[simp, scoped grind =]
def Proposition.equiv (φ₁ : Proposition T) (φ₂ : Proposition T) :=
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def Proposition.equiv (φ₁ : Proposition T) (φ₂ : Proposition T) :=
def Proposition.equiv (φ₁ : Proposition T) (φ₂ : Proposition T) : Prop :=

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of Proposition.equiv φ₁ φ₂, I think you should define Proposition.valid φ to mean that φ is true over all models ls. This is more general, because Proposition.equiv φ₁ φ₂ is simply Proposition.valid (φ₁.iff φ₂). (You didn't define Proposition.iff, but there is no reason why you shouldn't.). Also, Proposition.equiv φ₁ φ₂ biases you toward equational reasoning. But sometimes it is more natural to reason about implications.

∀ (ls : ωSequence (Set T)) , (ls ⊧ φ₁) ↔ ls ⊧ φ₂
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to give \models a higher precedence than \iff, so that we can get rid of the parentheses on the LHS of \iff?


notation:50 φ₁ " ≈ " φ₂ => Proposition.equiv φ₁ φ₂

/-- Negation can be brought inside the `next` operator. -/
@[scoped grind =]
theorem next_self_dual {T} : ∀ (φ : Proposition T), φ.next.not ≈ φ.not.next :=
by simp
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style should be

Suggested change
theorem next_self_dual {T} : ∀ (φ : Proposition T), φ.next.not ≈ φ.not.next :=
by simp
theorem next_self_dual {T} : ∀ (φ : Proposition T), φ.next.not ≈ φ.not.next := by
simp

(throughout)


/-- The `eventually` operator distributes on disjunction. -/
@[scoped grind =]
theorem distrib_eventually_or {T} :
∀ (φ : Proposition T) (ψ : Proposition T) ,
Proposition.eventually (φ.or ψ) ≈ (Proposition.or (φ.eventually) (ψ.eventually))
:= by
simp
grind

/-- Expansion rule for the `until` operator. -/
@[scoped grind =]
theorem expansion_until {T} : ∀ (φ : Proposition T) (ψ : Proposition T) ,
Proposition.until_op φ ψ ≈ Proposition.or ψ (Proposition.and φ ((Proposition.until_op φ ψ).next)) :=
by
intros
Comment on lines +96 to +98
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
theorem expansion_until {T} : ∀ (φ : Proposition T) (ψ : Proposition T) ,
Proposition.until_op φ ψ ≈ Proposition.or ψ (Proposition.and φ ((Proposition.until_op φ ψ).next)) :=
by
intros
theorem expansion_until {T} (φ : Proposition T) (ψ : Proposition T) :
φ.until_op ψ ≈ ψ.or (φ.and ((φ.until_op ψ).next)) := by

unfold Proposition.equiv
intro
apply Iff.intro
· intro h
unfold Satisfies
simp only [Satisfies, ωSequence.drop_drop]
rcases h with ⟨x, hx⟩
cases x
· simp only [ωSequence.drop_zero, not_lt_zero, IsEmpty.forall_iff, implies_true, and_true] at hx
left
exact hx
· right
constructor
· have hxr := hx.right
specialize hxr 0
simp only [lt_add_iff_pos_left, Order.lt_add_one_iff,
zero_le, ωSequence.drop_zero, forall_const] at hxr
exact hxr
· grind
· intro h
rcases h with hL | hR
· exists 0
simp only [ωSequence.drop_zero, not_lt_zero, IsEmpty.forall_iff, implies_true, and_true]
exact hL
have hRr := hR.right
rcases hRr with ⟨x, hx⟩
exists (1 + x)
constructor
· have hxl := hx.left
simp only [ωSequence.drop_drop] at hxl
exact hxl
· intro i hi
rcases i with rfl | j
· have hRl := hR.left
exact hRl
· have hxr := hx.right
specialize hxr j
have hi' : Nat.succ j < Nat.succ x := by
simpa [Nat.succ_eq_add_one, Nat.add_comm, Nat.add_left_comm, Nat.add_assoc] using hi
have hj : j < x := Nat.lt_of_succ_lt_succ hi'
rw [Nat.add_comm j 1]
simp only [ωSequence.drop_drop] at hxr
exact (hxr hj)


/-- Expansion rule for the `eventually` operator. -/
@[scoped grind =]
theorem expansion_eventually {T} : ∀ (ψ : Proposition T) ,
Proposition.eventually ψ ≈ ψ.or (ψ.eventually.next) :=
by
simp only [Proposition.equiv, Satisfies, ωSequence.drop_drop]
intros
apply Iff.intro
· intro h
rcases h with ⟨x, hx⟩
cases x
· simp only [ωSequence.drop_zero] at hx
left
exact hx
· right
rename_i j
rw [← Nat.add_comm] at hx
exists j
· intro h
rcases h with hL | hR
· exists 0
· rcases hR with ⟨x, hx⟩
exists 1 + x


end Cslib.Logic.LTL