Skip to content

Commit 4ed0bfe

Browse files
authored
Split Surjectivity (#499)
# Description Pulling some of my changes out of #375 in hopes of getting back to it at some point. This PR defines split surjectivity, and also proves some misc. lemmas about surjective maps. I've done some minor cleanup in some of the base modules, and added some (hopefully useful!) equivalences. ## Checklist Before submitting a merge request, please check the items below: - [x] I've read [the contributing guidelines](https://github.com/plt-amy/1lab/blob/main/CONTRIBUTING.md). - [x] The imports of new modules have been sorted with `support/sort-imports.hs` (or `nix run --experimental-features nix-command -f . sort-imports`). - [x] All new code blocks have "agda" as their language. If your change affects many files without adding substantial content, and you don't want your name to appear on those pages (for example, treewide refactorings or reformattings), start the commit message and PR title with `chore:`.
1 parent bbc87ba commit 4ed0bfe

File tree

10 files changed

+373
-33
lines changed

10 files changed

+373
-33
lines changed

src/1Lab/Classical.lagda.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ Surjections-split =
122122
∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} → is-set A → is-set B
123123
→ (f : A → B)
124124
→ is-surjective f
125-
∥ (∀ b → fibre f b) ∥
125+
is-split-surjective f
126126
```
127127

128128
We show that these two statements are logically equivalent^[they are also

src/1Lab/Equiv.lagda.md

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,9 @@ Here in the 1Lab, we formalise three acceptable notions of equivalence:
7171
<!--
7272
```agda
7373
private variable
74-
ℓ₁ ℓ₂ : Level
75-
A A' B B' C : Type ℓ₁
74+
ℓ ℓ₁ ℓ₂ : Level
75+
A A' B B' C : Type ℓ
76+
P : A → Type ℓ
7677
```
7778
-->
7879

@@ -1094,6 +1095,58 @@ infix 3 _≃∎
10941095
infix 21 _≃_
10951096
10961097
syntax ≃⟨⟩-syntax x q p = x ≃⟨ p ⟩ q
1098+
```
1099+
-->
1100+
1101+
## Some useful equivalences
1102+
1103+
We can extend `subst`{.Agda} to an equivalence between `Σ[ y ∈ A ] (y ≡ x × P y)`
1104+
and `P x` for every `x : A` and `P : A → Type`. In informal mathematical practice,
1105+
applying this equivalence is sometimes called "contracting $y$ away", alluding to
1106+
the [[contractibility of singletons]].
1107+
1108+
```agda
1109+
subst≃
1110+
: (x : A) → (Σ[ y ∈ A ] (y ≡ x × P y)) ≃ P x
1111+
subst≃ {A = A} {P = P} x = Iso→Equiv (to , iso from invr invl)
1112+
where
1113+
to : Σ[ y ∈ A ] (y ≡ x × P y) → P x
1114+
to (y , y=x , py) = subst P y=x py
1115+
1116+
from : P x → Σ[ y ∈ A ] (y ≡ x × P y)
1117+
from px = x , refl , px
1118+
1119+
invr : is-right-inverse from to
1120+
invr = transport-refl
1121+
1122+
invl : is-left-inverse from to
1123+
invl (y , y=x , py) i =
1124+
(y=x (~ i)) ,
1125+
(λ j → y=x (~ i ∨ j)) ,
1126+
transp (λ j → P (y=x (~ i ∧ j))) i py
1127+
```
1128+
1129+
<!--
1130+
```agda
1131+
is-equiv≃fibre-is-contr
1132+
: ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'}
1133+
→ {f : A → B}
1134+
→ is-equiv f ≃ (∀ x → is-contr (fibre f x))
1135+
is-equiv≃fibre-is-contr {f = f} =
1136+
prop-ext
1137+
(is-equiv-is-prop f)
1138+
(λ f g i x → is-contr-is-prop (f x) (g x) i)
1139+
is-eqv
1140+
(λ fib-contr → record { is-eqv = fib-contr })
1141+
1142+
-- This ideally would go in 1Lab.HLevel, but we don't have equivalences
1143+
-- defined that early in the bootrapping process.
1144+
is-prop→is-contr-iff-inhabited
1145+
: ∀ {ℓ} {A : Type ℓ}
1146+
→ is-prop A
1147+
→ is-contr A ≃ A
1148+
is-prop→is-contr-iff-inhabited A-prop =
1149+
prop-ext is-contr-is-prop A-prop centre (is-prop∙→is-contr A-prop)
10971150
10981151
lift-inj
10991152
: ∀ {ℓ ℓ'} {A : Type ℓ} {a b : A}

src/1Lab/Function/Surjection.lagda.md

Lines changed: 257 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ open import 1Lab.Function.Embedding
44
open import 1Lab.Reflection.HLevel
55
open import 1Lab.HLevel.Closure
66
open import 1Lab.Truncation
7+
open import 1Lab.Type.Sigma
8+
open import 1Lab.Univalence
79
open import 1Lab.Inductive
10+
open import 1Lab.Type.Pi
811
open import 1Lab.HLevel
912
open import 1Lab.Equiv
1013
open import 1Lab.Path
@@ -22,8 +25,10 @@ module 1Lab.Function.Surjection where
2225
<!--
2326
```agda
2427
private variable
25-
ℓ ℓ' : Level
28+
ℓ ℓ' ℓ'' : Level
2629
A B C : Type ℓ
30+
P Q : A → Type ℓ'
31+
f g : A → B
2732
```
2833
-->
2934

@@ -95,6 +100,19 @@ is-equiv→is-surjective : {f : A → B} → is-equiv f → is-surjective f
95100
is-equiv→is-surjective eqv x = inc (eqv .is-eqv x .centre)
96101
```
97102
103+
Surjections also are closed under a weaker form of [[two-out-of-three]]:
104+
if $f \circ g$ is surjective, then $f$ must also be surjective.
105+
106+
```agda
107+
is-surjective-cancelr
108+
: {f : B → C} {g : A → B}
109+
→ is-surjective (f ∘ g)
110+
→ is-surjective f
111+
is-surjective-cancelr {g = g} fgs c = do
112+
(fg*x , p) ← fgs c
113+
pure (g fg*x , p)
114+
```
115+
98116
<!--
99117
```agda
100118
Equiv→Cover : A ≃ B → A ↠ B
@@ -140,3 +158,241 @@ injective-surjective→is-equiv! =
140158
injective-surjective→is-equiv (hlevel 2)
141159
```
142160
-->
161+
162+
## Surjectivity and images
163+
164+
A map $f : A \to B$ is surjective if and only if the inclusion of the
165+
image of $f$ into $B$ is an [[equivalence]].
166+
167+
```agda
168+
surjective-iff-image-equiv
169+
: ∀ {f : A → B}
170+
→ is-surjective f ≃ is-equiv {A = image f} fst
171+
```
172+
173+
First, note that the fibre of the inclusion of the image of $f$ at $b$
174+
is the [[propositional truncation]] of the fibre of $f$ at $b$, by
175+
construction. Asking for this inclusion to be an equivalence is the same as
176+
asking for those fibres to be [[contractible]], which thus amounts to
177+
asking for the fibres of $f$ to be [[merely]] inhabited, which is the
178+
definition of $f$ being surjective.
179+
180+
```agda
181+
surjective-iff-image-equiv {A = A} {B = B} {f = f} =
182+
Equiv.inverse $
183+
is-equiv fst ≃⟨ is-equiv≃fibre-is-contr ⟩
184+
(∀ b → is-contr (fibre fst b)) ≃⟨ Π-ap-cod (λ b → is-hlevel-ap 0 (Fibre-equiv _ _)) ⟩
185+
(∀ b → is-contr (∃[ a ∈ A ] (f a ≡ b))) ≃⟨ Π-ap-cod (λ b → is-prop→is-contr-iff-inhabited (hlevel 1)) ⟩
186+
(∀ b → ∃[ a ∈ A ] (f a ≡ b)) ≃⟨⟩
187+
is-surjective f ≃∎
188+
```
189+
190+
# Split surjective functions
191+
192+
:::{.definition #surjective-splitting}
193+
A **surjective splitting** of a function $f : A \to B$ consists of a designated
194+
element of the fibre $f^*b$ for each $b : B$.
195+
:::
196+
197+
```agda
198+
surjective-splitting : (A → B) → Type _
199+
surjective-splitting f = ∀ b → fibre f b
200+
```
201+
202+
Note that unlike "being surjective", a surjective splitting of $f$ is a *structure*
203+
on $f$, not a property. This difference becomes particularly striking when we
204+
look at functions into [[contractible]] types: if $B$ is contractible,
205+
then the type of surjective splittings of a function $f : A \to B$ is equivalent to $A$.
206+
207+
```agda
208+
private
209+
split-surjective-is-structure
210+
: (f : A → B)
211+
→ is-contr B
212+
→ surjective-splitting f ≃ A
213+
```
214+
215+
First, recall that dependent functions $(a : A) \to B(a)$ out of a contractible type are
216+
equivalent to an element of $B$ at the centre of contraction, so $(b : B) \to f^*(b)$ is
217+
equivalent to an element of the fibre of $f$ at the centre of contraction of $B$. Moreover,
218+
the type of paths in $B$ is also contractible, so that fibre is equivalent to $A$.
219+
220+
```agda
221+
split-surjective-is-structure {A = A} f B-contr =
222+
(∀ b → fibre f b) ≃⟨ Π-contr-eqv B-contr ⟩
223+
fibre f (B-contr .centre) ≃⟨ Σ-contr-snd (λ _ → Path-is-hlevel 0 B-contr) ⟩
224+
A ≃∎
225+
```
226+
227+
In light of this, we provide the following definition.
228+
229+
:::{.definition #split-surjective}
230+
A function $f : A \to B$ is **split surjective** if there merely exists a
231+
surjective splitting of $f$.
232+
:::
233+
234+
```agda
235+
is-split-surjective : (A → B) → Type _
236+
is-split-surjective f = ∥ surjective-splitting f ∥
237+
```
238+
239+
Every split surjective map is surjective.
240+
241+
```agda
242+
is-split-surjective→is-surjective : is-split-surjective f → is-surjective f
243+
is-split-surjective→is-surjective f-split-surj b = do
244+
f-splitting ← f-split-surj
245+
pure (f-splitting b)
246+
```
247+
248+
Note that we do not have a converse to this constructively: the statement that
249+
every surjective function between [[sets]] splits is [[equivalent to the axiom of choice|axiom-of-choice]]!
250+
251+
## Split surjective functions and sections
252+
253+
The type of surjective splittings of a function $f : A \to B$ is equivalent
254+
to the type of sections of $f$, i.e. functions $s : B \to A$ with $f \circ s = \id$.
255+
256+
```agda
257+
section≃surjective-splitting
258+
: (f : A → B)
259+
→ (Σ[ s ∈ (B → A) ] is-right-inverse s f) ≃ surjective-splitting f
260+
```
261+
262+
Somewhat surprisingly, this is an immediate consequence of the fact that
263+
sigma types distribute over pi types!
264+
265+
```agda
266+
section≃surjective-splitting {A = A} {B = B} f =
267+
(Σ[ s ∈ (B → A) ] ((x : B) → f (s x) ≡ x)) ≃˘⟨ Σ-Π-distrib ⟩
268+
((b : B) → Σ[ a ∈ A ] f a ≡ b) ≃⟨⟩
269+
surjective-splitting f ≃∎
270+
```
271+
272+
This means that a function $f$ is split surjective if and only if there
273+
[[merely]] exists some section of $f$.
274+
275+
```agda
276+
exists-section-iff-split-surjective
277+
: (f : A → B)
278+
→ (∃[ s ∈ (B → A) ] is-right-inverse s f) ≃ is-split-surjective f
279+
exists-section-iff-split-surjective f =
280+
∥-∥-ap (section≃surjective-splitting f)
281+
```
282+
283+
## Closure properties of split surjective functions
284+
285+
Like their non-split counterparts, split surjective functions are closed under composition.
286+
287+
```agda
288+
∘-surjective-splitting : ∘-closed surjective-splitting
289+
∘-is-split-surjective : ∘-closed is-split-surjective
290+
```
291+
292+
<details>
293+
<summary> The proof is essentially identical to the non-split case.
294+
</summary>
295+
296+
```agda
297+
∘-surjective-splitting {f = f} f-split g-split c =
298+
let (f*c , p) = f-split c
299+
(g*f*c , q) = g-split f*c
300+
in g*f*c , ap f q ∙ p
301+
302+
∘-is-split-surjective fs gs = ⦇ ∘-surjective-splitting fs gs ⦈
303+
```
304+
</details>
305+
306+
Every equivalence can be equipped with a surjective splitting, and
307+
is thus split surjective.
308+
309+
```agda
310+
is-equiv→surjective-splitting
311+
: is-equiv f
312+
→ surjective-splitting f
313+
314+
is-equiv→is-split-surjective
315+
: is-equiv f
316+
→ is-split-surjective f
317+
```
318+
319+
This follows immediately from the definition of equivalences: if the
320+
type of fibres is contractible, then we can pluck the element we need
321+
out of the centre of contraction!
322+
323+
```agda
324+
is-equiv→surjective-splitting f-equiv b =
325+
f-equiv .is-eqv b .centre
326+
327+
is-equiv→is-split-surjective f-equiv =
328+
pure (is-equiv→surjective-splitting f-equiv)
329+
```
330+
331+
Split surjective functions also satisfy left two-out-of-three.
332+
333+
```agda
334+
surjective-splitting-cancelr
335+
: surjective-splitting (f ∘ g)
336+
→ surjective-splitting f
337+
338+
is-split-surjective-cancelr
339+
: is-split-surjective (f ∘ g)
340+
→ is-split-surjective f
341+
```
342+
343+
<details>
344+
<summary>These proofs are also essentially identical to the non-split versions.
345+
</summary>
346+
347+
```agda
348+
surjective-splitting-cancelr {g = g} fg-split c =
349+
let (fg*c , p) = fg-split c
350+
in g fg*c , p
351+
352+
is-split-surjective-cancelr fg-split =
353+
map surjective-splitting-cancelr fg-split
354+
```
355+
</details>
356+
357+
A function is an equivalence if and only if it is a split-surjective
358+
[[embedding]].
359+
360+
```agda
361+
embedding-split-surjective≃is-equiv
362+
: {f : A → B}
363+
→ (is-embedding f × is-split-surjective f) ≃ is-equiv f
364+
embedding-split-surjective≃is-equiv {f = f} =
365+
prop-ext!
366+
(λ (f-emb , f-split-surj) →
367+
embedding-surjective→is-equiv
368+
f-emb
369+
(is-split-surjective→is-surjective f-split-surj))
370+
(λ f-equiv → is-equiv→is-embedding f-equiv , is-equiv→is-split-surjective f-equiv)
371+
```
372+
373+
# Surjectivity and connectedness
374+
375+
If $f : A \to B$ is a function out of a [[contractible]] type $A$,
376+
then $f$ is surjective if and only if $B$ is a [[pointed connected type]], where
377+
the basepoint of $B$ is given by $f$ applied to the centre of contraction of $A$.
378+
379+
```agda
380+
contr-dom-surjective-iff-connected-cod
381+
: ∀ {f : A → B}
382+
→ (A-contr : is-contr A)
383+
→ is-surjective f ≃ ((x : B) → ∥ x ≡ f (A-contr .centre) ∥)
384+
```
385+
386+
To see this, note that the fibre of $f$ over $x$ is equivalent
387+
to the type of paths $x = f(a_{\bullet})$, where $a_{\bullet}$ is the centre
388+
of contraction of $A$.
389+
390+
```agda
391+
contr-dom-surjective-iff-connected-cod {A = A} {B = B} {f = f} A-contr =
392+
Π-ap-cod (λ b → ∥-∥-ap (Σ-contr-fst A-contr ∙e sym-equiv))
393+
```
394+
395+
This correspondence is not a coincidence: surjective maps fit into
396+
a larger family of maps known as [[connected maps]]. In particular,
397+
a map is surjective exactly when it is (-1)-connected, and this lemma is
398+
a special case of `is-n-connected-point`{.Agda}.

src/1Lab/HLevel.lagda.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,13 @@ SinglP-is-contr A a .paths (x , p) i = _ , λ j → fill A (∂ i) j λ where
730730
SinglP-is-prop : ∀ {ℓ} {A : I → Type ℓ} {a : A i0} → is-prop (SingletonP A a)
731731
SinglP-is-prop = is-contr→is-prop (SinglP-is-contr _ _)
732732
733+
Single-is-contr : ∀ {x : A} → is-contr (Singleton x)
734+
Single-is-contr {x = x} .centre = x , refl
735+
Single-is-contr {x = x} .paths (y , p) i = p i , λ j → p (i ∧ j)
736+
737+
Single-is-contr' : ∀ {x : A} → is-contr (Σ[ y ∈ A ] y ≡ x)
738+
Single-is-contr' {x = x} .centre = x , refl
739+
Single-is-contr' {x = x} .paths (y , p) i = p (~ i) , λ j → p (~ i ∨ j)
733740
734741
is-prop→squarep
735742
: ∀ {B : I → I → Type ℓ} → ((i j : I) → is-prop (B i j))

src/1Lab/Truncation.lagda.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ open import 1Lab.HLevel.Closure
1212
open import 1Lab.Path.Reasoning
1313
open import 1Lab.Type.Sigma
1414
open import 1Lab.Inductive
15+
open import 1Lab.Type.Pi
1516
open import 1Lab.HLevel
1617
open import 1Lab.Equiv
1718
open import 1Lab.Path

0 commit comments

Comments
 (0)