module Data.Fin.Base whereFinite setsπ
The type is the type with exactly elements. We define it as a record type, packaging a natural number with a proof that
record Fin (n : Nat) : Type where
constructor fin
field
lower : Nat
β¦ bounded β¦ : Irr (lower Nat.< n)While the type
is a homotopy proposition, we would like to
enforce that constructions on
definitionally do not depend on the given proof. Therefore, we
have wrapped it in Irr.
In dependent type theory, itβs common to instead define the finite
sets as an inductive family indexed over Nat. However, in cubical type theory,
there is a good reason to avoid inductive families: they have subst as an additional constructor,
including along constant paths. This makes the normal form of
any expression involving substitution in an indexed family, even if the
thing being transported is a constructor form, very bad.
Instead, we would like the subst
operation on Fin to definitionally
commute with the constructors, and (if possible) to definitionally
preserve the underlying numeric value. Defining Fin as an indexed type with an irrelevant
proof field achieves exactly this. Moreover, if weβre substituting over
a loop, even at a neutral number, transport at Fin is definitionally the identity
function.
private
cast : β {m n} β m β‘ n β Fin m β Fin n
cast p (fin n β¦ i β¦) = record
{ lower = n
; bounded = subst (n Nat.<_) p <$> i
}
_ : β {m n} {p : m β‘ n} {x : Fin m} β subst Fin p x β‘ cast p x
_ = refl
_ : β {m} {p : m β‘ m} {x : Fin m} β subst Fin p x β‘ x
_ = reflopen Data.Irr using (make-irr) public
open Fin using (lower) public
pattern fzero = fin zeroWe can still prove that the definition above is equivalent
to an inductive family. In particular, itβs generated by the
βconstructorsβ fzero and fsuc.
_ : β {n} β Fin (suc n)
_ = fzero
fsuc : β {n} β Fin n β Fin (suc n)
fsuc (fin n β¦ x β¦) = fin (suc n) β¦ Nat.sβ€s <$> x β¦from-nat : β (n : Nat) β Fin (suc n)
from-nat zero = fzero
from-nat (suc n) = fsuc (from-nat n)
module _ {m n : Nat} (p : m β‘ n) (x : Fin m) where
_ : subst (Fin β suc) p (fsuc x) β‘ fsuc (subst Fin p x)
_ = refl
_ : subst (Fin β suc) p fzero β‘ fzero
_ = reflViewing elements of a finite setπ
Agda has good support, through the with abstraction,
to pretend that a type is inductively generated. We therefore expose a
type Fin-view which allows us to
discriminate on whether an element of
is fzero or fsuc.
data Fin-view : {n : Nat} β Fin n β Type where
zero : β {n} β Fin-view {suc n} fzero
suc : β {n} (i : Fin n) β Fin-view {suc n} (fsuc i)Of course, this family has a section, expressing that any finite number is generated by one of the two βconstructorsβ.
fin-view : β {n} (i : Fin n) β Fin-view i
fin-view {suc n} fzero = zero
fin-view {suc n} (fin (suc i) β¦ b β¦) = suc (fin i β¦ Nat.β€-peel <$> b β¦)
fin-view {zero} (fin _ β¦ forget i β¦) = absurd (Nat.Β¬sucβ€0 i)As a first application, we can prove that Fin 0 is
empty:
Fin-absurd : Fin 0 β β₯
Fin-absurd i with fin-view i
... | ()We can also define an elimination principle for the family which applies the view at βevery levelβ.
Fin-elim
: β {β} (P : β {n} β Fin n β Type β)
β (β {n} β P {suc n} fzero)
β (β {i} (j : Fin i) β P j β P (fsuc j))
β β {n} (i : Fin n) β P i
Fin-elim P pfzero pfsuc i with fin-view i
... | zero = pfzero
... | suc i = pfsuc i (Fin-elim P pfzero pfsuc i)fin-ap : β {n : I β Nat} {x : Fin (n i0)} {y : Fin (n i1)} β x .lower β‘ y .lower β PathP (Ξ» i β Fin (n i)) x y
fin-ap {n = n} {fin i β¦ q β¦} {fin j β¦ r β¦} s k = fin (s k) β¦ is-propβpathp (Ξ» k β hlevel {T = Irr (s k Nat.< n k)} 1) q r k β¦Next, we move on to one of the most useful functions for Fin: strength. This allows
us to (possibly) strengthen the upper bound on some
Fin n.
strengthen : β {n} β Fin (suc n) β Fin (suc n) β Fin n
strengthen {n = zero} k with fin-view k
... | vzero = inl fzero
strengthen {n = suc n} k with fin-view k
... | zero = inr fzero
... | suc i = β-map fsuc fsuc (strengthen i)On the other hand, weaken does
the opposite: it relaxes the upper bound on some Fin n,
allowing us to regard it as a Fin (suc n).
weaken : β {n} β Fin n β Fin (suc n)
weaken n with fin-view n
... | zero = fzero
... | suc i = fsuc (weaken i)We can also relax the upper bounds if m β€ n.
inject : β {m n} β m Nat.β€ n β Fin m β Fin n
inject p (fin n β¦ b β¦) = fin n β¦ (Ξ» e β Nat.β€-trans e p) <$> b β¦Discretenessπ
Since the finite set of size is a subset of the natural numbers, which have decidable equality, it follows that also has decidable equality.
instance
Discrete-Fin : β {n} β Discrete (Fin n)
Discrete-Fin .decide x y with x .lower β‘? y .lower
... | yes p = yes (fin-ap p)
... | no Β¬p = no Ξ» p β Β¬p (ap lower p)In particular, Hedbergβs theorem shows that is a set.
opaque
Fin-is-set : β {n} β is-set (Fin n)
Fin-is-set = Discreteβis-set Discrete-Fin
instance
H-Level-Fin : β {n k} β H-Level (Fin n) (2 + k)
H-Level-Fin = basic-instance 2 Fin-is-setHowever, we can also mimic parts of the proof that Nat itself is discrete, and obtain useful
combinators for reasoning with finite sets. For example, the zero
element in
is never equal to a successor:
fzeroβ fsuc : β {n k p} β Β¬ Path (Fin (suc n)) fzero (fin (suc k) β¦ p β¦)
fzeroβ fsuc p = Nat.zeroβ suc (ap lower p)fsucβ fzero : β {n k p} β Β¬ Path (Fin (suc n)) (fin (suc k) β¦ p β¦) fzero
fsucβ fzero p = Nat.sucβ zero (ap lower p)Moreover, since we can implement a βpredecessorβ operation, we get
that fsuc is an injection.
fsuc-inj : β {n} {i j : Fin n} β fsuc i β‘ fsuc j β i β‘ j
fsuc-inj {n = suc n} p = ap pred p where
pred : Fin (suc (suc n)) β Fin (suc n)
pred n with fin-view n
... | zero = fzero
... | suc i = iinstance
Number-Fin : β {n} β Number (Fin n)
Number-Fin {n} .Number.Constraint k = k Nat.< n
Number-Fin {n} .Number.fromNat k β¦ e β¦ = fin k β¦ forget e β¦
open import Data.Nat.Base using (0β€x ; sβ€s') public
Fin-cases : β {β} {n} {P : Fin (suc n) β Type β} β P 0 β (β x β P (fsuc x)) β β x β P x
Fin-cases p0 ps n with fin-view n
... | zero = p0
... | suc i = ps i
fin-cons : β {β} {n} {P : Fin (suc n) β Type β} β P 0 β (β x β P (fsuc x)) β β x β P x
fin-cons = Fin-cases
fin-nil : β {β} {P : Fin 0 β Type β} β β x β P x
fin-nil x = absurd (Fin-absurd x)Orderingπ
Keeping with the view that Fin
represents the type of bounded natural numbers, we can re-use the
ordering on Nat to induce an
ordering on Fin. This means that
any lemmas about the ordering on natural numbers apply immediately to
the ordering on standard finite sets.
_β€_ : β {n} β Fin n β Fin n β Type
i β€ j = i .lower Nat.β€ j .lower
infix 7 _β€_
_<_ : β {n} β Fin n β Fin n β Type
i < j = i .lower Nat.< j .lower
infix 7 _<_Next, we define a pair of functions squish and skip, which are the building blocks for
all monotone functions between Fin. squish i takes a
j : Fin (suc n) to a Fin n by mapping both
i and i+1 to i. Its counterpart
skip i takes some j : Fin n to a
Fin (suc n) by skipping over i instead.
squish : β {n} β Fin n β Fin (suc n) β Fin n
squish n k with fin-view n | fin-view k
... | zero | zero = fzero
... | zero | suc j = j
... | suc i | zero = fzero
... | suc i | suc j = fsuc (squish i j)
skip : β {n} β Fin (suc n) β Fin n β Fin (suc n)
skip n k with fin-view n
... | zero = fsuc k
... | suc i with fin-view k
... | zero = fzero
... | suc j = fsuc (skip i j)Arithmeticπ
split-+ : β {m n} β Fin (m + n) β Fin m β Fin n
split-+ {m = zero} i = inr i
split-+ {m = suc m} k with fin-view k
... | zero = inl fzero
... | suc i = β-map fsuc id (split-+ i)
avoid : β {n} (i j : Fin (suc n)) β i β j β Fin n
avoid {n = n} i j iβ j with fin-view i | fin-view j
... | zero | zero = absurd (iβ j refl)
... | zero | suc j = j
avoid {n = suc n} _ _ iβ j | suc i | zero = fzero
avoid {n = suc n} _ _ iβ j | suc i | suc j = fsuc (avoid i j (iβ j β ap fsuc))
fshift : β {n} (m : Nat) β Fin n β Fin (m + n)
fshift zero i = i
fshift (suc m) i = fsuc (fshift m i)
opposite : β {n} β Fin n β Fin n
opposite {n = n} i with fin-view i
opposite {n = suc n} _ | zero = from-nat n
opposite {n = suc n} _ | suc i = weaken (opposite i)Vector operationsπ
_[_β_]
: β {β} {A : Type β} {n}
β (Fin n β A) β Fin (suc n) β A
β Fin (suc n) β A
_[_β_] {n = n} Ο i a j with fin-view i | fin-view j
_[_β_] {n = n} Ο fzero a fzero | zero | zero = a
_[_β_] {n = n} Ο fzero a .(fsuc j) | zero | suc j = Ο j
_[_β_] {n = suc n} Ο .(fsuc i) a .fzero | suc i | zero = Ο fzero
_[_β_] {n = suc n} Ο .(fsuc i) a .(fsuc j) | suc i | suc j = ((Ο β fsuc) [ i β a ]) j
delete
: β {β} {A : Type β} {n}
β (Fin (suc n) β A) β Fin (suc n)
β Fin n β A
delete Ο i j = Ο (skip i j)