The powerset DFA (as it is defined in Lecture 4) has subsets of Q (the states of the original NFA) as its states. However, the automaton definitions in this formalisation don't use finite sets of states but instead lists over a Fintype Q. So we need to define something like a powerset but for lists. We also need to prove that the resulting "powerlist" contains only finitely many elements because the states of an NFA have to be of a Fintype.
The powerset of a set X just contains all possible subsets of X. (See Set.lean) We define the power of a list l as the list containing all lists up to the length if l with elements from l. The following recursive function computes all lists with elements from a given list l that have a length up to n. This includes lists with duplicate elements and all possible sequences. We do this by repeatedly appending elements of l to all lists we currently have.
Equations
- l.power_upto n = List.power_upto.loop l n
Instances For
Equations
- List.power_upto.loop l 0 = [[]]
- List.power_upto.loop l n.succ = List.power_upto.loop l n ++ List.flatMap (fun (l' : List α) => List.map (fun (e : α) => e :: l') l) (List.power_upto.loop l n)
Instances For
This example shows how the power of a list is computed. As you can see, all the different lists are added to the powerlist multiple times.
After defining the power of a list, we can use this function to compute the Powertype of a Fintype and prove that it is also finite. As a reminder: a Fintype is a type with a corresponding list ("elems") containing all things of this type (refer to Fintype.lean for further information).
The following 4 theorems are auxiliary results required to prove that for a Fintype T with elements of type α T.elems.power_upto (T.elems.length) contains all lists of type List α that are at most of the same length as T.elems.
T.elems.power_upto n contains every List α of length n
If a list l is contained in T.elems.power_upto n, then it is also an element of l ∈ T.elems.power_upto (n+1).
We use Finset instead of Set here because it enables easier proofs for (e.g.) DecidablePred (a ∈ X) and DecidableEq.
Equations
- instMembershipPowertype = { mem := fun (S : Powertype α) (a : α) => Finset.mem a S }
Equations
- Finset.instFintypeOfFintype = { elems := List.map (fun (x : Finset' α) => Finset.mk x) (Fintype.elems.power_upto Fintype.elems.length), complete := ⋯ }