module Data.Fin.Base where
Finite setsπ
The type Fin
is the type of size
n
. These are defined as an inductive family over Nat
, such that Fin 0
has 0
elements, Fin 1
has 1 element, and so on.
Another way to view Fin
is as
the type of numbers less than some upper bound. For instance,
fsuc fzero
is of type Fin 3
, but will
not typecheck as a Fin 1
!
data Fin : Nat β Type where
: β {n} β Fin (suc n)
fzero : β {n} β Fin n β Fin (suc n) fsuc
Keeping with the perspective of Fin
as a type of bounded natural numbers,
we provide conversion functions going back and forth.
: β (n : Nat) β Fin (suc n)
from-nat = fzero
from-nat zero (suc n) = fsuc (from-nat n)
from-nat
: β {n : Nat} β Fin n β Nat
to-nat = zero
to-nat fzero (fsuc i) = suc (to-nat i) to-nat
A note of caution: because of some β¨technical reasonsβ¨ cubical agda
cannot handle transports over indexed inductive types very well.
Instead, we define a function cast
that computes on the indices of Fin
, rather than on the path.
: β {m n} β m β‘ n β Fin m β Fin n
cast {suc m} {zero} p fzero = absurd (Nat.sucβ zero p)
cast {suc m} {suc n} p fzero = fzero
cast {suc m} {zero} p (fsuc i) = absurd (Nat.sucβ zero p)
cast {suc m} {suc n} p (fsuc i) = fsuc (cast (Nat.suc-inj p) i) cast
: β {m n} β (p : m β‘ n) β β x β cast (sym p) (cast p x) β‘ x
cast-uncast {suc m} {zero} p fzero = absurd (Nat.sucβ zero p)
cast-uncast {suc m} {suc n} p fzero = refl
cast-uncast {suc m} {zero} p (fsuc x) = absurd (Nat.sucβ zero p)
cast-uncast {suc m} {suc n} p (fsuc x) = ap fsuc (cast-uncast (Nat.suc-inj p) x)
cast-uncast
: β {m n} (p : m β‘ n) β is-equiv (cast p)
cast-is-equiv = is-isoβis-equiv $ iso
cast-is-equiv p (cast (sym p))
(cast-uncast (sym p))
(cast-uncast p)
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
.
: β {n} β Fin (suc n) β Fin (suc n) β Fin n
strengthen {n = zero} fzero = inl fzero
strengthen {n = suc n} fzero = inr fzero
strengthen {n = suc n} (fsuc i) = β-map fsuc fsuc (strengthen i) strengthen
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)
.
: β {n} β Fin n β Fin (suc n)
weaken = fzero
weaken fzero (fsuc i) = fsuc (weaken i) weaken
We can also relax the upper bounds if m β€ n
.
: β {m n} β m Nat.β€ n β Fin m β Fin n
inject {_} {suc n} le fzero = fzero
inject {_} {suc n} (Nat.sβ€s le) (fsuc i) = fsuc (inject le i) inject
Discretenessπ
The proof here mirrors the one found in Data.Nat.Base
, just with some
slight tweaks required to handle the indexing.
We begin by showing that one can distinguish
zero from successor:
: β {n} {i : Fin n} β Β¬ fzero β‘ fsuc i
fzeroβ fsuc {n = n} path = subst distinguish path tt where
fzeroβ fsuc : Fin (suc n) β Type
distinguish = β€
distinguish fzero (fsuc _) = β₯ distinguish
Next, we show that fsuc
is injective. This again follows
the proof in Data.Nat.Base
, but some extra
care must be taken to ensure that pred
is well typed!
: β {n} {i j : Fin n} β fsuc i β‘ fsuc j β i β‘ j
fsuc-inj {n = suc n} p = ap pred p
fsuc-inj where
: Fin (suc (suc n)) β Fin (suc n)
pred = fzero
pred fzero (fsuc i) = i pred
Finally, we pull everything together to show that Fin
is Discrete
. This is not exactly a shock
(after all, Nat
is discrete), but
itβs useful nonetheless!
instance
: β {n} β Discrete (Fin n)
Discrete-Fin {x = fzero} {fzero} = yes refl
Discrete-Fin {x = fzero} {fsuc j} = no fzeroβ fsuc
Discrete-Fin {x = fsuc i} {fzero} = no (fzeroβ fsuc β sym)
Discrete-Fin {x = fsuc i} {fsuc j} with Discrete-Fin {x = i} {j}
Discrete-Fin ... | yes p = yes (ap fsuc p)
... | no Β¬iβ‘j = no Ξ» si=sj β Β¬iβ‘j (fsuc-inj si=sj)
Hedbergβs theorem implies
that Fin
is a set, i.e., it only has
trivial paths.
opaque: β {n} β is-set (Fin n)
Fin-is-set = Discreteβis-set Discrete-Fin
Fin-is-set
instance
: β {n k} β H-Level (Fin n) (2 + k)
H-Level-Fin = basic-instance 2 Fin-is-set H-Level-Fin
instance
: β {n} β Number (Fin n)
Number-Fin {n} .Number.Constraint k = k Nat.< n
Number-Fin {n} .Number.fromNat k {{e}} = go k n e where
Number-Fin : β k n β k Nat.< n β Fin n
go (suc n) e = fzero
go zero (suc k) (suc n) (Nat.sβ€s e) = fsuc (go k n e)
go
open import Data.Nat.Base using (0β€x ; sβ€s') public
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
= pfzero
Fin-elim P pfzero pfsuc fzero (fsuc x) = pfsuc x (Fin-elim P pfzero pfsuc x)
Fin-elim P pfzero pfsuc
: β {β} {n} {P : Fin (suc n) β Type β} β P 0 β (β x β P (fsuc x)) β β x β P x
fin-cons = p0
fin-cons p0 ps fzero (fsuc x) = ps x
fin-cons p0 ps
: Fin 0 β β₯
fin-absurd () fin-absurd
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
= to-nat i Nat.β€ to-nat j
i β€ j infix 7 _β€_
_<_ : β {n} β Fin n β Fin n β Type
= to-nat i Nat.< to-nat j
i < j 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.
: β {n} β Fin n β Fin (suc n) β Fin n
squish = fzero
squish fzero fzero (fsuc j) = j
squish fzero (fsuc i) fzero = fzero
squish (fsuc i) (fsuc j) = fsuc (squish i j)
squish
: β {n} β Fin (suc n) β Fin n β Fin (suc n)
skip = fsuc j
skip fzero j (fsuc i) fzero = fzero
skip (fsuc i) (fsuc j) = fsuc (skip i j) skip
As a subsetπ
While Fin
is very conveniently
defined as an indexed family of types, it can also be defined as a
subset of the natural numbers: Namely, the finite ordinal
is the same type as as
This makes sense! Any set with
elements is equivalent to any other set with
elements, and a very canonical choice is the first
values of
: Nat β Type
β< = Ξ£[ n β Nat ] n Nat.< x
β< x
: β {n} β β< n β Fin n
from-β< {n = suc n} (zero , q) = fzero
from-β< {n = suc n} (suc p , Nat.sβ€s q) = fsuc (from-β< (p , q))
from-β<
: β {n} β Fin n β β< n
to-β< = to-nat x , p x where
to-β< x : β {n} (x : Fin n) β suc (to-nat x) Nat.β€ n
p {n = suc n} fzero = Nat.sβ€s Nat.0β€x
p {n = suc n} (fsuc x) = Nat.sβ€s (p x) p
Arithmeticπ
: β {m n} β m Nat.β€ n β Fin m β Fin n
weaken-β€ {suc m} {suc n} mβ€n fzero = fzero
weaken-β€ {suc m} {suc n} (Nat.sβ€s mβ€n) (fsuc i) = fsuc (weaken-β€ mβ€n i)
weaken-β€
: β {m n} β m Nat.β€ n β Fin m β Fin n
shift-β€ {n = suc zero} (Nat.sβ€s 0β€x) i = i
shift-β€ {n = suc (suc n)} (Nat.sβ€s 0β€x) i = fsuc (shift-β€ (Nat.sβ€s 0β€x) i)
shift-β€ {n = n} (Nat.sβ€s (Nat.sβ€s mβ€n)) fzero = weaken (shift-β€ (Nat.sβ€s mβ€n) fzero)
shift-β€ {n = n} (Nat.sβ€s (Nat.sβ€s mβ€n)) (fsuc i) = fsuc (shift-β€ (Nat.sβ€s mβ€n) i)
shift-β€
: β {m n} β Fin (m + n) β Fin m β Fin n
split-+ {m = zero} i = inr i
split-+ {m = suc m} fzero = inl fzero
split-+ {m = suc m} (fsuc i) = β-map fsuc id (split-+ i)
split-+
: β {n} (i j : Fin (suc n)) β i β j β Fin n
avoid = absurd (iβ j refl)
avoid fzero fzero iβ j {n = suc n} fzero (fsuc j) iβ j = j
avoid {n = suc n} (fsuc i) fzero iβ j = fzero
avoid {n = suc n} (fsuc i) (fsuc j) iβ j = fsuc (avoid i j (iβ j β ap fsuc))
avoid
: β {n} (m : Nat) β Fin n β Fin (m + n)
fshift = i
fshift zero i (suc m) i = fsuc (fshift m i)
fshift
: β {n} β Fin n β Fin n
opposite {n = suc n} fzero = from-nat n
opposite {n = suc n} (fsuc i) = weaken (opposite i) opposite
Vector operationsπ
_[_β_]
: β {β} {A : Type β} {n}
β (Fin n β A) β Fin (suc n) β A
β Fin (suc n) β A
_[_β_] {n = n} Ο fzero a fzero = a
_[_β_] {n = n} Ο fzero a (fsuc j) = Ο j
_[_β_] {n = suc n} Ο (fsuc i) a fzero = Ο fzero
_[_β_] {n = suc n} Ο (fsuc i) a (fsuc j) = ((Ο β fsuc) [ i β a ]) j
delete: β {β} {A : Type β} {n}
β (Fin (suc n) β A) β Fin (suc n)
β Fin n β A
= Ο (skip i j) delete Ο i j