Documentation

FormaleSystemeInLean.Lecture4

This file covers selected topics from lecture 4:

Slides are available at: https://iccl.inf.tu-dresden.de/w/images/c/c9/FS2025-Vorlesung-04-print.pdf

structure NFA (Q : Type u) (Sigma : Type v) [Fintype Q] [Fintype Sigma] :
Type (max u v)

An NFA (Nondeterministic Finite Automaton) is a structure depending on two types Q and Sigma both of which are finite. The transition function δ now has potentially many different values so it maps a state and a symbol to a list of states. That means when reading a symbol σ in a state q the NFA will end up in one of the states from the list. The reason why this definition uses a list instead of a set is that defining finite sets is not as easy as one might think. A list is always finite so it works just as well.

Instances For
    def NFA.δ_word {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] (nfa : NFA Q Sigma) (R : List Q) :
    Word SigmaList Q

    Transition function for words mapping a word w ∈ Σ* and a list of states R to another list of states.

    • w = ε: the NFA remains in one of the states from R so δ_word(R,ε) = R
    • w = av: δ_word(R,av) = δ_word(R',v) where R' is the list of states reachable from some state R with a
    Equations
    Instances For
      inductive NFA.Run {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] (nfa : NFA Q Sigma) :
      QQWord SigmaType (max u v)

      A run of an NFA on a word w is a sequence of states. We can express this using an inductive definition:

      • For every state q, the sequence q is a run on the empty word ε.
      • If an NFA has a run q2...qf on v and q2 is reachable with a from q1, then q1...qf is a run on av.
      Instances For
        def NFA.Run.from_start {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] {q0 q : Q} {w : Word Sigma} {nfa : NFA Q Sigma} :
        nfa.Run q0 q wProp

        A run beginning with a state from Q0

        Equations
        Instances For
          def NFA.Run.accepts {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] {q qf : Q} {w : Word Sigma} {nfa : NFA Q Sigma} :
          nfa.Run q qf wProp

          An accepting run for a word w ends with a final state.

          Equations
          Instances For
            def NFA.Language {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] (nfa : NFA Q Sigma) :

            The language of an NFA consists of all words w that have an accepting run beginning with some state q0 ∈ Q0 and ending in a state qf ∈ F.

            Equations
            Instances For

              In lecture 3 we defined the language of a DFA M as the set of words w satisfying δ_word(q0,w) ∈ F. We can do something similar for NFAs (using δ_word with a the list of starting states as an input) and prove that this is equal to the previous definition using the run of an NFA. The corresponding proof in lecture 4 can be found starting from slide 18 - feel free to compare it to the Lean version!

              theorem δ_subset_δ_word {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] (nfa : NFA Q Sigma) (q : Q) (R : List Q) (a : Sigma) :
              q Rnfa.δ q a nfa.δ_word R [a]

              Given a set of states R, the states reachable from a single state q ∈ R are a subset of the states reachable from R.

              theorem run_imp_mem_δ {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] (nfa : NFA Q Sigma) (q1 qn : Q) (R : List Q) (w : Word Sigma) :
              ∀ (a : nfa.Run q1 qn w), q1 Rqn nfa.δ_word R w

              For every run q1...qn on a word w with q1 ∈ R, qn ∈ δ_word(R, w).

              theorem run_from_δ_word {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] (nfa : NFA Q Sigma) (qn : Q) (R : List Q) (w : Word Sigma) :
              qn nfa.δ_word R w (q1 : Q), (x : nfa.Run q1 qn w), q1 R

              Given a set of states R and a state qn ∈ δ(R, w) we can also construct a run for w starting with a state in R.

              theorem acc_run_iff_δ_word_contains_final {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] (nfa : NFA Q Sigma) (w : Word Sigma) :
              w nfa.Language (q : Q), q nfa.δ_word nfa.Q0 w q nfa.F

              Using the two previous results, we can show that the two different definitions for the language accepted by an NFA are equal: An NFA has an accepting run q0...qf on a word w iff the set of states reachable from q0 ∈ Q0 contains a qf ∈ F.

              def DFA.to_NFA {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] (M : DFA Q Sigma) :
              NFA Q Sigma

              Every DFA can be turned into an NFA. We just need to map values of δ to singleton lists or the empty list and q0 to a singleton list as well.

              Equations
              Instances For
                def TotalDFA.to_NFA {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] (M : TotalDFA Q Sigma) :
                NFA Q Sigma

                Every total DFA can be turned into an NFA by mapping states to singleton lists.

                Equations
                Instances For

                  The following section deals with the conversion from DFA to NFA. We proceed in a similar manner as we did for the proof of totalDFA_eq_DFA in lecture3 by first showing that the transition functions of M and M.to_NFA are (almost) equal and then using this to prove the equality of M.Language and M.to_NFA.Language.

                  theorem totalDFA_NFA_δ_eq {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] {q' : Q} (M : TotalDFA Q Sigma) (a : Sigma) (q : Q) :
                  q' M.to_NFA.δ q a q' = M.δ q a
                  theorem totalDFA_NFA_δ_word_eq {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] {q' : Q} (M : TotalDFA Q Sigma) (w : Word Sigma) (q : Q) :
                  q' M.to_NFA.δ_word [q] w M.δ_word q w = q'
                  theorem totalDFA_NFA_lang_eq {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] (M : TotalDFA Q Sigma) :

                  Every NFA can be turned into a total DFA using the powerset construction. Since we defined the states Q as some type with a Fintype instance, computing the "powerset" of Q is a bit tricky. A Fintype is simply a type with finitely many elements. This can be expressed by requiring the existence of a list with all elements of Q. The Powertype of Q is the list of all possible subsets of this list. We use subsets instead of lists because the powertype needs to be finite. If you are interested in the details have a look at Powertype.lean. It is not required to understand the definitions and proofs concerning Powertype to understand the section toDFA.

                  def powerset_δ {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] (M : NFA Q Sigma) [DecidableEq Q] :
                  Powertype QSigmaPowertype Q
                  Equations
                  Instances For
                    def NFA.to_TotalDFA {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] (M : NFA Q Sigma) [DecidableEq Q] :
                    Equations
                    Instances For
                      theorem mem_powerset_δ_iff {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] (M : NFA Q Sigma) (a : Sigma) (R : List Q) (q : Q) [DecidableEq Q] :
                      theorem δ_NFA_eq_δ_TotalDFA {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] (M : NFA Q Sigma) (a : Sigma) (R : List Q) [DecidableEq Q] :
                      theorem δ_word_eq_DFA_NFA {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] (M : NFA Q Sigma) (w : Word Sigma) (R : List Q) [DecidableEq Q] (q : Q) :
                      theorem NFA_totalDFA_lang_eq {Q : Type u} {Sigma : Type v} [Fintype Q] [Fintype Sigma] (M : NFA Q Sigma) [DecidableEq Q] :