diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index f4b6a55a8..d5f30317d 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -6,7 +6,7 @@ Please include a quick description of the changes here.
Before submitting a merge request, please check the items below:
-- [ ] The imports are sorted (use `find -type f -name \*.agda -or -name \*.lagda.md | xargs support/sort-imports.hs`)
+- [ ] The imports are sorted with `support/sort-imports.hs`
- [ ] All code blocks have "agda" as their language. This is so that
tools like Tokei can report accurate line counts for proofs vs. text.
diff --git a/1lab.agda-lib b/1lab.agda-lib
index cf3ed3e66..655e99e19 100644
--- a/1lab.agda-lib
+++ b/1lab.agda-lib
@@ -1,4 +1,4 @@
-name: cubical-1lab
+name: 1lab
include:
src
wip
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b8e32aa48..c17f91c8a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -6,7 +6,7 @@ Thanks for taking the time to contribute!
This file holds the conventions we use around the codebase, but they're
guidelines, and not strict rules: If you're unsure of something, hop on
[the Discord](https://discord.gg/Zp2e8hYsuX) and ask there, or open [a
-discussion thread](https://github.com/plt-amy/cubical-1lab/discussions)
+discussion thread](https://github.com/plt-amy/1lab/discussions)
if that's more your style.
### General guidelines
@@ -14,7 +14,8 @@ if that's more your style.
Use British spelling everywhere that it differs from American: Homotopy
fib**re**, fib**red** category, colo**u**red operad, etc --- both in
prose and in Agda. Keep prose paragraphs limited to 72 characters of
-length. Prefer link anchors (Pandoc "reference links") to inline links.
+length. Prefer wikilinks or link anchors (Pandoc "reference links") to
+inline links.
### Agda code style
diff --git a/README.md b/README.md
index 0120c8184..5048f86ae 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
[![Discord](https://img.shields.io/discord/914172963157323776?label=Discord&logo=discord)](https://discord.gg/Zp2e8hYsuX)
-[![Build 1Lab](https://github.com/plt-amy/cubical-1lab/actions/workflows/build.yml/badge.svg)](https://github.com/plt-amy/cubical-1lab/actions/workflows/build.yml)
+[![Build 1Lab](https://github.com/plt-amy/1lab/actions/workflows/build.yml/badge.svg)](https://github.com/plt-amy/1lab/actions/workflows/build.yml)
# [1Lab](https://1lab.dev)
diff --git a/default.nix b/default.nix
index 0aaa13c68..aa1361a38 100644
--- a/default.nix
+++ b/default.nix
@@ -2,9 +2,10 @@
inNixShell ? false
# Do we want the full Agda package for interactive use? Set to false in CI
, interactive ? true
+, system ? builtins.currentSystem
}:
let
- pkgs = import ./support/nix/nixpkgs.nix;
+ pkgs = import ./support/nix/nixpkgs.nix { inherit system; };
inherit (pkgs) lib;
our-ghc = pkgs.labHaskellPackages.ghcWithPackages (ps: with ps; [
diff --git a/package-lock.json b/package-lock.json
index 007257bfc..f0a58b9fb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,11 +1,11 @@
{
- "name": "cubical-1lab",
+ "name": "1lab",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
- "name": "cubical-1lab",
+ "name": "1lab",
"version": "1.0.0",
"license": "AGPL-3.0",
"dependencies": {
diff --git a/package.json b/package.json
index 55197b704..fa35d7f73 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
{
- "name": "cubical-1lab",
+ "name": "1lab",
"version": "1.0.0",
"description": " A formalised, cross-linked reference resource for mathematics done in Homotopy Type Theory ",
"main": "index.js",
@@ -8,14 +8,14 @@
},
"repository": {
"type": "git",
- "url": "git+https://github.com/plt-amy/cubical-1lab.git"
+ "url": "git+https://github.com/plt-amy/1lab.git"
},
"author": "Amélia Liao et. al.",
"license": "AGPL-3.0",
"bugs": {
- "url": "https://github.com/plt-amy/cubical-1lab/issues"
+ "url": "https://github.com/plt-amy/1lab/issues"
},
- "homepage": "https://github.com/plt-amy/cubical-1lab#readme",
+ "homepage": "https://github.com/plt-amy/1lab#readme",
"devDependencies": {
"@types/d3": "^7.1.0",
"d3": "^7.4.4",
diff --git a/src/1Lab/Equiv/Biinv.lagda.md b/src/1Lab/Equiv/Biinv.lagda.md
index 4142c7247..a2380799e 100644
--- a/src/1Lab/Equiv/Biinv.lagda.md
+++ b/src/1Lab/Equiv/Biinv.lagda.md
@@ -176,11 +176,11 @@ suffices to show that `is-biinv`{.Agda} is contractible when it is
inhabited:
[a proposition]: agda://1Lab.HLevel#is-prop
-[contractible if inhabited]: agda://1Lab.HLevel#contractible-if-inhabited
+[contractible if inhabited]: agda://1Lab.HLevel#is-contr-if-inhabited→is-prop
```agda
is-biinv-is-prop : {f : A → B} → is-prop (is-biinv f)
-is-biinv-is-prop {f = f} = contractible-if-inhabited contract where
+is-biinv-is-prop {f = f} = is-contr-if-inhabited→is-prop contract where
contract : is-biinv f → is-contr (is-biinv f)
contract ibiinv =
×-is-hlevel 0 (is-iso→is-contr-linv iiso)
diff --git a/src/1Lab/Equiv/HalfAdjoint.lagda.md b/src/1Lab/Equiv/HalfAdjoint.lagda.md
index bce7353e4..ca00c9211 100644
--- a/src/1Lab/Equiv/HalfAdjoint.lagda.md
+++ b/src/1Lab/Equiv/HalfAdjoint.lagda.md
@@ -176,7 +176,7 @@ another $(x, p)$ using a very boring calculation:
path : ap f (ap g (sym p) ∙ η x) ∙ p ≡ ε y
path =
- ap f (ap g (sym p) ∙ η x) ∙ p ≡⟨ ap₂ _∙_ (ap-comp-path f (ap g (sym p)) (η x)) refl ∙ sym (∙-assoc _ _ _) ⟩
+ ap f (ap g (sym p) ∙ η x) ∙ p ≡⟨ ap₂ _∙_ (ap-∙ f (ap g (sym p)) (η x)) refl ∙ sym (∙-assoc _ _ _) ⟩
ap (λ x → f (g x)) (sym p) ∙ ⌜ ap f (η x) ⌝ ∙ p ≡⟨ ap! (zig _) ⟩ -- by the triangle identity
ap (f ∘ g) (sym p) ∙ ⌜ ε (f x) ∙ p ⌝ ≡⟨ ap! (homotopy-natural ε p) ⟩ -- by naturality of ε
```
@@ -189,7 +189,7 @@ $\varepsilon$ lets us "push it past $p$" to get something we can cancel:
```agda
ap (f ∘ g) (sym p) ∙ ap (f ∘ g) p ∙ ε y ≡⟨ ∙-assoc _ _ _ ⟩
- ⌜ ap (f ∘ g) (sym p) ∙ ap (f ∘ g) p ⌝ ∙ ε y ≡˘⟨ ap¡ (ap-comp-path (f ∘ g) (sym p) p) ⟩
+ ⌜ ap (f ∘ g) (sym p) ∙ ap (f ∘ g) p ⌝ ∙ ε y ≡˘⟨ ap¡ (ap-∙ (f ∘ g) (sym p) p) ⟩
ap (f ∘ g) ⌜ sym p ∙ p ⌝ ∙ ε y ≡⟨ ap! (∙-inv-r _) ⟩
ap (f ∘ g) refl ∙ ε y ≡⟨⟩
refl ∙ ε y ≡⟨ ∙-id-l (ε y) ⟩
diff --git a/src/1Lab/HIT/Truncation.lagda.md b/src/1Lab/HIT/Truncation.lagda.md
index 9986aa848..c52af2a4a 100644
--- a/src/1Lab/HIT/Truncation.lagda.md
+++ b/src/1Lab/HIT/Truncation.lagda.md
@@ -48,7 +48,7 @@ is-prop-∥-∥ = squash
```agda
instance
H-Level-truncation : ∀ {n} {ℓ} {A : Type ℓ} → H-Level ∥ A ∥ (suc n)
- H-Level-truncation = hlevel-instance (is-prop→is-hlevel-suc squash)
+ H-Level-truncation = prop-instance squash
```
-->
diff --git a/src/1Lab/HLevel.lagda.md b/src/1Lab/HLevel.lagda.md
index b5c4a15b2..0c6672ace 100644
--- a/src/1Lab/HLevel.lagda.md
+++ b/src/1Lab/HLevel.lagda.md
@@ -9,7 +9,7 @@ open import 1Lab.Type
module 1Lab.HLevel where
```
-# h-Levels
+# h-Levels {defines="h-level n-type truncated"}
The "homotopy level" (h-level for short) of a type is a measure of how
[truncated] it is, where the numbering is offset by 2. Specifically, a
@@ -36,8 +36,10 @@ _homotopy $(n-2)$-types_. For instance: "The sets are the homotopy
0-types". The use of the $-2$ offset is so the naming here matches that
of the HoTT book.
+:::{.definition #contractible}
The h-levels are defined by induction, where the base case are the
_contractible types_.
+:::
[truncated]: https://ncatlab.org/nlab/show/truncated+object
@@ -77,7 +79,7 @@ type.
interval-contractible .paths (seg i) j = seg (i ∧ j)
```
-:::{.definition #proposition}
+:::{.definition #proposition alias="property"}
A type is (n+1)-truncated if its path types are all n-truncated.
However, if we directly take this as the definition, the types we end up
with are very inconvenient! That's why we introduce this immediate step:
@@ -114,7 +116,9 @@ is-set : ∀ {ℓ} → Type ℓ → Type ℓ
is-set A = is-hlevel A 2
```
+:::{.definition #groupoid}
Similarly, the types of h-level 3 are called **groupoids**.
+:::
```agda
is-groupoid : ∀ {ℓ} → Type ℓ → Type ℓ
@@ -182,8 +186,12 @@ which is that the propositions are precisely the types which are
contractible when they are inhabited:
```agda
-contractible-if-inhabited : ∀ {ℓ} {A : Type ℓ} → (A → is-contr A) → is-prop A
-contractible-if-inhabited cont x y = is-contr→is-prop (cont x) x y
+is-contr-if-inhabited→is-prop : ∀ {ℓ} {A : Type ℓ} → (A → is-contr A) → is-prop A
+is-contr-if-inhabited→is-prop cont x y = is-contr→is-prop (cont x) x y
+
+is-prop→is-contr-if-inhabited : ∀ {ℓ} {A : Type ℓ} → is-prop A → A → is-contr A
+is-prop→is-contr-if-inhabited prop x .centre = x
+is-prop→is-contr-if-inhabited prop x .paths y = prop x y
```
The proof that any contractible type is a proposition is not too
@@ -372,6 +380,13 @@ is-hlevel-is-prop (suc (suc n)) x y i a b =
is-hlevel-is-prop (suc n) (x a b) (y a b) i
```
+
+
# Dependent h-Levels
In cubical type theory, it's natural to consider a notion of _dependent_
diff --git a/src/1Lab/HLevel/Retracts.lagda.md b/src/1Lab/HLevel/Retracts.lagda.md
index 002ad46c3..5a2770464 100644
--- a/src/1Lab/HLevel/Retracts.lagda.md
+++ b/src/1Lab/HLevel/Retracts.lagda.md
@@ -352,9 +352,10 @@ instance
H-Level-sigma {n = n} .H-Level.has-hlevel =
Σ-is-hlevel n (hlevel n) λ _ → hlevel n
- H-Level-path′
- : ∀ {n} ⦃ s : H-Level S (suc n) ⦄ {x y} → H-Level (Path S x y) n
- H-Level-path′ {n = n} .H-Level.has-hlevel = Path-is-hlevel' n (hlevel (suc n)) _ _
+ H-Level-PathP
+ : ∀ {n} {S : I → Type ℓ} ⦃ s : H-Level (S i1) (suc n) ⦄ {x y}
+ → H-Level (PathP S x y) n
+ H-Level-PathP {n = n} .H-Level.has-hlevel = PathP-is-hlevel' n (hlevel (suc n)) _ _
H-Level-Lift
: ∀ {n} ⦃ s : H-Level T n ⦄ → H-Level (Lift ℓ T) n
diff --git a/src/1Lab/Path.lagda.md b/src/1Lab/Path.lagda.md
index 0db153116..54c1caf50 100644
--- a/src/1Lab/Path.lagda.md
+++ b/src/1Lab/Path.lagda.md
@@ -268,6 +268,21 @@ Square : ∀ {ℓ} {A : Type ℓ} {a00 a01 a10 a11 : A}
Square p q s r = PathP (λ i → p i ≡ r i) q s
```
+
+
The arguments to `Square`{.Agda} are as in the following diagram, listed
in the order “PQSR”. This order is a bit unusual (it's one off from
being alphabetical, for instance) but it does have a significant
@@ -1028,6 +1043,8 @@ be reflexivity. For definiteness, we chose the left face:
_∙_ : ∀ {ℓ} {A : Type ℓ} {x y z : A}
→ x ≡ y → y ≡ z → x ≡ z
p ∙ q = refl ·· p ·· q
+
+infixr 30 _∙_
```
The ordinary, “single composite” of $p$ and $q$ is the dashed face in
@@ -1061,17 +1078,29 @@ setting the _right_ face to `refl`{.Agda}.
```
We can use the filler and heterogeneous composition to define composition of `PathP`{.Agda}s
-in a given type family:
+and `Square`{.Agda}s:
```agda
_∙P_ : ∀ {ℓ ℓ′} {A : Type ℓ} {B : A → Type ℓ′} {x y z : A} {x′ : B x} {y′ : B y} {z′ : B z} {p : x ≡ y} {q : y ≡ z}
- → PathP (λ i → B (p i)) x′ y′ → PathP (λ i → B (q i)) y′ z′
+ → PathP (λ i → B (p i)) x′ y′
+ → PathP (λ i → B (q i)) y′ z′
→ PathP (λ i → B ((p ∙ q) i)) x′ z′
_∙P_ {B = B} {x′ = x′} {p = p} {q = q} p′ q′ i =
comp (λ j → B (∙-filler p q j i)) (∂ i) λ where
j (i = i0) → x′
j (i = i1) → q′ j
j (j = i0) → p′ i
+
+_∙₂_ : ∀ {ℓ} {A : Type ℓ} {a00 a01 a02 a10 a11 a12 : A}
+ {p : a00 ≡ a01} {p′ : a01 ≡ a02}
+ {q : a00 ≡ a10} {s : a01 ≡ a11} {t : a02 ≡ a12}
+ {r : a10 ≡ a11} {r′ : a11 ≡ a12}
+ → Square p q s r
+ → Square p′ s t r′
+ → Square (p ∙ p′) q t (r ∙ r′)
+(α ∙₂ β) i j = ((λ i → α i j) ∙ (λ i → β i j)) i
+
+infixr 30 _∙P_ _∙₂_
```
## Uniqueness
@@ -1196,6 +1225,12 @@ its filler), it is contractible:
→ r ≡ p ∙ q
∙-unique {p = p} {q} r square i =
··-unique refl p q (_ , square) (_ , (∙-filler p q)) i .fst
+
+··-unique' : ∀ {ℓ} {A : Type ℓ} {w x y z : A}
+ → {p : w ≡ x} {q : x ≡ y} {r : y ≡ z} {s : w ≡ z}
+ → (β : Square (sym p) q s r)
+ → s ≡ p ·· q ·· r
+··-unique' β i = ··-contract _ _ _ (_ , β) (~ i) .fst
```
-->
@@ -1246,6 +1281,18 @@ apd : ∀ {a b} {A : I → Type a} {B : (i : I) → A i → Type b}
→ (p : PathP A x y)
→ PathP (λ i → B i (p i)) (f i0 x) (f i1 y)
apd f p i = f i (p i)
+
+ap-square
+ : ∀ {ℓ ℓ′} {A : Type ℓ} {B : A → Type ℓ′}
+ {a00 a01 a10 a11 : A}
+ {p : a00 ≡ a01}
+ {q : a00 ≡ a10}
+ {s : a01 ≡ a11}
+ {r : a10 ≡ a11}
+ → (f : (a : A) → B a)
+ → (α : Square p q s r)
+ → SquareP (λ i j → B (α i j)) (ap f p) (ap f q) (ap f s) (ap f r)
+ap-square f α i j = f (α i j)
```
-->
@@ -1261,9 +1308,9 @@ module _ where
f : A → B
g : B → C
- ap-comp : {x y : A} {p : x ≡ y}
- → ap (λ x → g (f x)) p ≡ ap g (ap f p)
- ap-comp = refl
+ ap-∘ : {x y : A} {p : x ≡ y}
+ → ap (λ x → g (f x)) p ≡ ap g (ap f p)
+ ap-∘ = refl
ap-id : {x y : A} {p : x ≡ y}
→ ap (λ x → x) p ≡ p
@@ -1284,12 +1331,13 @@ for the open box with sides `refl`, `ap f p` and `ap f q`, so they must be equal
[uniqueness]: 1Lab.Path.html#uniqueness
```agda
- ap-comp-path : (f : A → B) {x y z : A} (p : x ≡ y) (q : y ≡ z)
- → ap f (p ∙ q) ≡ ap f p ∙ ap f q
- ap-comp-path f p q i = ··-unique refl (ap f p) (ap f q)
- (ap f (p ∙ q) , λ k j → f (∙-filler p q k j))
- (ap f p ∙ ap f q , ∙-filler _ _)
- i .fst
+ ap-·· : (f : A → B) {x y z w : A} (p : x ≡ y) (q : y ≡ z) (r : z ≡ w)
+ → ap f (p ·· q ·· r) ≡ ap f p ·· ap f q ·· ap f r
+ ap-·· f p q r = ··-unique' (ap-square f (··-filler p q r))
+
+ ap-∙ : (f : A → B) {x y z : A} (p : x ≡ y) (q : y ≡ z)
+ → ap f (p ∙ q) ≡ ap f p ∙ ap f q
+ ap-∙ f p q = ap-·· f refl p q
```
# Syntax Sugar
@@ -1323,7 +1371,6 @@ x ≡⟨⟩ x≡y = x≡y
_∎ : ∀ {ℓ} {A : Type ℓ} (x : A) → x ≡ x
x ∎ = refl
-infixr 30 _∙_ _∙P_
infixr 2 _≡⟨⟩_ _≡˘⟨_⟩_
infix 3 _∎
@@ -1359,21 +1406,6 @@ your convenience, it's here too:
Try pressing it!
-
-
# Dependent Paths
Surprisingly often, we want to compare inhabitants $a : A$ and $b : B$
diff --git a/src/1Lab/Path/Groupoid.lagda.md b/src/1Lab/Path/Groupoid.lagda.md
index f47467456..62ff3eb7e 100644
--- a/src/1Lab/Path/Groupoid.lagda.md
+++ b/src/1Lab/Path/Groupoid.lagda.md
@@ -19,7 +19,7 @@ module 1Lab.Path.Groupoid where
_ = Path
_ = hfill
_ = ap-refl
-_ = ap-comp-path
+_ = ap-∙
_ = ap-sym
```
-->
@@ -208,7 +208,7 @@ equal to `sym (sym p)`. In that case, we show that `sym p ∙ sym (sym p)
In addition to the groupoid identities for paths in a type, it has been
established that functions behave like functors: These are the lemmas
-`ap-refl`{.Agda}, `ap-comp-path`{.Agda} and `ap-sym`{.Agda} in the
+`ap-refl`{.Agda}, `ap-∙`{.Agda} and `ap-sym`{.Agda} in the
[1Lab.Path] module.
[1Lab.Path]: 1Lab.Path.html#functorial-action
diff --git a/src/1Lab/Path/Reasoning.lagda.md b/src/1Lab/Path/Reasoning.lagda.md
index 7787df204..b427c614f 100644
--- a/src/1Lab/Path/Reasoning.lagda.md
+++ b/src/1Lab/Path/Reasoning.lagda.md
@@ -105,12 +105,39 @@ module _ (s≡pq : s ≡ p ∙ q) where
∙-pushr : r ∙ s ≡ (r ∙ p) ∙ q
∙-pushr = sym (∙-pullr (sym s≡pq))
+ ∙→square : Square refl p s q
+ ∙→square = ∙-filler p q ▷ sym s≡pq
+
+ ∙→square' : Square (sym p) q s refl
+ ∙→square' = ∙-filler' p q ▷ sym s≡pq
+
module _ (pq≡rs : p ∙ q ≡ r ∙ s) where
∙-extendl : p ∙ (q ∙ t) ≡ r ∙ (s ∙ t)
∙-extendl {t = t} = ∙-assoc _ _ _ ·· ap (_∙ t) pq≡rs ·· sym (∙-assoc _ _ _)
∙-extendr : (t ∙ p) ∙ q ≡ (t ∙ r) ∙ s
∙-extendr {t = t} = sym (∙-assoc _ _ _) ·· ap (t ∙_) pq≡rs ·· ∙-assoc _ _ _
+
+··-stack : (sym p′ ·· (sym p ·· q ·· r) ·· r′) ≡ (sym (p ∙ p′) ·· q ·· (r ∙ r′))
+··-stack = ··-unique' (··-filler _ _ _ ∙₂ ··-filler _ _ _)
+
+··-chain : (sym p ·· q ·· r) ∙ (sym r ·· q′ ·· s) ≡ sym p ·· (q ∙ q′) ·· s
+··-chain {p = p} {q = q} {r = r} {q′ = q′} {s = s} = sym (∙-unique _ square) where
+ square : Square refl (sym p ·· q ·· r) (sym p ·· (q ∙ q′) ·· s) (sym r ·· q′ ·· s)
+ square i j = hcomp (~ j ∨ (j ∧ (i ∨ ~ i))) λ where
+ k (k = i0) → ∙-filler q q′ i j
+ k (j = i0) → p k
+ k (j = i1) (i = i0) → r k
+ k (j = i1) (i = i1) → s k
+
+··-∙-assoc : p ·· q ·· (r ∙ s) ≡ (p ·· q ·· r) ∙ s
+··-∙-assoc {p = p} {q = q} {r = r} {s = s} = sym (··-unique' square) where
+ square : Square (sym p) q ((p ·· q ·· r) ∙ s) (r ∙ s)
+ square i j = hcomp (~ i ∨ ~ j ∨ (i ∧ j)) λ where
+ k (k = i0) → ··-filler p q r i j
+ k (i = i0) → q j
+ k (j = i0) → p (~ i)
+ k (i = i1) (j = i1) → s k
```
## Cancellation
diff --git a/src/1Lab/Prelude.agda b/src/1Lab/Prelude.agda
index 98d501813..cad8e643f 100644
--- a/src/1Lab/Prelude.agda
+++ b/src/1Lab/Prelude.agda
@@ -31,6 +31,7 @@ open import 1Lab.Univalence.SIP public
open import 1Lab.Type.Pi public
open import 1Lab.Type.Sigma public
+open import 1Lab.Type.Pointed public
open import 1Lab.HIT.Truncation public
diff --git a/src/1Lab/Reflection.lagda.md b/src/1Lab/Reflection.lagda.md
index f1fb984e5..edd62a037 100644
--- a/src/1Lab/Reflection.lagda.md
+++ b/src/1Lab/Reflection.lagda.md
@@ -6,9 +6,9 @@ open import 1Lab.Path
open import 1Lab.Type hiding (absurd)
open import Data.Product.NAry
+open import Data.List.Base
open import Data.Vec.Base
open import Data.Bool
-open import Data.List.Base
```
-->
diff --git a/src/1Lab/Reflection/HLevel.agda b/src/1Lab/Reflection/HLevel.agda
index 6c09cb642..530cbbaf2 100644
--- a/src/1Lab/Reflection/HLevel.agda
+++ b/src/1Lab/Reflection/HLevel.agda
@@ -9,8 +9,8 @@ open import 1Lab.Equiv
open import 1Lab.Path
open import 1Lab.Type
-open import Data.Bool
open import Data.List.Base
+open import Data.Bool
open import Meta.Foldable
@@ -25,7 +25,7 @@ support for arbitrary level offsets (`level-minus) and searching under
binders (`search-under). Ambiguity is explicitly supported: the first
goal for which we can complete a proof tree is the one we go with.
-The tactic works in a naÏve way, trying h-level lemmas until one
+The tactic works in a naïve way, trying h-level lemmas until one
succeeds. There are three ways of making progress: Using a *projection
hint*, using a *decomposition hint*, or by falling back to instance
selection. The instance selection fallback is self-explanatory.
@@ -78,14 +78,15 @@ data Arg-spec : Type where
-- lambdas. This is suitable for lemmas of type
-- (∀ x y z → is-hlevel ...) → is-hlevel ...
- `meta : Arg-spec
- -- ^ Insert a meta at this argument position. No search will be
- -- performed for this meta, so it must be solved from the context in
+ `term : Term → Arg-spec
+ -- ^ Insert a literal term at this argument position. No search will be
+ -- performed if this is a meta, so it must be solved from the context in
-- which the lemma is used.
-- Common patterns: Keep the level, search in the current scope.
pattern `search = `search-under 0
pattern `level = `level-minus 0
+pattern `meta = `term unknown
-- | A specification for how to decompose the type @T@ into
-- sub-components, to establish an h-level result.
@@ -147,7 +148,7 @@ private
-- an application of is-hlevel/is-prop/is-set into an 'underlying
-- type' and level arguments.
hlevel-types : List Name
- hlevel-types = quote is-hlevel ∷ quote is-prop ∷ quote is-set ∷ []
+ hlevel-types = quote is-hlevel ∷ quote is-prop ∷ quote is-set ∷ quote is-groupoid ∷ []
pattern nat-lit n =
def (quote Number.fromNat) (_ ∷ _ ∷ _ ∷ lit (nat n) v∷ _)
@@ -169,6 +170,10 @@ private
def (quote is-hlevel) (_ ∷ ty v∷ lv v∷ []) ← pure ty
where
-- Handle the ones with special names:
+ def (quote is-groupoid) (_ ∷ ty v∷ []) → do
+ ty ← wait-just-a-bit ty
+ pure (ty , quoteTerm 3)
+
def (quote is-set) (_ ∷ ty v∷ []) → do
ty ← wait-just-a-bit ty
pure (ty , quoteTerm 2)
@@ -242,7 +247,6 @@ from the wanted level (k + n) until is-hlevel-+ n (sucᵏ′ n) w works.
let's-hope = do
debugPrint "tactic.hlevel" 30 $ "Lifting loop: Trying " ∷ termErr (lift-sol solution l1 it) ∷ " for level " ∷ termErr l2 ∷ []
unify goal (lift-sol solution l1 it)
- -- con (quote suc) (
-- Projection decomposition.
treat-as-n-type : ∀ {n} → hlevel-projection n → Term → TC ⊤
@@ -453,9 +457,7 @@ from the wanted level (k + n) until is-hlevel-+ n (sucᵏ′ n) w works.
debugPrint "tactic.hlevel" 10 $ "Dunno how to take 1 from " ∷ termErr tm ∷ []
typeError []
- -- Insert a metavariable, to be solved by Agda. It'd be sad if the
- -- macro handled everything!
- ... | `meta = gen-args has-alts level defn args (unknown v∷ accum) cont
+ ... | `term t = gen-args has-alts level defn args (t v∷ accum) cont
... | `search-under under = do
-- To search under some variables, we work in a scope extended
@@ -558,13 +560,13 @@ from the wanted level (k + n) until is-hlevel-+ n (sucᵏ′ n) w works.
decompose-is-hlevel-top goal =
do
ty ← withReduceDefs (false , hlevel-types) $
- (inferType goal >>= reduce) >>= wait-just-a-bit
+ inferType goal >>= reduce >>= wait-just-a-bit
go ty
where
go : Term → TC _
go (pi (arg as at) (abs vn cd)) = do
(inner , hlevel , enter , leave) ← go cd
- pure $ inner , hlevel , extendContext vn (arg as at) , λ t → lam (ArgInfo.arg-vis as) (abs vn t)
+ pure $ inner , hlevel , extendContext vn (arg as at) ∘ enter , λ t → lam (ArgInfo.arg-vis as) (abs vn (leave t))
go tm = do
(inner , hlevel) ← decompose-is-hlevel′ tm
pure $ inner , hlevel , (λ x → x) , (λ x → x)
@@ -636,6 +638,31 @@ instance
decomp-lift : ∀ {ℓ ℓ′} {T : Type ℓ} → hlevel-decomposition (Lift ℓ′ T)
decomp-lift = decomp (quote Lift-is-hlevel) (`level ∷ `search ∷ [])
+ -- h-level types themselves are propositions. These instances should be tried
+ -- before Π types.
+
+ decomp-is-prop : ∀ {ℓ} {A : Type ℓ} → hlevel-decomposition (is-prop A)
+ decomp-is-prop = decomp (quote is-hlevel-is-hlevel-suc) (`level-minus 1 ∷ `term (quoteTerm 1) ∷ [])
+
+ decomp-is-set : ∀ {ℓ} {A : Type ℓ} → hlevel-decomposition (is-set A)
+ decomp-is-set = decomp (quote is-hlevel-is-hlevel-suc) (`level-minus 1 ∷ `term (quoteTerm 2) ∷ [])
+
+ decomp-is-groupoid : ∀ {ℓ} {A : Type ℓ} → hlevel-decomposition (is-groupoid A)
+ decomp-is-groupoid = decomp (quote is-hlevel-is-hlevel-suc) (`level-minus 1 ∷ `term (quoteTerm 3) ∷ [])
+
+ {-
+ Since `is-prop A` starts with a Π, the decomp-piⁿ instances below could "bite" into
+ it and make decomp-is-prop inapplicable. To avoid this, we handle those situations explicitly:
+ -}
+
+ decomp-pi²-is-prop : ∀ {ℓa ℓb ℓc} {A : Type ℓa} {B : A → Type ℓb} {C : ∀ a (b : B a) → Type ℓc}
+ → hlevel-decomposition (∀ a b → is-prop (C a b))
+ decomp-pi²-is-prop = decomp (quote Π-is-hlevel²) (`level ∷ `search-under 2 ∷ [])
+
+ decomp-pi-is-prop : ∀ {ℓa ℓb} {A : Type ℓa} {B : A → Type ℓb}
+ → hlevel-decomposition (∀ a → is-prop (B a))
+ decomp-pi-is-prop = decomp (quote Π-is-hlevel) (`level ∷ `search-under 1 ∷ [])
+
-- -- Non-dependent Π and Σ for readability first:
-- decomp-fun = decomp (quote fun-is-hlevel) (`level ∷ `search ∷ [])
@@ -644,6 +671,7 @@ instance
-- decomp-prod = decomp (quote ×-is-hlevel) (`level ∷ `search ∷ `search ∷ [])
-- Dependent type formers:
+
decomp-pi³
: ∀ {ℓa ℓb ℓc ℓd} {A : Type ℓa} {B : A → Type ℓb} {C : ∀ x (y : B x) → Type ℓc}
→ {D : ∀ x y (z : C x y) → Type ℓd}
@@ -715,4 +743,13 @@ private
_ = hlevel!
_ : ∀ n (x : n-Type ℓ n) → is-hlevel ∣ x ∣ (2 + n)
- _ = λ n x → hlevel!
+ _ = hlevel!
+
+ _ : ∀ {ℓ} {A : Type ℓ} → is-prop ((x : A) → is-prop A)
+ _ = hlevel!
+
+ _ : ∀ {ℓ} {A : Type ℓ} → is-prop ((x y : A) → is-prop A)
+ _ = hlevel!
+
+ _ : ∀ {ℓ} {A : Type ℓ} → is-groupoid (is-hlevel A 5)
+ _ = hlevel!
diff --git a/src/1Lab/Reflection/Record.agda b/src/1Lab/Reflection/Record.agda
index 3696d6446..0b4b9ebae 100644
--- a/src/1Lab/Reflection/Record.agda
+++ b/src/1Lab/Reflection/Record.agda
@@ -4,7 +4,6 @@ open import 1Lab.Equiv
open import 1Lab.Path
open import 1Lab.Type
-
import Prim.Data.Sigma as S
import Prim.Data.Nat as N
diff --git a/src/1Lab/Reflection/Variables.agda b/src/1Lab/Reflection/Variables.agda
index 8626dfe0c..6df19d576 100644
--- a/src/1Lab/Reflection/Variables.agda
+++ b/src/1Lab/Reflection/Variables.agda
@@ -1,9 +1,9 @@
open import 1Lab.Reflection hiding (reverse)
open import 1Lab.Type
+open import Data.List.Base hiding (reverse)
open import Data.Fin.Base
open import Data.Nat.Base
-open import Data.List.Base hiding (reverse)
module 1Lab.Reflection.Variables where
diff --git a/src/1Lab/Type.lagda.md b/src/1Lab/Type.lagda.md
index bcbb2f1d8..0a8058ab4 100644
--- a/src/1Lab/Type.lagda.md
+++ b/src/1Lab/Type.lagda.md
@@ -49,6 +49,10 @@ data ⊥ : Type where
absurd : ∀ {ℓ} {A : Type ℓ} → ⊥ → A
absurd ()
+
+¬_ : ∀ {ℓ} → Type ℓ → Type ℓ
+¬ A = A → ⊥
+infix 3 ¬_
```
The non-dependent product type `_×_`{.Agda} can be defined in terms of
@@ -112,12 +116,5 @@ f $ₛ x = f x
diff --git a/src/1Lab/Type/Pi.lagda.md b/src/1Lab/Type/Pi.lagda.md
index 76395483b..5bb2b8c94 100644
--- a/src/1Lab/Type/Pi.lagda.md
+++ b/src/1Lab/Type/Pi.lagda.md
@@ -185,5 +185,16 @@ funext²
→ (∀ i j → f i j ≡ g i j)
→ f ≡ g
funext² p i x y = p x y i
+
+funext-square
+ : ∀ {ℓ ℓ′} {A : Type ℓ} {B : A → Type ℓ′}
+ {f00 f01 f10 f11 : (a : A) → B a}
+ {p : f00 ≡ f01}
+ {q : f00 ≡ f10}
+ {s : f01 ≡ f11}
+ {r : f10 ≡ f11}
+ → (∀ a → Square (p $ₚ a) (q $ₚ a) (s $ₚ a) (r $ₚ a))
+ → Square p q s r
+funext-square p i j a = p a i j
```
-->
diff --git a/src/1Lab/Type/Pointed.lagda.md b/src/1Lab/Type/Pointed.lagda.md
new file mode 100644
index 000000000..c906ba9a2
--- /dev/null
+++ b/src/1Lab/Type/Pointed.lagda.md
@@ -0,0 +1,47 @@
+
+
+```agda
+module 1Lab.Type.Pointed where
+```
+
+## Pointed types {defines="pointed pointed-type pointed-map pointed-homotopy"}
+
+A **pointed type** is a type $A$ equipped with a choice of base point $\point{A}$.
+
+```agda
+Type∙ : ∀ ℓ → Type (lsuc ℓ)
+Type∙ ℓ = Σ (Type ℓ) (λ A → A)
+```
+
+
+
+If we have pointed types $(A, a)$ and $(B, b)$, the most natural notion
+of function between them is not simply the type of functions $A \to B$,
+but rather those functions $A \to B$ which _preserve the basepoint_,
+i.e. the functions $f : A \to B$ equipped with paths $f(a) \equiv b$.
+
+```agda
+_→∙_ : Type∙ ℓ → Type∙ ℓ′ → Type _
+(A , a) →∙ (B , b) = Σ[ f ∈ (A → B) ] (f a ≡ b)
+```
+
+Paths between pointed maps are characterised as **pointed homotopies**:
+
+```agda
+funext∙ : {f g : A →∙ B}
+ → (h : ∀ x → f .fst x ≡ g .fst x)
+ → Square (h (A .snd)) (f .snd) (g .snd) refl
+ → f ≡ g
+funext∙ h pth i = funext h i , pth i
+```
diff --git a/src/1Lab/Type/Sigma.lagda.md b/src/1Lab/Type/Sigma.lagda.md
index 03ef364c0..f493a271a 100644
--- a/src/1Lab/Type/Sigma.lagda.md
+++ b/src/1Lab/Type/Sigma.lagda.md
@@ -208,7 +208,10 @@ into an equivalence:
→ {x y : Σ _ B}
→ (x .fst ≡ y .fst) ≃ (x ≡ y)
Σ-prop-path≃ bp = Σ-prop-path bp , Σ-prop-path-is-equiv bp
+```
+
## Dependent sums of contractibles
diff --git a/src/1Lab/Underlying.agda b/src/1Lab/Underlying.agda
index 97354cddb..f22d934d2 100644
--- a/src/1Lab/Underlying.agda
+++ b/src/1Lab/Underlying.agda
@@ -14,6 +14,10 @@ open Underlying ⦃ ... ⦄ using (⌞_⌟) public
open Underlying using (ℓ-underlying)
instance
+ Underlying-Type : ∀ {ℓ} → Underlying (Type ℓ)
+ Underlying-Type {ℓ} .ℓ-underlying = ℓ
+ Underlying-Type .⌞_⌟ x = x
+
Underlying-n-Type : ∀ {ℓ n} → Underlying (n-Type ℓ n)
Underlying-n-Type {ℓ} .ℓ-underlying = ℓ
Underlying-n-Type .⌞_⌟ x = ∣ x ∣
diff --git a/src/Algebra/Group/Concrete.lagda.md b/src/Algebra/Group/Concrete.lagda.md
new file mode 100644
index 000000000..ffb27bc9e
--- /dev/null
+++ b/src/Algebra/Group/Concrete.lagda.md
@@ -0,0 +1,421 @@
+
+
+```agda
+module Algebra.Group.Concrete where
+```
+
+
+
+# Concrete groups {defines="concrete-group"}
+
+In homotopy type theory, we can give an alternative definition of [[groups]]:
+they are the [[pointed|pointed type]], [[connected]] [[groupoids]].
+The idea is that those groupoids contain exactly the same information as their
+[[fundamental group]].
+
+Such groups are dubbed **concrete**, because they represent the groups of symmetries
+of a given object (the base point); by opposition, "algebraic" `Group`{.Agda}s are
+called **abstract**.
+
+```agda
+record ConcreteGroup ℓ : Type (lsuc ℓ) where
+ no-eta-equality
+ constructor concrete-group
+ field
+ B : Type∙ ℓ
+ has-is-connected : is-connected∙ B
+ has-is-groupoid : is-groupoid ⌞ B ⌟
+
+ pt : ⌞ B ⌟
+ pt = B .snd
+```
+
+Given a concrete group $G$, the underlying pointed type is denoted $\B{G}$, by analogy
+with the [[delooping]] of an abstract group; note that, here, the delooping *is* the
+chosen representation of $G$, so `B`{.Agda} is just a record field.
+We write $\point{G}$ for the base point.
+
+Concrete groups are pointed connected types, so they enjoy the following elimination
+principle, which will be useful later:
+
+```agda
+ B-elim-contr : {P : ⌞ B ⌟ → Type ℓ′}
+ → is-contr (P pt)
+ → ∀ x → P x
+ B-elim-contr {P = P} c = connected∙-elim-prop {P = P} has-is-connected
+ (is-contr→is-prop c) (c .centre)
+```
+
+
+
+A central example of a concrete group is the [[circle]]: the delooping of the [[integers]].
+
+```agda
+S¹-is-groupoid : is-groupoid S¹
+S¹-is-groupoid = connected∙-elim-prop S¹-is-connected hlevel!
+ $ connected∙-elim-prop S¹-is-connected hlevel!
+ $ is-hlevel≃ 2 ΩS¹≃integers (hlevel 2)
+
+S¹-concrete : ConcreteGroup lzero
+S¹-concrete .B = S¹ , base
+S¹-concrete .has-is-connected = S¹-is-connected
+S¹-concrete .has-is-groupoid = S¹-is-groupoid
+```
+
+## The category of concrete groups
+
+Concrete groups naturally form a [[category]], where the morphisms are given by
+[[pointed maps]] $\B{G} \to \B{H}$.
+
+```agda
+ConcreteGroups : ∀ ℓ → Precategory (lsuc ℓ) ℓ
+ConcreteGroups ℓ .Ob = ConcreteGroup ℓ
+ConcreteGroups _ .Hom G H = B G →∙ B H
+```
+
+We immediately see one reason why the pointedness condition is needed: without it,
+the morphisms between concrete groups would not form a set.
+
+```agda
+ConcreteGroups _ .Hom-set G H (f , ptf) (g , ptg) p q =
+ Σ-set-square hlevel! (funext-square (B-elim-contr G square))
+ where
+ open ConcreteGroup H using (H-Level-B)
+ square : is-contr ((λ j → p j .fst (pt G)) ≡ (λ j → q j .fst (pt G)))
+ square .centre i j = hcomp (∂ i ∨ ∂ j) λ where
+ k (k = i0) → pt H
+ k (i = i0) → p j .snd (~ k)
+ k (i = i1) → q j .snd (~ k)
+ k (j = i0) → ptf (~ k)
+ k (j = i1) → ptg (~ k)
+ square .paths _ = H .has-is-groupoid _ _ _ _ _ _
+```
+
+
+The rest of the categorical structure is inherited from functions and paths in a
+straightforward way.
+
+
+```agda
+ConcreteGroups _ .id = (λ x → x) , refl
+ConcreteGroups _ ._∘_ (f , ptf) (g , ptg) = f ⊙ g , ap f ptg ∙ ptf
+ConcreteGroups _ .idr f = Σ-pathp refl (∙-id-l _)
+ConcreteGroups _ .idl f = Σ-pathp refl (∙-id-r _)
+ConcreteGroups _ .assoc (f , ptf) (g , ptg) (h , pth) = Σ-pathp refl $
+ ⌜ ap f (ap g pth ∙ ptg) ⌝ ∙ ptf ≡⟨ ap! (ap-∙ f _ _) ⟩
+ (ap (f ⊙ g) pth ∙ ap f ptg) ∙ ptf ≡⟨ sym (∙-assoc _ _ _) ⟩
+ ap (f ⊙ g) pth ∙ ap f ptg ∙ ptf ∎
+```
+