diff --git a/src/1Lab/Classical.lagda.md b/src/1Lab/Classical.lagda.md
index 8e457f380..6407b053e 100644
--- a/src/1Lab/Classical.lagda.md
+++ b/src/1Lab/Classical.lagda.md
@@ -122,7 +122,7 @@ Surjections-split =
∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} → is-set A → is-set B
→ (f : A → B)
→ is-surjective f
- → ∥ (∀ b → fibre f b) ∥
+ → is-split-surjective f
```
We show that these two statements are logically equivalent^[they are also
diff --git a/src/1Lab/Equiv.lagda.md b/src/1Lab/Equiv.lagda.md
index d71e53c1b..63d8d2919 100644
--- a/src/1Lab/Equiv.lagda.md
+++ b/src/1Lab/Equiv.lagda.md
@@ -71,8 +71,9 @@ Here in the 1Lab, we formalise three acceptable notions of equivalence:
@@ -1087,6 +1088,58 @@ infix 3 _≃∎
infix 21 _≃_
syntax ≃⟨⟩-syntax x q p = x ≃⟨ p ⟩ q
+```
+-->
+
+## Some useful equivalences
+
+We can extend `subst`{.Agda} to an equivalence between `Σ[ y ∈ A ] (y ≡ x × P y)`
+and `P x` for every `x : A` and `P : A → Type`. In informal mathematical practice,
+applying this equivalence is sometimes called "contracting $y$ away", alluding to
+the [[contractibility of singletons]].
+
+```agda
+subst≃
+ : (x : A) → (Σ[ y ∈ A ] (y ≡ x × P y)) ≃ P x
+subst≃ {A = A} {P = P} x = Iso→Equiv (to , iso from invr invl)
+ where
+ to : Σ[ y ∈ A ] (y ≡ x × P y) → P x
+ to (y , y=x , py) = subst P y=x py
+
+ from : P x → Σ[ y ∈ A ] (y ≡ x × P y)
+ from px = x , refl , px
+
+ invr : is-right-inverse from to
+ invr = transport-refl
+
+ invl : is-left-inverse from to
+ invl (y , y=x , py) i =
+ (y=x (~ i)) ,
+ (λ j → y=x (~ i ∨ j)) ,
+ transp (λ j → P (y=x (~ i ∧ j))) i py
+```
+
+
@@ -99,6 +104,19 @@ is-equiv→is-surjective : {f : A → B} → is-equiv f → is-surjective f
is-equiv→is-surjective eqv x = inc (eqv .is-eqv x .centre)
```
+Surjections also are closed under a weaker form of [[two-out-of-three]]:
+if $f \circ g$ is surjective, then $f$ must also be surjective.
+
+```agda
+is-surjective-cancelr
+ : {f : B → C} {g : A → B}
+ → is-surjective (f ∘ g)
+ → is-surjective f
+is-surjective-cancelr {g = g} fgs c = do
+ (fg*x , p) ← fgs c
+ pure (g fg*x , p)
+```
+
+
+## Surjectivity and images
+
+A map $f : A \to B$ is surjective if and only if the inclusion of the
+image of $f$ into $B$ is an [[equivalence]].
+
+```agda
+surjective-iff-image-equiv
+ : ∀ {f : A → B}
+ → is-surjective f ≃ is-equiv {A = image f} fst
+```
+
+First, note that the fibre of the inclusion of the image of $f$ at $b$
+is the [[propositional truncation]] of the fibre of $f$ at $b$, by
+construction. Asking for this inclusion to be an equivalence is the same as
+asking for those fibres to be [[contractible]], which thus amounts to
+asking for the fibres of $f$ to be [[merely]] inhabited, which is the
+definition of $f$ being surjective.
+
+```agda
+surjective-iff-image-equiv {A = A} {B = B} {f = f} =
+ Equiv.inverse $
+ is-equiv fst ≃⟨ is-equiv≃fibre-is-contr ⟩
+ (∀ b → is-contr (fibre fst b)) ≃⟨ Π-cod≃ (λ b → is-hlevel-ap 0 (Fibre-equiv _ _)) ⟩
+ (∀ b → is-contr (∃[ a ∈ A ] (f a ≡ b))) ≃⟨ Π-cod≃ (λ b → is-prop→is-contr-iff-inhabited (hlevel 1)) ⟩
+ (∀ b → ∃[ a ∈ A ] (f a ≡ b)) ≃⟨⟩
+ is-surjective f ≃∎
+```
+
+# Split surjective functions
+
+:::{.definition #surjective-splitting}
+A **surjective splitting** of a function $f : A \to B$ consists of a designated
+element of the fibre $f^*b$ for each $b : B$.
+:::
+
+```agda
+surjective-splitting : (A → B) → Type _
+surjective-splitting f = ∀ b → fibre f b
+```
+
+Note that unlike "being surjective", a surjective splitting of $f$ is a *structure*
+on $f$, not a property. This difference becomes particularly striking when we
+look at functions into [[contractible]] types: if $B$ is contractible,
+then the type of surjective splittings of a function $f : A \to B$ is equivalent to $A$.
+
+```agda
+private
+ split-surjective-is-structure
+ : (f : A → B)
+ → is-contr B
+ → surjective-splitting f ≃ A
+```
+
+First, recall that dependent functions $(a : A) \to B(a)$ out of a contractible type are
+equivalent to an element of $B$ at the centre of contraction, so $(b : B) \to f^*(b)$ is
+equivalent to an element of the fibre of $f$ at the centre of contraction of $B$. Moreover,
+the type of paths in $B$ is also contractible, so that fibre is equivalent to $A$.
+
+```agda
+ split-surjective-is-structure {A = A} f B-contr =
+ (∀ b → fibre f b) ≃⟨ Π-contr-eqv B-contr ⟩
+ fibre f (B-contr .centre) ≃⟨ Σ-contract (λ _ → Path-is-hlevel 0 B-contr) ⟩
+ A ≃∎
+```
+
+In light of this, we provide the following definition.
+
+:::{.definition #split-surjective}
+A function $f : A \to B$ is **split surjective** if there merely exists a
+surjective splitting of $f$.
+:::
+
+```agda
+is-split-surjective : (A → B) → Type _
+is-split-surjective f = ∥ surjective-splitting f ∥
+```
+
+Every split surjective map is surjective.
+
+```agda
+is-split-surjective→is-surjective : is-split-surjective f → is-surjective f
+is-split-surjective→is-surjective f-split-surj b = do
+ f-splitting ← f-split-surj
+ pure (f-splitting b)
+```
+
+Note that we do not have a converse to this constructively: the statement that
+every surjective function between [[sets]] splits is [[equivalent to the axiom of choice|axiom-of-choice]]!
+
+## Split surjective functions and sections
+
+The type of surjective splittings of a function $f : A \to B$ is equivalent
+to the type of sections of $f$, i.e. functions $s : B \to A$ with $f \circ s = \id$.
+
+```agda
+section≃surjective-splitting
+ : (f : A → B)
+ → (Σ[ s ∈ (B → A) ] is-right-inverse s f) ≃ surjective-splitting f
+```
+
+Somewhat surprisingly, this is an immediate consequence of the fact that
+sigma types distribute over pi types!
+
+```agda
+section≃surjective-splitting {A = A} {B = B} f =
+ (Σ[ s ∈ (B → A) ] ((x : B) → f (s x) ≡ x)) ≃˘⟨ Σ-Π-distrib ⟩
+ ((b : B) → Σ[ a ∈ A ] f a ≡ b) ≃⟨⟩
+ surjective-splitting f ≃∎
+```
+
+This means that a function $f$ is split surjective if and only if there
+[[merely]] exists some section of $f$.
+
+```agda
+exists-section-iff-split-surjective
+ : (f : A → B)
+ → (∃[ s ∈ (B → A) ] is-right-inverse s f) ≃ is-split-surjective f
+exists-section-iff-split-surjective f =
+ ∥-∥-ap (section≃surjective-splitting f)
+```
+
+## Closure properties of split surjective functions
+
+Like their non-split counterparts, split surjective functions are closed under composition.
+
+```agda
+∘-surjective-splitting
+ : surjective-splitting f
+ → surjective-splitting g
+ → surjective-splitting (f ∘ g)
+
+∘-is-split-surjective
+ : is-split-surjective f
+ → is-split-surjective g
+ → is-split-surjective (f ∘ g)
+```
+
+
+ The proof is essentially identical to the non-split case.
+
+
+```agda
+∘-surjective-splitting {f = f} f-split g-split c =
+ let (f*c , p) = f-split c
+ (g*f*c , q) = g-split f*c
+ in g*f*c , ap f q ∙ p
+
+∘-is-split-surjective fs gs = ⦇ ∘-surjective-splitting fs gs ⦈
+```
+
+
+Every equivalence can be equipped with a surjective splitting, and
+is thus split surjective.
+
+```agda
+is-equiv→surjective-splitting
+ : is-equiv f
+ → surjective-splitting f
+
+is-equiv→is-split-surjective
+ : is-equiv f
+ → is-split-surjective f
+```
+
+This follows immediately from the definition of equivalences: if the
+type of fibres is contractible, then we can pluck the element we need
+out of the centre of contraction!
+
+```agda
+is-equiv→surjective-splitting f-equiv b =
+ f-equiv .is-eqv b .centre
+
+is-equiv→is-split-surjective f-equiv =
+ pure (is-equiv→surjective-splitting f-equiv)
+```
+
+Split surjective functions also satisfy left two-out-of-three.
+
+```agda
+surjective-splitting-cancelr
+ : surjective-splitting (f ∘ g)
+ → surjective-splitting f
+
+is-split-surjective-cancelr
+ : is-split-surjective (f ∘ g)
+ → is-split-surjective f
+```
+
+
+These proofs are also essentially identical to the non-split versions.
+
+
+```agda
+surjective-splitting-cancelr {g = g} fg-split c =
+ let (fg*c , p) = fg-split c
+ in g fg*c , p
+
+is-split-surjective-cancelr fg-split =
+ map surjective-splitting-cancelr fg-split
+```
+
+
+A function is an equivalence if and only if it is a split-surjective
+[[embedding]].
+
+```agda
+embedding-split-surjective≃is-equiv
+ : {f : A → B}
+ → (is-embedding f × is-split-surjective f) ≃ is-equiv f
+embedding-split-surjective≃is-equiv {f = f} =
+ prop-ext!
+ (λ (f-emb , f-split-surj) →
+ embedding-surjective→is-equiv
+ f-emb
+ (is-split-surjective→is-surjective f-split-surj))
+ (λ f-equiv → is-equiv→is-embedding f-equiv , is-equiv→is-split-surjective f-equiv)
+```
+
+# Surjectivity and connectedness
+
+If $f : A \to B$ is a function out of a [[contractible]] type $A$,
+then $f$ is surjective if and only if $B$ is a [[pointed connected type]], where
+the basepoint of $B$ is given by $f$ applied to the centre of contraction of $A$.
+
+```agda
+contr-dom-surjective-iff-connected-cod
+ : ∀ {f : A → B}
+ → (A-contr : is-contr A)
+ → is-surjective f ≃ ((x : B) → ∥ x ≡ f (A-contr .centre) ∥)
+```
+
+To see this, note that the fibre of $f$ over $x$ is equivalent
+to the type of paths $x = f(a_{\bullet})$, where $a_{\bullet}$ is the centre
+of contraction of $A$.
+
+```agda
+contr-dom-surjective-iff-connected-cod {A = A} {B = B} {f = f} A-contr =
+ Π-cod≃ (λ b → ∥-∥-ap (Σ-contr-eqv A-contr ∙e sym-equiv))
+```
+
+This correspondence is not a coincidence: surjective maps fit into
+a larger family of maps known as [[connected maps]]. In particular,
+a map is surjective exactly when it is (-1)-connected, and this lemma is
+a special case of `is-n-connected-point`{.Agda}.
diff --git a/src/1Lab/HIT/Truncation.lagda.md b/src/1Lab/HIT/Truncation.lagda.md
index 53962a1b7..8c5c1bdca 100644
--- a/src/1Lab/HIT/Truncation.lagda.md
+++ b/src/1Lab/HIT/Truncation.lagda.md
@@ -12,6 +12,7 @@ open import 1Lab.HLevel.Closure
open import 1Lab.Path.Reasoning
open import 1Lab.Type.Sigma
open import 1Lab.Inductive
+open import 1Lab.Type.Pi
open import 1Lab.HLevel
open import 1Lab.Equiv
open import 1Lab.Path
@@ -154,6 +155,13 @@ truncation extends to a functor:
∥-∥-map f (squash x y i) = squash (∥-∥-map f x) (∥-∥-map f y) i
```
+This means that propositional truncation preserves equivalences.
+
+```agda
+∥-∥-ap : ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} → A ≃ B → ∥ A ∥ ≃ ∥ B ∥
+∥-∥-ap f = prop-ext! (∥-∥-map (Equiv.to f)) (∥-∥-map (Equiv.from f))
+```
+
+
## Functions into n-types
We can now prove that the $n$-types are closed under all type formers
diff --git a/src/1Lab/Type/Sigma.lagda.md b/src/1Lab/Type/Sigma.lagda.md
index 85f77911a..f1ef51d9c 100644
--- a/src/1Lab/Type/Sigma.lagda.md
+++ b/src/1Lab/Type/Sigma.lagda.md
@@ -17,6 +17,7 @@ private variable
ℓ ℓ₁ : Level
A A' X X' Y Y' Z Z' : Type ℓ
B P Q : A → Type ℓ
+ C : (x : A) → B x → Type ℓ
```
-->
@@ -25,6 +26,26 @@ private variable
This module contains properties of $\Sigma$ types, not necessarily
organised in any way.
+## Universal property
+
+If we have a pair of maps $f : (x : A) \to B(x)$ and $g : (x : A) \to C(x, f(x))$,
+then there exists a unique universal map $\langle f , g \rangle : (x : A) \to \Sigma (B x) (C x)$
+that commutes with the projections. This is essentially a dependently
+typed version of the universal property of [[products]].
+
+```agda
+⟨_,_⟩ : (f : (x : A) → B x) → (g : (x : A) → C x (f x)) → (x : A) → Σ (B x) (C x)
+⟨ f , g ⟩ x = f x , g x
+
+⟨⟩-unique
+ : ∀ {f : (x : A) → B x} {g : (x : A) → C x (f x)}
+ → (h : (x : A) → Σ (B x) (C x))
+ → (p : fst ∘ h ≡ f)
+ → PathP (λ i → (x : A) → C x (p i x)) (snd ∘ h) g
+ → h ≡ ⟨ f , g ⟩
+⟨⟩-unique h p q i x = p i x , q i x
+```
+
## Groupoid structure
The first thing we prove is that _paths in sigmas are sigmas of paths_.
@@ -121,19 +142,15 @@ they are included for completeness.
Σ-assoc : ∀ {ℓ ℓ' ℓ''} {A : Type ℓ} {B : A → Type ℓ'} {C : (x : A) → B x → Type ℓ''}
→ (Σ[ x ∈ A ] Σ[ y ∈ B x ] C x y) ≃ (Σ[ x ∈ Σ _ B ] (C (x .fst) (x .snd)))
Σ-assoc .fst (x , y , z) = (x , y) , z
-Σ-assoc .snd = is-iso→is-equiv λ where
- .is-iso.from ((x , y) , z) → x , y , z
- .is-iso.linv p → refl
- .is-iso.rinv p → refl
+Σ-assoc .snd .is-eqv ((x , y), z) = contr (fib .fst) (fib .snd)
+ where fib = strict-fibres _ ((x , y) , z)
Σ-Π-distrib : ∀ {ℓ ℓ' ℓ''} {A : Type ℓ} {B : A → Type ℓ'} {C : (x : A) → B x → Type ℓ''}
→ ((x : A) → Σ[ y ∈ B x ] C x y)
≃ (Σ[ f ∈ ((x : A) → B x) ] ((x : A) → C x (f x)))
-Σ-Π-distrib .fst f = (λ x → f x .fst) , λ x → f x .snd
-Σ-Π-distrib .snd = is-iso→is-equiv λ where
- .is-iso.from (f , r) x → f x , r x
- .is-iso.linv p → refl
- .is-iso.rinv p → refl
+Σ-Π-distrib .fst f = (fst ∘ f) , (snd ∘ f)
+Σ-Π-distrib .snd .is-eqv (f , r) = contr (fib .fst) (fib .snd)
+ where fib = strict-fibres (λ h → ⟨ h .fst , h .snd ⟩) (f , r)
```
@@ -252,9 +269,6 @@ If `B` is a family of contractible types, then `Σ B ≃ A`:
Σ-map₂ : ({x : A} → P x → Q x) → Σ _ P → Σ _ Q
Σ-map₂ f (x , y) = (x , f y)
-⟨_,_⟩ : (X → Y) → (X → Z) → X → Y × Z
-⟨ f , g ⟩ x = f x , g x
-
×-map : (A → A') → (X → X') → A × X → A' × X'
×-map f g (x , y) = (f x , g y)
diff --git a/src/Cat/Prelude.agda b/src/Cat/Prelude.agda
index 3312ed96d..14b868d32 100644
--- a/src/Cat/Prelude.agda
+++ b/src/Cat/Prelude.agda
@@ -12,7 +12,7 @@ open import 1Lab.Prelude
; _∘⟨_ to _⊙⟨_
; _⟩∘_ to _⟩⊙_
)
- hiding (id ; map ; _↠_ ; ⟨_,_⟩)
+ hiding (id ; map ; _↠_ ; ⟨_,_⟩; ⟨⟩-unique)
public
open import Data.Set.Truncation public
diff --git a/src/Data/Fin/Properties.lagda.md b/src/Data/Fin/Properties.lagda.md
index 17d90ba35..213f4d1b4 100644
--- a/src/Data/Fin/Properties.lagda.md
+++ b/src/Data/Fin/Properties.lagda.md
@@ -262,8 +262,9 @@ _between_ finite sets) [[merely]] split:
```agda
finite-surjection-split
: ∀ {ℓ} {n} {B : Type ℓ}
- → (f : B → Fin n) → is-surjective f
- → ∥ (∀ x → fibre f x) ∥
+ → (f : B → Fin n)
+ → is-surjective f
+ → is-split-surjective f
finite-surjection-split f = finite-choice _
```
diff --git a/src/Data/Set/Projective.lagda.md b/src/Data/Set/Projective.lagda.md
index 73131df22..b36828daf 100644
--- a/src/Data/Set/Projective.lagda.md
+++ b/src/Data/Set/Projective.lagda.md
@@ -4,7 +4,6 @@ description: |
---
+
```agda
+set-surjections-split : (A : Type ℓ) → (κ : Level) → Type _
+set-surjections-split {ℓ = ℓ} A κ =
+ ∀ (E : Type κ)
+ → is-set E
+ → (f : E → A)
+ → is-surjective f
+ → is-split-surjective f
+
surjections-split→set-projective
- : ∀ {ℓ ℓ'} {A : Type ℓ}
+ : ∀ {ℓ κ} {A : Type ℓ}
→ is-set A
- → (∀ (E : Type (ℓ ⊔ ℓ')) → is-set E
- → (f : E → A) → is-surjective f
- → ∥ (∀ a → fibre f a) ∥)
- → is-set-projective A (ℓ ⊔ ℓ')
+ → set-surjections-split A (ℓ ⊔ κ)
+ → is-set-projective A (ℓ ⊔ κ)
sets-projective→surjections-split
- : ∀ {ℓ ℓ'} {A : Type ℓ}
+ : ∀ {ℓ κ} {A : Type ℓ}
→ is-set A
- → is-set-projective A (ℓ ⊔ ℓ')
- → ∀ {E : Type ℓ'} → is-set E
- → (f : E → A) → is-surjective f
- → ∥ (∀ a → fibre f a) ∥
+ → is-set-projective A (ℓ ⊔ κ)
+ → set-surjections-split A (ℓ ⊔ κ)
```
@@ -76,7 +84,7 @@ surjections-split→set-projective {A = A} A-set surj-split P P-set ∥P∥ =
(surj-split (Σ[ x ∈ A ] (P x)) (Σ-is-hlevel 2 A-set P-set) fst λ x →
∥-∥-map (Equiv.from (Fibre-equiv P x)) (∥P∥ x))
-sets-projective→surjections-split A-set A-pro E-set f =
+sets-projective→surjections-split A-set A-pro E E-set f =
A-pro (fibre f) (λ x → fibre-is-hlevel 2 E-set A-set f x)
```
diff --git a/src/Homotopy/Connectedness.lagda.md b/src/Homotopy/Connectedness.lagda.md
index 4adef5ea8..9fa711ffd 100644
--- a/src/Homotopy/Connectedness.lagda.md
+++ b/src/Homotopy/Connectedness.lagda.md
@@ -77,7 +77,7 @@ is-n-connected-map f n = ∀ x → is-n-connected (fibre f x) n
```
:::
-## Pointed connected types
+## Pointed connected types {defines="pointed-connected-type"}
In the case of [[pointed types]], there is an equivalent definition of
being connected that is sometimes easier to work with: a pointed type is