Dependently Typed Programming with Finite Sets
Denis Firsov and Tarmo Uustalu
Institute of Cybernetics at TUT
November 13, 2015
1 / 67
Dependently Typed Programming with Finite Sets Denis Firsov and - - PowerPoint PPT Presentation
Dependently Typed Programming with Finite Sets Denis Firsov and Tarmo Uustalu Institute of Cybernetics at TUT November 13, 2015 1 / 67 Outline The problem and motivation Different notions of finiteness Pragmatic finite subsets Approaches to
Denis Firsov and Tarmo Uustalu
Institute of Cybernetics at TUT
November 13, 2015
1 / 67
The problem and motivation Different notions of finiteness Pragmatic finite subsets Approaches to defining functions from finite sets Prover for quantified formulas over decidable properties on finite sets
2 / 67
A finite set could be defined as an inductive enumeration type: data Pauli : Set where X : Pauli Y : Pauli Z : Pauli I : Pauli
3 / 67
A finite set could be defined as an inductive enumeration type: data Pauli : Set where X : Pauli Y : Pauli Z : Pauli I : Pauli Next, we can list all the elements: listPauli : List Pauli listPauli = X :: Y :: Z :: I :: []
4 / 67
A finite set could be defined as an inductive enumeration type: data Pauli : Set where X : Pauli Y : Pauli Z : Pauli I : Pauli Next, we can list all the elements: listPauli : List Pauli listPauli = X :: Y :: Z :: I :: [] Finally, we can prove that the list is indeed complete: allPauli : (x : Pauli) → x ∈ listPauli allPauli X = here allPauli Y = there here allPauli Z = there (there here) allPauli I = there (there (there here))
5 / 67
Typically we also want decidable equality:
Dec : Set → Set Dec P = P ⊎ ¬ P
6 / 67
Typically we also want decidable equality:
Dec : Set → Set Dec P = P ⊎ ¬ P _≡P?_ : (x1 x2 : Pauli) → Dec (x1 ≡ x2) X ≡P? X = inj1 refl X ≡P? Y = inj2 λ() X ≡P? Z = inj2 λ() X ≡P? I = inj2 λ() Y ≡P? X = inj2 λ() Y ≡P? Y = inj1 refl Y ≡P? Z = inj2 λ() Y ≡P? I = inj2 λ() Z ≡P? X = inj2 λ() Z ≡P? Y = inj2 λ() Z ≡P? Z = inj1 refl Z ≡P? I = inj2 λ() I ≡P? X = inj2 λ() I ≡P? Y = inj2 λ() I ≡P? Z = inj2 λ() I ≡P? I = inj1 refl
7 / 67
All X xs says that list xs has all elements of type X. All : (X : Set) → List X → Set All X xs = (x : X) → x ∈ xs
8 / 67
All X xs says that list xs has all elements of type X. All : (X : Set) → List X → Set All X xs = (x : X) → x ∈ xs A set X is listable if there is a list xs so that All X xs Listable : (X : Set) → Set Listable X = Σ[ xs ∈ List X ] All X xs
9 / 67
All X xs says that list xs has all elements of type X. All : (X : Set) → List X → Set All X xs = (x : X) → x ∈ xs A set X is listable if there is a list xs so that All X xs Listable : (X : Set) → Set Listable X = Σ[ xs ∈ List X ] All X xs It is the same as asking for a surjection from an initial segment of N: FinSurj : (X : Set) → Set FinSurj X = Σ[ n ∈ N ] Σ[ fromFin ∈ (Fin n → X) ] Σ[ toFin ∈ (X → Fin n) ] ((x : X) → fromFin (toFin x) ≡ x)
10 / 67
All X xs says that list xs has all elements of type X. All : (X : Set) → List X → Set All X xs = (x : X) → x ∈ xs A set X is listable if there is a list xs so that All X xs Listable : (X : Set) → Set Listable X = Σ[ xs ∈ List X ] All X xs It is the same as asking for a surjection from an initial segment of N: FinSurj : (X : Set) → Set FinSurj X = Σ[ n ∈ N ] Σ[ fromFin ∈ (Fin n → X) ] Σ[ toFin ∈ (X → Fin n) ] ((x : X) → fromFin (toFin x) ≡ x) surj2lstbl : {X : Set} → FinSurj X → Listable X lstbl2surj : {X : Set} → Listable X → FinSurj X
11 / 67
NoDup xs says that the list xs has no duplicates: NoDup : {X : Set} → List X → Set NoDup {X} xs = (x : X) → (p1 p2 : x ∈ xs) → p1 ≡ p2
12 / 67
NoDup xs says that the list xs has no duplicates: NoDup : {X : Set} → List X → Set NoDup {X} xs = (x : X) → (p1 p2 : x ∈ xs) → p1 ≡ p2 Now, we can define duplicate-free listability of a set: ListableNoDup : (X : Set) → Set ListableNoDup X = Σ[ xs ∈ List X ] All X xs × NoDup xs
13 / 67
NoDup xs says that the list xs has no duplicates: NoDup : {X : Set} → List X → Set NoDup {X} xs = (x : X) → (p1 p2 : x ∈ xs) → p1 ≡ p2 Now, we can define duplicate-free listability of a set: ListableNoDup : (X : Set) → Set ListableNoDup X = Σ[ xs ∈ List X ] All X xs × NoDup xs This is equivalent to having a bijection from an initial segment of N: FinBij : (X : Set) → Set FinBij X = Σ[ n ∈ N ] Σ[ fromFin ∈ (Fin n → X) ] Σ[ toFin ∈ (X → Fin n) ] ((x : X) → fromFin (toFin x) ≡ x) × ((i : Fin n) → toFin (fromFin i) ≡ i)
14 / 67
NoDup xs says that the list xs has no duplicates: NoDup : {X : Set} → List X → Set NoDup {X} xs = (x : X) → (p1 p2 : x ∈ xs) → p1 ≡ p2 Now, we can define duplicate-free listability of a set: ListableNoDup : (X : Set) → Set ListableNoDup X = Σ[ xs ∈ List X ] All X xs × NoDup xs This is equivalent to having a bijection from an initial segment of N: FinBij : (X : Set) → Set FinBij X = Σ[ n ∈ N ] Σ[ fromFin ∈ (Fin n → X) ] Σ[ toFin ∈ (X → Fin n) ] ((x : X) → fromFin (toFin x) ≡ x) × ((i : Fin n) → toFin (fromFin i) ≡ i) bij2lstblnd : {X : Set} → FinBij X → ListableNoDup X lstblnd2bij : {X : Set} → ListableNoDup X → FinBij X
15 / 67
All four notions of finiteness (Listable, FinSurj, ListableNoDup, FinBij) are equivalent.
16 / 67
All four notions of finiteness (Listable, FinSurj, ListableNoDup, FinBij) are equivalent. Indeed, equality on a listable set is decidable: lstbl2deq : {X : Set} → Listable X → DecEq X
17 / 67
All four notions of finiteness (Listable, FinSurj, ListableNoDup, FinBij) are equivalent. Indeed, equality on a listable set is decidable: lstbl2deq : {X : Set} → Listable X → DecEq X Therefore, we can implement removal of duplicates and convert Listable to ListableNoDup: lstbl2nodup : {X : Set} → Listable X → ListableNoDup X
18 / 67
All four notions of finiteness (Listable, FinSurj, ListableNoDup, FinBij) are equivalent. Indeed, equality on a listable set is decidable: lstbl2deq : {X : Set} → Listable X → DecEq X Therefore, we can implement removal of duplicates and convert Listable to ListableNoDup: lstbl2nodup : {X : Set} → Listable X → ListableNoDup X The other direction is trivial: nodup2lstbl : {X : Set} → ListableNoDup X → Listable X
19 / 67
The generic proof lstbl2deq also provides an alternative way for defining an equality decider for concrete listable types like Pauli: listablePauli : Listable Pauli listablePauli = listPauli , allPauli _≡P?_ : DecEq Pauli _≡P?_ = lstbl2deq listablePauli Recall that the direct implementation took |Pauli|2 lines of code.
20 / 67
We can give a special definition of listability of a subset given by a predicate on some base set: ListableSub : (U : Set) → (U → Set) → Set ListableSub U P = Σ[ xs ∈ List U ] ((x : U) → P x → x ∈ xs) × ((x : U) → x ∈ xs → P x)
21 / 67
We can give a special definition of listability of a subset given by a predicate on some base set: ListableSub : (U : Set) → (U → Set) → Set ListableSub U P = Σ[ xs ∈ List U ] ((x : U) → P x → x ∈ xs) × ((x : U) → x ∈ xs → P x) Listable sets are a special case of listable subsets: lstbl2lsub : {U : Set} → Listable U → ListableSub U (λ _ → ⊤) lsub2lstbl : {U : Set} → ListableSub U (λ _ → ⊤) → Listable U
22 / 67
In general, equality on a finite subset is not decidable: deqLstblSub : {U : Set} → (P : U → Set) → ListableSub U P → (x1 x2 : U) → P x1 → P x2 → Dec (x1 ≡ x2) deqLstblSub = ???
23 / 67
In general, equality on a finite subset is not decidable: deqLstblSub : {U : Set} → (P : U → Set) → ListableSub U P → (x1 x2 : U) → P x1 → P x2 → Dec (x1 ≡ x2) deqLstblSub = ??? If P is a mere proposition, then equality is decidable: deqLstblSub1 : {U : Set} → (P : U → Set) → ListableSub U P → ((x : U) → (p1 p2 : P x) → p1 ≡ p2) → (x1 x2 : U) → P x1 → P x2 → Dec (x1 ≡ x2)
24 / 67
In general, equality on a finite subset is not decidable: deqLstblSub : {U : Set} → (P : U → Set) → ListableSub U P → (x1 x2 : U) → P x1 → P x2 → Dec (x1 ≡ x2) deqLstblSub = ??? If P is a mere proposition, then equality is decidable: deqLstblSub1 : {U : Set} → (P : U → Set) → ListableSub U P → ((x : U) → (p1 p2 : P x) → p1 ≡ p2) → (x1 x2 : U) → P x1 → P x2 → Dec (x1 ≡ x2) If the list contains no duplicates, then equality is decidable: deqLstblSub2 : {U : Set} → (P : U → Set) → (p : ListableSub U P) → NoDup (proj1 p) → (x1 x2 : U) → P x1 → P x2 → Dec (x1 ≡ x2)
25 / 67
If a set P is decidable, we can effectively squash P:
_ : {P : Set} → Dec P → Set inj1 _ = ⊤ inj2 _ = ⊥
26 / 67
If a set P is decidable, we can effectively squash P:
_ : {P : Set} → Dec P → Set inj1 _ = ⊤ inj2 _ = ⊥ We describe a finite subset by listing all its elements with or without duplicates: data FinSubDesc (U : Set) (eq : DecEq U) : Bool → Set where fsd-plain : List U → FinSubDesc U eq true fsd-nodup : (xs : List U) → { nodup? xs } → FinSubDesc U eq false
27 / 67
If a set P is decidable, we can effectively squash P:
_ : {P : Set} → Dec P → Set inj1 _ = ⊤ inj2 _ = ⊥ We describe a finite subset by listing all its elements with or without duplicates: data FinSubDesc (U : Set) (eq : DecEq U) : Bool → Set where fsd-plain : List U → FinSubDesc U eq true fsd-nodup : (xs : List U) → { nodup? xs } → FinSubDesc U eq false An element of a FinSubDesc is a dependent pair of an element together with a squashed proof that it belongs to the subset: Elem : {U : Set}{eq : DecEq U}{b : Bool} → FinSubDesc U eq b → Set Elem {U} {eq} D = Σ[ x ∈ U ] x ∈? toList D
28 / 67
For every FinSubDesc we can automatically generate the list of all its elements, the proof that the list is complete, and decidable equality:
29 / 67
For every FinSubDesc we can automatically generate the list of all its elements, the proof that the list is complete, and decidable equality:
listElem : {U : Set}{eq : DecEq U}{b : Bool} → (D : FinSubDesc U eq b) → List (Elem D)
30 / 67
For every FinSubDesc we can automatically generate the list of all its elements, the proof that the list is complete, and decidable equality:
listElem : {U : Set}{eq : DecEq U}{b : Bool} → (D : FinSubDesc U eq b) → List (Elem D) allElem : {U : Set}{eq : DecEq U}{b : Bool} → (D : FinSubDesc U eq b) → (xp : Elem D) → xp ∈ listElem D
31 / 67
For every FinSubDesc we can automatically generate the list of all its elements, the proof that the list is complete, and decidable equality:
listElem : {U : Set}{eq : DecEq U}{b : Bool} → (D : FinSubDesc U eq b) → List (Elem D) allElem : {U : Set}{eq : DecEq U}{b : Bool} → (D : FinSubDesc U eq b) → (xp : Elem D) → xp ∈ listElem D ndElem : {U : Set}{eq : DecEq U} → (D : FinSubDesc U eq false) → NoDup (listElem D)
32 / 67
For every FinSubDesc we can automatically generate the list of all its elements, the proof that the list is complete, and decidable equality:
listElem : {U : Set}{eq : DecEq U}{b : Bool} → (D : FinSubDesc U eq b) → List (Elem D) allElem : {U : Set}{eq : DecEq U}{b : Bool} → (D : FinSubDesc U eq b) → (xp : Elem D) → xp ∈ listElem D ndElem : {U : Set}{eq : DecEq U} → (D : FinSubDesc U eq false) → NoDup (listElem D) lstblElem : {U : Set}{eq : DecEq U}{b : Bool} → (D : FinSubDesc U eq b) → Listable (Elem D)
33 / 67
For every FinSubDesc we can automatically generate the list of all its elements, the proof that the list is complete, and decidable equality:
listElem : {U : Set}{eq : DecEq U}{b : Bool} → (D : FinSubDesc U eq b) → List (Elem D) allElem : {U : Set}{eq : DecEq U}{b : Bool} → (D : FinSubDesc U eq b) → (xp : Elem D) → xp ∈ listElem D ndElem : {U : Set}{eq : DecEq U} → (D : FinSubDesc U eq false) → NoDup (listElem D) lstblElem : {U : Set}{eq : DecEq U}{b : Bool} → (D : FinSubDesc U eq b) → Listable (Elem D) deqElem : {U : Set}{eq : DecEq U}{b : Bool} → (f : FinSubDesc U eq b) → DecEq (Elem D)
34 / 67
Given a view of a finite set as a subset of some base set with decidable equality, we can define it by listing its elements only once: MyPauli : FinSubDesc Char _=?_ false MyPauli = fsd-nodup (’X’ :: ’Y’ :: ’Z’ :: ’I’ :: [])
35 / 67
Given a view of a finite set as a subset of some base set with decidable equality, we can define it by listing its elements only once: MyPauli : FinSubDesc Char _=?_ false MyPauli = fsd-nodup (’X’ :: ’Y’ :: ’Z’ :: ’I’ :: []) We can refer to some particular element. The second projection is the squashed proof that I is indeed an element of MyPauli identity : Elem MyPauli identity = (’I’, tt)
36 / 67
Given a view of a finite set as a subset of some base set with decidable equality, we can define it by listing its elements only once: MyPauli : FinSubDesc Char _=?_ false MyPauli = fsd-nodup (’X’ :: ’Y’ :: ’Z’ :: ’I’ :: []) We can refer to some particular element. The second projection is the squashed proof that I is indeed an element of MyPauli identity : Elem MyPauli identity = (’I’, tt) identityBad : Elem MyPauli identityBad = (’W’, ?)
37 / 67
Given a view of a finite set as a subset of some base set with decidable equality, we can define it by listing its elements only once: MyPauli : FinSubDesc Char _=?_ false MyPauli = fsd-nodup (’X’ :: ’Y’ :: ’Z’ :: ’I’ :: []) We can refer to some particular element. The second projection is the squashed proof that I is indeed an element of MyPauli identity : Elem MyPauli identity = (’I’, tt) identityBad : Elem MyPauli identityBad = (’W’, ?) The complete list of elements is generated automatically: listMyPauli : List (Elem MyPauli) listMyPauli = listElem MyPauli
38 / 67
Given a view of a finite set as a subset of some base set with decidable equality, we can define it by listing its elements only once: MyPauli : FinSubDesc Char _=?_ false MyPauli = fsd-nodup (’X’ :: ’Y’ :: ’Z’ :: ’I’ :: []) We can refer to some particular element. The second projection is the squashed proof that I is indeed an element of MyPauli identity : Elem MyPauli identity = (’I’, tt) identityBad : Elem MyPauli identityBad = (’W’, ?) The complete list of elements is generated automatically: listMyPauli : List (Elem MyPauli) listMyPauli = listElem MyPauli Completeness of allMyPauli is implied: allMyPauli : (p : Elem MyPauli) → p ∈ allMyPauli allMyPauli = allElem MyPauli
39 / 67
Given a view of a finite set as a subset of some base set with decidable equality, we can define it by listing its elements only once: MyPauli : FinSubDesc Char _=?_ false MyPauli = fsd-nodup (’X’ :: ’Y’ :: ’Z’ :: ’I’ :: []) We can refer to some particular element. The second projection is the squashed proof that I is indeed an element of MyPauli identity : Elem MyPauli identity = (’I’, tt) identityBad : Elem MyPauli identityBad = (’W’, ?) The complete list of elements is generated automatically: listMyPauli : List (Elem MyPauli) listMyPauli = listElem MyPauli Completeness of allMyPauli is implied: allMyPauli : (p : Elem MyPauli) → p ∈ allMyPauli allMyPauli = allElem MyPauli Decidable equality is implied: _=?_ : DecEq (Elem MyPauli) _=?_ = deqElem MyPauli
40 / 67
If X is listable set. How to implement a function f : X → Y that is defined piecewise: f (x) = f1(x) if P1(x) f2(x) if P2(x) . . . fn(x) if Pn(x)
41 / 67
If X is listable set. How to implement a function f : X → Y that is defined piecewise: f (x) = f1(x) if P1(x) f2(x) if P2(x) . . . fn(x) if Pn(x) The straightforward approach has a number of shortcomings: f x = if P1 x then f1 x else if P2 x then f2 x else if P3 x then f3 x else ... There is always a default case and possible dead branches.
42 / 67
unreached takes a list of predicates and a list of elements and returns the list of predicates which are not satisfied by any element: unreached : {X : Set} → List (X → Bool) → List X → List (X → Bool)
43 / 67
unreached takes a list of predicates and a list of elements and returns the list of predicates which are not satisfied by any element: unreached : {X : Set} → List (X → Bool) → List X → List (X → Bool) unmatched returns the list of all those elements which are not satisfied by any predicate: unmatched : {X : Set} → List (X → Bool) → List X → List X
44 / 67
unreached takes a list of predicates and a list of elements and returns the list of predicates which are not satisfied by any element: unreached : {X : Set} → List (X → Bool) → List X → List (X → Bool) unmatched returns the list of all those elements which are not satisfied by any predicate: unmatched : {X : Set} → List (X → Bool) → List X → List X A list of predicate–function tuples without unmatched and unreached elements represents a function: predicateMatching : {X Y : Set} → (ps : List ((X → Bool) × (X → Y))) → (p : Listable X) → unmatched (map proj1 ps) (proj1 p) ≡ [] → unreached (map proj1 ps) (proj1 p) ≡ [] → X → Y
45 / 67
MyNats : FinSubDesc N _=?_ false MyNats = fsd-nodup (1 :: 2 :: 3 :: 4 :: 5 :: [])
46 / 67
MyNats : FinSubDesc N _=?_ false MyNats = fsd-nodup (1 :: 2 :: 3 :: 4 :: 5 :: []) e2o3 : Elem MyNats → N e2o3 = predicateMatching (lstblElem MyNats) (odd , (λ (x , p) → x * 3) :: even, (λ (x , p) → x * 2) :: []) refl refl
47 / 67
MyNats : FinSubDesc N _=?_ false MyNats = fsd-nodup (1 :: 2 :: 3 :: 4 :: 5 :: []) e2o3 : Elem MyNats → N e2o3 = predicateMatching (lstblElem MyNats) (odd , (λ (x , p) → x * 3) :: even, (λ (x , p) → x * 2) :: []) refl refl For this definition the typechecker will complain 1 :: 3 :: 5 :: [] != [], giving us a valuable hint: e2o3’ : Elem MyNats → N e2o3’ = predicateMatching (lstblElem MyNats) (even, (λ (x , p) → x * 2) :: []) refl refl
48 / 67
Conceptually, the prover for quantified formulas over decidable properties on finite sets checks all the combinations of elements (depending on the arity) to find proofs for universals or existentials.
49 / 67
Conceptually, the prover for quantified formulas over decidable properties on finite sets checks all the combinations of elements (depending on the arity) to find proofs for universals or existentials. The combinator subAll? takes a decidable predicate P on elements
subAll? : {U : Set}{P : U → Set} → ListableSub U P → {Q : U → Set} → ((x : U) → {P x} → Dec (Q x)) → Dec ((x : U) → {P x} → Q x)
50 / 67
Conceptually, the prover for quantified formulas over decidable properties on finite sets checks all the combinations of elements (depending on the arity) to find proofs for universals or existentials. The combinator subAll? takes a decidable predicate P on elements
subAll? : {U : Set}{P : U → Set} → ListableSub U P → {Q : U → Set} → ((x : U) → {P x} → Dec (Q x)) → Dec ((x : U) → {P x} → Q x) Similarly, for existentials: subAny? : {U : Set}{P : U → Set} → ListableSub U P → {Q : U → Set} → ((x : U) → {P x} → Dec (Q x)) → Dec (Σ[ x ∈ U ] P x × Q x)
51 / 67
The group operation on Pauli: _·_ : Pauli → Pauli → Pauli X · X = I X · Y = Z X · Z = Y Y · X = Z Y · Y = I Y · Z = X Z · X = Y Z · Y = X Z · Z = I a · I = a I · a = a
52 / 67
We add some syntactic sugar on top of subAll? and subAny?: syntax subAll? f (λ x → z) = Π x ∈ f , z syntax subAny? f (λ x → z) = ∃ x ∈ f , z
53 / 67
We add some syntactic sugar on top of subAll? and subAny?: syntax subAll? f (λ x → z) = Π x ∈ f , z syntax subAny? f (λ x → z) = ∃ x ∈ f , z One always has a proof of P if the squashed version is inhabited: fromSq : {P : Set} → (d : Dec P) → { d } → P
54 / 67
We add some syntactic sugar on top of subAll? and subAny?: syntax subAll? f (λ x → z) = Π x ∈ f , z syntax subAny? f (λ x → z) = ∃ x ∈ f , z One always has a proof of P if the squashed version is inhabited: fromSq : {P : Set} → (d : Dec P) → { d } → P The proofs are done by just repeating the property in syntactic sugar and providing the decider of a property in question (_≡P?_ for _≡_): ·-comm : (p1 p2 : Pauli) → p1 · p2 ≡ p2 · p1 ·-comm = fromSq $ Π p1 ∈ listablePauli , Π p2 ∈ listablePauli , p1 · p2 ≡P? p2 · p1
55 / 67
We add some syntactic sugar on top of subAll? and subAny?: syntax subAll? f (λ x → z) = Π x ∈ f , z syntax subAny? f (λ x → z) = ∃ x ∈ f , z One always has a proof of P if the squashed version is inhabited: fromSq : {P : Set} → (d : Dec P) → { d } → P The proofs are done by just repeating the property in syntactic sugar and providing the decider of a property in question (_≡P?_ for _≡_): ·-comm : (p1 p2 : Pauli) → p1 · p2 ≡ p2 · p1 ·-comm = fromSq $ Π p1 ∈ listablePauli , Π p2 ∈ listablePauli , p1 · p2 ≡P? p2 · p1 ·-id : Σ[ i ∈ Pauli ] (p : Pauli) → i · p ≡ p ·-id = fromSq $ ∃ i ∈ listablePauli , Π p ∈ listablePauli , i · p ≡P? p
56 / 67
57 / 67