module Data.Fin.Finite where
Finite types🔗
This module pieces together a couple of pre-existing constructions: In terms of the standard finite sets (which are defined for natural numbers and deloopings of automorphism groups, we construct the type of finite types. By univalence, the space of finite types classifies maps with finite fibres.
But what does it mean for a type to be finite? A naïve first approach is to define “ is finite” to mean “ is equipped with and ” but this turns out to be too strong: This doesn’t just equip the type with a cardinality, but also with a choice of total order. Additionally, defined like this, the type of finite types is a set!
: is-set (Σ[ X ∈ Type ] Σ[ n ∈ Nat ] Fin n ≃ X)
naïve-fin-is-set = Equiv→is-hlevel 2 Σ-swap₂ $
naïve-fin-is-set 2 (hlevel 2) λ x → is-prop→is-hlevel-suc {n = 1} $
Σ-is-hlevel (Fin x) is-contr→is-prop $ Equiv-is-contr
That’s because, as the proof above shows, it’s equivalent to the type of natural numbers: The type
is equivalent to the type
and univalence says (rather directly) that the sum of as ranges over a universe is contractible, so we’re left with the type of natural numbers.
This simply won’t do: we want the type of finite sets to be equivalent to the (core of the) category of finite sets, where the automorphism group of has elements, not exactly one element. What we do is appeal to a basic intuition: A groupoid is the sum over its connected components, and we have representatives for every connected component (given by the standard finite sets):
: Type (lsuc lzero)
Fin-type = Σ[ n ∈ Nat ] BAut (Fin n)
Fin-type
: is-hlevel Fin-type 3
Fin-type-is-groupoid = Σ-is-hlevel 3 (hlevel 3) λ _ →
Fin-type-is-groupoid (Fin _) 2 (hlevel 2) BAut-is-hlevel
Informed by this, we now express the correct definition of “being finite”, namely, being merely equivalent to some standard finite set. Rather than using Σ types for this, we can set up typeclass machinery for automatically deriving boring instances of finiteness, i.e. those that follow directly from the closure properties.
record Finite {ℓ} (T : Type ℓ) : Type ℓ where
constructor fin
field
{cardinality} : Nat
: ∥ T ≃ Fin cardinality ∥ enumeration
: is-set T
Finite→is-set =
Finite→is-set (is-hlevel-is-prop 2) (λ e → Equiv→is-hlevel 2 e (hlevel 2)) enumeration
∥-∥-rec
instance
: H-Level T 2
Finite→H-Level = basic-instance 2 Finite→is-set
Finite→H-Level
open Finite ⦃ ... ⦄ using (cardinality; enumeration) public
open Finite using (Finite→is-set) public
instance opaque
: ∀ {ℓ} {A : Type ℓ} {n : Nat} → H-Level (Finite A) (suc n)
H-Level-Finite = prop-instance {T = Finite _} λ where
H-Level-Finite .Finite.cardinality → ∥-∥-out!
x y i (⦇ ⦇ x .enumeration e⁻¹ ⦈ ∙e y .enumeration ⦈) ⦈
⦇ Fin-injective
i.Finite.enumeration → is-prop→pathp
x y i {B = λ i → ∥ _ ≃ Fin (∥-∥-out! ⦇ Fin-injective (⦇ ⦇ x .enumeration e⁻¹ ⦈ ∙e y .enumeration ⦈) ⦈ i) ∥}
(λ _ → squash)
(x .enumeration) (y .enumeration) i
: ∀ {ℓ} {A : Type ℓ} → ⦃ Finite A ⦄ → Discrete A
Finite→Discrete {A = A} ⦃ f ⦄ {x} {y} = rec! go (f .enumeration) where
Finite→Discrete open Finite f using (Finite→H-Level)
: A ≃ Fin (f .cardinality) → Dec (x ≡ y)
go with Equiv.to e x ≡? Equiv.to e y
go e ... | yes p = yes (Equiv.injective e p)
... | no ¬p = no λ p → ¬p (ap (e .fst) p)
: ∀ {ℓ} {A : Type ℓ} → is-prop A → Dec A → Finite A
Dec→Finite = fin (inc (Dec→Fin ap d .snd e⁻¹))
Dec→Finite ap d
: ∀ {ℓ} {A : Type ℓ} → Discrete A → {x y : A} → Finite (x ≡ y)
Discrete→Finite≡ = Dec→Finite (Discrete→is-set d _ _) d
Discrete→Finite≡ d
Finite-choice: ∀ {ℓ ℓ'} {A : Type ℓ} {B : A → Type ℓ'}
→ ⦃ Finite A ⦄
→ (∀ x → ∥ B x ∥) → ∥ (∀ x → B x) ∥
{B = B} ⦃ fin {sz} e ⦄ k = do
Finite-choice
e ← eλ x → k (equiv→inverse (e .snd) x)
choose ← finite-choice sz λ x → subst B (equiv→unit (e .snd) x) (choose (e .fst x))
pure $
: ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} → ⦃ Finite A ⦄ → A ≃ B → Finite B
Finite-≃ {n} e ⦄ e' = fin (∥-∥-map (e' e⁻¹ ∙e_) e)
Finite-≃ ⦃ fin
equiv→same-cardinality: ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} ⦃ fa : Finite A ⦄ ⦃ fb : Finite B ⦄
→ ∥ A ≃ B ∥ → fa .Finite.cardinality ≡ fb .Finite.cardinality
= ∥-∥-out! do
equiv→same-cardinality ⦃ fa ⦄ ⦃ fb ⦄ e
e ← e.Finite.enumeration
ea ← fa .Finite.enumeration
eb ← fb (Fin-injective (ea e⁻¹ ∙e e ∙e eb))
pure
same-cardinality→equiv: ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} ⦃ fa : Finite A ⦄ ⦃ fb : Finite B ⦄
→ fa .Finite.cardinality ≡ fb .Finite.cardinality → ∥ A ≃ B ∥
= do
same-cardinality→equiv ⦃ fa ⦄ ⦃ fb ⦄ p .Finite.enumeration
ea ← fa .Finite.enumeration
eb ← fb (ea ∙e (_ , cast-is-equiv p) ∙e eb e⁻¹)
pure
module _ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} ⦃ fb : Finite B ⦄
(e : ∥ A ≃ B ∥) (f : A → B) where
: injective f → is-equiv f
Finite-injection→equiv = ∥-∥-out! do
Finite-injection→equiv inj
e ← e.Finite.enumeration
eb ← fb
pure(eb .snd)
$ equiv-cancell ((eb e⁻¹ ∙e e e⁻¹) .snd)
$ equiv-cancelr _
$ Fin-injection→equiv .injective (eb e⁻¹ ∙e e e⁻¹) ∘ inj ∘ Equiv.injective eb
$ Equiv
: is-surjective f → is-equiv f
Finite-surjection→equiv = ∥-∥-out! do
Finite-surjection→equiv surj
e ← e.Finite.enumeration
eb ← fb
pure(eb .snd)
$ equiv-cancell ((eb e⁻¹ ∙e e e⁻¹) .snd)
$ equiv-cancelr _
$ Fin-surjection→equiv (is-equiv→is-surjective (eb .snd))
$ ∘-is-surjective
$ ∘-is-surjective surj((eb e⁻¹ ∙e e e⁻¹) .snd)
$ is-equiv→is-surjective
private variable
: Level
ℓ : Type ℓ
A B : A → Type ℓ P Q
instance
: ∀ {n} → Finite (Fin n)
Finite-Fin : ⦃ Finite A ⦄ → ⦃ Finite B ⦄ → Finite (A ⊎ B)
Finite-⊎
Finite-Σ: {P : A → Type ℓ} → ⦃ Finite A ⦄ → ⦃ ∀ {x} → Finite (P x) ⦄ → Finite (Σ A P)
Finite-Π: {P : A → Type ℓ} → ⦃ Finite A ⦄ → ⦃ ∀ {x} → Finite (P x) ⦄ → Finite (∀ x → P x)
: Finite ⊥
Finite-⊥ : Finite ⊤
Finite-⊤ : Finite Bool
Finite-Bool
Finite-PathP: ∀ {A : I → Type ℓ} ⦃ s : Finite (A i1) ⦄ {x y}
→ Finite (PathP A x y)
: ∀ {ℓ} → ⦃ Finite A ⦄ → Finite (Lift ℓ A) Finite-Lift
= fin (inc (_ , id-equiv))
Finite-Fin
{A = A} {B = B} = fin $ do
Finite-⊎ {T = A}
aeq ← enumeration {T = B}
beq ← enumeration (⊎-ap aeq beq ∙e Finite-coproduct)
pure
{A = A} {P = P} ⦃ afin ⦄ ⦃ pfin ⦄ = ∥-∥-out! do
Finite-Π .Finite.enumeration
aeq ← afin let
module aeq = Equiv aeq
: Fin (afin .Finite.cardinality) → Nat
bc = pfin {aeq.from x} .Finite.cardinality
bc x do
pure $ fin λ x → pfin {x} .Finite.enumeration
t ← Finite-choice (Π-cod≃ t ∙e Π-dom≃ aeq.inverse ∙e Finite-product bc)
pure
{A = A} {P = P} ⦃ afin ⦄ ⦃ pfin ⦄ = ∥-∥-out! do
Finite-Σ .Finite.enumeration
aeq ← afin let
module aeq = Equiv aeq
: Fin (afin .Finite.cardinality) → Nat
bc = pfin {aeq.from x} .Finite.cardinality
bc x do
pure $ fin λ x → pfin {x} .Finite.enumeration
t ← Finite-choice (Σ-ap-snd t ∙e Σ-ap-fst aeq.inverse e⁻¹ ∙e Finite-sum bc)
pure
= fin (inc (Finite-zero-is-initial e⁻¹))
Finite-⊥ = fin (inc (is-contr→≃⊤ Finite-one-is-contr e⁻¹))
Finite-⊤
: Bool ≃ Fin 2
Bool≃Fin2 = Iso→Equiv enum where
Bool≃Fin2 : Iso Bool (Fin 2)
enum .fst false = 0
enum .fst true = 1
enum .snd .is-iso.inv fzero = false
enum .snd .is-iso.inv (fsuc fzero) = true
enum .snd .is-iso.rinv fzero = refl
enum .snd .is-iso.rinv (fsuc fzero) = refl
enum .snd .is-iso.linv true = refl
enum .snd .is-iso.linv false = refl
enum
= fin (inc Bool≃Fin2)
Finite-Bool
= subst Finite (sym (PathP≡Path _ _ _)) (Discrete→Finite≡ Finite→Discrete)
Finite-PathP
= Finite-≃ (Lift-≃ e⁻¹) Finite-Lift
abstract instance
: ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} {f g : A → B} ⦃ _ : Finite A ⦄ ⦃ _ : Finite B ⦄ → Finite (Coeq f g) Finite-Coeq
{A = A} {B} {f} {g} ⦃ fin ae ⦄ ⦃ fin be ⦄ = ∥-∥-out! do
Finite-Coeq
ae ← ae
be ← belet
= Equiv.to be ∘ f ∘ Equiv.from ae
f' = Equiv.to be ∘ g ∘ Equiv.from ae
g'
: Σ[ n ∈ Nat ] Fin n ≃ Coeq f' g'
fn = Finite-coequaliser f' g'
fn
(fin {cardinality = fn .fst} (inc (Coeq-ap ae be refl refl ∙e Equiv.inverse (fn .snd)))) pure
: ∥ A ≃ Fin 0 ∥ → ¬ A
card-zero→empty = rec! (λ e → fin-absurd (Equiv.to e a)) ∥e∥ card-zero→empty ∥e∥ a