/
Image.lagda.md
304 lines (245 loc) · 11.4 KB
/
Image.lagda.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
<!--
```agda
open import 1Lab.Prelude
open import Data.Id.Base
open import Data.Bool
```
-->
```agda
module Data.Image where
```
# Images and replacement
The [image] of a function $f : A \to B$ is the subtype of $B$ where points
are [[merely]] equipped with a fibre of $f$. This has the expected
universal property: we can factor any $f$ into
$$
A \epi \im(f) \mono B
$$,
and $\im(f) \mono B$ is universal among factorisations of $f$ through a
subtype of its codomain.
[image]: 1Lab.HIT.Truncation.html#maps-into-sets
In general, we can consider images of arbitrary functions $f : A \to B$,
where $A$ is a $\ell_1$-small type, and $B$ is a $\ell_2$-small type;
This results in a type $\im f$, which, according to the rules for
assigning universe levels, lives in the $(\ell_1 \sqcup \ell_2)$th
universe. While the rules are that way for good reasons, in this case,
they defy intuition: the type $\im f$, in a sense, is "at most the size
of $A$".
Can we do better? It turns out that we can! This generally goes by the
name of **type-theoretic replacement**, after Rijke [@Rijke:2017 §5]; in
turn, the name _replacement_ comes from the axiom of material set theory
saying the image of a set under a function is again set.^[Keep in mind
that material set theory says "is a set" in a very different way than we
do; They mean it about size.] Here we implement a slight generalization
of [Evan Cavallo's construction] in terms of higher induction-recursion.
[Evan Cavallo's construction]: https://github.com/agda/cubical/pull/972
We understand this construction as generalising the [first isomorphism
theorem] from the setting of algebraic structures^[A class which
includes $\Sets$, as models of the trivial theory] to the setting of
general types. Recall that the first isomorphism theorem says you can
compute $\im f$ as the quotient $A/\ker f$.[^ker]
[first isomorphism theorem]: Algebra.Group.Subgroup.html#the-first-isomorphism-theorem
[^ker]: The meaning of kernel we're using generalises slightly that of
groups, where a normal subgroup completely determines an equivalence
relation. Instead, we mean the _kernel pair_, the pullback of a morphism
along itself.
If we're working with sets, that's the end of it: We can define a
relation $x \sim y$ by $f(x) \sim f(y)$, which [can be made to] live in
the zeroth universe, so $A/\ker f$ lives in the same universe as $A$.
That's because, when working with sets, there are no coherence problems
to get stuck on: we can first define $A/\ker f$ as a higher inductive
type, then, separately, define the embedding $A/\ker f \mono B$.
[can be made to]: 1Lab.Resizing.html
However, in the case of general types, we would like the h-level of $\im
f$ to match that of $B$, so we certainly can't set-truncate.
Anyway, The next immediate attempt might be a type which looks like
<!--
```agda
private module Attempts where
```
-->
```agda
data Im1 {ℓa ℓb} {A : Type ℓa} {B : Type ℓb} (f : A → B)
: Type (ℓa ⊔ ℓb) where
inc : A → Im1 f
quot : ∀ x y → f x ≡ f y → inc x ≡ inc y
```
But this type isn't particularly well-behaved. For example, the
`Im1`{.Agda}-image of the identity map on the unit type is the circle.
This can be established by writing equivalences back and forth, but in
the interest of brevity (and our dependency graph), we show it has a
non-trivial path.
```agda
Cover : Im1 {A = ⊤} {⊤} (λ { tt → tt }) → Type
Cover (inc x) = Bool
Cover (quot tt tt _ i) = ua (not , not-is-equiv) i
Im1-nontriv : subst Cover (quot tt tt refl) true ≡ false
Im1-nontriv = refl
```
It's fairly common that defining higher inductive types like this will,
sometimes, introduce more paths than you might expect. For an analogy,
if we were interested in computing _propositional truncations_ instead,
our type `Im1`{.Agda} above would correspond to this "one-step
truncation":
```agda
data Tr1 {ℓa} (A : Type ℓa) : Type ℓa where
inc : A → Tr1 A
quot : (x y : A) → inc x ≡ inc y
```
And, investigating the case of truncations, we might come up with a
couple different fixes. One is to define a process that could be
_iterated_: each step adds new paths, and at the limit --- the
_sequential co_-limit --- we have our original type. This can be made to
work for the propositional truncation, and [@Rijke:2017]'s construction
of the image is similar in spirit.
But if we have _recursive_ higher inductive types, where the type being
defined can appear in the _arguments_ to its own path constructors, we
can sometimes do these constructions in a single big, recursive step.
That's the usual [[propositional truncation]]. A guiding, heuristic
principle would be to avoid "green slime": do not mention the
constructors of the type in the _endpoints_ of the path constructor.
Types without green slime are much more merciful than the judges of
coherence hell, because you don't have to match to apply the path
constructors, as you would in `Tr1`{.Agda}: If you have the arguments
handy, you can apply them _targeting_ arbitrary points. Lovely! But In
the image case, this still doesn't really work, because we don't want to
identify _arbitrary_ points. Our requirements are something like this:
1. A tractable description: finitely many constructors, and hopefully
"no more than a few". This guarantees that we can tell Agda Agda about
the construction and _actually work with it_, which is also important.
2. Without any green slime, to _hopefully_ avoid the coherent issues.
3. So that points from $a$ are identified in $\im f$ exactly how they
would be identified in $b$ under $f$.
If we _had_ such a type, we could define an [[embedding]] $f' : \im f
\mono B$, which tells us how to compute the path spaces in $\im f$: $(x
\equiv y) \simeq (f'(x) \equiv f'(y))$. In fact, since images are almost
entirely characterised by having such an embedding, we can use our
hypothetical $f'$ to rewrite the third bullet point:
3. With a constructor coherently mapping proofs of $f'(x) \equiv f'(y)$
to $x \equiv y$.
Also, note that, since we were trying to get a _smaller_ image, we can't
just use $B$'s path types: those live at the same universe as $B$. What
we can do instead is parametrise over an [[identity system]] on $B$, a
reflexive family of types $x \sim y$ which is equivalent to $x \equiv y$
but which might be smaller. So, our requirement on identifications
should be
3. With a constructor coherently mapping proofs of $f'(x) \sim f'(y)$ to
$x \equiv y$.
But, identity system or not, this is hopeless, right? We don't know how
to specify $\im f$ without first defining $f'$; and it makes no sense to
define $f'$ before its domain type. The only way forward would be to
somehow define them at the same time. That's impossible, right?
## Higher induction-recursion
It's actually totally possible to, at least in Agda, define higher
inductive types at the same time as we define pattern-matching functions
on them. And that's exactly what we'll do: specify $\im f$
higher-inductively _at the same time as_ we define $f' : \im f \mono b$
by recursion. Our three bullet points from before become the
specification of the inductive type!
```agda
module Replacement
{ℓₐ ℓₜ ℓᵢ} {A : Type ℓₐ} {T : Type ℓₜ}
{_∼_ : T → T → Type ℓᵢ} {rr : ∀ x → x ∼ x}
(locally-small : is-identity-system _∼_ rr)
(f : A → T)
where
private module ls = Ids locally-small
data Image : Type (ℓₐ ⊔ ℓᵢ)
embed : Image → T
data Image where
inc : A → Image
quot : ∀ {r r'} → embed r ∼ embed r' → r ≡ r'
embed (inc a) = f a
embed (quot p i) = locally-small .to-path p i
```
And, having used inductive-recursion to tie the dependency knot, we're
actually done: the construction above is coherent enough, _even if_ it
looks like the `quot`{.Agda} constructor only says that `embed`{.Agda}
is an injection. We can use the algebraic properties of identity systems
to show that it's actually a proper embedding:
```agda
embed-is-embedding' : ∀ x → is-contr (fibre embed (embed x))
embed-is-embedding' x .centre = x , refl
embed-is-embedding' x .paths (y , q) =
Σ-pathp (quot (ls.from (sym q))) (commutes→square coh)
where abstract
coh : ls.to (ls.from (sym q)) ∙ q ≡ refl ∙ refl
coh = ap (_∙ q) (ls.ε (sym q)) ·· ∙-invl q ·· sym (∙-idl refl)
embed-is-embedding : is-embedding embed
embed-is-embedding = embedding-lemma embed-is-embedding'
```
And it's possible to pull back the identity system on $b$ to one on $\im
f$, to really drive home the point that points in the image are
identified precisely through their identification, under $f$, in the
codomain.
```agda
Image-identity-system : is-identity-system (λ x y → embed x ∼ embed y) (λ _ → rr _)
Image-identity-system = pullback-identity-system locally-small
(embed , embed-is-embedding)
```
<!--
```agda
Image-is-hlevel : ∀ n → is-hlevel T (suc n) → is-hlevel Image (suc n)
Image-is-hlevel n = embedding→is-hlevel n embed-is-embedding
```
-->
As usual with these things, we can establish properties of
`Image`{.Agda} without caring about the higher constructors.
```agda
Image-elim-prop
: ∀ {ℓ'} {P : Image → Type ℓ'}
→ (∀ x → is-prop (P x))
→ (∀ x → P (inc x))
→ ∀ x → P x
Image-elim-prop pprop pinc (inc x) = pinc x
Image-elim-prop pprop pinc (quot {x} {y} p i) =
is-prop→pathp (λ i → pprop (quot p i))
(Image-elim-prop pprop pinc x)
(Image-elim-prop pprop pinc y) i
```
From which surjectivity follows immediately:
```agda
inc-is-surjective : is-surjective inc
inc-is-surjective = Image-elim-prop (λ _ → squash) (λ x → inc (x , refl))
```
## Comparison
We define a "comparison" map from the resized image to the "ordinary"
image. This map is a bit annoying to define, and it relies on being able
to easily map from the `Image`{.Agda} into propositions. It's
definitional that projecting from `Image→image`{.Agda} gives our
`embed`{.Agda}ding, since that's how we _define_ the map.
```agda
Image→image : Image → image f
Image→image x .fst = embed x
Image→image x .snd =
Image-elim-prop {P = λ x → ∥ fibre f (embed x) ∥} (λ _ → squash)
(λ x → inc (x , refl))
x
```
Establishing that `Image→image`{.Agda} is an equivalence is one of the
rare cases where it's easier to show that it has contractible fibres.
That's because we can eliminate the propositional truncation as the
first step, and deal only with untruncated data from then on.
```agda
Image→image-is-equiv : is-equiv Image→image
Image→image-is-equiv .is-eqv (x , p) =
∥-∥-elim {P = λ p → is-contr (fibre Image→image (x , p))}
(λ _ → is-contr-is-prop)
(λ { (i , p) → J
(λ x p → is-contr (fibre Image→image (x , inc (i , p))))
(work' i) p })
p
where
work' : (f⁻¹x : A) → is-contr (fibre Image→image (f f⁻¹x , inc (_ , refl)))
work' f⁻¹x .centre = inc f⁻¹x , refl -- inc f⁻¹x , refl
```
Contracting the fibres is where we get some mileage out of having gotten
the green slime out of `quot`{.Agda}. We have to show $f\inv(x) = i$,
as elements of the image, but we have an assumption that
$\mathrm{embed}(i) = ff\inv(x)$, which, under `quot`{.agda}, is exactly
what we need.
```agda
work' f⁻¹x .paths (i , α) = Σ-pathp (quot (ls.from (sym (ap fst α)))) $
Σ-prop-square (λ _ → squash) $ commutes→square $
(ap₂ _∙_ (ls.ε (sym (ap fst α))) refl ∙ ∙-invl _ ∙ sym (∙-idl _))
```