From 96fb1d3a3b76400fb3201cde0d393373f0515803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 23 Mar 2018 10:08:28 +0100 Subject: [PATCH 01/93] Formatting --- src/Cat/Category/Monad/Voevodsky.agda | 30 +++++++++++---------------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/Cat/Category/Monad/Voevodsky.agda b/src/Cat/Category/Monad/Voevodsky.agda index f30aa9a..dfcdbda 100644 --- a/src/Cat/Category/Monad/Voevodsky.agda +++ b/src/Cat/Category/Monad/Voevodsky.agda @@ -72,12 +72,12 @@ module voe {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where } field - isMnd : IsMonad rawMnd + isMonad : IsMonad rawMnd toMonad : Monad toMonad = record { raw = rawMnd - ; isMonad = isMnd + ; isMonad = isMonad } record §2 : Set ℓ where @@ -94,36 +94,30 @@ module voe {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where } field - isMnd : IsMonad rawMnd + isMonad : IsMonad rawMnd toMonad : Monad toMonad = record { raw = rawMnd - ; isMonad = isMnd + ; isMonad = isMonad } §1-fromMonad : (m : M.Monad) → §2-3.§1 (M.Monad.Romap m) (λ {X} → M.Monad.pureT m X) - -- voe-2-3-1-fromMonad : (m : M.Monad) → voe.§2-3.§1 (M.Monad.Romap m) (λ {X} → M.Monad.pureT m X) §1-fromMonad m = record - { fmap = Functor.fmap R + { fmap = Functor.fmap R ; RisFunctor = Functor.isFunctor R - ; pureN = pureN - ; join = λ {X} → joinT X - ; joinN = joinN - ; isMnd = M.Monad.isMonad m + ; pureN = pureN + ; join = λ {X} → joinT X + ; joinN = joinN + ; isMonad = M.Monad.isMonad m } where - raw = M.Monad.raw m - R = M.RawMonad.R raw - pureT = M.RawMonad.pureT raw - pureN = M.RawMonad.pureN raw - joinT = M.RawMonad.joinT raw - joinN = M.RawMonad.joinN raw + open M.Monad m §2-fromMonad : (m : K.Monad) → §2-3.§2 (K.Monad.omap m) (K.Monad.pure m) §2-fromMonad m = record - { bind = K.Monad.bind m - ; isMnd = K.Monad.isMonad m + { bind = K.Monad.bind m + ; isMonad = K.Monad.isMonad m } -- | In the following we seek to transform the equivalence `Monoidal≃Kleisli` From c8c61a8d03a86906ec926bf6250f0b08fe487ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 23 Mar 2018 11:11:44 +0100 Subject: [PATCH 02/93] Half-time report --- proposal/halftime.tex | 108 +++++++++++++++++++++++++++++++++++++----- proposal/macros.tex | 13 ++++- src/Cat/Category.agda | 2 +- 3 files changed, 107 insertions(+), 16 deletions(-) diff --git a/proposal/halftime.tex b/proposal/halftime.tex index 11dc836..96f6094 100644 --- a/proposal/halftime.tex +++ b/proposal/halftime.tex @@ -81,7 +81,7 @@ Definition of what it means for an object to be a product in a given category. Definition of what it means for a category to have all products. -\WIP Prove propositionality for being a product and having products. +\WIP{} Prove propositionality for being a product and having products. \subsubsection{Exponentials} Definition of what it means to be an exponential object. @@ -132,25 +132,45 @@ Propositionality proofs and equality principle is provided. \subsubsubsection{Voevodsky's construction} -Provides construction 2.3 as presented in an unpublished paper by the late -Vladimir Voevodsky. This construction is similiar to the equivalence provided -for the two preceding formulations +Provides construction 2.3 as presented in an unpublished paper by Vladimir +Voevodsky. This construction is similiar to the equivalence provided for the two +preceding formulations \footnote{ TODO: I would like to include in the thesis some motivation for why this construction is particularly interesting.} \subsubsection{Homotopy sets} The typical category of sets where the objects are modelled by an Agda set -(henceforth ``type'') at a given level is not a valid category in this cubical -settings, we need to restrict the types to be those that are homotopy sets. Thus the objects of this category are: +(henceforth ``$\Type$'') at a given level is not a valid category in this cubical +settings, we need to restrict the types to be those that are homotopy sets. Thus +the objects of this category are: % -$$\Set_\ell \defeq \sum_{A \tp \MCU_\ell} \isSet\ A$$ +$$\hSet_\ell \defeq \sum_{A \tp \MCU_\ell} \isSet\ A$$ % -\WIP{} I'm still missing a few details for the proof that this category is -univalent. Indeed this doesn't not follow immediately from +The definition of univalence for categories I have defined is: % -$$\mathit{univalence} \tp (A \cong B) \simeq (A \simeq B)$$ +$$\isEquiv\ (\hA \equiv \hB)\ (\hA \cong \hB)\ \idToIso$$ % -since $A$ and $B$ are of type $\MCU \neq \Set$. +Where $\hA and \hB$ denote objects in the category. Note that this is stronger +than +% +$$(\hA \equiv \hB) \simeq (\hA \cong \hB)$$ +% +Because we require that the equivalence is constructed from the witness to: +% +$$\id \comp f \equiv f \x f \comp \id \equiv f$$ +% +And indeed univalence does not follow immediately from univalence for types: +% +$$(A \equiv B) \simeq (A \simeq B)$$ +% +Because $A\ B \tp \Type$ whereas $\hA\ \hB \tp \hSet$. + +For this reason I have shown that this category satisfies the following +equivalent formulation of being univalent: +% +$$\prod_{A \tp hSet} \isContr \left( \sum_{X \tp hSet} A \cong X \right)$$ +% +But I have not shown that it is indeed equivalent to my former definition. \subsubsection{Categories} Note that this category does in fact not exist. In stead I provide the definition of the ``raw'' category as well as some of the laws. @@ -169,9 +189,71 @@ the set of presheaf categories. \WIP{} I have not shown that the category of functors is univalent. \subsubsection{Relations} -The category of relations. \WIP I have not shown that this category is +The category of relations. \WIP{} I have not shown that this category is univalent. Not sure I intend to do so either. \subsubsection{Free category} -The free category of a category. \WIP I have not shown that this category is +The free category of a category. \WIP{} I have not shown that this category is univalent. + +\subsection{Current Challenges} +Besides the items marked \WIP{} above I still feel a bit unsure about what to +include in my report. Most of my work so far has been specifically about +developing this library. Some ideas: +% +\begin{itemize} +\item + Modularity properties +\item + Compare with setoid-approach to solve similiar problems. +\item + How to structure an implementation to best deal with types that have no + structure (propositions) and those that do (sets and everything above) +\end{itemize} +% +\subsection{Ideas for future developments} +\subsubsection{Higher categories} +I only have a notion of (1-)categories. Perhaps it would be nice to also +formalize higher categories. + +\subsubsection{Hierarchy of concepts related to monads} +In Haskell the type-class Monad sits in a hierarchy atop the notion of a functor +and applicative functors. There's probably a similiar notion in the +category-theoretic approach to developing this. + +As I have already defined monads from these two perspectives, it would be +interesting to take this idea even further and actually show how monads are +related to applicative functors and functors. I'm not entirely sure how this +would look in Agda though. + +\subsubsection{Use formulation on the standard library} +I also thought it would be interesting to use this library to show certain +properties about functors, applicative functors and monads used in the Agda +Standard library. So I went ahead and tried to show that agda's standard +library's notion of a functor (along with suitable laws) is equivalent to my +formulation (in the category of homotopic sets). I ran into two problems here, +however; the first one is that the standard library's notion of a functor is +indexed by the object map: +% +$$ +\Functor & \tp (\Type \to \Type) \to \Type +$$ +% +Where $\Functor\ F$ has the member: +% +$$ +\fmap \tp (A \to B) \to F A \to F B +$$ +% +Whereas the object map in my definition is existentially quantified: +% +$$ +\Functor & \tp \Type +$$ +% +And $\Functor$ has these members: +\begin{align*} +F & \tp \Type \to \Type \\ +\fmap & \tp (A \to B) \to F A \to F B\} +\end{align*} +% diff --git a/proposal/macros.tex b/proposal/macros.tex index 2653ac3..9384ae6 100644 --- a/proposal/macros.tex +++ b/proposal/macros.tex @@ -19,8 +19,17 @@ \newcommand{\idFun}{\mathit{id}} \newcommand{\Sets}{\mathit{Sets}} \newcommand{\Set}{\mathit{Set}} +\newcommand{\hSet}{\mathit{hSet}} +\newcommand{\Type}{\mathcal{U}} +\newcommand{\isEquiv}{\mathit{isEquiv}} +\newcommand{\idToIso}{\mathit{idToIso}} \newcommand{\MCU}{\UU} \newcommand{\isSet}{\mathit{isSet}} -\newcommand{\tp}{\;\mathord{:}\;} +\newcommand{\isContr}{\mathit{isContr}} +\newcommand{\id}{\mathit{id}} +\newcommand{\tp}{\,\mathord{:}\,} +\newcommand\hA{\mathit{hA}} +\newcommand\hB{\mathit{hB}} +\newcommand\Functor{\mathit{Functor}} \newcommand{\subsubsubsection}[1]{\textbf{#1}} -\newcommand{\WIP}[1]{\textbf{[WIP]}} +\newcommand{\WIP}{\textbf{WIP}} diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 70eb654..a603599 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -113,7 +113,7 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where module Univalence (isIdentity : IsIdentity 𝟙) where -- | The identity isomorphism idIso : (A : Object) → A ≅ A - idIso A = 𝟙 , (𝟙 , isIdentity) + idIso A = 𝟙 , 𝟙 , isIdentity -- | Extract an isomorphism from an equality -- From 8ff93e04ec600a3c35b0232ca99296b93f399afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 23 Mar 2018 11:13:52 +0100 Subject: [PATCH 03/93] Move proposal to doc/ --- .gitignore | 1 - {proposal => doc}/.gitignore | 0 {proposal => doc}/BACKLOG.md | 0 {proposal => doc}/Makefile | 0 {proposal => doc}/chalmerstitle.sty | 0 {proposal => doc}/halftime.tex | 0 {proposal => doc}/macros.tex | 0 {proposal => doc}/planning.tex | 0 {proposal => doc}/proposal.tex | 0 {proposal => doc}/refs.bib | 0 report/.gitignore | 1 - report/Makefile | 40 ------------- report/cat.md | 90 ----------------------------- report/refs.bib | 42 -------------- 14 files changed, 174 deletions(-) delete mode 100644 .gitignore rename {proposal => doc}/.gitignore (100%) rename {proposal => doc}/BACKLOG.md (100%) rename {proposal => doc}/Makefile (100%) rename {proposal => doc}/chalmerstitle.sty (100%) rename {proposal => doc}/halftime.tex (100%) rename {proposal => doc}/macros.tex (100%) rename {proposal => doc}/planning.tex (100%) rename {proposal => doc}/proposal.tex (100%) rename {proposal => doc}/refs.bib (100%) delete mode 100644 report/.gitignore delete mode 100644 report/Makefile delete mode 100644 report/cat.md delete mode 100644 report/refs.bib diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 6f49e84..0000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -references/ diff --git a/proposal/.gitignore b/doc/.gitignore similarity index 100% rename from proposal/.gitignore rename to doc/.gitignore diff --git a/proposal/BACKLOG.md b/doc/BACKLOG.md similarity index 100% rename from proposal/BACKLOG.md rename to doc/BACKLOG.md diff --git a/proposal/Makefile b/doc/Makefile similarity index 100% rename from proposal/Makefile rename to doc/Makefile diff --git a/proposal/chalmerstitle.sty b/doc/chalmerstitle.sty similarity index 100% rename from proposal/chalmerstitle.sty rename to doc/chalmerstitle.sty diff --git a/proposal/halftime.tex b/doc/halftime.tex similarity index 100% rename from proposal/halftime.tex rename to doc/halftime.tex diff --git a/proposal/macros.tex b/doc/macros.tex similarity index 100% rename from proposal/macros.tex rename to doc/macros.tex diff --git a/proposal/planning.tex b/doc/planning.tex similarity index 100% rename from proposal/planning.tex rename to doc/planning.tex diff --git a/proposal/proposal.tex b/doc/proposal.tex similarity index 100% rename from proposal/proposal.tex rename to doc/proposal.tex diff --git a/proposal/refs.bib b/doc/refs.bib similarity index 100% rename from proposal/refs.bib rename to doc/refs.bib diff --git a/report/.gitignore b/report/.gitignore deleted file mode 100644 index acf395a..0000000 --- a/report/.gitignore +++ /dev/null @@ -1 +0,0 @@ -cat.pdf diff --git a/report/Makefile b/report/Makefile deleted file mode 100644 index 0e61431..0000000 --- a/report/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -PROJECT = cat -PDF = $(PROJECT).pdf -NOTES = $(PROJECT).md - -preview: report - xdg-open $(PDF) - -report: $(PDF) - -$(PDF): $(NOTES) - pandoc $(NOTES) \ - -o $(PDF) \ - --latex-engine=xelatex \ - --variable urlcolor=cyan \ - -V papersize:a4 \ - -V geometry:margin=1.5in \ - --filter pandoc-citeproc - -github: README.md - -README.md: $(NOTES) - pandoc $(NOTES) \ - -o README.md - -run: - stack exec lab4 - -build: - stack build - -dist: report - tar \ - --transform "s/^/$(PROJECT)\//" \ - -zcvf $(PROJECT).tar.gz \ - $(SOURCE) \ - LICENSE \ - stack.yaml \ - lab4.cabal \ - Makefile \ - $(PDF) diff --git a/report/cat.md b/report/cat.md deleted file mode 100644 index 6119866..0000000 --- a/report/cat.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -title: Formalizing category theory in Agda - Project description -date: May 27th 2017 -author: Frederik Hanghøj Iversen `` -bibliography: refs.bib ---- - -Background -========== - -Functional extensionality gives rise to a notion of equality of functions not -present in intensional dependent type theory. A type-system called cubical -type-theory is outlined in [@cohen-2016] that recovers the computational -interprtation of the univalence theorem. - -Keywords: The category of sets, limits, colimits, functors, natural -transformations, kleisly category, yoneda lemma, closed cartesian categories, -propositional logic. - - - -Aim -=== - -The aim of the project is two-fold. The first part of the project will be -concerned with formalizing some concepts from category theory in Agda's -type-system. This formalization should aim to incorporate definitions and -theorems that allow us to express the correpondence in the second part: Namely -showing the correpondence between well-typed terms in cubical type theory as -presented in Huber and Thierry's paper and with that of some concepts from Category Theory. - -This latter part is not entirely clear for me yet, I know that all these are relevant keywords: - - * The category, C, of names and substitutions - * Cubical Sets, i.e.: Functors from C to Set (the category of sets) - * Presheaves - * Fibers and fibrations - -These are all formulated in the language of Category Theory. The purpose it to -show what they correspond to in the in Cubical Type Theory. As I understand it -at least the last buzzword on this list corresponds to Type Families. - -I'm not sure how I'll go about expressing this in Agda. I suspect it might -be a matter of demostrating that these two formulations are isomorphic. - -So far I have some experience with at least expressing some categorical -concepts in Agda using this new notion of equality. That is, equaility is in -some sense a continuuous path from a point of some type to another. So at the -moment, my understanding of cubical type theory is just that it has another -notion of equality but is otherwise pretty much the same. - -Timeplan -======== - -The first part of the project will focus on studying and understanding the -foundations for this project namely; familiarizing myself with basic concepts -from category theory, understanding how cubical type theory gives rise to -expressing functional extensionality and the univalence theorem. - -After I have understood these fundamental concepts I will use them in the -formalization of functors, applicative functors, monads, etc.. in Agda. This -should be done before the end of the first semester of the school-year -2017/2018. - -At this point I will also have settled on a direction for the rest of the -project and developed a time-plan for the second phase of the project. But -cerainly it will involve applying the result of phase 1 in some context as -mentioned in [the project aim][aim]. - -Resources -========= - -* Cubical demo by Andrea Vezossi: [@cubical-demo] -* Paper on cubical type theory [@cohen-2016] -* Book on homotopy type theory: [@hott-2013] -* Book on category theory: [@awodey-2006] -* Modal logic - Modal type theory, - see [ncatlab](https://ncatlab.org/nlab/show/modal+type+theory). - -References -========== diff --git a/report/refs.bib b/report/refs.bib deleted file mode 100644 index 855fcf9..0000000 --- a/report/refs.bib +++ /dev/null @@ -1,42 +0,0 @@ -@article{cohen-2016, - author = {Cyril Cohen and - Thierry Coquand and - Simon Huber and - Anders M{\"{o}}rtberg}, - title = - { Cubical Type Theory: - a constructive interpretation of the univalence axiom - }, - journal = {CoRR}, - volume = {abs/1611.02108}, - year = {2016}, - url = {http://arxiv.org/abs/1611.02108}, - timestamp = {Thu, 01 Dec 2016 19:32:08 +0100}, - biburl = {http://dblp.uni-trier.de/rec/bib/journals/corr/CohenCHM16}, - bibsource = {dblp computer science bibliography, http://dblp.org} -} -@book{hott-2013, - author = {The {Univalent Foundations Program}}, - title = {Homotopy Type Theory: Univalent Foundations of Mathematics}, - publisher = {\url{https://homotopytypetheory.org/book}}, - address = {Institute for Advanced Study}, - year = 2013 -} -@book{awodey-2006, - title={Category Theory}, - author={Awodey, S.}, - isbn={9780191513824}, - series={Oxford Logic Guides}, - url={https://books.google.se/books?id=IK\_sIDI2TCwC}, - year={2006}, - publisher={Ebsco Publishing} -} -@misc{cubical-demo, - author = {Andrea Vezzosi}, - title = {Cubical Type Theory Demo}, - year = {2017}, - publisher = {GitHub}, - journal = {GitHub repository}, - howpublished = {\url{https://github.com/Saizan/cubical-demo}}, - commit = {a51d5654c439111110d5b6df3605b0043b10b753} -} \ No newline at end of file From 1dde3f8e747dce6ab29d83b7c236cc2eaf79ade8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 23 Mar 2018 11:22:17 +0100 Subject: [PATCH 04/93] Restructure latex-stuff --- doc/Makefile | 6 +++--- doc/main.tex | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ doc/proposal.tex | 51 ----------------------------------------------- 3 files changed, 55 insertions(+), 54 deletions(-) create mode 100644 doc/main.tex diff --git a/doc/Makefile b/doc/Makefile index 8561a59..4d43828 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -3,7 +3,7 @@ # Originally from : http://tex.stackexchange.com/a/40759 # # Change only the variable below to the name of the main tex file. -PROJNAME=proposal +PROJNAME=univalent-categories # You want latexmk to *always* run, because make does not have all the info. # Also, include non-file targets in .PHONY so they are run regardless of any @@ -36,8 +36,8 @@ all: $(PROJNAME).pdf # -interactive=nonstopmode keeps the pdflatex backend from stopping at a # missing file reference and interactively asking you for an alternative. -$(PROJNAME).pdf: $(PROJNAME).tex - latexmk -pdf -pdflatex="pdflatex -interactive=nonstopmode" -use-make $< +$(PROJNAME).pdf: main.tex + latexmk -jobname=$(PROJNAME) -pdf -pdflatex="pdflatex -interactive=nonstopmode" -use-make $< cleanall: latexmk -C diff --git a/doc/main.tex b/doc/main.tex new file mode 100644 index 0000000..fd5f132 --- /dev/null +++ b/doc/main.tex @@ -0,0 +1,52 @@ +\documentclass{article} + + + +\usepackage[utf8]{inputenc} + +\usepackage{natbib} +\usepackage[hidelinks]{hyperref} + +\usepackage{graphicx} + +\usepackage{parskip} +\usepackage{multicol} +\usepackage{amsmath,amssymb} +\usepackage[toc,page]{appendix} +\usepackage{xspace} + +% \setlength{\parskip}{10pt} + +% \usepackage{tikz} +% \usetikzlibrary{arrows, decorations.markings} + +% \usepackage{chngcntr} +% \counterwithout{figure}{section} + +\usepackage{chalmerstitle} +\input{macros.tex} + +\title{Category Theory and Cubical Type Theory} +\author{Frederik Hanghøj Iversen} +\authoremail{hanghj@student.chalmers.se} +\supervisor{Thierry Coquand} +\supervisoremail{coquand@chalmers.se} +\cosupervisor{Andrea Vezzosi} +\cosupervisoremail{vezzosi@chalmers.se} +\institution{Chalmers University of Technology} + +\begin{document} + +\maketitle + +\input{proposal.tex} + +\bibliographystyle{plainnat} +\nocite{cubical-demo} +\nocite{coquand-2013} +\bibliography{refs} +\begin{appendices} +\input{planning.tex} +\input{halftime.tex} +\end{appendices} +\end{document} diff --git a/doc/proposal.tex b/doc/proposal.tex index 073ecb5..aad24c5 100644 --- a/doc/proposal.tex +++ b/doc/proposal.tex @@ -1,44 +1,3 @@ -\documentclass{article} - - - -\usepackage[utf8]{inputenc} - -\usepackage{natbib} -\usepackage[hidelinks]{hyperref} - -\usepackage{graphicx} - -\usepackage{parskip} -\usepackage{multicol} -\usepackage{amsmath,amssymb} -\usepackage[toc,page]{appendix} -\usepackage{xspace} - -% \setlength{\parskip}{10pt} - -% \usepackage{tikz} -% \usetikzlibrary{arrows, decorations.markings} - -% \usepackage{chngcntr} -% \counterwithout{figure}{section} - -\usepackage{chalmerstitle} -\input{macros.tex} - -\title{Category Theory and Cubical Type Theory} -\author{Frederik Hanghøj Iversen} -\authoremail{hanghj@student.chalmers.se} -\supervisor{Thierry Coquand} -\supervisoremail{coquand@chalmers.se} -\cosupervisor{Andrea Vezzosi} -\cosupervisoremail{vezzosi@chalmers.se} -\institution{Chalmers University of Technology} - -\begin{document} - -\maketitle -% \section{Introduction} % Functional extensionality and univalence is not expressible in @@ -277,13 +236,3 @@ intend to formally implement the language of dependent type theory in this project. The thesis shall conclude with a discussion about the benefits of Cubical Agda. -% -\bibliographystyle{plainnat} -\nocite{cubical-demo} -\nocite{coquand-2013} -\bibliography{refs} -\begin{appendices} -\input{planning.tex} -\input{halftime.tex} -\end{appendices} -\end{document} From a713d560d5b2c5f4e6f172ac364343b182258d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 23 Mar 2018 11:33:55 +0100 Subject: [PATCH 05/93] Preview target --- doc/Makefile | 8 ++++++-- doc/halftime.tex | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/doc/Makefile b/doc/Makefile index 4d43828..c942a7e 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -4,16 +4,20 @@ # # Change only the variable below to the name of the main tex file. PROJNAME=univalent-categories +MAIN=main.tex # You want latexmk to *always* run, because make does not have all the info. # Also, include non-file targets in .PHONY so they are run regardless of any # file of the given name existing. -.PHONY: $(PROJNAME).pdf all clean +.PHONY: $(PROJNAME).pdf all clean preview # The first rule in a Makefile is the one executed by default ("make"). It # should always be the "all" rule, so that "make" and "make all" are identical. all: $(PROJNAME).pdf +preview: $(MAIN) + latexmk -pvc -jobname=$(PROJNAME) -pdf -pdflatex="pdflatex -interactive=nonstopmode" $< + # CUSTOM BUILD RULES # In case you didn't know, '$@' is a variable holding the name of the target, @@ -36,7 +40,7 @@ all: $(PROJNAME).pdf # -interactive=nonstopmode keeps the pdflatex backend from stopping at a # missing file reference and interactively asking you for an alternative. -$(PROJNAME).pdf: main.tex +$(PROJNAME).pdf: $(MAIN) latexmk -jobname=$(PROJNAME) -pdf -pdflatex="pdflatex -interactive=nonstopmode" -use-make $< cleanall: diff --git a/doc/halftime.tex b/doc/halftime.tex index 96f6094..2f3d2fa 100644 --- a/doc/halftime.tex +++ b/doc/halftime.tex @@ -236,7 +236,7 @@ however; the first one is that the standard library's notion of a functor is indexed by the object map: % $$ -\Functor & \tp (\Type \to \Type) \to \Type +\Functor \tp (\Type \to \Type) \to \Type $$ % Where $\Functor\ F$ has the member: @@ -248,7 +248,7 @@ $$ Whereas the object map in my definition is existentially quantified: % $$ -\Functor & \tp \Type +\Functor \tp \Type $$ % And $\Functor$ has these members: From ef688202a2390b2410e06ac17b76e7b80b71b7a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 23 Mar 2018 13:55:03 +0100 Subject: [PATCH 06/93] Move identity functor laws to functor module... and make progress on univalence in the functor category --- src/Cat/Categories/Cat.agda | 24 +----- src/Cat/Categories/Fun.agda | 93 +++++++++++++++++---- src/Cat/Category/Functor.agda | 84 +++++++++++++------ src/Cat/Category/Monad.agda | 4 +- src/Cat/Category/Monad/Kleisli.agda | 2 +- src/Cat/Category/Monad/Monoidal.agda | 6 +- src/Cat/Category/Monad/Voevodsky.agda | 4 +- src/Cat/Category/NaturalTransformation.agda | 2 +- 8 files changed, 148 insertions(+), 71 deletions(-) diff --git a/src/Cat/Categories/Cat.agda b/src/Cat/Categories/Cat.agda index e8a6f73..22b4a27 100644 --- a/src/Cat/Categories/Cat.agda +++ b/src/Cat/Categories/Cat.agda @@ -14,32 +14,12 @@ open import Cat.Categories.Fun -- The category of categories module _ (ℓ ℓ' : Level) where - private - module _ {𝔸 𝔹 ℂ 𝔻 : Category ℓ ℓ'} {F : Functor 𝔸 𝔹} {G : Functor 𝔹 ℂ} {H : Functor ℂ 𝔻} where - assc : F[ H ∘ F[ G ∘ F ] ] ≡ F[ F[ H ∘ G ] ∘ F ] - assc = Functor≡ refl - - module _ {ℂ 𝔻 : Category ℓ ℓ'} {F : Functor ℂ 𝔻} where - ident-r : F[ F ∘ identity ] ≡ F - ident-r = Functor≡ refl - - ident-l : F[ identity ∘ F ] ≡ F - ident-l = Functor≡ refl - RawCat : RawCategory (lsuc (ℓ ⊔ ℓ')) (ℓ ⊔ ℓ') RawCategory.Object RawCat = Category ℓ ℓ' RawCategory.Arrow RawCat = Functor - RawCategory.𝟙 RawCat = identity + RawCategory.𝟙 RawCat = Functors.identity RawCategory._∘_ RawCat = F[_∘_] - private - open RawCategory RawCat - isAssociative : IsAssociative - isAssociative {f = F} {G} {H} = assc {F = F} {G = G} {H = H} - - isIdentity : IsIdentity identity - isIdentity = ident-l , ident-r - -- NB! `ArrowsAreSets RawCat` is *not* provable. The type of functors, -- however, form a groupoid! Therefore there is no (1-)category of -- categories. There does, however, exist a 2-category of 1-categories. @@ -283,7 +263,7 @@ module CatExponential {ℓ : Level} (ℂ 𝔻 : Category ℓ ℓ) where : Functor 𝔸 object → Functor ℂ ℂ → Functor (𝔸 ⊗ ℂ) (object ⊗ ℂ) transpose : Functor 𝔸 object - eq : F[ eval ∘ (parallelProduct transpose (identity {C = ℂ})) ] ≡ F + eq : F[ eval ∘ (parallelProduct transpose (Functors.identity {ℂ = ℂ})) ] ≡ F -- eq : F[ :eval: ∘ {!!} ] ≡ F -- eq : Catℓ [ :eval: ∘ (HasProducts._|×|_ hasProducts transpose (𝟙 Catℓ {o = ℂ})) ] ≡ F -- eq' : (Catℓ [ :eval: ∘ diff --git a/src/Cat/Categories/Fun.agda b/src/Cat/Categories/Fun.agda index 18165d3..140b535 100644 --- a/src/Cat/Categories/Fun.agda +++ b/src/Cat/Categories/Fun.agda @@ -4,7 +4,7 @@ module Cat.Categories.Fun where open import Cat.Prelude open import Cat.Category -open import Cat.Category.Functor hiding (identity) +open import Cat.Category.Functor open import Cat.Category.NaturalTransformation module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : Category ℓd ℓd') where @@ -14,20 +14,18 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C module ℂ = Category ℂ module 𝔻 = Category 𝔻 private - module _ {A B C D : Functor ℂ 𝔻} {θ' : NaturalTransformation A B} - {η' : NaturalTransformation B C} {ζ' : NaturalTransformation C D} where - θ = proj₁ θ' - η = proj₁ η' - ζ = proj₁ ζ' - θNat = proj₂ θ' - ηNat = proj₂ η' - ζNat = proj₂ ζ' - L : NaturalTransformation A D - L = (NT[_∘_] {A} {C} {D} ζ' (NT[_∘_] {A} {B} {C} η' θ')) - R : NaturalTransformation A D - R = (NT[_∘_] {A} {B} {D} (NT[_∘_] {B} {C} {D} ζ' η') θ') - _g⊕f_ = NT[_∘_] {A} {B} {C} - _h⊕g_ = NT[_∘_] {B} {C} {D} + module _ {A B C D : Functor ℂ 𝔻} {θNT : NaturalTransformation A B} + {ηNT : NaturalTransformation B C} {ζNT : NaturalTransformation C D} where + open Σ θNT renaming (proj₁ to θ ; proj₂ to θNat) + open Σ ηNT renaming (proj₁ to η ; proj₂ to ηNat) + open Σ ζNT renaming (proj₁ to ζ ; proj₂ to ζNat) + private + L : NaturalTransformation A D + L = (NT[_∘_] {A} {C} {D} ζNT (NT[_∘_] {A} {B} {C} ηNT θNT)) + R : NaturalTransformation A D + R = (NT[_∘_] {A} {B} {D} (NT[_∘_] {B} {C} {D} ζNT ηNT) θNT) + _g⊕f_ = NT[_∘_] {A} {B} {C} + _h⊕g_ = NT[_∘_] {B} {C} {D} isAssociative : L ≡ R isAssociative = lemSig (naturalIsProp {F = A} {D}) L R (funExt (λ x → 𝔻.isAssociative)) @@ -62,6 +60,71 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C open RawCategory RawFun open Univalence (λ {A} {B} {f} → isIdentity {A} {B} {f}) + private + module _ (F : Functor ℂ 𝔻) where + center : Σ[ G ∈ Object ] (F ≅ G) + center = F , id-to-iso F F refl + + open Σ center renaming (proj₂ to isoF) + + module _ (cG : Σ[ G ∈ Object ] (F ≅ G)) where + open Σ cG renaming (proj₁ to G ; proj₂ to isoG) + module G = Functor G + open Σ isoG renaming (proj₁ to θNT ; proj₂ to invθNT) + open Σ invθNT renaming (proj₁ to ηNT ; proj₂ to areInv) + open Σ θNT renaming (proj₁ to θ ; proj₂ to θN) + open Σ ηNT renaming (proj₁ to η ; proj₂ to ηN) + open Σ areInv renaming (proj₁ to ve-re ; proj₂ to re-ve) + + -- f ~ Transformation G G + -- f : (X : ℂ.Object) → 𝔻 [ G.omap X , G.omap X ] + -- f X = T[ θ ∘ η ] X + -- g = T[ η ∘ θ ] {!!} + + ntF : NaturalTransformation F F + ntF = 𝟙 {A = F} + + ntG : NaturalTransformation G G + ntG = 𝟙 {A = G} + + idFunctor = Functors.identity + + -- Dunno if this is the way to go, but if I can construct a an inverse of + -- G that is also inverse of F (possibly by being propositionally equal to + -- another functor F~) + postulate + G~ : Functor 𝔻 ℂ + F~ : Functor 𝔻 ℂ + F~ = G~ + postulate + prop0 : F[ G~ ∘ G ] ≡ idFunctor + prop1 : F[ F ∘ G~ ] ≡ idFunctor + + lem : F[ F ∘ F~ ] ≡ idFunctor + lem = begin + F[ F ∘ F~ ] ≡⟨⟩ + F[ F ∘ G~ ] ≡⟨ prop1 ⟩ + idFunctor ∎ + + open import Cubical.Univalence + p0 : F ≡ G + p0 = begin + F ≡⟨ sym Functors.rightIdentity ⟩ + F[ F ∘ idFunctor ] ≡⟨ cong (λ φ → F[ F ∘ φ ]) (sym prop0) ⟩ + F[ F ∘ F[ G~ ∘ G ] ] ≡⟨ Functors.isAssociative {F = G} {G = G~} {H = F} ⟩ + F[ F[ F ∘ G~ ] ∘ G ] ≡⟨⟩ + F[ F[ F ∘ F~ ] ∘ G ] ≡⟨ cong (λ φ → F[ φ ∘ G ]) lem ⟩ + F[ idFunctor ∘ G ] ≡⟨ Functors.leftIdentity ⟩ + G ∎ + + p1 : (λ i → Σ (Arrow F (p0 i)) (Isomorphism {A = F} {B = p0 i})) [ isoF ≡ isoG ] + p1 = {!!} + + isContractible : (F , isoF) ≡ (G , isoG) + isContractible i = p0 i , p1 i + + univalent[Contr] : isContr (Σ[ G ∈ Object ] (F ≅ G)) + univalent[Contr] = center , isContractible private module _ {A B : Functor ℂ 𝔻} where diff --git a/src/Cat/Category/Functor.agda b/src/Cat/Category/Functor.agda index 390d8bc..bbdda14 100644 --- a/src/Cat/Category/Functor.agda +++ b/src/Cat/Category/Functor.agda @@ -1,7 +1,7 @@ {-# OPTIONS --cubical #-} module Cat.Category.Functor where -open import Agda.Primitive +open import Cat.Prelude open import Function open import Cubical @@ -9,31 +9,31 @@ open import Cubical.NType.Properties using (lemPropF) open import Cat.Category -open Category hiding (_∘_ ; raw ; IsIdentity) - module _ {ℓc ℓc' ℓd ℓd'} (ℂ : Category ℓc ℓc') (𝔻 : Category ℓd ℓd') where private + module ℂ = Category ℂ + module 𝔻 = Category 𝔻 ℓ = ℓc ⊔ ℓc' ⊔ ℓd ⊔ ℓd' 𝓤 = Set ℓ - Omap = Object ℂ → Object 𝔻 + Omap = ℂ.Object → 𝔻.Object Fmap : Omap → Set _ Fmap omap = ∀ {A B} → ℂ [ A , B ] → 𝔻 [ omap A , omap B ] record RawFunctor : 𝓤 where field - omap : Object ℂ → Object 𝔻 + omap : ℂ.Object → 𝔻.Object fmap : ∀ {A B} → ℂ [ A , B ] → 𝔻 [ omap A , omap B ] IsIdentity : Set _ - IsIdentity = {A : Object ℂ} → fmap (𝟙 ℂ {A}) ≡ 𝟙 𝔻 {omap A} + IsIdentity = {A : ℂ.Object} → fmap (ℂ.𝟙 {A}) ≡ 𝔻.𝟙 {omap A} IsDistributive : Set _ - IsDistributive = {A B C : Object ℂ} {f : ℂ [ A , B ]} {g : ℂ [ B , C ]} + IsDistributive = {A B C : ℂ.Object} {f : ℂ [ A , B ]} {g : ℂ [ B , C ]} → fmap (ℂ [ g ∘ f ]) ≡ 𝔻 [ fmap g ∘ fmap f ] -- | Equality principle for raw functors @@ -120,11 +120,18 @@ module _ {ℓc ℓc' ℓd ℓd' : Level} {ℂ : Category ℓc ℓc'} {𝔻 : Cat res : (λ i → IsFunctor ℂ 𝔻 (eq i)) [ isFunctor F ≡ isFunctor G ] res = IsFunctorIsProp' (isFunctor F) (isFunctor G) -module _ {ℓ ℓ' : Level} {A B C : Category ℓ ℓ'} (F : Functor B C) (G : Functor A B) where +module _ {ℓ0 ℓ1 ℓ2 ℓ3 ℓ4 ℓ5 : Level} + {A : Category ℓ0 ℓ1} + {B : Category ℓ2 ℓ3} + {C : Category ℓ4 ℓ5} + (F : Functor B C) (G : Functor A B) where private + module A = Category A + module B = Category B + module C = Category C module F = Functor F module G = Functor G - module _ {a0 a1 a2 : Object A} {α0 : A [ a0 , a1 ]} {α1 : A [ a1 , a2 ]} where + module _ {a0 a1 a2 : A.Object} {α0 : A [ a0 , a1 ]} {α1 : A [ a1 , a2 ]} where dist : (F.fmap ∘ G.fmap) (A [ α1 ∘ α0 ]) ≡ C [ (F.fmap ∘ G.fmap) α1 ∘ (F.fmap ∘ G.fmap) α0 ] dist = begin (F.fmap ∘ G.fmap) (A [ α1 ∘ α0 ]) @@ -143,10 +150,10 @@ module _ {ℓ ℓ' : Level} {A B C : Category ℓ ℓ'} (F : Functor B C) (G : F isFunctor : IsFunctor A C raw isFunctor = record { isIdentity = begin - (F.fmap ∘ G.fmap) (𝟙 A) ≡⟨ refl ⟩ - F.fmap (G.fmap (𝟙 A)) ≡⟨ cong F.fmap (G.isIdentity)⟩ - F.fmap (𝟙 B) ≡⟨ F.isIdentity ⟩ - 𝟙 C ∎ + (F.fmap ∘ G.fmap) A.𝟙 ≡⟨ refl ⟩ + F.fmap (G.fmap A.𝟙) ≡⟨ cong F.fmap (G.isIdentity)⟩ + F.fmap B.𝟙 ≡⟨ F.isIdentity ⟩ + C.𝟙 ∎ ; isDistributive = dist } @@ -154,15 +161,42 @@ module _ {ℓ ℓ' : Level} {A B C : Category ℓ ℓ'} (F : Functor B C) (G : F Functor.raw F[_∘_] = raw Functor.isFunctor F[_∘_] = isFunctor --- The identity functor -identity : ∀ {ℓ ℓ'} → {C : Category ℓ ℓ'} → Functor C C -identity = record - { raw = record - { omap = λ x → x - ; fmap = λ x → x - } - ; isFunctor = record - { isIdentity = refl - ; isDistributive = refl - } - } +-- | The identity functor +module Functors where + module _ {ℓc ℓcc : Level} {ℂ : Category ℓc ℓcc} where + private + raw : RawFunctor ℂ ℂ + RawFunctor.omap raw = Function.id + RawFunctor.fmap raw = Function.id + + isFunctor : IsFunctor ℂ ℂ raw + IsFunctor.isIdentity isFunctor = refl + IsFunctor.isDistributive isFunctor = refl + + identity : Functor ℂ ℂ + Functor.raw identity = raw + Functor.isFunctor identity = isFunctor + + module _ + {ℓa ℓaa ℓb ℓbb ℓc ℓcc ℓd ℓdd : Level} + {𝔸 : Category ℓa ℓaa} + {𝔹 : Category ℓb ℓbb} + {ℂ : Category ℓc ℓcc} + {𝔻 : Category ℓd ℓdd} + {F : Functor 𝔸 𝔹} {G : Functor 𝔹 ℂ} {H : Functor ℂ 𝔻} where + isAssociative : F[ H ∘ F[ G ∘ F ] ] ≡ F[ F[ H ∘ G ] ∘ F ] + isAssociative = Functor≡ refl + + module _ + {ℓc ℓcc ℓd ℓdd : Level} + {ℂ : Category ℓc ℓcc} + {𝔻 : Category ℓd ℓdd} + {F : Functor ℂ 𝔻} where + leftIdentity : F[ identity ∘ F ] ≡ F + leftIdentity = Functor≡ refl + + rightIdentity : F[ F ∘ identity ] ≡ F + rightIdentity = Functor≡ refl + + isIdentity : F[ identity ∘ F ] ≡ F × F[ F ∘ identity ] ≡ F + isIdentity = leftIdentity , rightIdentity diff --git a/src/Cat/Category/Monad.agda b/src/Cat/Category/Monad.agda index 3b65149..d2aa713 100644 --- a/src/Cat/Category/Monad.agda +++ b/src/Cat/Category/Monad.agda @@ -176,9 +176,9 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where pureTEq : M.RawMonad.pureT (backRaw (forth m)) ≡ pureT pureTEq = funExt (λ X → refl) - pureNTEq : (λ i → NaturalTransformation F.identity (Req i)) + pureNTEq : (λ i → NaturalTransformation Functors.identity (Req i)) [ M.RawMonad.pureNT (backRaw (forth m)) ≡ pureNT ] - pureNTEq = lemSigP (λ i → propIsNatural F.identity (Req i)) _ _ pureTEq + pureNTEq = lemSigP (λ i → propIsNatural Functors.identity (Req i)) _ _ pureTEq joinTEq : M.RawMonad.joinT (backRaw (forth m)) ≡ joinT joinTEq = funExt (λ X → begin diff --git a/src/Cat/Category/Monad/Kleisli.agda b/src/Cat/Category/Monad/Kleisli.agda index 7377cdf..be48a8d 100644 --- a/src/Cat/Category/Monad/Kleisli.agda +++ b/src/Cat/Category/Monad/Kleisli.agda @@ -119,7 +119,7 @@ record IsMonad (raw : RawMonad) : Set ℓ where open NaturalTransformation ℂ ℂ R⁰ : EndoFunctor ℂ - R⁰ = F.identity + R⁰ = Functors.identity R² : EndoFunctor ℂ R² = F[ R ∘ R ] module R = Functor R diff --git a/src/Cat/Category/Monad/Monoidal.agda b/src/Cat/Category/Monad/Monoidal.agda index 360e5df..4270323 100644 --- a/src/Cat/Category/Monad/Monoidal.agda +++ b/src/Cat/Category/Monad/Monoidal.agda @@ -22,14 +22,14 @@ open NaturalTransformation ℂ ℂ record RawMonad : Set ℓ where field R : EndoFunctor ℂ - pureNT : NaturalTransformation F.identity R + pureNT : NaturalTransformation Functors.identity R joinNT : NaturalTransformation F[ R ∘ R ] R -- Note that `pureT` and `joinT` differs from their definition in the -- kleisli formulation only by having an explicit parameter. - pureT : Transformation F.identity R + pureT : Transformation Functors.identity R pureT = proj₁ pureNT - pureN : Natural F.identity R pureT + pureN : Natural Functors.identity R pureT pureN = proj₂ pureNT joinT : Transformation F[ R ∘ R ] R diff --git a/src/Cat/Category/Monad/Voevodsky.agda b/src/Cat/Category/Monad/Voevodsky.agda index dfcdbda..6dfb245 100644 --- a/src/Cat/Category/Monad/Voevodsky.agda +++ b/src/Cat/Category/Monad/Voevodsky.agda @@ -50,9 +50,9 @@ module voe {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where pureT X = pure {X} field - pureN : Natural F.identity R pureT + pureN : Natural Functors.identity R pureT - pureNT : NaturalTransformation F.identity R + pureNT : NaturalTransformation Functors.identity R pureNT = pureT , pureN joinT : (A : Object) → ℂ [ omap (omap A) , omap A ] diff --git a/src/Cat/Category/NaturalTransformation.agda b/src/Cat/Category/NaturalTransformation.agda index 13e3d89..016f9a5 100644 --- a/src/Cat/Category/NaturalTransformation.agda +++ b/src/Cat/Category/NaturalTransformation.agda @@ -26,7 +26,7 @@ open import Data.Nat using (_≤_ ; z≤n ; s≤s) module Nat = Data.Nat open import Cat.Category -open import Cat.Category.Functor hiding (identity) +open import Cat.Category.Functor open import Cat.Wishlist module NaturalTransformation {ℓc ℓc' ℓd ℓd' : Level} From d3864dbae506033c43c58258ca44f19d163ee109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 23 Mar 2018 15:20:26 +0100 Subject: [PATCH 07/93] Move properties about natural transformations to that module --- src/Cat/Categories/Cat.agda | 7 +- src/Cat/Categories/Fun.agda | 171 ++++++++------------ src/Cat/Category/Monad.agda | 5 +- src/Cat/Category/Monad/Kleisli.agda | 4 +- src/Cat/Category/Monad/Monoidal.agda | 3 +- src/Cat/Category/Monad/Voevodsky.agda | 4 +- src/Cat/Category/NaturalTransformation.agda | 148 ++++++++++------- src/Cat/Category/Yoneda.agda | 8 +- 8 files changed, 171 insertions(+), 179 deletions(-) diff --git a/src/Cat/Categories/Cat.agda b/src/Cat/Categories/Cat.agda index 22b4a27..8843914 100644 --- a/src/Cat/Categories/Cat.agda +++ b/src/Cat/Categories/Cat.agda @@ -9,7 +9,7 @@ open import Cat.Category open import Cat.Category.Functor open import Cat.Category.Product open import Cat.Category.Exponential hiding (_×_ ; product) -open import Cat.Category.NaturalTransformation +import Cat.Category.NaturalTransformation open import Cat.Categories.Fun -- The category of categories @@ -155,6 +155,9 @@ module _ {ℓ ℓ' : Level} (unprovable : IsCategory (RawCat ℓ ℓ')) where -- | The category of categories have expoentntials - and because it has products -- it is therefory also cartesian closed. module CatExponential {ℓ : Level} (ℂ 𝔻 : Category ℓ ℓ) where + open Cat.Category.NaturalTransformation ℂ 𝔻 + renaming (identity to identityNT) + using () private module ℂ = Category ℂ module 𝔻 = Category 𝔻 @@ -189,7 +192,7 @@ module CatExponential {ℓ : Level} (ℂ 𝔻 : Category ℓ ℓ) where module _ {c : Functor ℂ 𝔻 × ℂ.Object} where open Σ c renaming (proj₁ to F ; proj₂ to C) - ident : fmap {c} {c} (NT.identity F , ℂ.𝟙 {A = snd c}) ≡ 𝔻.𝟙 + ident : fmap {c} {c} (identityNT F , ℂ.𝟙 {A = snd c}) ≡ 𝔻.𝟙 ident = begin fmap {c} {c} (Category.𝟙 (object ⊗ ℂ) {c}) ≡⟨⟩ fmap {c} {c} (idN F , ℂ.𝟙) ≡⟨⟩ diff --git a/src/Cat/Categories/Fun.agda b/src/Cat/Categories/Fun.agda index 140b535..791ddc6 100644 --- a/src/Cat/Categories/Fun.agda +++ b/src/Cat/Categories/Fun.agda @@ -5,62 +5,26 @@ open import Cat.Prelude open import Cat.Category open import Cat.Category.Functor -open import Cat.Category.NaturalTransformation module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : Category ℓd ℓd') where - module NT = NaturalTransformation ℂ 𝔻 - open NT public + import Cat.Category.NaturalTransformation ℂ 𝔻 + as NaturalTransformation + open NaturalTransformation public hiding (module Properties) + open NaturalTransformation.Properties private module ℂ = Category ℂ module 𝔻 = Category 𝔻 - private - module _ {A B C D : Functor ℂ 𝔻} {θNT : NaturalTransformation A B} - {ηNT : NaturalTransformation B C} {ζNT : NaturalTransformation C D} where - open Σ θNT renaming (proj₁ to θ ; proj₂ to θNat) - open Σ ηNT renaming (proj₁ to η ; proj₂ to ηNat) - open Σ ζNT renaming (proj₁ to ζ ; proj₂ to ζNat) - private - L : NaturalTransformation A D - L = (NT[_∘_] {A} {C} {D} ζNT (NT[_∘_] {A} {B} {C} ηNT θNT)) - R : NaturalTransformation A D - R = (NT[_∘_] {A} {B} {D} (NT[_∘_] {B} {C} {D} ζNT ηNT) θNT) - _g⊕f_ = NT[_∘_] {A} {B} {C} - _h⊕g_ = NT[_∘_] {B} {C} {D} - isAssociative : L ≡ R - isAssociative = lemSig (naturalIsProp {F = A} {D}) - L R (funExt (λ x → 𝔻.isAssociative)) - private - module _ {A B : Functor ℂ 𝔻} {f : NaturalTransformation A B} where - allNatural = naturalIsProp {F = A} {B} - f' = proj₁ f - eq-r : ∀ C → (𝔻 [ f' C ∘ identityTrans A C ]) ≡ f' C - eq-r C = begin - 𝔻 [ f' C ∘ identityTrans A C ] ≡⟨⟩ - 𝔻 [ f' C ∘ 𝔻.𝟙 ] ≡⟨ 𝔻.rightIdentity ⟩ - f' C ∎ - eq-l : ∀ C → (𝔻 [ identityTrans B C ∘ f' C ]) ≡ f' C - eq-l C = 𝔻.leftIdentity - ident-r : (NT[_∘_] {A} {A} {B} f (NT.identity A)) ≡ f - ident-r = lemSig allNatural _ _ (funExt eq-r) - ident-l : (NT[_∘_] {A} {B} {B} (NT.identity B) f) ≡ f - ident-l = lemSig allNatural _ _ (funExt eq-l) - isIdentity - : (NT[_∘_] {A} {B} {B} (NT.identity B) f) ≡ f - × (NT[_∘_] {A} {A} {B} f (NT.identity A)) ≡ f - isIdentity = ident-l , ident-r - -- Functor categories. Objects are functors, arrows are natural transformations. - RawFun : RawCategory (ℓc ⊔ ℓc' ⊔ ℓd ⊔ ℓd') (ℓc ⊔ ℓc' ⊔ ℓd') - RawFun = record - { Object = Functor ℂ 𝔻 - ; Arrow = NaturalTransformation - ; 𝟙 = λ {F} → NT.identity F - ; _∘_ = λ {F G H} → NT[_∘_] {F} {G} {H} - } + -- Functor categories. Objects are functors, arrows are natural transformations. + raw : RawCategory (ℓc ⊔ ℓc' ⊔ ℓd ⊔ ℓd') (ℓc ⊔ ℓc' ⊔ ℓd') + RawCategory.Object raw = Functor ℂ 𝔻 + RawCategory.Arrow raw = NaturalTransformation + RawCategory.𝟙 raw {F} = identity F + RawCategory._∘_ raw {F} {G} {H} = NT[_∘_] {F} {G} {H} + + open RawCategory raw + open Univalence (λ {A} {B} {f} → isIdentity {F = A} {B} {f}) - open RawCategory RawFun - open Univalence (λ {A} {B} {f} → isIdentity {A} {B} {f}) - private module _ (F : Functor ℂ 𝔻) where center : Σ[ G ∈ Object ] (F ≅ G) center = F , id-to-iso F F refl @@ -126,7 +90,6 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C univalent[Contr] : isContr (Σ[ G ∈ Object ] (F ≅ G)) univalent[Contr] = center , isContractible - private module _ {A B : Functor ℂ 𝔻} where module A = Functor A module B = Functor B @@ -176,69 +139,67 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C fromEq : NaturalTransformation A B fromEq = coe𝟙 , nat - module _ {A B : Functor ℂ 𝔻} where - obverse : A ≡ B → A ≅ B - obverse p = res - where - ob : Arrow A B - ob = fromEq p - re : Arrow B A - re = fromEq (sym p) - vr : _∘_ {A = A} {B} {A} re ob ≡ 𝟙 {A} - vr = {!!} - rv : _∘_ {A = B} {A} {B} ob re ≡ 𝟙 {B} - rv = {!!} - isInverse : IsInverseOf {A} {B} ob re - isInverse = vr , rv - iso : Isomorphism {A} {B} ob - iso = re , isInverse - res : A ≅ B - res = ob , iso + module _ {A B : Functor ℂ 𝔻} where + obverse : A ≡ B → A ≅ B + obverse p = res + where + ob : Arrow A B + ob = fromEq p + re : Arrow B A + re = fromEq (sym p) + vr : _∘_ {A = A} {B} {A} re ob ≡ 𝟙 {A} + vr = {!!} + rv : _∘_ {A = B} {A} {B} ob re ≡ 𝟙 {B} + rv = {!!} + isInverse : IsInverseOf {A} {B} ob re + isInverse = vr , rv + iso : Isomorphism {A} {B} ob + iso = re , isInverse + res : A ≅ B + res = ob , iso - reverse : A ≅ B → A ≡ B - reverse iso = {!!} + reverse : A ≅ B → A ≡ B + reverse iso = {!!} - ve-re : (y : A ≅ B) → obverse (reverse y) ≡ y - ve-re = {!!} + ve-re : (y : A ≅ B) → obverse (reverse y) ≡ y + ve-re = {!!} - re-ve : (x : A ≡ B) → reverse (obverse x) ≡ x - re-ve = {!!} + re-ve : (x : A ≡ B) → reverse (obverse x) ≡ x + re-ve = {!!} - done : isEquiv (A ≡ B) (A ≅ B) (Univalence.id-to-iso (λ { {A} {B} → isIdentity {A} {B}}) A B) - done = {!gradLemma obverse reverse ve-re re-ve!} + done : isEquiv (A ≡ B) (A ≅ B) (Univalence.id-to-iso (λ { {A} {B} → isIdentity {F = A} {B}}) A B) + done = {!gradLemma obverse reverse ve-re re-ve!} - univalent : Univalent - univalent = done + -- univalent : Univalent + -- univalent = done - instance - isCategory : IsCategory RawFun - isCategory = record - { isAssociative = λ {A B C D} → isAssociative {A} {B} {C} {D} - ; isIdentity = λ {A B} → isIdentity {A} {B} - ; arrowsAreSets = λ {F} {G} → naturalTransformationIsSet {F} {G} - ; univalent = univalent - } + isCategory : IsCategory raw + IsCategory.isAssociative isCategory {A} {B} {C} {D} = isAssociative {A} {B} {C} {D} + IsCategory.isIdentity isCategory {A} {B} = isIdentity {A} {B} + IsCategory.arrowsAreSets isCategory {F} {G} = naturalTransformationIsSet {F} {G} + IsCategory.univalent isCategory = {!!} Fun : Category (ℓc ⊔ ℓc' ⊔ ℓd ⊔ ℓd') (ℓc ⊔ ℓc' ⊔ ℓd') - Category.raw Fun = RawFun + Category.raw Fun = raw + Category.isCategory Fun = isCategory -module _ {ℓ ℓ' : Level} (ℂ : Category ℓ ℓ') where - private - open import Cat.Categories.Sets - open NaturalTransformation (opposite ℂ) (𝓢𝓮𝓽 ℓ') +-- module _ {ℓ ℓ' : Level} (ℂ : Category ℓ ℓ') where +-- private +-- open import Cat.Categories.Sets +-- open NaturalTransformation (opposite ℂ) (𝓢𝓮𝓽 ℓ') - -- Restrict the functors to Presheafs. - rawPresh : RawCategory (ℓ ⊔ lsuc ℓ') (ℓ ⊔ ℓ') - rawPresh = record - { Object = Presheaf ℂ - ; Arrow = NaturalTransformation - ; 𝟙 = λ {F} → identity F - ; _∘_ = λ {F G H} → NT[_∘_] {F = F} {G = G} {H = H} - } - instance - isCategory : IsCategory rawPresh - isCategory = Fun.isCategory _ _ +-- -- Restrict the functors to Presheafs. +-- rawPresh : RawCategory (ℓ ⊔ lsuc ℓ') (ℓ ⊔ ℓ') +-- rawPresh = record +-- { Object = Presheaf ℂ +-- ; Arrow = NaturalTransformation +-- ; 𝟙 = λ {F} → identity F +-- ; _∘_ = λ {F G H} → NT[_∘_] {F = F} {G = G} {H = H} +-- } +-- instance +-- isCategory : IsCategory rawPresh +-- isCategory = Fun.isCategory _ _ - Presh : Category (ℓ ⊔ lsuc ℓ') (ℓ ⊔ ℓ') - Category.raw Presh = rawPresh - Category.isCategory Presh = isCategory +-- Presh : Category (ℓ ⊔ lsuc ℓ') (ℓ ⊔ ℓ') +-- Category.raw Presh = rawPresh +-- Category.isCategory Presh = isCategory diff --git a/src/Cat/Category/Monad.agda b/src/Cat/Category/Monad.agda index d2aa713..8fc6c56 100644 --- a/src/Cat/Category/Monad.agda +++ b/src/Cat/Category/Monad.agda @@ -23,7 +23,7 @@ module Cat.Category.Monad where open import Cat.Prelude open import Cat.Category open import Cat.Category.Functor as F -open import Cat.Category.NaturalTransformation +import Cat.Category.NaturalTransformation import Cat.Category.Monad.Monoidal import Cat.Category.Monad.Kleisli open import Cat.Categories.Fun @@ -33,6 +33,7 @@ module Kleisli = Cat.Category.Monad.Kleisli -- | The monoidal- and kleisli presentation of monads are equivalent. module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where + open Cat.Category.NaturalTransformation ℂ ℂ private module ℂ = Category ℂ open ℂ using (Object ; Arrow ; 𝟙 ; _∘_ ; _>>>_) @@ -171,8 +172,6 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where Req : M.RawMonad.R (backRaw (forth m)) ≡ R Req = Functor≡ rawEq - open NaturalTransformation ℂ ℂ - pureTEq : M.RawMonad.pureT (backRaw (forth m)) ≡ pureT pureTEq = funExt (λ X → refl) diff --git a/src/Cat/Category/Monad/Kleisli.agda b/src/Cat/Category/Monad/Kleisli.agda index be48a8d..bf79a5f 100644 --- a/src/Cat/Category/Monad/Kleisli.agda +++ b/src/Cat/Category/Monad/Kleisli.agda @@ -8,11 +8,11 @@ open import Cat.Prelude open import Cat.Category open import Cat.Category.Functor as F -open import Cat.Category.NaturalTransformation open import Cat.Categories.Fun -- "A monad in the Kleisli form" [voe] module Cat.Category.Monad.Kleisli {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where +open import Cat.Category.NaturalTransformation ℂ ℂ hiding (propIsNatural) private ℓ = ℓa ⊔ ℓb module ℂ = Category ℂ @@ -116,8 +116,6 @@ record IsMonad (raw : RawMonad) : Set ℓ where Functor.isFunctor R = isFunctorR private - open NaturalTransformation ℂ ℂ - R⁰ : EndoFunctor ℂ R⁰ = Functors.identity R² : EndoFunctor ℂ diff --git a/src/Cat/Category/Monad/Monoidal.agda b/src/Cat/Category/Monad/Monoidal.agda index 4270323..69f3865 100644 --- a/src/Cat/Category/Monad/Monoidal.agda +++ b/src/Cat/Category/Monad/Monoidal.agda @@ -8,7 +8,6 @@ open import Cat.Prelude open import Cat.Category open import Cat.Category.Functor as F -open import Cat.Category.NaturalTransformation open import Cat.Categories.Fun module Cat.Category.Monad.Monoidal {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where @@ -18,7 +17,7 @@ private ℓ = ℓa ⊔ ℓb open Category ℂ using (Object ; Arrow ; 𝟙 ; _∘_) -open NaturalTransformation ℂ ℂ +open import Cat.Category.NaturalTransformation ℂ ℂ record RawMonad : Set ℓ where field R : EndoFunctor ℂ diff --git a/src/Cat/Category/Monad/Voevodsky.agda b/src/Cat/Category/Monad/Voevodsky.agda index 6dfb245..6563cb8 100644 --- a/src/Cat/Category/Monad/Voevodsky.agda +++ b/src/Cat/Category/Monad/Voevodsky.agda @@ -9,17 +9,17 @@ open import Function open import Cat.Category open import Cat.Category.Functor as F -open import Cat.Category.NaturalTransformation +import Cat.Category.NaturalTransformation open import Cat.Category.Monad open import Cat.Categories.Fun open import Cat.Equivalence module voe {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where + open Cat.Category.NaturalTransformation ℂ ℂ private ℓ = ℓa ⊔ ℓb module ℂ = Category ℂ open ℂ using (Object ; Arrow) - open NaturalTransformation ℂ ℂ module M = Monoidal ℂ module K = Kleisli ℂ diff --git a/src/Cat/Category/NaturalTransformation.agda b/src/Cat/Category/NaturalTransformation.agda index 016f9a5..a478aee 100644 --- a/src/Cat/Category/NaturalTransformation.agda +++ b/src/Cat/Category/NaturalTransformation.agda @@ -18,8 +18,6 @@ -- -- * A composition operator. {-# OPTIONS --allow-unsolved-metas --cubical #-} -module Cat.Category.NaturalTransformation where - open import Cat.Prelude open import Data.Nat using (_≤_ ; z≤n ; s≤s) @@ -29,77 +27,79 @@ open import Cat.Category open import Cat.Category.Functor open import Cat.Wishlist -module NaturalTransformation {ℓc ℓc' ℓd ℓd' : Level} +module Cat.Category.NaturalTransformation + {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : Category ℓd ℓd') where - open Category using (Object ; 𝟙) +open Category using (Object ; 𝟙) +private + module ℂ = Category ℂ + module 𝔻 = Category 𝔻 + +module _ (F G : Functor ℂ 𝔻) where private - module ℂ = Category ℂ - module 𝔻 = Category 𝔻 + module F = Functor F + module G = Functor G + -- What do you call a non-natural tranformation? + Transformation : Set (ℓc ⊔ ℓd') + Transformation = (C : Object ℂ) → 𝔻 [ F.omap C , G.omap C ] - module _ (F G : Functor ℂ 𝔻) where - private - module F = Functor F - module G = Functor G - -- What do you call a non-natural tranformation? - Transformation : Set (ℓc ⊔ ℓd') - Transformation = (C : Object ℂ) → 𝔻 [ F.omap C , G.omap C ] + Natural : Transformation → Set (ℓc ⊔ (ℓc' ⊔ ℓd')) + Natural θ + = {A B : Object ℂ} + → (f : ℂ [ A , B ]) + → 𝔻 [ θ B ∘ F.fmap f ] ≡ 𝔻 [ G.fmap f ∘ θ A ] - Natural : Transformation → Set (ℓc ⊔ (ℓc' ⊔ ℓd')) - Natural θ - = {A B : Object ℂ} - → (f : ℂ [ A , B ]) - → 𝔻 [ θ B ∘ F.fmap f ] ≡ 𝔻 [ G.fmap f ∘ θ A ] + NaturalTransformation : Set (ℓc ⊔ ℓc' ⊔ ℓd') + NaturalTransformation = Σ Transformation Natural - NaturalTransformation : Set (ℓc ⊔ ℓc' ⊔ ℓd') - NaturalTransformation = Σ Transformation Natural + -- Think I need propPi and that arrows are sets + propIsNatural : (θ : _) → isProp (Natural θ) + propIsNatural θ x y i {A} {B} f = 𝔻.arrowsAreSets _ _ (x f) (y f) i - -- Think I need propPi and that arrows are sets - propIsNatural : (θ : _) → isProp (Natural θ) - propIsNatural θ x y i {A} {B} f = 𝔻.arrowsAreSets _ _ (x f) (y f) i + NaturalTransformation≡ : {α β : NaturalTransformation} + → (eq₁ : α .proj₁ ≡ β .proj₁) + → α ≡ β + NaturalTransformation≡ eq = lemSig propIsNatural _ _ eq - NaturalTransformation≡ : {α β : NaturalTransformation} - → (eq₁ : α .proj₁ ≡ β .proj₁) - → α ≡ β - NaturalTransformation≡ eq = lemSig propIsNatural _ _ eq +identityTrans : (F : Functor ℂ 𝔻) → Transformation F F +identityTrans F C = 𝟙 𝔻 - identityTrans : (F : Functor ℂ 𝔻) → Transformation F F - identityTrans F C = 𝟙 𝔻 +identityNatural : (F : Functor ℂ 𝔻) → Natural F F (identityTrans F) +identityNatural F {A = A} {B = B} f = begin + 𝔻 [ identityTrans F B ∘ F→ f ] ≡⟨⟩ + 𝔻 [ 𝟙 𝔻 ∘ F→ f ] ≡⟨ 𝔻.leftIdentity ⟩ + F→ f ≡⟨ sym 𝔻.rightIdentity ⟩ + 𝔻 [ F→ f ∘ 𝟙 𝔻 ] ≡⟨⟩ + 𝔻 [ F→ f ∘ identityTrans F A ] ∎ + where + module F = Functor F + F→ = F.fmap - identityNatural : (F : Functor ℂ 𝔻) → Natural F F (identityTrans F) - identityNatural F {A = A} {B = B} f = begin - 𝔻 [ identityTrans F B ∘ F→ f ] ≡⟨⟩ - 𝔻 [ 𝟙 𝔻 ∘ F→ f ] ≡⟨ 𝔻.leftIdentity ⟩ - F→ f ≡⟨ sym 𝔻.rightIdentity ⟩ - 𝔻 [ F→ f ∘ 𝟙 𝔻 ] ≡⟨⟩ - 𝔻 [ F→ f ∘ identityTrans F A ] ∎ - where - module F = Functor F - F→ = F.fmap +identity : (F : Functor ℂ 𝔻) → NaturalTransformation F F +identity F = identityTrans F , identityNatural F - identity : (F : Functor ℂ 𝔻) → NaturalTransformation F F - identity F = identityTrans F , identityNatural F +module _ {F G H : Functor ℂ 𝔻} where + private + module F = Functor F + module G = Functor G + module H = Functor H + T[_∘_] : Transformation G H → Transformation F G → Transformation F H + T[ θ ∘ η ] C = 𝔻 [ θ C ∘ η C ] - module _ {F G H : Functor ℂ 𝔻} where - private - module F = Functor F - module G = Functor G - module H = Functor H - T[_∘_] : Transformation G H → Transformation F G → Transformation F H - T[ θ ∘ η ] C = 𝔻 [ θ C ∘ η C ] - - NT[_∘_] : NaturalTransformation G H → NaturalTransformation F G → NaturalTransformation F H - proj₁ NT[ (θ , _) ∘ (η , _) ] = T[ θ ∘ η ] - proj₂ NT[ (θ , θNat) ∘ (η , ηNat) ] {A} {B} f = begin - 𝔻 [ T[ θ ∘ η ] B ∘ F.fmap f ] ≡⟨⟩ - 𝔻 [ 𝔻 [ θ B ∘ η B ] ∘ F.fmap f ] ≡⟨ sym 𝔻.isAssociative ⟩ - 𝔻 [ θ B ∘ 𝔻 [ η B ∘ F.fmap f ] ] ≡⟨ cong (λ φ → 𝔻 [ θ B ∘ φ ]) (ηNat f) ⟩ - 𝔻 [ θ B ∘ 𝔻 [ G.fmap f ∘ η A ] ] ≡⟨ 𝔻.isAssociative ⟩ - 𝔻 [ 𝔻 [ θ B ∘ G.fmap f ] ∘ η A ] ≡⟨ cong (λ φ → 𝔻 [ φ ∘ η A ]) (θNat f) ⟩ - 𝔻 [ 𝔻 [ H.fmap f ∘ θ A ] ∘ η A ] ≡⟨ sym 𝔻.isAssociative ⟩ - 𝔻 [ H.fmap f ∘ 𝔻 [ θ A ∘ η A ] ] ≡⟨⟩ - 𝔻 [ H.fmap f ∘ T[ θ ∘ η ] A ] ∎ + NT[_∘_] : NaturalTransformation G H → NaturalTransformation F G → NaturalTransformation F H + proj₁ NT[ (θ , _) ∘ (η , _) ] = T[ θ ∘ η ] + proj₂ NT[ (θ , θNat) ∘ (η , ηNat) ] {A} {B} f = begin + 𝔻 [ T[ θ ∘ η ] B ∘ F.fmap f ] ≡⟨⟩ + 𝔻 [ 𝔻 [ θ B ∘ η B ] ∘ F.fmap f ] ≡⟨ sym 𝔻.isAssociative ⟩ + 𝔻 [ θ B ∘ 𝔻 [ η B ∘ F.fmap f ] ] ≡⟨ cong (λ φ → 𝔻 [ θ B ∘ φ ]) (ηNat f) ⟩ + 𝔻 [ θ B ∘ 𝔻 [ G.fmap f ∘ η A ] ] ≡⟨ 𝔻.isAssociative ⟩ + 𝔻 [ 𝔻 [ θ B ∘ G.fmap f ] ∘ η A ] ≡⟨ cong (λ φ → 𝔻 [ φ ∘ η A ]) (θNat f) ⟩ + 𝔻 [ 𝔻 [ H.fmap f ∘ θ A ] ∘ η A ] ≡⟨ sym 𝔻.isAssociative ⟩ + 𝔻 [ H.fmap f ∘ 𝔻 [ θ A ∘ η A ] ] ≡⟨⟩ + 𝔻 [ H.fmap f ∘ T[ θ ∘ η ] A ] ∎ +module Properties where module _ {F G : Functor ℂ 𝔻} where transformationIsSet : isSet (Transformation F G) transformationIsSet _ _ p q i j C = 𝔻.arrowsAreSets _ _ (λ l → p l C) (λ l → q l C) i j @@ -118,3 +118,31 @@ module NaturalTransformation {ℓc ℓc' ℓd ℓd' : Level} naturalTransformationIsSet : isSet (NaturalTransformation F G) naturalTransformationIsSet = sigPresSet transformationIsSet naturalIsSet + + module _ + {F G H I : Functor ℂ 𝔻} + {θ : NaturalTransformation F G} + {η : NaturalTransformation G H} + {ζ : NaturalTransformation H I} where + -- isAssociative : NT[ ζ ∘ NT[ η ∘ θ ] ] ≡ NT[ NT[ ζ ∘ η ] ∘ θ ] + isAssociative + : NT[_∘_] {F} {H} {I} ζ (NT[_∘_] {F} {G} {H} η θ) + ≡ NT[_∘_] {F} {G} {I} (NT[_∘_] {G} {H} {I} ζ η) θ + isAssociative + = lemSig (naturalIsProp {F = F} {I}) _ _ + (funExt (λ _ → 𝔻.isAssociative)) + + module _ {F G : Functor ℂ 𝔻} {θNT : NaturalTransformation F G} where + private + propNat = naturalIsProp {F = F} {G} + + rightIdentity : (NT[_∘_] {F} {F} {G} θNT (identity F)) ≡ θNT + rightIdentity = lemSig propNat _ _ (funExt (λ _ → 𝔻.rightIdentity)) + + leftIdentity : (NT[_∘_] {F} {G} {G} (identity G) θNT) ≡ θNT + leftIdentity = lemSig propNat _ _ (funExt (λ _ → 𝔻.leftIdentity)) + + isIdentity + : (NT[_∘_] {F} {G} {G} (identity G) θNT) ≡ θNT + × (NT[_∘_] {F} {F} {G} θNT (identity F)) ≡ θNT + isIdentity = leftIdentity , rightIdentity diff --git a/src/Cat/Category/Yoneda.agda b/src/Cat/Category/Yoneda.agda index 47ac1ec..1efc90e 100644 --- a/src/Cat/Category/Yoneda.agda +++ b/src/Cat/Category/Yoneda.agda @@ -6,8 +6,11 @@ open import Cat.Prelude open import Cat.Category open import Cat.Category.Functor +open import Cat.Category.NaturalTransformation + renaming (module Properties to F) + using () -open import Cat.Categories.Fun +open import Cat.Categories.Fun using (module Fun) open import Cat.Categories.Sets hiding (presheaf) -- There is no (small) category of categories. So we won't use _⇑_ from @@ -47,10 +50,11 @@ module _ {ℓ : Level} {ℂ : Category ℓ ℓ} where open RawFunctor rawYoneda hiding (fmap) isIdentity : IsIdentity - isIdentity {c} = lemSig (naturalIsProp {F = presheaf c} {presheaf c}) _ _ eq + isIdentity {c} = lemSig prp _ _ eq where eq : (λ C x → ℂ [ ℂ.𝟙 ∘ x ]) ≡ identityTrans (presheaf c) eq = funExt λ A → funExt λ B → ℂ.leftIdentity + prp = F.naturalIsProp _ _ {F = presheaf c} {presheaf c} isDistributive : IsDistributive isDistributive {A} {B} {C} {f = f} {g} From 9898685491db72fb3151ed18900178b0b206955f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Mon, 26 Mar 2018 14:11:15 +0200 Subject: [PATCH 08/93] Prove that the opposite category is a category --- src/Cat/Category.agda | 86 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 72 insertions(+), 14 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index a603599..09f2e4e 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -57,10 +57,10 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where -- | Operations on data - domain : { a b : Object } → Arrow a b → Object - domain {a = a} _ = a + domain : {a b : Object} → Arrow a b → Object + domain {a} _ = a - codomain : { a b : Object } → Arrow a b → Object + codomain : {a b : Object} → Arrow a b → Object codomain {b = b} _ = b _>>>_ : {A B C : Object} → (Arrow A B) → (Arrow B C) → Arrow A C @@ -92,10 +92,10 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where module _ {A B : Object} where Epimorphism : {X : Object } → (f : Arrow A B) → Set ℓb - Epimorphism {X} f = ( g₀ g₁ : Arrow B X ) → g₀ ∘ f ≡ g₁ ∘ f → g₀ ≡ g₁ + Epimorphism {X} f = (g₀ g₁ : Arrow B X) → g₀ ∘ f ≡ g₁ ∘ f → g₀ ≡ g₁ Monomorphism : {X : Object} → (f : Arrow A B) → Set ℓb - Monomorphism {X} f = ( g₀ g₁ : Arrow X A ) → f ∘ g₀ ≡ f ∘ g₁ → g₀ ≡ g₁ + Monomorphism {X} f = (g₀ g₁ : Arrow X A) → f ∘ g₀ ≡ f ∘ g₁ → g₀ ≡ g₁ IsInitial : Object → Set (ℓa ⊔ ℓb) IsInitial I = {X : Object} → isContr (Arrow I X) @@ -254,6 +254,7 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where isIdentity : (λ _ → IsIdentity 𝟙) [ X.isIdentity ≡ Y.isIdentity ] isIdentity = Prop.propIsIdentity X.isIdentity Y.isIdentity + U : ∀ {a : IsIdentity 𝟙} → (λ _ → IsIdentity 𝟙) [ X.isIdentity ≡ a ] → (b : Univalent a) @@ -339,17 +340,74 @@ module Opposite {ℓa ℓb : Level} where open Univalence isIdentity module _ {A B : ℂ.Object} where + open import Cat.Equivalence as Equivalence hiding (_≅_) + k : Equivalence.Isomorphism (ℂ.id-to-iso A B) + k = Equiv≃.toIso _ _ ℂ.univalent + open Σ k renaming (proj₁ to f ; proj₂ to inv) + open AreInverses inv + + _⊙_ = Function._∘_ + infixr 9 _⊙_ + + -- f : A ℂ.≅ B → A ≡ B + flipDem : A ≅ B → A ℂ.≅ B + flipDem (f , g , inv) = g , f , inv + + flopDem : A ℂ.≅ B → A ≅ B + flopDem (f , g , inv) = g , f , inv + + flipInv : ∀ {x} → (flipDem ⊙ flopDem) x ≡ x + flipInv = refl + + -- Shouldn't be necessary to use `arrowsAreSets` here, but we have it, + -- so why not? + lem : (p : A ≡ B) → id-to-iso A B p ≡ flopDem (ℂ.id-to-iso A B p) + lem p i = l≡r i + where + l = id-to-iso A B p + r = flopDem (ℂ.id-to-iso A B p) + open Σ l renaming (proj₁ to l-obv ; proj₂ to l-areInv) + open Σ l-areInv renaming (proj₁ to l-invs ; proj₂ to l-iso) + open Σ l-iso renaming (proj₁ to l-l ; proj₂ to l-r) + open Σ r renaming (proj₁ to r-obv ; proj₂ to r-areInv) + open Σ r-areInv renaming (proj₁ to r-invs ; proj₂ to r-iso) + open Σ r-iso renaming (proj₁ to r-l ; proj₂ to r-r) + l-obv≡r-obv : l-obv ≡ r-obv + l-obv≡r-obv = refl + l-invs≡r-invs : l-invs ≡ r-invs + l-invs≡r-invs = refl + l-l≡r-l : l-l ≡ r-l + l-l≡r-l = ℂ.arrowsAreSets _ _ l-l r-l + l-r≡r-r : l-r ≡ r-r + l-r≡r-r = ℂ.arrowsAreSets _ _ l-r r-r + l≡r : l ≡ r + l≡r i = l-obv≡r-obv i , l-invs≡r-invs i , l-l≡r-l i , l-r≡r-r i + + ff : A ≅ B → A ≡ B + ff = f ⊙ flipDem + + -- inv : AreInverses (ℂ.id-to-iso A B) f + invv : AreInverses (id-to-iso A B) ff + -- recto-verso : ℂ.id-to-iso A B ∘ f ≡ idFun (A ℂ.≅ B) + invv = record + { verso-recto = funExt (λ x → begin + (ff ⊙ id-to-iso A B) x ≡⟨⟩ + (f ⊙ flipDem ⊙ id-to-iso A B) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → f ⊙ flipDem ⊙ φ) (funExt lem)) ⟩ + (f ⊙ flipDem ⊙ flopDem ⊙ ℂ.id-to-iso A B) x ≡⟨⟩ + (f ⊙ ℂ.id-to-iso A B) x ≡⟨ (λ i → verso-recto i x) ⟩ + x ∎) + ; recto-verso = funExt (λ x → begin + (id-to-iso A B ⊙ f ⊙ flipDem) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → φ ⊙ f ⊙ flipDem) (funExt lem)) ⟩ + (flopDem ⊙ ℂ.id-to-iso A B ⊙ f ⊙ flipDem) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → flopDem ⊙ φ ⊙ flipDem) recto-verso) ⟩ + (flopDem ⊙ flipDem) x ≡⟨⟩ + x ∎) + } + + h : Equivalence.Isomorphism (id-to-iso A B) + h = ff , invv univalent : isEquiv (A ≡ B) (A ≅ B) (Univalence.id-to-iso (swap ℂ.isIdentity) A B) - fst (univalent iso) = flipFiber (fst (ℂ.univalent (flipIso iso))) - where - flipIso : A ≅ B → B ℂ.≅ A - flipIso (f , f~ , iso) = f , f~ , swap iso - flipFiber - : fiber (ℂ.id-to-iso B A) (flipIso iso) - → fiber ( id-to-iso A B) iso - flipFiber (eq , eqIso) = sym eq , {!!} - snd (univalent iso) = {!!} + univalent = Equiv≃.fromIso _ _ h isCategory : IsCategory opRaw IsCategory.isAssociative isCategory = sym ℂ.isAssociative From b7a80d0b86e841d283e75f53b46263788acac2fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 27 Mar 2018 12:20:24 +0200 Subject: [PATCH 09/93] Proof: Being an initial- terminal- object is a mere proposition Also tries to use this to prove that being a product is a mere proposition --- src/Cat/Category.agda | 31 +++++++++ src/Cat/Category/Product.agda | 117 +++++++++++++++++++++++++++++++++- 2 files changed, 147 insertions(+), 1 deletion(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 09f2e4e..556fbd2 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -238,6 +238,37 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc propUnivalent : isProp Univalent propUnivalent a b i = propPi (λ iso → propIsContr) a b i + propIsTerminal : ∀ T → isProp (IsTerminal T) + propIsTerminal T x y i {X} = res X i + where + module _ (X : Object) where + open Σ (x {X}) renaming (proj₁ to fx ; proj₂ to cx) + open Σ (y {X}) renaming (proj₁ to fy ; proj₂ to cy) + fp : fx ≡ fy + fp = cx fy + prop : (x : Arrow X T) → isProp (∀ f → x ≡ f) + prop x = propPi (λ y → arrowsAreSets x y) + cp : (λ i → ∀ f → fp i ≡ f) [ cx ≡ cy ] + cp = lemPropF prop fp + res : (fx , cx) ≡ (fy , cy) + res i = fp i , cp i + + -- Merely the dual of the above statement. + propIsInitial : ∀ I → isProp (IsInitial I) + propIsInitial I x y i {X} = res X i + where + module _ (X : Object) where + open Σ (x {X}) renaming (proj₁ to fx ; proj₂ to cx) + open Σ (y {X}) renaming (proj₁ to fy ; proj₂ to cy) + fp : fx ≡ fy + fp = cx fy + prop : (x : Arrow I X) → isProp (∀ f → x ≡ f) + prop x = propPi (λ y → arrowsAreSets x y) + cp : (λ i → ∀ f → fp i ≡ f) [ cx ≡ cy ] + cp = lemPropF prop fp + res : (fx , cx) ≡ (fy , cy) + res i = fp i , cp i + -- | Propositionality of being a category module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where open RawCategory ℂ diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 1ce45c5..a601ca9 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -1,4 +1,4 @@ -{-# OPTIONS --allow-unsolved-metas #-} +{-# OPTIONS --allow-unsolved-metas --cubical #-} module Cat.Category.Product where open import Cat.Prelude hiding (_×_ ; proj₁ ; proj₂) @@ -118,3 +118,118 @@ module _ {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} {A B : Category.Object propHasProducts : isProp (HasProducts ℂ) propHasProducts = propHasProducts' + +module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} + (let module ℂ = Category ℂ) {A B : ℂ.Object} (p : Product ℂ A B) where + + -- open Product p hiding (raw) + open import Data.Product + + raw : RawCategory _ _ + raw = record + { Object = Σ[ X ∈ ℂ.Object ] ℂ.Arrow X A × ℂ.Arrow X B + ; Arrow = λ{ (A , _) (B , _) → ℂ.Arrow A B} + ; 𝟙 = λ{ {A , _} → ℂ.𝟙 {A}} + ; _∘_ = ℂ._∘_ + } + + open RawCategory raw + open Univalence ℂ.isIdentity + open import Cat.Equivalence hiding (_≅_) + + k : {A B : ℂ.Object} → isEquiv (A ≡ B) (A ℂ.≅ B) (ℂ.id-to-iso A B) + k = ℂ.univalent + + module _ {X' Y' : Σ[ X ∈ ℂ.Object ] (ℂ [ X , A ] × ℂ [ X , B ])} where + open Σ X' renaming (proj₁ to X) using () + open Σ (proj₂ X') renaming (proj₁ to Xxa ; proj₂ to Xxb) + open Σ Y' renaming (proj₁ to Y) using () + open Σ (proj₂ Y') renaming (proj₁ to Yxa ; proj₂ to Yxb) + module _ (p : X ≡ Y) where + D : ∀ y → X ≡ y → Set _ + D y q = ∀ b → (λ i → ℂ [ q i , A ]) [ Xxa ≡ b ] + -- Not sure this is actually provable - but if it were it might involve + -- something like the ump of the product -- in which case perhaps the + -- objects of the category I'm constructing should not merely be the + -- data-part of the product but also the laws. + + -- d : D X refl + d : ∀ b → (λ i → ℂ [ X , A ]) [ Xxa ≡ b ] + d b = {!!} + kk : D Y p + kk = pathJ D d Y p + a : (λ i → ℂ [ p i , A ]) [ Xxa ≡ Yxa ] + a = kk Yxa + b : (λ i → ℂ [ p i , B ]) [ Xxb ≡ Yxb ] + b = {!!} + f : X' ≡ Y' + f i = p i , a i , b i + + module _ (p : X' ≡ Y') where + g : X ≡ Y + g i = proj₁ (p i) + + step0 : (X' ≡ Y') ≃ (X ≡ Y) + step0 = Equiv≃.fromIsomorphism _ _ (g , f , record { verso-recto = {!refl!} ; recto-verso = refl}) + + step1 : (X ≡ Y) ≃ X ℂ.≅ Y + step1 = ℂ.univalent≃ + + -- Just a reminder + step1-5 : (X' ≅ Y') ≡ (X ℂ.≅ Y) + step1-5 = refl + + step2 : (X' ≡ Y') ≃ (X ℂ.≅ Y) + step2 = Equivalence.compose step0 step1 + + univalent : isEquiv (X' ≡ Y') (X ℂ.≅ Y) (id-to-iso X' Y') + univalent = proj₂ step2 + + isCategory : IsCategory raw + isCategory = record + { isAssociative = ℂ.isAssociative + ; isIdentity = ℂ.isIdentity + ; arrowsAreSets = ℂ.arrowsAreSets + ; univalent = univalent + } + + category : Category _ _ + category = record + { raw = raw + ; isCategory = isCategory + } + + open Category category hiding (IsTerminal ; Object) + + -- Essential turns `p : Product ℂ A B` into a triple + productObject : Object + productObject = Product.object p , Product.proj₁ p , Product.proj₂ p + + productObjectIsTerminal : IsTerminal productObject + productObjectIsTerminal = {!!} + + proppp : isProp (IsTerminal productObject) + proppp = Propositionality.propIsTerminal productObject + +module Try1 {ℓa ℓb : Level} (A B : Set) where + open import Data.Product + raw : RawCategory _ _ + raw = record + { Object = Σ[ X ∈ Set ] (X → A) × (X → B) + ; Arrow = λ{ (X0 , f0 , g0) (X1 , f1 , g1) → X0 → X1} + ; 𝟙 = λ x → x + ; _∘_ = λ x x₁ x₂ → x (x₁ x₂) + } + + open RawCategory raw + + isCategory : IsCategory raw + isCategory = record + { isAssociative = refl + ; isIdentity = refl , refl + ; arrowsAreSets = {!!} + ; univalent = {!!} + } + + t : IsTerminal ((A × B) , proj₁ , proj₂) + t = {!!} From facd1167e0c8455e2f790a5fa6df8ebe1fb4eef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 27 Mar 2018 14:18:13 +0200 Subject: [PATCH 10/93] Fix unique existential --- src/Cat/Categories/Cat.agda | 12 +++++++++++- src/Cat/Categories/Sets.agda | 14 +++++++++++++- src/Cat/Prelude.agda | 2 +- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/Cat/Categories/Cat.agda b/src/Cat/Categories/Cat.agda index 8843914..3021268 100644 --- a/src/Cat/Categories/Cat.agda +++ b/src/Cat/Categories/Cat.agda @@ -126,7 +126,17 @@ module CatProduct {ℓ ℓ' : Level} (ℂ 𝔻 : Category ℓ ℓ') where isUniq = isUniqL , isUniqR isProduct : ∃![ x ] (F[ proj₁ ∘ x ] ≡ x₁ × F[ proj₂ ∘ x ] ≡ x₂) - isProduct = x , isUniq + isProduct = x , isUniq , uq + where + module _ {y : Functor X object} (eq : F[ proj₁ ∘ y ] ≡ x₁ × F[ proj₂ ∘ y ] ≡ x₂) where + omapEq : Functor.omap x ≡ Functor.omap y + omapEq = {!!} + -- fmapEq : (λ i → {!{A B : ?} → Arrow A B → 𝔻 [ ? A , ? B ]!}) [ Functor.fmap x ≡ Functor.fmap y ] + -- fmapEq = {!!} + rawEq : Functor.raw x ≡ Functor.raw y + rawEq = {!!} + uq : x ≡ y + uq = Functor≡ rawEq module _ {ℓ ℓ' : Level} (unprovable : IsCategory (RawCat ℓ ℓ')) where private diff --git a/src/Cat/Categories/Sets.agda b/src/Cat/Categories/Sets.agda index 05c64b3..f4c59fd 100644 --- a/src/Cat/Categories/Sets.agda +++ b/src/Cat/Categories/Sets.agda @@ -328,7 +328,19 @@ module _ {ℓ : Level} where isProduct : IsProduct 𝓢 _ _ rawProduct IsProduct.ump isProduct {X = hX} f g - = (f &&& g) , ump hX f g + = f &&& g , ump hX f g , λ eq → funExt (umpUniq eq) + where + open Σ hX renaming (proj₁ to X) using () + module _ {y : X → A × B} (eq : proj₁ Function.∘′ y ≡ f × proj₂ Function.∘′ y ≡ g) (x : X) where + p1 : proj₁ ((f &&& g) x) ≡ proj₁ (y x) + p1 = begin + proj₁ ((f &&& g) x) ≡⟨⟩ + f x ≡⟨ (λ i → sym (proj₁ eq) i x) ⟩ + proj₁ (y x) ∎ + p2 : proj₂ ((f &&& g) x) ≡ proj₂ (y x) + p2 = λ i → sym (proj₂ eq) i x + umpUniq : (f &&& g) x ≡ y x + umpUniq i = p1 i , p2 i product : Product 𝓢 hA hB Product.raw product = rawProduct diff --git a/src/Cat/Prelude.agda b/src/Cat/Prelude.agda index f561330..036d2c7 100644 --- a/src/Cat/Prelude.agda +++ b/src/Cat/Prelude.agda @@ -52,7 +52,7 @@ module _ (ℓ : Level) where ∃! = ∃!≈ _≡_ ∃!-syntax : ∀ {a b} {A : Set a} → (A → Set b) → Set (a ⊔ b) -∃!-syntax = ∃ +∃!-syntax = ∃! syntax ∃!-syntax (λ x → B) = ∃![ x ] B From 8ac6b9721392c5ad9e4881e37b07b26e33f7d5d2 Mon Sep 17 00:00:00 2001 From: Andrea Vezzosi Date: Thu, 29 Mar 2018 00:07:49 +0200 Subject: [PATCH 11/93] isProp (Product C A B) setup --- src/Cat/Category.agda | 7 ++ src/Cat/Category/Product.agda | 213 ++++++++++++++++++---------------- 2 files changed, 120 insertions(+), 100 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 556fbd2..cac045e 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -253,6 +253,10 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc res : (fx , cx) ≡ (fy , cy) res i = fp i , cp i + -- this needs the univalence of the category + propTerminal : isProp Terminal + propTerminal = {!!} + -- Merely the dual of the above statement. propIsInitial : ∀ I → isProp (IsInitial I) propIsInitial I x y i {X} = res X i @@ -269,6 +273,9 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc res : (fx , cx) ≡ (fy , cy) res i = fp i , cp i + propInitial : isProp Initial + propInitial = {!!} + -- | Propositionality of being a category module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where open RawCategory ℂ diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index a601ca9..d2526b1 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -1,6 +1,7 @@ {-# OPTIONS --allow-unsolved-metas --cubical #-} module Cat.Category.Product where +open import Cubical.NType.Properties open import Cat.Prelude hiding (_×_ ; proj₁ ; proj₂) import Data.Product as P @@ -128,108 +129,120 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} raw : RawCategory _ _ raw = record { Object = Σ[ X ∈ ℂ.Object ] ℂ.Arrow X A × ℂ.Arrow X B - ; Arrow = λ{ (A , _) (B , _) → ℂ.Arrow A B} - ; 𝟙 = λ{ {A , _} → ℂ.𝟙 {A}} - ; _∘_ = ℂ._∘_ - } - - open RawCategory raw - open Univalence ℂ.isIdentity - open import Cat.Equivalence hiding (_≅_) - - k : {A B : ℂ.Object} → isEquiv (A ≡ B) (A ℂ.≅ B) (ℂ.id-to-iso A B) - k = ℂ.univalent - - module _ {X' Y' : Σ[ X ∈ ℂ.Object ] (ℂ [ X , A ] × ℂ [ X , B ])} where - open Σ X' renaming (proj₁ to X) using () - open Σ (proj₂ X') renaming (proj₁ to Xxa ; proj₂ to Xxb) - open Σ Y' renaming (proj₁ to Y) using () - open Σ (proj₂ Y') renaming (proj₁ to Yxa ; proj₂ to Yxb) - module _ (p : X ≡ Y) where - D : ∀ y → X ≡ y → Set _ - D y q = ∀ b → (λ i → ℂ [ q i , A ]) [ Xxa ≡ b ] - -- Not sure this is actually provable - but if it were it might involve - -- something like the ump of the product -- in which case perhaps the - -- objects of the category I'm constructing should not merely be the - -- data-part of the product but also the laws. - - -- d : D X refl - d : ∀ b → (λ i → ℂ [ X , A ]) [ Xxa ≡ b ] - d b = {!!} - kk : D Y p - kk = pathJ D d Y p - a : (λ i → ℂ [ p i , A ]) [ Xxa ≡ Yxa ] - a = kk Yxa - b : (λ i → ℂ [ p i , B ]) [ Xxb ≡ Yxb ] - b = {!!} - f : X' ≡ Y' - f i = p i , a i , b i - - module _ (p : X' ≡ Y') where - g : X ≡ Y - g i = proj₁ (p i) - - step0 : (X' ≡ Y') ≃ (X ≡ Y) - step0 = Equiv≃.fromIsomorphism _ _ (g , f , record { verso-recto = {!refl!} ; recto-verso = refl}) - - step1 : (X ≡ Y) ≃ X ℂ.≅ Y - step1 = ℂ.univalent≃ - - -- Just a reminder - step1-5 : (X' ≅ Y') ≡ (X ℂ.≅ Y) - step1-5 = refl - - step2 : (X' ≡ Y') ≃ (X ℂ.≅ Y) - step2 = Equivalence.compose step0 step1 - - univalent : isEquiv (X' ≡ Y') (X ℂ.≅ Y) (id-to-iso X' Y') - univalent = proj₂ step2 - - isCategory : IsCategory raw - isCategory = record - { isAssociative = ℂ.isAssociative - ; isIdentity = ℂ.isIdentity - ; arrowsAreSets = ℂ.arrowsAreSets - ; univalent = univalent - } - - category : Category _ _ - category = record - { raw = raw - ; isCategory = isCategory - } - - open Category category hiding (IsTerminal ; Object) - - -- Essential turns `p : Product ℂ A B` into a triple - productObject : Object - productObject = Product.object p , Product.proj₁ p , Product.proj₂ p - - productObjectIsTerminal : IsTerminal productObject - productObjectIsTerminal = {!!} - - proppp : isProp (IsTerminal productObject) - proppp = Propositionality.propIsTerminal productObject - -module Try1 {ℓa ℓb : Level} (A B : Set) where - open import Data.Product - raw : RawCategory _ _ - raw = record - { Object = Σ[ X ∈ Set ] (X → A) × (X → B) - ; Arrow = λ{ (X0 , f0 , g0) (X1 , f1 , g1) → X0 → X1} - ; 𝟙 = λ x → x - ; _∘_ = λ x x₁ x₂ → x (x₁ x₂) + ; Arrow = λ{ (X , xa , xb) (Y , ya , yb) → Σ[ xy ∈ ℂ.Arrow X Y ] (ℂ [ ya ∘ xy ] ≡ xa) × (ℂ [ yb ∘ xy ] ≡ xb) } + ; 𝟙 = λ{ {A , _} → ℂ.𝟙 {A} , {!!}} + ; _∘_ = \ { (f , p) (g , q) → ℂ._∘_ f g , {!!} } } open RawCategory raw - isCategory : IsCategory raw - isCategory = record - { isAssociative = refl - ; isIdentity = refl , refl - ; arrowsAreSets = {!!} - ; univalent = {!!} - } + cat : IsCategory raw + cat = {!!} - t : IsTerminal ((A × B) , proj₁ , proj₂) - t = {!!} + module cat = IsCategory cat + + lemma : Terminal ≃ Product ℂ A B + lemma = {!!} + + thm : isProp (Product ℂ A B) + thm = equivPreservesNType {n = ⟨-1⟩} lemma cat.Propositionality.propTerminal + +-- open Univalence ℂ.isIdentity +-- open import Cat.Equivalence hiding (_≅_) + +-- k : {A B : ℂ.Object} → isEquiv (A ≡ B) (A ℂ.≅ B) (ℂ.id-to-iso A B) +-- k = ℂ.univalent + +-- module _ {X' Y' : Σ[ X ∈ ℂ.Object ] (ℂ [ X , A ] × ℂ [ X , B ])} where +-- open Σ X' renaming (proj₁ to X) using () +-- open Σ (proj₂ X') renaming (proj₁ to Xxa ; proj₂ to Xxb) +-- open Σ Y' renaming (proj₁ to Y) using () +-- open Σ (proj₂ Y') renaming (proj₁ to Yxa ; proj₂ to Yxb) +-- module _ (p : X ≡ Y) where +-- D : ∀ y → X ≡ y → Set _ +-- D y q = ∀ b → (λ i → ℂ [ q i , A ]) [ Xxa ≡ b ] +-- -- Not sure this is actually provable - but if it were it might involve +-- -- something like the ump of the product -- in which case perhaps the +-- -- objects of the category I'm constructing should not merely be the +-- -- data-part of the product but also the laws. + +-- -- d : D X refl +-- d : ∀ b → (λ i → ℂ [ X , A ]) [ Xxa ≡ b ] +-- d b = {!!} +-- kk : D Y p +-- kk = pathJ D d Y p +-- a : (λ i → ℂ [ p i , A ]) [ Xxa ≡ Yxa ] +-- a = kk Yxa +-- b : (λ i → ℂ [ p i , B ]) [ Xxb ≡ Yxb ] +-- b = {!!} +-- f : X' ≡ Y' +-- f i = p i , a i , b i + +-- module _ (p : X' ≡ Y') where +-- g : X ≡ Y +-- g i = proj₁ (p i) + +-- step0 : (X' ≡ Y') ≃ (X ≡ Y) +-- step0 = Equiv≃.fromIsomorphism _ _ (g , f , record { verso-recto = {!refl!} ; recto-verso = refl}) + +-- step1 : (X ≡ Y) ≃ X ℂ.≅ Y +-- step1 = ℂ.univalent≃ + +-- -- Just a reminder +-- step1-5 : (X' ≅ Y') ≡ (X ℂ.≅ Y) +-- step1-5 = refl + +-- step2 : (X' ≡ Y') ≃ (X ℂ.≅ Y) +-- step2 = Equivalence.compose step0 step1 + +-- univalent : isEquiv (X' ≡ Y') (X ℂ.≅ Y) (id-to-iso X' Y') +-- univalent = proj₂ step2 + +-- isCategory : IsCategory raw +-- isCategory = record +-- { isAssociative = ℂ.isAssociative +-- ; isIdentity = ℂ.isIdentity +-- ; arrowsAreSets = ℂ.arrowsAreSets +-- ; univalent = univalent +-- } + +-- category : Category _ _ +-- category = record +-- { raw = raw +-- ; isCategory = isCategory +-- } + +-- open Category category hiding (IsTerminal ; Object) + +-- -- Essential turns `p : Product ℂ A B` into a triple +-- productObject : Object +-- productObject = Product.object p , Product.proj₁ p , Product.proj₂ p + +-- productObjectIsTerminal : IsTerminal productObject +-- productObjectIsTerminal = {!!} + +-- proppp : isProp (IsTerminal productObject) +-- proppp = Propositionality.propIsTerminal productObject + +-- module Try1 {ℓa ℓb : Level} (A B : Set) where +-- open import Data.Product +-- raw : RawCategory _ _ +-- raw = record +-- { Object = Σ[ X ∈ Set ] (X → A) × (X → B) +-- ; Arrow = λ{ (X0 , f0 , g0) (X1 , f1 , g1) → X0 → X1} +-- ; 𝟙 = λ x → x +-- ; _∘_ = λ x x₁ x₂ → x (x₁ x₂) +-- } + +-- open RawCategory raw + +-- isCategory : IsCategory raw +-- isCategory = record +-- { isAssociative = refl +-- ; isIdentity = refl , refl +-- ; arrowsAreSets = {!!} +-- ; univalent = {!!} +-- } + +-- t : IsTerminal ((A × B) , proj₁ , proj₂) +-- t = {!!} From 8752b1435d53b394fa93752a6950cff197e4a94b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 29 Mar 2018 13:32:06 +0200 Subject: [PATCH 12/93] Update report --- doc/chalmerstitle.sty | 10 +- doc/main.tex | 27 +----- doc/packages.tex | 28 ++++++ doc/proposal.tex | 218 ++++++++++++++---------------------------- doc/refs.bib | 6 ++ 5 files changed, 109 insertions(+), 180 deletions(-) create mode 100644 doc/packages.tex diff --git a/doc/chalmerstitle.sty b/doc/chalmerstitle.sty index c2aa355..76a8111 100644 --- a/doc/chalmerstitle.sty +++ b/doc/chalmerstitle.sty @@ -15,7 +15,7 @@ \begin{center} -{\scshape\LARGE Master thesis project proposal\\} +{\scshape\LARGE Master thesis\\} \vspace{0.5cm} @@ -39,14 +39,6 @@ \vspace{1.5cm} -{\large Relevant completed courses:\par} -{\itshape -Logic in Computer Science -- DAT060\\ -Models of Computation -- TDA184\\ -Research topic in Computer Science -- DAT235\\ -Types for programs and proofs -- DAT140 -} - \vfill {\large \@institution\\\today\\} diff --git a/doc/main.tex b/doc/main.tex index fd5f132..7c84463 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -1,32 +1,9 @@ \documentclass{article} - - -\usepackage[utf8]{inputenc} - -\usepackage{natbib} -\usepackage[hidelinks]{hyperref} - -\usepackage{graphicx} - -\usepackage{parskip} -\usepackage{multicol} -\usepackage{amsmath,amssymb} -\usepackage[toc,page]{appendix} -\usepackage{xspace} - -% \setlength{\parskip}{10pt} - -% \usepackage{tikz} -% \usetikzlibrary{arrows, decorations.markings} - -% \usepackage{chngcntr} -% \counterwithout{figure}{section} - -\usepackage{chalmerstitle} +\input{packages.tex} \input{macros.tex} -\title{Category Theory and Cubical Type Theory} +\title{Univalent categories} \author{Frederik Hanghøj Iversen} \authoremail{hanghj@student.chalmers.se} \supervisor{Thierry Coquand} diff --git a/doc/packages.tex b/doc/packages.tex new file mode 100644 index 0000000..fcd169e --- /dev/null +++ b/doc/packages.tex @@ -0,0 +1,28 @@ +\usepackage[utf8]{inputenc} + +\usepackage{natbib} +\usepackage[hidelinks]{hyperref} + +\usepackage{graphicx} + +\usepackage{parskip} +\usepackage{multicol} +\usepackage{amsmath,amssymb} +\usepackage[toc,page]{appendix} +\usepackage{xspace} + +% \setlength{\parskip}{10pt} + +% \usepackage{tikz} +% \usetikzlibrary{arrows, decorations.markings} + +% \usepackage{chngcntr} +% \counterwithout{figure}{section} + +\usepackage{listings} +\usepackage{fancyvrb} + +\usepackage{chalmerstitle} + +\usepackage{fontspec} +\setmonofont{FreeMono.otf} diff --git a/doc/proposal.tex b/doc/proposal.tex index aad24c5..bcf85d9 100644 --- a/doc/proposal.tex +++ b/doc/proposal.tex @@ -7,22 +7,12 @@ Recent developments have, however, resulted in \nomen{Cubical Type Theory} (CTT) which permits a constructive proof of these two important notions. Furthermore an extension has been implemented for the proof assistant Agda -(\cite{agda}) that allows us to work in such a ``cubical setting''. This project -will be concerned with exploring the usefulness of this extension. As a -case-study I will consider \nomen{category theory}. This will serve a dual -purpose: First off category theory is a field where the notion of functional -extensionality and univalence wil be particularly useful. Secondly, Category -Theory gives rise to a \nomen{model} for CTT. +(\cite{agda}, \cite{cubical-agda}) that allows us to work in such a ``cubical +setting''. This thesis will explore the usefulness of this extension in the +context of category theory. -The project will consist of two parts: The first part will be concerned with -formalizing concepts from category theory. The focus will be on formalizing -parts that will be useful in the second part of the project: Showing that -\nomen{Cubical Sets} give rise to a model of CTT. -% -\section{Problem} -% -In the following two subsections I present two examples that illustrate the -limitation inherent in ITT and by extension to the expressiveness of Agda. +In the following two sections I present two examples that illustrate some +limitations inherent in ITT and -- by extension -- Agda. % \subsection{Functional extensionality} Consider the functions: @@ -33,8 +23,8 @@ $f \defeq (n : \bN) \mapsto (0 + n : \bN)$ $g \defeq (n : \bN) \mapsto (n + 0 : \bN)$ \end{multicols} % -$n + 0$ is definitionally equal to $n$. We call this \nomen{definitional -equality} and write $n + 0 = n$ to assert this fact. We call it definitional +$n + 0$ is \nomen{definitionally} equal to $n$ which we write as $n + 0 = n$. +This is also called \nomen{judgmental} equality. We call it definitional equality because the \emph{equality} arises from the \emph{definition} of $+$ which is: % @@ -48,9 +38,9 @@ which is: Note that $0 + n$ is \emph{not} definitionally equal to $n$. $0 + n$ is in normal form. I.e.; there is no rule for $+$ whose left-hand-side matches this expression. We \emph{do}, however, have that they are \nomen{propositionally} -equal. We write $n + 0 \equiv n$ to assert this fact. Propositional equality -means that there is a proof that exhibits this relation. Since equality is a -transitive relation we have that $n + 0 \equiv 0 + n$. +equal which we write as $n + 0 \equiv n$. Propositional equality means that +there is a proof that exhibits this relation. Since equality is a transitive +relation we have that $n + 0 \equiv 0 + n$. Unfortunately we don't have $f \equiv g$.\footnote{Actually showing this is outside the scope of this text. Essentially it would involve giving a model @@ -62,10 +52,9 @@ interested in; that they are equal for all inputs. We call this \nomen{pointwise equality}, where the \emph{points} of a function refers to it's arguments. -In the context of category theory the principle of functional extensionality is -for instance useful in the context of showing that representable functors are -indeed functors. The representable functor for a category $\bC$ and a fixed -object in $A \in \bC$ is defined to be: +In the context of category theory functional extensionality is e.g. needed to +show that representable functors are indeed functors. The representable functor +for a category $\bC$ and a fixed object in $A \in \bC$ is defined to be: % \begin{align*} \fmap \defeq X \mapsto \Hom_{\bC}(A, X) @@ -80,19 +69,8 @@ The proof obligation that this satisfies the identity law of functors % One needs functional extensionality to ``go under'' the function arrow and apply the (left) identity law of the underlying category to proove $\idFun \comp g -\equiv g$ and thus closing the above proof. +\equiv g$ and thus closing the. % -\iffalse -I also want to talk about: -\begin{itemize} -\item - Foundational systems -\item - Theory vs. metatheory -\item - Internal type theory -\end{itemize} -\fi \subsection{Equality of isomorphic types} % Let $\top$ denote the unit type -- a type with a single constructor. In the @@ -106,22 +84,16 @@ $x$. A mathematician would immediately conclude $\{x \mid \phi\ x \land \psi\ x\} \equiv \{x \mid \phi\ x\}$ without thinking twice. Unfortunately such an identification can not be performed in ITT. -More specifically; what we are interested in is a way of identifying types that -are in a one-to-one correspondence. We say that such types are -\nomen{isomorphic} and write $A \cong B$ to assert this. - -To prove two types isomorphic is to give an \nomen{isomorphism} between them. -That is, a function $f : A \to B$ with an inverse $f^{-1} : B \to A$, i.e.: -$f^{-1} \comp f \equiv id_A$. If such a function exist we say that $A$ and $B$ -are isomorphic and write $A \cong B$. - -Furthermore we want to \emph{identify} such isomorphic types. This, we get from -the principle of univalence:\footnote{It's often referred to as the univalence -axiom, but since it is not an axiom in this setting but rather a theorem I -refer to this just as a `principle'.} +More specifically; what we are interested in is a way of identifying +\nomen{equivalent} types. I will return to the definition of equivalence later, +but for now, it is sufficient to think of an equivalence as a one-to-one +correspondence. We write $A \simeq B$ to assert that $A$ and $B$ are equivalent +types. The principle of univalence says that: % -$$(A \cong B) \cong (A \equiv B)$$ +$$\mathit{univalence} \tp (A \simeq B) \simeq (A \equiv B)$$ % +In particular this allows us to construct an equality from an equivalence $\mathit{ua} \tp +(A \simeq B) \to (A \equiv B)$ and vice-versa. \subsection{Formalizing Category Theory} % The above examples serve to illustrate the limitation of Agda. One case where @@ -130,109 +102,63 @@ Theory. At a glance category theory can be described as ``the mathematical study of (abstract) algebras of functions'' (\cite{awodey-2006}). So by that token functional extensionality is particularly useful for formulating Category Theory. In Category theory it is also common to identify isomorphic structures -and this is exactly what we get from univalence. +and this is exactly what we get from univalence. In fact we can formulate this +requirement within our formulation of categories by requiring the +\emph{categories} themselves to be univalent as we shall see. -\subsection{Cubical model for Cubical Type Theory} -% -A model is a way of giving meaning to a formal system in a \emph{meta-theory}. A -typical example of a model is that of sets as models for predicate logic. Thus -set-theory becomes the meta-theory of the formal language of predicate logic. - -In the context of a given type theory and restricting ourselves to -\emph{categorical} models a model will consist of mapping `things' from the -type-theory (types, terms, contexts, context morphisms) to `things' in the -meta-theory (objects, morphisms) in such a way that the axioms of the -type-theory (typing-rules) are validated in the meta-theory. In -\cite{dybjer-1995} the author describes a way of constructing such models for -dependent type theory called \emph{Categories with Families} (CwFs). - -In \cite{bezem-2014} the authors devise a CwF for Cubical Type Theory. This -project will study and formalize this model. Note that I will \emph{not} aim to -formalize CTT itself and therefore also not give the formal translation between -the type theory and the meta-theory. Instead the translation will be accounted -for informally. - -The project will formalize CwF's. It will also define what pieces of data are -needed for a model of CTT (without explicitly showing that it does in fact model -CTT). It will then show that a CwF gives rise to such a model. Furthermore I -will show that cubical sets are presheaf categories and that any presheaf -category is itself a CwF. This is the precise way by which the project aims to -provide a model of CTT. Note that this formalization specifcally does not -mention the language of CTT itself. Only be referencing this previous work do we -arrive at a model of CTT. -% \section{Context} % -In \cite{bezem-2014} a categorical model for cubical type theory is presented. -In \cite{cohen-2016} a type-theory where univalence is expressible is presented. -The categorical model in the previous reference serve as a model of this type -theory. So these two ideas are closely related. Cubical type theory arose out of -\nomen{Homotopy Type Theory} (\cite{hott-2013}) and is also of interest as a -foundation of mathematics (\cite{voevodsky-2011}). - -An implementation of cubical type theory can be found as an extension to Agda. -This is due to \citeauthor{cubical-agda}. This, of course, will be central to -this thesis. - -The idea of formalizing Category Theory in proof assistants is not a new -idea\footnote{There are a multitude of these available online. Just as first -reference see this question on Math Overflow: \cite{mo-formalizations}}. The -contribution of this thesis is to explore how working in a cubical setting will -make it possible to prove more things and to reuse proofs. +\begin{verbatim} +Inspiration: +* Awodey - formulation of categories +* HoTT - sketch of homotopy proofs +\end{verbatim} +The idea of formalizing Category Theory in proof assistants is not new. There +are a multitude of these available online. Just as first reference see this +question on Math Overflow: \cite{mo-formalizations}. Notably these two implementations of category theory in Agda: +\begin{itemize} +\item +\url{https://github.com/copumpkin/categories} - setoid interpretation +\item +\url{https://github.com/pcapriotti/agda-categories} - homotopic setting with postulates +\item +\url{https://github.com/pcapriotti/agda-categories} - homotopic setting in coq +\item +\url{https://github.com/mortberg/cubicaltt} - homotopic setting in \texttt{cubicaltt} +\end{itemize} +The contribution of this +thesis is to explore how working in a cubical setting will make it possible to +prove more things and to reuse proofs. There are alternative approaches to working in a cubical setting where one can still have univalence and functional extensionality. One option is to postulate these as axioms. This approach, however, has other shortcomings, e.g.; you lose -\nomen{canonicity} (\cite{huber-2016}). Canonicity means that any well-type -term will (under evaluation) reduce to a \emph{canonical} form. For example for -an integer $e : \bN$ it will be the case that $e$ is definitionally equal to $n$ -applications of $\mathit{suc}$ to $0$ for some $n$; $e = \mathit{suc}^n\ 0$. -Without canonicity terms in the language can get ``stuck'' when they are -evaluated. +\nomen{canonicity} (\cite{huber-2016}). Canonicity means that any well-typed +term evaluates to a \emph{canonical} form. For example for a closed term $e : +\bN$ it will be the case that $e$ reduces to $n$ applications of $\mathit{suc}$ +to $0$ for some $n$; $e = \mathit{suc}^n\ 0$. Without canonicity terms in the +language can get ``stuck'' -- meaning that they do not reduce to a canonical +form. Another approach is to use the \emph{setoid interpretation} of type theory -(\cite{hofmann-1995,huber-2016}). Types should additionally `carry around' an -equivalence relation that should serve as propositional equality. This approach -has other drawbacks; it does not satisfy all judgemental equalites of type -theory and is cumbersome to work with in practice (\cite[p. 4]{huber-2016}). -% -\section{Goals and Challenges} -% -In summary, the aim of the project is to: -% -\begin{itemize} -\item -Formalize Category Theory in Cubical Agda -\item -Formalize Cubical Sets in Agda -% \item -% Formalize Cubical Type Theory in Agda -\item -Show that Cubical Sets are a model for Cubical Type Theory -\end{itemize} -% -The formalization of category theory will focus on extracting the elements from -Category Theory that we need in the latter part of the project. In doing so I'll -be gaining experience with working with Cubical Agda. Equality proofs using -cubical Agda can be tricky, so working with that will be a challenge in itself. -Most of the proofs in the context of cubical models I will formalize are based -on previous work. Those proofs, however, are not formalized in a proof -assistant. +(\cite{hofmann-1995,huber-2016}). With this approach one works with +\nomen{extensionals sets} $(X, \sim)$, that is a type $X \tp \MCU$ and an +equivalence relation $\sim$. -One particular challenge in this context is that in a cubical setting there can -be multiple distinct terms that inhabit a given equality proof.\footnote{This is -in contrast with ITT where one \emph{can} have \nomen{Uniqueness of identity proofs} -(\cite[p. 4]{huber-2016}).} This means that the choice for a given equality -proof can influence later proofs that refer back to said proof. This is new and -relatively unexplored territory. - -Another challenge is that Category Theory is something that I only know the -basics of. So learning the necessary concepts from Category Theory will also be -a goal and a challenge in itself. - -After this has been implemented it would also be possible to formalize Cubical -Type Theory and formally show that Cubical Sets are a model of this. I do not -intend to formally implement the language of dependent type theory in this -project. - -The thesis shall conclude with a discussion about the benefits of Cubical Agda. +Types should additionally `carry around' an equivalence relation that serve as +propositional equality. This approach has other drawbacks; it does not satisfy +all judgemental equalites of type theory, is cumbersome to work with in practice +(\cite[p. 4]{huber-2016}) and makes equational proofs less reusable since +equational proofs $a \sim_{X} b$ are inherently `local' to the extensional set +$(X , \sim)$. +% +\section{The equality type} +The usual definition of equality in Agda is an inductive data-type with a single +constructor: +% +%% \VerbatimInput{../libs/main.tex} +% \def\verbatim@font{xits} +\begin{verbatim} +data _≡_ {a} {A : Set a} (x : A) : A → Set a where + instance refl : x ≡ x +\end{verbatim} diff --git a/doc/refs.bib b/doc/refs.bib index 93665a7..2e376a0 100644 --- a/doc/refs.bib +++ b/doc/refs.bib @@ -111,4 +111,10 @@ year={2014}, EPRINT = {\url{https://mathoverflow.net/q/152497}}, URL = {https://mathoverflow.net/q/152497} +} +@Misc{UniMath, + author = {Voevodsky, Vladimir and Ahrens, Benedikt and Grayson, Daniel and others}, + title = {{UniMath --- a computer-checked library of univalent mathematics}}, + url = {https://github.com/UniMath/UniMath}, + howpublished = {{available} at \url{https://github.com/UniMath/UniMath}} } \ No newline at end of file From 2f6b129ed6e7367f5d9aa7b4f8b082d39393aa99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 29 Mar 2018 13:32:48 +0200 Subject: [PATCH 13/93] Move proposal to report, use xelatex --- doc/Makefile | 4 ++-- doc/main.tex | 2 +- doc/{proposal.tex => report.tex} | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename doc/{proposal.tex => report.tex} (100%) diff --git a/doc/Makefile b/doc/Makefile index c942a7e..ff8e36c 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -16,7 +16,7 @@ MAIN=main.tex all: $(PROJNAME).pdf preview: $(MAIN) - latexmk -pvc -jobname=$(PROJNAME) -pdf -pdflatex="pdflatex -interactive=nonstopmode" $< + latexmk -pvc -jobname=$(PROJNAME) -pdf -xelatex $< # CUSTOM BUILD RULES @@ -41,7 +41,7 @@ preview: $(MAIN) # missing file reference and interactively asking you for an alternative. $(PROJNAME).pdf: $(MAIN) - latexmk -jobname=$(PROJNAME) -pdf -pdflatex="pdflatex -interactive=nonstopmode" -use-make $< + latexmk -jobname=$(PROJNAME) -pdf -xelatex -use-make $< cleanall: latexmk -C diff --git a/doc/main.tex b/doc/main.tex index 7c84463..e2542f7 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -16,7 +16,7 @@ \maketitle -\input{proposal.tex} +\input{report.tex} \bibliographystyle{plainnat} \nocite{cubical-demo} diff --git a/doc/proposal.tex b/doc/report.tex similarity index 100% rename from doc/proposal.tex rename to doc/report.tex From 52ac9b4b782ffa843b29ae7bf50fd1dc5b89ad26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 29 Mar 2018 14:26:47 +0200 Subject: [PATCH 14/93] Terminal objects are propositional --- src/Cat/Category.agda | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index cac045e..d3f5e2a 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -255,7 +255,35 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc -- this needs the univalence of the category propTerminal : isProp Terminal - propTerminal = {!!} + propTerminal Xt Yt = res + where + open Σ Xt renaming (proj₁ to X ; proj₂ to Xit) + open Σ Yt renaming (proj₁ to Y ; proj₂ to Yit) + open Σ (Xit {Y}) renaming (proj₁ to Y→X) using () + open Σ (Yit {X}) renaming (proj₁ to X→Y) using () + open import Cat.Equivalence hiding (_≅_) + -- Need to show `left` and `right`, what we know is that the arrows are + -- unique. Well, I know that if I compose these two arrows they must give + -- the identity, since also the identity is the unique such arrow (by X + -- and Y both being terminal objects.) + Xprop : isProp (Arrow X X) + Xprop f g = trans (sym (snd Xit f)) (snd Xit g) + Yprop : isProp (Arrow Y Y) + Yprop f g = trans (sym (snd Yit f)) (snd Yit g) + left : Y→X ∘ X→Y ≡ 𝟙 + left = Xprop _ _ + right : X→Y ∘ Y→X ≡ 𝟙 + right = Yprop _ _ + iso : X ≅ Y + iso = X→Y , Y→X , left , right + fromIso : X ≅ Y → X ≡ Y + fromIso = fst (Equiv≃.toIso (X ≡ Y) (X ≅ Y) univalent) + p0 : X ≡ Y + p0 = fromIso iso + p1 : (λ i → IsTerminal (p0 i)) [ Xit ≡ Yit ] + p1 = lemPropF propIsTerminal p0 + res : Xt ≡ Yt + res i = p0 i , p1 i -- Merely the dual of the above statement. propIsInitial : ∀ I → isProp (IsInitial I) From ffedb832101b4b834e064f880e9eac8d5a9b0839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 29 Mar 2018 14:31:03 +0200 Subject: [PATCH 15/93] Initial objects are also propositional --- src/Cat/Category.agda | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index d3f5e2a..8408cf0 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -253,7 +253,11 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc res : (fx , cx) ≡ (fy , cy) res i = fp i , cp i - -- this needs the univalence of the category + -- | Terminal objects are propositional - a.k.a uniqueness of terminal + -- | objects. + -- + -- Having two terminal objects induces an isomorphism between them - and + -- because of univalence this is equivalent to equality. propTerminal : isProp Terminal propTerminal Xt Yt = res where @@ -302,7 +306,36 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc res i = fp i , cp i propInitial : isProp Initial - propInitial = {!!} + propInitial Xi Yi = {!!} + where + open Σ Xi renaming (proj₁ to X ; proj₂ to Xii) + open Σ Yi renaming (proj₁ to Y ; proj₂ to Yii) + open Σ (Xii {Y}) renaming (proj₁ to Y→X) using () + open Σ (Yii {X}) renaming (proj₁ to X→Y) using () + open import Cat.Equivalence hiding (_≅_) + -- Need to show `left` and `right`, what we know is that the arrows are + -- unique. Well, I know that if I compose these two arrows they must give + -- the identity, since also the identity is the unique such arrow (by X + -- and Y both being terminal objects.) + Xprop : isProp (Arrow X X) + Xprop f g = trans (sym (snd Xii f)) (snd Xii g) + Yprop : isProp (Arrow Y Y) + Yprop f g = trans (sym (snd Yii f)) (snd Yii g) + left : Y→X ∘ X→Y ≡ 𝟙 + left = Yprop _ _ + right : X→Y ∘ Y→X ≡ 𝟙 + right = Xprop _ _ + iso : X ≅ Y + iso = Y→X , X→Y , right , left + fromIso : X ≅ Y → X ≡ Y + fromIso = fst (Equiv≃.toIso (X ≡ Y) (X ≅ Y) univalent) + p0 : X ≡ Y + p0 = fromIso iso + p1 : (λ i → IsInitial (p0 i)) [ Xii ≡ Yii ] + p1 = lemPropF propIsInitial p0 + res : Xi ≡ Yi + res i = p0 i , p1 i + -- | Propositionality of being a category module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where From 432cc788211b7ca3a89dc75fc1451af395732011 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 29 Mar 2018 15:47:43 +0200 Subject: [PATCH 16/93] Prove assoc and ident for funky category --- src/Cat/Category/Product.agda | 85 +++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 4 deletions(-) diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index d2526b1..1ea3372 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -129,15 +129,92 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} raw : RawCategory _ _ raw = record { Object = Σ[ X ∈ ℂ.Object ] ℂ.Arrow X A × ℂ.Arrow X B - ; Arrow = λ{ (X , xa , xb) (Y , ya , yb) → Σ[ xy ∈ ℂ.Arrow X Y ] (ℂ [ ya ∘ xy ] ≡ xa) × (ℂ [ yb ∘ xy ] ≡ xb) } - ; 𝟙 = λ{ {A , _} → ℂ.𝟙 {A} , {!!}} - ; _∘_ = \ { (f , p) (g , q) → ℂ._∘_ f g , {!!} } + ; Arrow = λ{ (X , xa , xb) (Y , ya , yb) + → Σ[ xy ∈ ℂ.Arrow X Y ] + ( ℂ [ ya ∘ xy ] ≡ xa) + × ℂ [ yb ∘ xy ] ≡ xb + } + ; 𝟙 = λ{ {A , f , g} → ℂ.𝟙 {A} , ℂ.rightIdentity , ℂ.rightIdentity} + ; _∘_ = λ { {A , a0 , a1} {B , b0 , b1} {C , c0 , c1} (f , f0 , f1) (g , g0 , g1) + → (f ℂ.∘ g) + , (begin + ℂ [ c0 ∘ ℂ [ f ∘ g ] ] ≡⟨ ℂ.isAssociative ⟩ + ℂ [ ℂ [ c0 ∘ f ] ∘ g ] ≡⟨ cong (λ φ → ℂ [ φ ∘ g ]) f0 ⟩ + ℂ [ b0 ∘ g ] ≡⟨ g0 ⟩ + a0 ∎ + ) + , (begin + ℂ [ c1 ∘ ℂ [ f ∘ g ] ] ≡⟨ ℂ.isAssociative ⟩ + ℂ [ ℂ [ c1 ∘ f ] ∘ g ] ≡⟨ cong (λ φ → ℂ [ φ ∘ g ]) f1 ⟩ + ℂ [ b1 ∘ g ] ≡⟨ g1 ⟩ + a1 ∎ + ) + } } open RawCategory raw + isAssocitaive : IsAssociative + isAssocitaive {A , a0 , a1} {B , _} {C , c0 , c1} {D , d0 , d1} {ff@(f , f0 , f1)} {gg@(g , g0 , g1)} {hh@(h , h0 , h1)} i + = s0 i , rl i , rr i + where + l = hh ∘ (gg ∘ ff) + r = hh ∘ gg ∘ ff + -- s0 : h ℂ.∘ (g ℂ.∘ f) ≡ h ℂ.∘ g ℂ.∘ f + s0 : proj₁ l ≡ proj₁ r + s0 = ℂ.isAssociative {f = f} {g} {h} + prop0 : ∀ a → isProp (ℂ [ d0 ∘ a ] ≡ a0) + prop0 a = ℂ.arrowsAreSets (ℂ [ d0 ∘ a ]) a0 + rl : (λ i → (ℂ [ d0 ∘ s0 i ]) ≡ a0) [ proj₁ (proj₂ l) ≡ proj₁ (proj₂ r) ] + rl = lemPropF prop0 s0 + prop1 : ∀ a → isProp ((ℂ [ d1 ∘ a ]) ≡ a1) + prop1 a = ℂ.arrowsAreSets _ _ + rr : (λ i → (ℂ [ d1 ∘ s0 i ]) ≡ a1) [ proj₂ (proj₂ l) ≡ proj₂ (proj₂ r) ] + rr = lemPropF prop1 s0 + + isIdentity : IsIdentity 𝟙 + isIdentity {AA@(A , a0 , a1)} {BB@(B , b0 , b1)} {f , f0 , f1} = leftIdentity , rightIdentity + where + leftIdentity : 𝟙 ∘ (f , f0 , f1) ≡ (f , f0 , f1) + leftIdentity i = l i , rl i , rr i + where + L = 𝟙 ∘ (f , f0 , f1) + R : Arrow AA BB + R = f , f0 , f1 + l : proj₁ L ≡ proj₁ R + l = ℂ.leftIdentity + prop0 : ∀ a → isProp ((ℂ [ b0 ∘ a ]) ≡ a0) + prop0 a = ℂ.arrowsAreSets _ _ + rl : (λ i → (ℂ [ b0 ∘ l i ]) ≡ a0) [ proj₁ (proj₂ L) ≡ proj₁ (proj₂ R) ] + rl = lemPropF prop0 l + prop1 : ∀ a → isProp (ℂ [ b1 ∘ a ] ≡ a1) + prop1 _ = ℂ.arrowsAreSets _ _ + rr : (λ i → (ℂ [ b1 ∘ l i ]) ≡ a1) [ proj₂ (proj₂ L) ≡ proj₂ (proj₂ R) ] + rr = lemPropF prop1 l + rightIdentity : (f , f0 , f1) ∘ 𝟙 ≡ (f , f0 , f1) + rightIdentity i = l i , rl i , {!!} + where + L = (f , f0 , f1) ∘ 𝟙 + R : Arrow AA BB + R = (f , f0 , f1) + l : ℂ [ f ∘ ℂ.𝟙 ] ≡ f + l = ℂ.rightIdentity + prop0 : ∀ a → isProp ((ℂ [ b0 ∘ a ]) ≡ a0) + prop0 _ = ℂ.arrowsAreSets _ _ + rl : (λ i → (ℂ [ b0 ∘ l i ]) ≡ a0) [ proj₁ (proj₂ L) ≡ proj₁ (proj₂ R) ] + rl = lemPropF prop0 l + prop1 : ∀ a → isProp ((ℂ [ b1 ∘ a ]) ≡ a1) + prop1 _ = ℂ.arrowsAreSets _ _ + rr : (λ i → (ℂ [ b1 ∘ l i ]) ≡ a1) [ proj₂ (proj₂ L) ≡ proj₂ (proj₂ R) ] + rr = lemPropF prop1 l + cat : IsCategory raw - cat = {!!} + cat = record + { isAssociative = isAssocitaive + ; isIdentity = isIdentity + ; arrowsAreSets = {!!} + ; univalent = {!!} + } module cat = IsCategory cat From ba80fe96dc2a0dbcb40ab1ab90dbc7e082b00a2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 30 Mar 2018 00:12:01 +0200 Subject: [PATCH 17/93] [WIP] Propositionality for products --- src/Cat/Category/Product.agda | 386 +++++++++++++++++----------------- 1 file changed, 198 insertions(+), 188 deletions(-) diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 1ea3372..d735082 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -121,205 +121,215 @@ module _ {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} {A B : Category.Object propHasProducts = propHasProducts' module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} - (let module ℂ = Category ℂ) {A B : ℂ.Object} (p : Product ℂ A B) where + (let module ℂ = Category ℂ) {A B : ℂ.Object} where - -- open Product p hiding (raw) open import Data.Product - raw : RawCategory _ _ - raw = record - { Object = Σ[ X ∈ ℂ.Object ] ℂ.Arrow X A × ℂ.Arrow X B - ; Arrow = λ{ (X , xa , xb) (Y , ya , yb) - → Σ[ xy ∈ ℂ.Arrow X Y ] - ( ℂ [ ya ∘ xy ] ≡ xa) - × ℂ [ yb ∘ xy ] ≡ xb + module _ where + raw : RawCategory _ _ + raw = record + { Object = Σ[ X ∈ ℂ.Object ] ℂ.Arrow X A × ℂ.Arrow X B + ; Arrow = λ{ (X , xa , xb) (Y , ya , yb) + → Σ[ xy ∈ ℂ.Arrow X Y ] + ( ℂ [ ya ∘ xy ] ≡ xa) + × ℂ [ yb ∘ xy ] ≡ xb + } + ; 𝟙 = λ{ {A , f , g} → ℂ.𝟙 {A} , ℂ.rightIdentity , ℂ.rightIdentity} + ; _∘_ = λ { {A , a0 , a1} {B , b0 , b1} {C , c0 , c1} (f , f0 , f1) (g , g0 , g1) + → (f ℂ.∘ g) + , (begin + ℂ [ c0 ∘ ℂ [ f ∘ g ] ] ≡⟨ ℂ.isAssociative ⟩ + ℂ [ ℂ [ c0 ∘ f ] ∘ g ] ≡⟨ cong (λ φ → ℂ [ φ ∘ g ]) f0 ⟩ + ℂ [ b0 ∘ g ] ≡⟨ g0 ⟩ + a0 ∎ + ) + , (begin + ℂ [ c1 ∘ ℂ [ f ∘ g ] ] ≡⟨ ℂ.isAssociative ⟩ + ℂ [ ℂ [ c1 ∘ f ] ∘ g ] ≡⟨ cong (λ φ → ℂ [ φ ∘ g ]) f1 ⟩ + ℂ [ b1 ∘ g ] ≡⟨ g1 ⟩ + a1 ∎ + ) } - ; 𝟙 = λ{ {A , f , g} → ℂ.𝟙 {A} , ℂ.rightIdentity , ℂ.rightIdentity} - ; _∘_ = λ { {A , a0 , a1} {B , b0 , b1} {C , c0 , c1} (f , f0 , f1) (g , g0 , g1) - → (f ℂ.∘ g) - , (begin - ℂ [ c0 ∘ ℂ [ f ∘ g ] ] ≡⟨ ℂ.isAssociative ⟩ - ℂ [ ℂ [ c0 ∘ f ] ∘ g ] ≡⟨ cong (λ φ → ℂ [ φ ∘ g ]) f0 ⟩ - ℂ [ b0 ∘ g ] ≡⟨ g0 ⟩ - a0 ∎ - ) - , (begin - ℂ [ c1 ∘ ℂ [ f ∘ g ] ] ≡⟨ ℂ.isAssociative ⟩ - ℂ [ ℂ [ c1 ∘ f ] ∘ g ] ≡⟨ cong (λ φ → ℂ [ φ ∘ g ]) f1 ⟩ - ℂ [ b1 ∘ g ] ≡⟨ g1 ⟩ - a1 ∎ - ) } - } - open RawCategory raw + open RawCategory raw - isAssocitaive : IsAssociative - isAssocitaive {A , a0 , a1} {B , _} {C , c0 , c1} {D , d0 , d1} {ff@(f , f0 , f1)} {gg@(g , g0 , g1)} {hh@(h , h0 , h1)} i - = s0 i , rl i , rr i - where - l = hh ∘ (gg ∘ ff) - r = hh ∘ gg ∘ ff - -- s0 : h ℂ.∘ (g ℂ.∘ f) ≡ h ℂ.∘ g ℂ.∘ f - s0 : proj₁ l ≡ proj₁ r - s0 = ℂ.isAssociative {f = f} {g} {h} - prop0 : ∀ a → isProp (ℂ [ d0 ∘ a ] ≡ a0) - prop0 a = ℂ.arrowsAreSets (ℂ [ d0 ∘ a ]) a0 - rl : (λ i → (ℂ [ d0 ∘ s0 i ]) ≡ a0) [ proj₁ (proj₂ l) ≡ proj₁ (proj₂ r) ] - rl = lemPropF prop0 s0 - prop1 : ∀ a → isProp ((ℂ [ d1 ∘ a ]) ≡ a1) - prop1 a = ℂ.arrowsAreSets _ _ - rr : (λ i → (ℂ [ d1 ∘ s0 i ]) ≡ a1) [ proj₂ (proj₂ l) ≡ proj₂ (proj₂ r) ] - rr = lemPropF prop1 s0 - - isIdentity : IsIdentity 𝟙 - isIdentity {AA@(A , a0 , a1)} {BB@(B , b0 , b1)} {f , f0 , f1} = leftIdentity , rightIdentity - where - leftIdentity : 𝟙 ∘ (f , f0 , f1) ≡ (f , f0 , f1) - leftIdentity i = l i , rl i , rr i + isAssocitaive : IsAssociative + isAssocitaive + {A , a0 , a1} + {B , b0 , b1} + {C , c0 , c1} + {D , d0 , d1} + {ff@(f , f0 , f1)} + {gg@(g , g0 , g1)} + {hh@(h , h0 , h1)} + i + = s0 i , rl i , rr i where - L = 𝟙 ∘ (f , f0 , f1) - R : Arrow AA BB - R = f , f0 , f1 - l : proj₁ L ≡ proj₁ R - l = ℂ.leftIdentity - prop0 : ∀ a → isProp ((ℂ [ b0 ∘ a ]) ≡ a0) - prop0 a = ℂ.arrowsAreSets _ _ - rl : (λ i → (ℂ [ b0 ∘ l i ]) ≡ a0) [ proj₁ (proj₂ L) ≡ proj₁ (proj₂ R) ] - rl = lemPropF prop0 l - prop1 : ∀ a → isProp (ℂ [ b1 ∘ a ] ≡ a1) - prop1 _ = ℂ.arrowsAreSets _ _ - rr : (λ i → (ℂ [ b1 ∘ l i ]) ≡ a1) [ proj₂ (proj₂ L) ≡ proj₂ (proj₂ R) ] - rr = lemPropF prop1 l - rightIdentity : (f , f0 , f1) ∘ 𝟙 ≡ (f , f0 , f1) - rightIdentity i = l i , rl i , {!!} + l = hh ∘ (gg ∘ ff) + r = hh ∘ gg ∘ ff + -- s0 : h ℂ.∘ (g ℂ.∘ f) ≡ h ℂ.∘ g ℂ.∘ f + s0 : proj₁ l ≡ proj₁ r + s0 = ℂ.isAssociative {f = f} {g} {h} + prop0 : ∀ a → isProp (ℂ [ d0 ∘ a ] ≡ a0) + prop0 a = ℂ.arrowsAreSets (ℂ [ d0 ∘ a ]) a0 + rl : (λ i → (ℂ [ d0 ∘ s0 i ]) ≡ a0) [ proj₁ (proj₂ l) ≡ proj₁ (proj₂ r) ] + rl = lemPropF prop0 s0 + prop1 : ∀ a → isProp ((ℂ [ d1 ∘ a ]) ≡ a1) + prop1 a = ℂ.arrowsAreSets _ _ + rr : (λ i → (ℂ [ d1 ∘ s0 i ]) ≡ a1) [ proj₂ (proj₂ l) ≡ proj₂ (proj₂ r) ] + rr = lemPropF prop1 s0 + + isIdentity : IsIdentity 𝟙 + isIdentity {AA@(A , a0 , a1)} {BB@(B , b0 , b1)} {f , f0 , f1} = leftIdentity , rightIdentity where - L = (f , f0 , f1) ∘ 𝟙 - R : Arrow AA BB - R = (f , f0 , f1) - l : ℂ [ f ∘ ℂ.𝟙 ] ≡ f - l = ℂ.rightIdentity - prop0 : ∀ a → isProp ((ℂ [ b0 ∘ a ]) ≡ a0) - prop0 _ = ℂ.arrowsAreSets _ _ - rl : (λ i → (ℂ [ b0 ∘ l i ]) ≡ a0) [ proj₁ (proj₂ L) ≡ proj₁ (proj₂ R) ] - rl = lemPropF prop0 l - prop1 : ∀ a → isProp ((ℂ [ b1 ∘ a ]) ≡ a1) - prop1 _ = ℂ.arrowsAreSets _ _ - rr : (λ i → (ℂ [ b1 ∘ l i ]) ≡ a1) [ proj₂ (proj₂ L) ≡ proj₂ (proj₂ R) ] - rr = lemPropF prop1 l + leftIdentity : 𝟙 ∘ (f , f0 , f1) ≡ (f , f0 , f1) + leftIdentity i = l i , rl i , rr i + where + L = 𝟙 ∘ (f , f0 , f1) + R : Arrow AA BB + R = f , f0 , f1 + l : proj₁ L ≡ proj₁ R + l = ℂ.leftIdentity + prop0 : ∀ a → isProp ((ℂ [ b0 ∘ a ]) ≡ a0) + prop0 a = ℂ.arrowsAreSets _ _ + rl : (λ i → (ℂ [ b0 ∘ l i ]) ≡ a0) [ proj₁ (proj₂ L) ≡ proj₁ (proj₂ R) ] + rl = lemPropF prop0 l + prop1 : ∀ a → isProp (ℂ [ b1 ∘ a ] ≡ a1) + prop1 _ = ℂ.arrowsAreSets _ _ + rr : (λ i → (ℂ [ b1 ∘ l i ]) ≡ a1) [ proj₂ (proj₂ L) ≡ proj₂ (proj₂ R) ] + rr = lemPropF prop1 l + rightIdentity : (f , f0 , f1) ∘ 𝟙 ≡ (f , f0 , f1) + rightIdentity i = l i , rl i , rr i + where + L = (f , f0 , f1) ∘ 𝟙 + R : Arrow AA BB + R = (f , f0 , f1) + l : ℂ [ f ∘ ℂ.𝟙 ] ≡ f + l = ℂ.rightIdentity + prop0 : ∀ a → isProp ((ℂ [ b0 ∘ a ]) ≡ a0) + prop0 _ = ℂ.arrowsAreSets _ _ + rl : (λ i → (ℂ [ b0 ∘ l i ]) ≡ a0) [ proj₁ (proj₂ L) ≡ proj₁ (proj₂ R) ] + rl = lemPropF prop0 l + prop1 : ∀ a → isProp ((ℂ [ b1 ∘ a ]) ≡ a1) + prop1 _ = ℂ.arrowsAreSets _ _ + rr : (λ i → (ℂ [ b1 ∘ l i ]) ≡ a1) [ proj₂ (proj₂ L) ≡ proj₂ (proj₂ R) ] + rr = lemPropF prop1 l - cat : IsCategory raw - cat = record - { isAssociative = isAssocitaive - ; isIdentity = isIdentity - ; arrowsAreSets = {!!} - ; univalent = {!!} - } + arrowsAreSets : ArrowsAreSets + arrowsAreSets {X , x0 , x1} {Y , y0 , y1} (f , f0 , f1) (g , g0 , g1) p q = {!!} + where + prop : ∀ {X Y} (x y : ℂ.Arrow X Y) → isProp (x ≡ y) + prop = ℂ.arrowsAreSets + a0 a1 : f ≡ g + a0 i = proj₁ (p i) + a1 i = proj₁ (q i) + a : a0 ≡ a1 + a = ℂ.arrowsAreSets _ _ a0 a1 + res : p ≡ q + res i j = a i j , {!b i j!} , {!!} + where + -- b0 b1 : (λ j → (ℂ [ y0 ∘ a i j ]) ≡ x0) [ f0 ≡ g0 ] + -- b0 = lemPropF (λ x → prop (ℂ [ y0 ∘ x ]) x0) (a i) + -- b1 = lemPropF (λ x → prop (ℂ [ y0 ∘ x ]) x0) (a i) + b0 : (λ j → (ℂ [ y0 ∘ a0 j ]) ≡ x0) [ f0 ≡ g0 ] + b0 = lemPropF (λ x → prop (ℂ [ y0 ∘ x ]) x0) a0 + b1 : (λ j → (ℂ [ y0 ∘ a1 j ]) ≡ x0) [ f0 ≡ g0 ] + b1 = lemPropF (λ x → prop (ℂ [ y0 ∘ x ]) x0) a1 + -- b : b0 ≡ b1 + -- b = {!!} - module cat = IsCategory cat + isCat : IsCategory raw + isCat = record + { isAssociative = isAssocitaive + ; isIdentity = isIdentity + ; arrowsAreSets = arrowsAreSets + ; univalent = {!!} + } - lemma : Terminal ≃ Product ℂ A B - lemma = {!!} + cat : Category _ _ + cat = record + { raw = raw + ; isCategory = isCat + } + + open Category cat + + open import Cat.Equivalence + + lemma : Terminal ≃ Product ℂ A B + lemma = Equiv≃.fromIsomorphism Terminal (Product ℂ A B) (f , g , inv) + where + f : Terminal → Product ℂ A B + f ((X , x0 , x1) , uniq) = p + where + rawP : RawProduct ℂ A B + rawP = record + { object = X + ; proj₁ = x0 + ; proj₂ = x1 + } + -- open RawProduct rawP renaming (proj₁ to x0 ; proj₂ to x1) + module _ {Y : ℂ.Object} (p0 : ℂ [ Y , A ]) (p1 : ℂ [ Y , B ]) where + uy : isContr (Arrow (Y , p0 , p1) (X , x0 , x1)) + uy = uniq {Y , p0 , p1} + open Σ uy renaming (proj₁ to Y→X ; proj₂ to contractible) + open Σ Y→X renaming (proj₁ to p0×p1 ; proj₂ to cond) + ump : ∃![ f×g ] (ℂ [ x0 ∘ f×g ] ≡ p0 P.× ℂ [ x1 ∘ f×g ] ≡ p1) + ump = p0×p1 , cond , λ {y} x → let k = contractible (y , x) in λ i → proj₁ (k i) + isP : IsProduct ℂ A B rawP + isP = record { ump = ump } + p : Product ℂ A B + p = record + { raw = rawP + ; isProduct = isP + } + g : Product ℂ A B → Terminal + g p = o , t + where + module p = Product p + module isp = IsProduct p.isProduct + o : Object + o = p.object , p.proj₁ , p.proj₂ + module _ {Xx : Object} where + open Σ Xx renaming (proj₁ to X ; proj₂ to x) + ℂXo : ℂ [ X , isp.object ] + ℂXo = isp._P[_×_] (proj₁ x) (proj₂ x) + ump = p.ump (proj₁ x) (proj₂ x) + Xoo = proj₁ (proj₂ ump) + Xo : Arrow Xx o + Xo = ℂXo , Xoo + contractible : ∀ y → Xo ≡ y + contractible (y , yy) = res + where + k : ℂXo ≡ y + k = proj₂ (proj₂ ump) (yy) + prp : ∀ a → isProp + ( (ℂ [ p.proj₁ ∘ a ] ≡ proj₁ x) + × (ℂ [ p.proj₂ ∘ a ] ≡ proj₂ x) + ) + prp ab ac ad i + = ℂ.arrowsAreSets _ _ (proj₁ ac) (proj₁ ad) i + , ℂ.arrowsAreSets _ _ (proj₂ ac) (proj₂ ad) i + h : + ( λ i + → ℂ [ p.proj₁ ∘ k i ] ≡ proj₁ x + × ℂ [ p.proj₂ ∘ k i ] ≡ proj₂ x + ) [ Xoo ≡ yy ] + h = lemPropF prp k + res : (ℂXo , Xoo) ≡ (y , yy) + res i = k i , h i + t : IsTerminal o + t {Xx} = Xo , contractible + ve-re : ∀ x → g (f x) ≡ x + ve-re x = Propositionality.propTerminal _ _ + re-ve : ∀ x → f (g x) ≡ x + re-ve x = {!!} + inv : AreInverses f g + inv = record + { verso-recto = funExt ve-re + ; recto-verso = funExt re-ve + } thm : isProp (Product ℂ A B) - thm = equivPreservesNType {n = ⟨-1⟩} lemma cat.Propositionality.propTerminal - --- open Univalence ℂ.isIdentity --- open import Cat.Equivalence hiding (_≅_) - --- k : {A B : ℂ.Object} → isEquiv (A ≡ B) (A ℂ.≅ B) (ℂ.id-to-iso A B) --- k = ℂ.univalent - --- module _ {X' Y' : Σ[ X ∈ ℂ.Object ] (ℂ [ X , A ] × ℂ [ X , B ])} where --- open Σ X' renaming (proj₁ to X) using () --- open Σ (proj₂ X') renaming (proj₁ to Xxa ; proj₂ to Xxb) --- open Σ Y' renaming (proj₁ to Y) using () --- open Σ (proj₂ Y') renaming (proj₁ to Yxa ; proj₂ to Yxb) --- module _ (p : X ≡ Y) where --- D : ∀ y → X ≡ y → Set _ --- D y q = ∀ b → (λ i → ℂ [ q i , A ]) [ Xxa ≡ b ] --- -- Not sure this is actually provable - but if it were it might involve --- -- something like the ump of the product -- in which case perhaps the --- -- objects of the category I'm constructing should not merely be the --- -- data-part of the product but also the laws. - --- -- d : D X refl --- d : ∀ b → (λ i → ℂ [ X , A ]) [ Xxa ≡ b ] --- d b = {!!} --- kk : D Y p --- kk = pathJ D d Y p --- a : (λ i → ℂ [ p i , A ]) [ Xxa ≡ Yxa ] --- a = kk Yxa --- b : (λ i → ℂ [ p i , B ]) [ Xxb ≡ Yxb ] --- b = {!!} --- f : X' ≡ Y' --- f i = p i , a i , b i - --- module _ (p : X' ≡ Y') where --- g : X ≡ Y --- g i = proj₁ (p i) - --- step0 : (X' ≡ Y') ≃ (X ≡ Y) --- step0 = Equiv≃.fromIsomorphism _ _ (g , f , record { verso-recto = {!refl!} ; recto-verso = refl}) - --- step1 : (X ≡ Y) ≃ X ℂ.≅ Y --- step1 = ℂ.univalent≃ - --- -- Just a reminder --- step1-5 : (X' ≅ Y') ≡ (X ℂ.≅ Y) --- step1-5 = refl - --- step2 : (X' ≡ Y') ≃ (X ℂ.≅ Y) --- step2 = Equivalence.compose step0 step1 - --- univalent : isEquiv (X' ≡ Y') (X ℂ.≅ Y) (id-to-iso X' Y') --- univalent = proj₂ step2 - --- isCategory : IsCategory raw --- isCategory = record --- { isAssociative = ℂ.isAssociative --- ; isIdentity = ℂ.isIdentity --- ; arrowsAreSets = ℂ.arrowsAreSets --- ; univalent = univalent --- } - --- category : Category _ _ --- category = record --- { raw = raw --- ; isCategory = isCategory --- } - --- open Category category hiding (IsTerminal ; Object) - --- -- Essential turns `p : Product ℂ A B` into a triple --- productObject : Object --- productObject = Product.object p , Product.proj₁ p , Product.proj₂ p - --- productObjectIsTerminal : IsTerminal productObject --- productObjectIsTerminal = {!!} - --- proppp : isProp (IsTerminal productObject) --- proppp = Propositionality.propIsTerminal productObject - --- module Try1 {ℓa ℓb : Level} (A B : Set) where --- open import Data.Product --- raw : RawCategory _ _ --- raw = record --- { Object = Σ[ X ∈ Set ] (X → A) × (X → B) --- ; Arrow = λ{ (X0 , f0 , g0) (X1 , f1 , g1) → X0 → X1} --- ; 𝟙 = λ x → x --- ; _∘_ = λ x x₁ x₂ → x (x₁ x₂) --- } - --- open RawCategory raw - --- isCategory : IsCategory raw --- isCategory = record --- { isAssociative = refl --- ; isIdentity = refl , refl --- ; arrowsAreSets = {!!} --- ; univalent = {!!} --- } - --- t : IsTerminal ((A × B) , proj₁ , proj₂) --- t = {!!} + thm = equivPreservesNType {n = ⟨-1⟩} lemma Propositionality.propTerminal From 34e633902fe0b8da18143191e45ff155178745ee Mon Sep 17 00:00:00 2001 From: Andrea Vezzosi Date: Fri, 30 Mar 2018 11:06:45 +0200 Subject: [PATCH 18/93] Category.Product: Factor out use of arrowAreSets to shorten proofs --- src/Cat/Category/Product.agda | 37 +++++++++-------------------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 1ea3372..fe6cfb7 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -154,59 +154,40 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} open RawCategory raw + propEqs : ∀ {X' : Object}{Y' : Object} (let X , xa , xb = X') (let Y , ya , yb = Y') + → (xy : ℂ.Arrow X Y) → isProp (ℂ [ ya ∘ xy ] ≡ xa × ℂ [ yb ∘ xy ] ≡ xb) + propEqs xs = propSig (ℂ.arrowsAreSets _ _) (\ _ → ℂ.arrowsAreSets _ _) + isAssocitaive : IsAssociative - isAssocitaive {A , a0 , a1} {B , _} {C , c0 , c1} {D , d0 , d1} {ff@(f , f0 , f1)} {gg@(g , g0 , g1)} {hh@(h , h0 , h1)} i - = s0 i , rl i , rr i + isAssocitaive {A'@(A , a0 , a1)} {B , _} {C , c0 , c1} {D'@(D , d0 , d1)} {ff@(f , f0 , f1)} {gg@(g , g0 , g1)} {hh@(h , h0 , h1)} i + = s0 i , lemPropF propEqs s0 {proj₂ l} {proj₂ r} i where l = hh ∘ (gg ∘ ff) r = hh ∘ gg ∘ ff -- s0 : h ℂ.∘ (g ℂ.∘ f) ≡ h ℂ.∘ g ℂ.∘ f s0 : proj₁ l ≡ proj₁ r s0 = ℂ.isAssociative {f = f} {g} {h} - prop0 : ∀ a → isProp (ℂ [ d0 ∘ a ] ≡ a0) - prop0 a = ℂ.arrowsAreSets (ℂ [ d0 ∘ a ]) a0 - rl : (λ i → (ℂ [ d0 ∘ s0 i ]) ≡ a0) [ proj₁ (proj₂ l) ≡ proj₁ (proj₂ r) ] - rl = lemPropF prop0 s0 - prop1 : ∀ a → isProp ((ℂ [ d1 ∘ a ]) ≡ a1) - prop1 a = ℂ.arrowsAreSets _ _ - rr : (λ i → (ℂ [ d1 ∘ s0 i ]) ≡ a1) [ proj₂ (proj₂ l) ≡ proj₂ (proj₂ r) ] - rr = lemPropF prop1 s0 + isIdentity : IsIdentity 𝟙 isIdentity {AA@(A , a0 , a1)} {BB@(B , b0 , b1)} {f , f0 , f1} = leftIdentity , rightIdentity where leftIdentity : 𝟙 ∘ (f , f0 , f1) ≡ (f , f0 , f1) - leftIdentity i = l i , rl i , rr i + leftIdentity i = l i , lemPropF propEqs l {proj₂ L} {proj₂ R} i where L = 𝟙 ∘ (f , f0 , f1) R : Arrow AA BB R = f , f0 , f1 l : proj₁ L ≡ proj₁ R l = ℂ.leftIdentity - prop0 : ∀ a → isProp ((ℂ [ b0 ∘ a ]) ≡ a0) - prop0 a = ℂ.arrowsAreSets _ _ - rl : (λ i → (ℂ [ b0 ∘ l i ]) ≡ a0) [ proj₁ (proj₂ L) ≡ proj₁ (proj₂ R) ] - rl = lemPropF prop0 l - prop1 : ∀ a → isProp (ℂ [ b1 ∘ a ] ≡ a1) - prop1 _ = ℂ.arrowsAreSets _ _ - rr : (λ i → (ℂ [ b1 ∘ l i ]) ≡ a1) [ proj₂ (proj₂ L) ≡ proj₂ (proj₂ R) ] - rr = lemPropF prop1 l rightIdentity : (f , f0 , f1) ∘ 𝟙 ≡ (f , f0 , f1) - rightIdentity i = l i , rl i , {!!} + rightIdentity i = l i , lemPropF propEqs l {proj₂ L} {proj₂ R} i where L = (f , f0 , f1) ∘ 𝟙 R : Arrow AA BB R = (f , f0 , f1) l : ℂ [ f ∘ ℂ.𝟙 ] ≡ f l = ℂ.rightIdentity - prop0 : ∀ a → isProp ((ℂ [ b0 ∘ a ]) ≡ a0) - prop0 _ = ℂ.arrowsAreSets _ _ - rl : (λ i → (ℂ [ b0 ∘ l i ]) ≡ a0) [ proj₁ (proj₂ L) ≡ proj₁ (proj₂ R) ] - rl = lemPropF prop0 l - prop1 : ∀ a → isProp ((ℂ [ b1 ∘ a ]) ≡ a1) - prop1 _ = ℂ.arrowsAreSets _ _ - rr : (λ i → (ℂ [ b1 ∘ l i ]) ≡ a1) [ proj₂ (proj₂ L) ≡ proj₂ (proj₂ R) ] - rr = lemPropF prop1 l cat : IsCategory raw cat = record From 1c6d9ad2b5a65d6c2922c48c71d9ecbddb9fbf4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 3 Apr 2018 11:36:09 +0200 Subject: [PATCH 19/93] Rename identity in category to ascii-name --- src/Cat/Categories/Cat.agda | 42 ++++---- src/Cat/Categories/Cube.agda | 2 +- src/Cat/Categories/Fam.agda | 12 +-- src/Cat/Categories/Free.agda | 10 +- src/Cat/Categories/Fun.agda | 109 ++++++++++++-------- src/Cat/Categories/Rel.agda | 2 +- src/Cat/Categories/Sets.agda | 8 +- src/Cat/Category.agda | 72 ++++++------- src/Cat/Category/Exponential.agda | 4 +- src/Cat/Category/Functor.agda | 10 +- src/Cat/Category/Monad.agda | 34 +++--- src/Cat/Category/Monad/Kleisli.agda | 80 +++++++------- src/Cat/Category/Monad/Monoidal.agda | 10 +- src/Cat/Category/NaturalTransformation.agda | 8 +- src/Cat/Category/Product.agda | 14 +-- src/Cat/Category/Yoneda.agda | 2 +- 16 files changed, 221 insertions(+), 198 deletions(-) diff --git a/src/Cat/Categories/Cat.agda b/src/Cat/Categories/Cat.agda index 3021268..a5d986e 100644 --- a/src/Cat/Categories/Cat.agda +++ b/src/Cat/Categories/Cat.agda @@ -15,10 +15,10 @@ open import Cat.Categories.Fun -- The category of categories module _ (ℓ ℓ' : Level) where RawCat : RawCategory (lsuc (ℓ ⊔ ℓ')) (ℓ ⊔ ℓ') - RawCategory.Object RawCat = Category ℓ ℓ' - RawCategory.Arrow RawCat = Functor - RawCategory.𝟙 RawCat = Functors.identity - RawCategory._∘_ RawCat = F[_∘_] + RawCategory.Object RawCat = Category ℓ ℓ' + RawCategory.Arrow RawCat = Functor + RawCategory.identity RawCat = Functors.identity + RawCategory._∘_ RawCat = F[_∘_] -- NB! `ArrowsAreSets RawCat` is *not* provable. The type of functors, -- however, form a groupoid! Therefore there is no (1-)category of @@ -48,8 +48,8 @@ module CatProduct {ℓ ℓ' : Level} (ℂ 𝔻 : Category ℓ ℓ') where Obj = ℂ.Object × 𝔻.Object Arr : Obj → Obj → Set ℓ' Arr (c , d) (c' , d') = ℂ [ c , c' ] × 𝔻 [ d , d' ] - 𝟙 : {o : Obj} → Arr o o - 𝟙 = ℂ.𝟙 , 𝔻.𝟙 + identity : {o : Obj} → Arr o o + identity = ℂ.identity , 𝔻.identity _∘_ : {a b c : Obj} → Arr b c → @@ -58,16 +58,16 @@ module CatProduct {ℓ ℓ' : Level} (ℂ 𝔻 : Category ℓ ℓ') where _∘_ = λ { (bc∈C , bc∈D) (ab∈C , ab∈D) → ℂ [ bc∈C ∘ ab∈C ] , 𝔻 [ bc∈D ∘ ab∈D ]} rawProduct : RawCategory ℓ ℓ' - RawCategory.Object rawProduct = Obj - RawCategory.Arrow rawProduct = Arr - RawCategory.𝟙 rawProduct = 𝟙 - RawCategory._∘_ rawProduct = _∘_ + RawCategory.Object rawProduct = Obj + RawCategory.Arrow rawProduct = Arr + RawCategory.identity rawProduct = identity + RawCategory._∘_ rawProduct = _∘_ open RawCategory rawProduct arrowsAreSets : ArrowsAreSets arrowsAreSets = setSig {sA = ℂ.arrowsAreSets} {sB = λ x → 𝔻.arrowsAreSets} - isIdentity : IsIdentity 𝟙 + isIdentity : IsIdentity identity isIdentity = Σ≡ (fst ℂ.isIdentity) (fst 𝔻.isIdentity) , Σ≡ (snd ℂ.isIdentity) (snd 𝔻.isIdentity) @@ -202,14 +202,14 @@ module CatExponential {ℓ : Level} (ℂ 𝔻 : Category ℓ ℓ) where module _ {c : Functor ℂ 𝔻 × ℂ.Object} where open Σ c renaming (proj₁ to F ; proj₂ to C) - ident : fmap {c} {c} (identityNT F , ℂ.𝟙 {A = snd c}) ≡ 𝔻.𝟙 + ident : fmap {c} {c} (identityNT F , ℂ.identity {A = snd c}) ≡ 𝔻.identity ident = begin - fmap {c} {c} (Category.𝟙 (object ⊗ ℂ) {c}) ≡⟨⟩ - fmap {c} {c} (idN F , ℂ.𝟙) ≡⟨⟩ - 𝔻 [ identityTrans F C ∘ F.fmap ℂ.𝟙 ] ≡⟨⟩ - 𝔻 [ 𝔻.𝟙 ∘ F.fmap ℂ.𝟙 ] ≡⟨ 𝔻.leftIdentity ⟩ - F.fmap ℂ.𝟙 ≡⟨ F.isIdentity ⟩ - 𝔻.𝟙 ∎ + fmap {c} {c} (Category.identity (object ⊗ ℂ) {c}) ≡⟨⟩ + fmap {c} {c} (idN F , ℂ.identity) ≡⟨⟩ + 𝔻 [ identityTrans F C ∘ F.fmap ℂ.identity ] ≡⟨⟩ + 𝔻 [ 𝔻.identity ∘ F.fmap ℂ.identity ] ≡⟨ 𝔻.leftIdentity ⟩ + F.fmap ℂ.identity ≡⟨ F.isIdentity ⟩ + 𝔻.identity ∎ where module F = Functor F @@ -278,16 +278,16 @@ module CatExponential {ℓ : Level} (ℂ 𝔻 : Category ℓ ℓ) where transpose : Functor 𝔸 object eq : F[ eval ∘ (parallelProduct transpose (Functors.identity {ℂ = ℂ})) ] ≡ F -- eq : F[ :eval: ∘ {!!} ] ≡ F - -- eq : Catℓ [ :eval: ∘ (HasProducts._|×|_ hasProducts transpose (𝟙 Catℓ {o = ℂ})) ] ≡ F + -- eq : Catℓ [ :eval: ∘ (HasProducts._|×|_ hasProducts transpose (identity Catℓ {o = ℂ})) ] ≡ F -- eq' : (Catℓ [ :eval: ∘ -- (record { product = product } HasProducts.|×| transpose) - -- (𝟙 Catℓ) + -- (identity Catℓ) -- ]) -- ≡ F -- For some reason after `e8215b2c051062c6301abc9b3f6ec67106259758` -- `catTranspose` makes Agda hang. catTranspose : ∃![ F~ ] (Catℓ [ - -- :eval: ∘ (parallelProduct F~ (𝟙 Catℓ {o = ℂ}))] ≡ F) catTranspose = + -- :eval: ∘ (parallelProduct F~ (identity Catℓ {o = ℂ}))] ≡ F) catTranspose = -- transpose , eq -- We don't care about filling out the holes below since they are anyways hidden diff --git a/src/Cat/Categories/Cube.agda b/src/Cat/Categories/Cube.agda index f338343..5322b16 100644 --- a/src/Cat/Categories/Cube.agda +++ b/src/Cat/Categories/Cube.agda @@ -67,7 +67,7 @@ module _ {ℓ ℓ' : Level} (Ns : Set ℓ) where Rawℂ : RawCategory ℓ ℓ -- ℓo (lsuc lzero ⊔ ℓo) Raw.Object Rawℂ = FiniteDecidableSubset Raw.Arrow Rawℂ = Hom - Raw.𝟙 Rawℂ {o} = inj₁ , λ { (i , ii) (j , jj) eq → Σ≡ eq {!refl!} } + Raw.identity Rawℂ {o} = inj₁ , λ { (i , ii) (j , jj) eq → Σ≡ eq {!refl!} } Raw._∘_ Rawℂ = {!!} postulate IsCategoryℂ : IsCategory Rawℂ diff --git a/src/Cat/Categories/Fam.agda b/src/Cat/Categories/Fam.agda index 5ffde56..ff4fafc 100644 --- a/src/Cat/Categories/Fam.agda +++ b/src/Cat/Categories/Fam.agda @@ -11,9 +11,9 @@ module _ (ℓa ℓb : Level) where Object = Σ[ hA ∈ hSet ℓa ] (proj₁ hA → hSet ℓb) Arr : Object → Object → Set (ℓa ⊔ ℓb) Arr ((A , _) , B) ((A' , _) , B') = Σ[ f ∈ (A → A') ] ({x : A} → proj₁ (B x) → proj₁ (B' (f x))) - 𝟙 : {A : Object} → Arr A A - proj₁ 𝟙 = λ x → x - proj₂ 𝟙 = λ b → b + identity : {A : Object} → Arr A A + proj₁ identity = λ x → x + proj₂ identity = λ b → b _∘_ : {a b c : Object} → Arr b c → Arr a b → Arr a c (g , g') ∘ (f , f') = g Function.∘ f , g' Function.∘ f' @@ -21,16 +21,16 @@ module _ (ℓa ℓb : Level) where RawFam = record { Object = Object ; Arrow = Arr - ; 𝟙 = λ { {A} → 𝟙 {A = A}} + ; identity = λ { {A} → identity {A = A}} ; _∘_ = λ {a b c} → _∘_ {a} {b} {c} } - open RawCategory RawFam hiding (Object ; 𝟙) + open RawCategory RawFam hiding (Object ; identity) isAssociative : IsAssociative isAssociative = Σ≡ refl refl - isIdentity : IsIdentity λ { {A} → 𝟙 {A} } + isIdentity : IsIdentity λ { {A} → identity {A} } isIdentity = (Σ≡ refl refl) , Σ≡ refl refl open import Cubical.NType.Properties diff --git a/src/Cat/Categories/Free.agda b/src/Cat/Categories/Free.agda index 1d262dd..29d6bbe 100644 --- a/src/Cat/Categories/Free.agda +++ b/src/Cat/Categories/Free.agda @@ -27,10 +27,10 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where module ℂ = Category ℂ RawFree : RawCategory ℓa (ℓa ⊔ ℓb) - RawCategory.Object RawFree = ℂ.Object - RawCategory.Arrow RawFree = Path ℂ.Arrow - RawCategory.𝟙 RawFree = empty - RawCategory._∘_ RawFree = concatenate + RawCategory.Object RawFree = ℂ.Object + RawCategory.Arrow RawFree = Path ℂ.Arrow + RawCategory.identity RawFree = empty + RawCategory._∘_ RawFree = concatenate open RawCategory RawFree @@ -52,7 +52,7 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where ident-l : ∀ {A} {B} {p : Path ℂ.Arrow A B} → concatenate empty p ≡ p ident-l = refl - isIdentity : IsIdentity 𝟙 + isIdentity : IsIdentity identity isIdentity = ident-l , ident-r open Univalence isIdentity diff --git a/src/Cat/Categories/Fun.agda b/src/Cat/Categories/Fun.agda index 791ddc6..1cd2e0a 100644 --- a/src/Cat/Categories/Fun.agda +++ b/src/Cat/Categories/Fun.agda @@ -1,28 +1,28 @@ -{-# OPTIONS --allow-unsolved-metas --cubical #-} +{-# OPTIONS --allow-unsolved-metas --cubical --caching #-} module Cat.Categories.Fun where open import Cat.Prelude open import Cat.Category open import Cat.Category.Functor +import Cat.Category.NaturalTransformation + as NaturalTransformation module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : Category ℓd ℓd') where - import Cat.Category.NaturalTransformation ℂ 𝔻 - as NaturalTransformation - open NaturalTransformation public hiding (module Properties) - open NaturalTransformation.Properties + open NaturalTransformation ℂ 𝔻 public hiding (module Properties) + open NaturalTransformation.Properties ℂ 𝔻 private module ℂ = Category ℂ module 𝔻 = Category 𝔻 -- Functor categories. Objects are functors, arrows are natural transformations. raw : RawCategory (ℓc ⊔ ℓc' ⊔ ℓd ⊔ ℓd') (ℓc ⊔ ℓc' ⊔ ℓd') - RawCategory.Object raw = Functor ℂ 𝔻 - RawCategory.Arrow raw = NaturalTransformation - RawCategory.𝟙 raw {F} = identity F - RawCategory._∘_ raw {F} {G} {H} = NT[_∘_] {F} {G} {H} + RawCategory.Object raw = Functor ℂ 𝔻 + RawCategory.Arrow raw = NaturalTransformation + RawCategory.identity raw {F} = identity F + RawCategory._∘_ raw {F} {G} {H} = NT[_∘_] {F} {G} {H} - open RawCategory raw + open RawCategory raw hiding (identity) open Univalence (λ {A} {B} {f} → isIdentity {F = A} {B} {f}) module _ (F : Functor ℂ 𝔻) where @@ -32,7 +32,7 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C open Σ center renaming (proj₂ to isoF) module _ (cG : Σ[ G ∈ Object ] (F ≅ G)) where - open Σ cG renaming (proj₁ to G ; proj₂ to isoG) + open Σ cG renaming (proj₁ to G ; proj₂ to isoG) module G = Functor G open Σ isoG renaming (proj₁ to θNT ; proj₂ to invθNT) open Σ invθNT renaming (proj₁ to ηNT ; proj₂ to areInv) @@ -46,10 +46,10 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C -- g = T[ η ∘ θ ] {!!} ntF : NaturalTransformation F F - ntF = 𝟙 {A = F} + ntF = identity F ntG : NaturalTransformation G G - ntG = 𝟙 {A = G} + ntG = identity G idFunctor = Functors.identity @@ -103,14 +103,14 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C -- The transformation will be the identity on 𝔻. Such an arrow has the -- type `A.omap A → A.omap A`. Which we can coerce to have the type -- `A.omap → B.omap` since `A` and `B` are equal. - coe𝟙 : Transformation A B - coe𝟙 X = coe coerceAB 𝔻.𝟙 + coeidentity : Transformation A B + coeidentity X = coe coerceAB 𝔻.identity module _ {a b : ℂ.Object} (f : ℂ [ a , b ]) where - nat' : 𝔻 [ coe𝟙 b ∘ A.fmap f ] ≡ 𝔻 [ B.fmap f ∘ coe𝟙 a ] + nat' : 𝔻 [ coeidentity b ∘ A.fmap f ] ≡ 𝔻 [ B.fmap f ∘ coeidentity a ] nat' = begin - (𝔻 [ coe𝟙 b ∘ A.fmap f ]) ≡⟨ {!!} ⟩ - (𝔻 [ B.fmap f ∘ coe𝟙 a ]) ∎ + (𝔻 [ coeidentity b ∘ A.fmap f ]) ≡⟨ {!!} ⟩ + (𝔻 [ B.fmap f ∘ coeidentity a ]) ∎ transs : (i : I) → Transformation A (p i) transs = {!!} @@ -118,26 +118,26 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C natt : (i : I) → Natural A (p i) {!!} natt = {!!} - t : Natural A B coe𝟙 + t : Natural A B coeidentity t = coe c (identityNatural A) where - c : Natural A A (identityTrans A) ≡ Natural A B coe𝟙 + c : Natural A A (identityTrans A) ≡ Natural A B coeidentity c = begin Natural A A (identityTrans A) ≡⟨ (λ x → {!natt ?!}) ⟩ - Natural A B coe𝟙 ∎ + Natural A B coeidentity ∎ -- cong (λ φ → {!Natural A A (identityTrans A)!}) {!!} - k : Natural A A (identityTrans A) → Natural A B coe𝟙 + k : Natural A A (identityTrans A) → Natural A B coeidentity k n {a} {b} f = res where - res : (𝔻 [ coe𝟙 b ∘ A.fmap f ]) ≡ (𝔻 [ B.fmap f ∘ coe𝟙 a ]) + res : (𝔻 [ coeidentity b ∘ A.fmap f ]) ≡ (𝔻 [ B.fmap f ∘ coeidentity a ]) res = {!!} - nat : Natural A B coe𝟙 + nat : Natural A B coeidentity nat = nat' fromEq : NaturalTransformation A B - fromEq = coe𝟙 , nat + fromEq = coeidentity , nat module _ {A B : Functor ℂ 𝔻} where obverse : A ≡ B → A ≅ B @@ -147,9 +147,9 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C ob = fromEq p re : Arrow B A re = fromEq (sym p) - vr : _∘_ {A = A} {B} {A} re ob ≡ 𝟙 {A} + vr : _∘_ {A = A} {B} {A} re ob ≡ identity A vr = {!!} - rv : _∘_ {A = B} {A} {B} ob re ≡ 𝟙 {B} + rv : _∘_ {A = B} {A} {B} ob re ≡ identity B rv = {!!} isInverse : IsInverseOf {A} {B} ob re isInverse = vr , rv @@ -183,23 +183,42 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C Category.raw Fun = raw Category.isCategory Fun = isCategory --- module _ {ℓ ℓ' : Level} (ℂ : Category ℓ ℓ') where --- private --- open import Cat.Categories.Sets --- open NaturalTransformation (opposite ℂ) (𝓢𝓮𝓽 ℓ') +module _ {ℓ ℓ' : Level} (ℂ : Category ℓ ℓ') where + private + open import Cat.Categories.Sets + open NaturalTransformation (opposite ℂ) (𝓢𝓮𝓽 ℓ') + module K = Fun (opposite ℂ) (𝓢𝓮𝓽 ℓ') + module F = Category K.Fun --- -- Restrict the functors to Presheafs. --- rawPresh : RawCategory (ℓ ⊔ lsuc ℓ') (ℓ ⊔ ℓ') --- rawPresh = record --- { Object = Presheaf ℂ --- ; Arrow = NaturalTransformation --- ; 𝟙 = λ {F} → identity F --- ; _∘_ = λ {F G H} → NT[_∘_] {F = F} {G = G} {H = H} --- } --- instance --- isCategory : IsCategory rawPresh --- isCategory = Fun.isCategory _ _ + -- Restrict the functors to Presheafs. + raw : RawCategory (ℓ ⊔ lsuc ℓ') (ℓ ⊔ ℓ') + raw = record + { Object = Presheaf ℂ + ; Arrow = NaturalTransformation + ; identity = λ {F} → identity F + ; _∘_ = λ {F G H} → NT[_∘_] {F = F} {G = G} {H = H} + } --- Presh : Category (ℓ ⊔ lsuc ℓ') (ℓ ⊔ ℓ') --- Category.raw Presh = rawPresh --- Category.isCategory Presh = isCategory + isCategory : IsCategory raw + isCategory = record + { isAssociative = + λ{ {A} {B} {C} {D} {f} {g} {h} + → F.isAssociative {A} {B} {C} {D} {f} {g} {h} + } + ; isIdentity = + λ{ {A} {B} {f} + → F.isIdentity {A} {B} {f} + } + ; arrowsAreSets = + λ{ {A} {B} + → F.arrowsAreSets {A} {B} + } + ; univalent = + λ{ {A} {B} + → F.univalent {A} {B} + } + } + + Presh : Category (ℓ ⊔ lsuc ℓ') (ℓ ⊔ ℓ') + Category.raw Presh = raw + Category.isCategory Presh = isCategory diff --git a/src/Cat/Categories/Rel.agda b/src/Cat/Categories/Rel.agda index 5b44601..73d4bff 100644 --- a/src/Cat/Categories/Rel.agda +++ b/src/Cat/Categories/Rel.agda @@ -153,7 +153,7 @@ RawRel : RawCategory (lsuc lzero) (lsuc lzero) RawRel = record { Object = Set ; Arrow = λ S R → Subset (S × R) - ; 𝟙 = λ {S} → Diag S + ; identity = λ {S} → Diag S ; _∘_ = λ {A B C} S R → λ {( a , c ) → Σ[ b ∈ B ] ( (a , b) ∈ R × (b , c) ∈ S )} } diff --git a/src/Cat/Categories/Sets.agda b/src/Cat/Categories/Sets.agda index f4c59fd..8536870 100644 --- a/src/Cat/Categories/Sets.agda +++ b/src/Cat/Categories/Sets.agda @@ -60,10 +60,10 @@ module _ {ℓ : Level} {A B : Set ℓ} {a : A} where module _ (ℓ : Level) where private SetsRaw : RawCategory (lsuc ℓ) ℓ - RawCategory.Object SetsRaw = hSet ℓ - RawCategory.Arrow SetsRaw (T , _) (U , _) = T → U - RawCategory.𝟙 SetsRaw = Function.id - RawCategory._∘_ SetsRaw = Function._∘′_ + RawCategory.Object SetsRaw = hSet ℓ + RawCategory.Arrow SetsRaw (T , _) (U , _) = T → U + RawCategory.identity SetsRaw = Function.id + RawCategory._∘_ SetsRaw = Function._∘′_ open RawCategory SetsRaw hiding (_∘_) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 8408cf0..2576ee2 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -12,7 +12,7 @@ -- -- Data -- ---- --- 𝟙; the identity arrow +-- identity; the identity arrow -- _∘_; function composition -- -- Laws @@ -48,10 +48,10 @@ import Function record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where no-eta-equality field - Object : Set ℓa - Arrow : Object → Object → Set ℓb - 𝟙 : {A : Object} → Arrow A A - _∘_ : {A B C : Object} → Arrow B C → Arrow A B → Arrow A C + Object : Set ℓa + Arrow : Object → Object → Set ℓb + identity : {A : Object} → Arrow A A + _∘_ : {A B C : Object} → Arrow B C → Arrow A B → Arrow A C infixl 10 _∘_ _>>>_ @@ -82,7 +82,7 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where ArrowsAreSets = ∀ {A B : Object} → isSet (Arrow A B) IsInverseOf : ∀ {A B} → (Arrow A B) → (Arrow B A) → Set ℓb - IsInverseOf = λ f g → g ∘ f ≡ 𝟙 × f ∘ g ≡ 𝟙 + IsInverseOf = λ f g → g ∘ f ≡ identity × f ∘ g ≡ identity Isomorphism : ∀ {A B} → (f : Arrow A B) → Set ℓb Isomorphism {A} {B} f = Σ[ g ∈ Arrow B A ] IsInverseOf f g @@ -110,10 +110,10 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where Terminal = Σ Object IsTerminal -- | Univalence is indexed by a raw category as well as an identity proof. - module Univalence (isIdentity : IsIdentity 𝟙) where + module Univalence (isIdentity : IsIdentity identity) where -- | The identity isomorphism idIso : (A : Object) → A ≅ A - idIso A = 𝟙 , 𝟙 , isIdentity + idIso A = identity , identity , isIdentity -- | Extract an isomorphism from an equality -- @@ -150,16 +150,16 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc open RawCategory ℂ public field isAssociative : IsAssociative - isIdentity : IsIdentity 𝟙 + isIdentity : IsIdentity identity arrowsAreSets : ArrowsAreSets open Univalence isIdentity public field univalent : Univalent - leftIdentity : {A B : Object} {f : Arrow A B} → 𝟙 ∘ f ≡ f + leftIdentity : {A B : Object} {f : Arrow A B} → identity ∘ f ≡ f leftIdentity {A} {B} {f} = fst (isIdentity {A = A} {B} {f}) - rightIdentity : {A B : Object} {f : Arrow A B} → f ∘ 𝟙 ≡ f + rightIdentity : {A B : Object} {f : Arrow A B} → f ∘ identity ≡ f rightIdentity {A} {B} {f} = snd (isIdentity {A = A} {B} {f}) ------------ @@ -171,24 +171,24 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc iso→epi : Isomorphism f → Epimorphism {X = X} f iso→epi (f- , left-inv , right-inv) g₀ g₁ eq = begin g₀ ≡⟨ sym rightIdentity ⟩ - g₀ ∘ 𝟙 ≡⟨ cong (_∘_ g₀) (sym right-inv) ⟩ + g₀ ∘ identity ≡⟨ cong (_∘_ g₀) (sym right-inv) ⟩ g₀ ∘ (f ∘ f-) ≡⟨ isAssociative ⟩ (g₀ ∘ f) ∘ f- ≡⟨ cong (λ φ → φ ∘ f-) eq ⟩ (g₁ ∘ f) ∘ f- ≡⟨ sym isAssociative ⟩ g₁ ∘ (f ∘ f-) ≡⟨ cong (_∘_ g₁) right-inv ⟩ - g₁ ∘ 𝟙 ≡⟨ rightIdentity ⟩ + g₁ ∘ identity ≡⟨ rightIdentity ⟩ g₁ ∎ iso→mono : Isomorphism f → Monomorphism {X = X} f iso→mono (f- , left-inv , right-inv) g₀ g₁ eq = begin g₀ ≡⟨ sym leftIdentity ⟩ - 𝟙 ∘ g₀ ≡⟨ cong (λ φ → φ ∘ g₀) (sym left-inv) ⟩ + identity ∘ g₀ ≡⟨ cong (λ φ → φ ∘ g₀) (sym left-inv) ⟩ (f- ∘ f) ∘ g₀ ≡⟨ sym isAssociative ⟩ f- ∘ (f ∘ g₀) ≡⟨ cong (_∘_ f-) eq ⟩ f- ∘ (f ∘ g₁) ≡⟨ isAssociative ⟩ (f- ∘ f) ∘ g₁ ≡⟨ cong (λ φ → φ ∘ g₁) left-inv ⟩ - 𝟙 ∘ g₁ ≡⟨ leftIdentity ⟩ + identity ∘ g₁ ≡⟨ leftIdentity ⟩ g₁ ∎ iso→epi×mono : Isomorphism f → Epimorphism {X = X} f × Monomorphism {X = X} f @@ -228,12 +228,12 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc where geq : g ≡ g' geq = begin - g ≡⟨ sym rightIdentity ⟩ - g ∘ 𝟙 ≡⟨ cong (λ φ → g ∘ φ) (sym ε') ⟩ - g ∘ (f ∘ g') ≡⟨ isAssociative ⟩ - (g ∘ f) ∘ g' ≡⟨ cong (λ φ → φ ∘ g') η ⟩ - 𝟙 ∘ g' ≡⟨ leftIdentity ⟩ - g' ∎ + g ≡⟨ sym rightIdentity ⟩ + g ∘ identity ≡⟨ cong (λ φ → g ∘ φ) (sym ε') ⟩ + g ∘ (f ∘ g') ≡⟨ isAssociative ⟩ + (g ∘ f) ∘ g' ≡⟨ cong (λ φ → φ ∘ g') η ⟩ + identity ∘ g' ≡⟨ leftIdentity ⟩ + g' ∎ propUnivalent : isProp Univalent propUnivalent a b i = propPi (λ iso → propIsContr) a b i @@ -274,9 +274,9 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc Xprop f g = trans (sym (snd Xit f)) (snd Xit g) Yprop : isProp (Arrow Y Y) Yprop f g = trans (sym (snd Yit f)) (snd Yit g) - left : Y→X ∘ X→Y ≡ 𝟙 + left : Y→X ∘ X→Y ≡ identity left = Xprop _ _ - right : X→Y ∘ Y→X ≡ 𝟙 + right : X→Y ∘ Y→X ≡ identity right = Yprop _ _ iso : X ≅ Y iso = X→Y , Y→X , left , right @@ -321,9 +321,9 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc Xprop f g = trans (sym (snd Xii f)) (snd Xii g) Yprop : isProp (Arrow Y Y) Yprop f g = trans (sym (snd Yii f)) (snd Yii g) - left : Y→X ∘ X→Y ≡ 𝟙 + left : Y→X ∘ X→Y ≡ identity left = Yprop _ _ - right : X→Y ∘ Y→X ≡ 𝟙 + right : X→Y ∘ Y→X ≡ identity right = Xprop _ _ iso : X ≅ Y iso = Y→X , X→Y , right , left @@ -351,18 +351,18 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where -- adverse effects this may have. module Prop = X.Propositionality - isIdentity : (λ _ → IsIdentity 𝟙) [ X.isIdentity ≡ Y.isIdentity ] + isIdentity : (λ _ → IsIdentity identity) [ X.isIdentity ≡ Y.isIdentity ] isIdentity = Prop.propIsIdentity X.isIdentity Y.isIdentity - U : ∀ {a : IsIdentity 𝟙} - → (λ _ → IsIdentity 𝟙) [ X.isIdentity ≡ a ] + U : ∀ {a : IsIdentity identity} + → (λ _ → IsIdentity identity) [ X.isIdentity ≡ a ] → (b : Univalent a) → Set _ U eqwal univ = (λ i → Univalent (eqwal i)) [ X.univalent ≡ univ ] - P : (y : IsIdentity 𝟙) - → (λ _ → IsIdentity 𝟙) [ X.isIdentity ≡ y ] → Set _ + P : (y : IsIdentity identity) + → (λ _ → IsIdentity identity) [ X.isIdentity ≡ y ] → Set _ P y eq = ∀ (univ : Univalent y) → U eq univ p : ∀ (b' : Univalent X.isIdentity) → (λ _ → Univalent X.isIdentity) [ X.univalent ≡ b' ] @@ -426,14 +426,14 @@ module Opposite {ℓa ℓb : Level} where private module ℂ = Category ℂ opRaw : RawCategory ℓa ℓb - RawCategory.Object opRaw = ℂ.Object - RawCategory.Arrow opRaw = Function.flip ℂ.Arrow - RawCategory.𝟙 opRaw = ℂ.𝟙 - RawCategory._∘_ opRaw = Function.flip ℂ._∘_ + RawCategory.Object opRaw = ℂ.Object + RawCategory.Arrow opRaw = Function.flip ℂ.Arrow + RawCategory.identity opRaw = ℂ.identity + RawCategory._∘_ opRaw = Function.flip ℂ._∘_ open RawCategory opRaw - isIdentity : IsIdentity 𝟙 + isIdentity : IsIdentity identity isIdentity = swap ℂ.isIdentity open Univalence isIdentity @@ -530,7 +530,7 @@ module Opposite {ℓa ℓb : Level} where rawInv : Category.raw (opposite (opposite ℂ)) ≡ raw RawCategory.Object (rawInv _) = Object RawCategory.Arrow (rawInv _) = Arrow - RawCategory.𝟙 (rawInv _) = 𝟙 + RawCategory.identity (rawInv _) = identity RawCategory._∘_ (rawInv _) = _∘_ oppositeIsInvolution : opposite (opposite ℂ) ≡ ℂ diff --git a/src/Cat/Category/Exponential.agda b/src/Cat/Category/Exponential.agda index 76652d2..4b4f017 100644 --- a/src/Cat/Category/Exponential.agda +++ b/src/Cat/Category/Exponential.agda @@ -16,11 +16,11 @@ module _ {ℓ ℓ'} (ℂ : Category ℓ ℓ') {{hasProducts : HasProducts ℂ}} field uniq : ∀ (A : Object) (f : ℂ [ A × B , C ]) - → ∃![ f~ ] (ℂ [ eval ∘ f~ |×| Category.𝟙 ℂ ] ≡ f) + → ∃![ f~ ] (ℂ [ eval ∘ f~ |×| Category.identity ℂ ] ≡ f) IsExponential : (Cᴮ : Object) → ℂ [ Cᴮ × B , C ] → Set (ℓ ⊔ ℓ') IsExponential Cᴮ eval = ∀ (A : Object) (f : ℂ [ A × B , C ]) - → ∃![ f~ ] (ℂ [ eval ∘ f~ |×| Category.𝟙 ℂ ] ≡ f) + → ∃![ f~ ] (ℂ [ eval ∘ f~ |×| Category.identity ℂ ] ≡ f) record Exponential : Set (ℓ ⊔ ℓ') where field diff --git a/src/Cat/Category/Functor.agda b/src/Cat/Category/Functor.agda index bbdda14..c4a7346 100644 --- a/src/Cat/Category/Functor.agda +++ b/src/Cat/Category/Functor.agda @@ -30,7 +30,7 @@ module _ {ℓc ℓc' ℓd ℓd'} fmap : ∀ {A B} → ℂ [ A , B ] → 𝔻 [ omap A , omap B ] IsIdentity : Set _ - IsIdentity = {A : ℂ.Object} → fmap (ℂ.𝟙 {A}) ≡ 𝔻.𝟙 {omap A} + IsIdentity = {A : ℂ.Object} → fmap (ℂ.identity {A}) ≡ 𝔻.identity {omap A} IsDistributive : Set _ IsDistributive = {A B C : ℂ.Object} {f : ℂ [ A , B ]} {g : ℂ [ B , C ]} @@ -150,10 +150,10 @@ module _ {ℓ0 ℓ1 ℓ2 ℓ3 ℓ4 ℓ5 : Level} isFunctor : IsFunctor A C raw isFunctor = record { isIdentity = begin - (F.fmap ∘ G.fmap) A.𝟙 ≡⟨ refl ⟩ - F.fmap (G.fmap A.𝟙) ≡⟨ cong F.fmap (G.isIdentity)⟩ - F.fmap B.𝟙 ≡⟨ F.isIdentity ⟩ - C.𝟙 ∎ + (F.fmap ∘ G.fmap) A.identity ≡⟨ refl ⟩ + F.fmap (G.fmap A.identity) ≡⟨ cong F.fmap (G.isIdentity)⟩ + F.fmap B.identity ≡⟨ F.isIdentity ⟩ + C.identity ∎ ; isDistributive = dist } diff --git a/src/Cat/Category/Monad.agda b/src/Cat/Category/Monad.agda index 8fc6c56..6383ab0 100644 --- a/src/Cat/Category/Monad.agda +++ b/src/Cat/Category/Monad.agda @@ -33,10 +33,10 @@ module Kleisli = Cat.Category.Monad.Kleisli -- | The monoidal- and kleisli presentation of monads are equivalent. module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where - open Cat.Category.NaturalTransformation ℂ ℂ + open Cat.Category.NaturalTransformation ℂ ℂ using (NaturalTransformation ; propIsNatural) private module ℂ = Category ℂ - open ℂ using (Object ; Arrow ; 𝟙 ; _∘_ ; _>>>_) + open ℂ using (Object ; Arrow ; identity ; _∘_ ; _>>>_) module M = Monoidal ℂ module K = Kleisli ℂ @@ -84,11 +84,11 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where inv-l = begin joinT X ∘ pureT (R.omap X) ≡⟨⟩ join ∘ pure ≡⟨ proj₁ isInverse ⟩ - 𝟙 ∎ + identity ∎ inv-r = begin joinT X ∘ R.fmap (pureT X) ≡⟨⟩ join ∘ fmap pure ≡⟨ proj₂ isInverse ⟩ - 𝟙 ∎ + identity ∎ back : K.Monad → M.Monad Monoidal.Monad.raw (back m) = backRaw m @@ -103,21 +103,21 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where bindEq {X} {Y} = begin K.RawMonad.bind (forthRaw (backRaw m)) ≡⟨⟩ (λ f → join ∘ fmap f) ≡⟨⟩ - (λ f → bind (f >>> pure) >>> bind 𝟙) ≡⟨ funExt lem ⟩ + (λ f → bind (f >>> pure) >>> bind identity) ≡⟨ funExt lem ⟩ (λ f → bind f) ≡⟨⟩ bind ∎ where lem : (f : Arrow X (omap Y)) - → bind (f >>> pure) >>> bind 𝟙 + → bind (f >>> pure) >>> bind identity ≡ bind f lem f = begin - bind (f >>> pure) >>> bind 𝟙 + bind (f >>> pure) >>> bind identity ≡⟨ isDistributive _ _ ⟩ - bind ((f >>> pure) >>> bind 𝟙) + bind ((f >>> pure) >>> bind identity) ≡⟨ cong bind ℂ.isAssociative ⟩ - bind (f >>> (pure >>> bind 𝟙)) + bind (f >>> (pure >>> bind identity)) ≡⟨ cong (λ φ → bind (f >>> φ)) (isNatural _) ⟩ - bind (f >>> 𝟙) + bind (f >>> identity) ≡⟨ cong bind ℂ.leftIdentity ⟩ bind f ∎ @@ -146,10 +146,10 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where joinEq : ∀ {X} → KM.join ≡ joinT X joinEq {X} = begin KM.join ≡⟨⟩ - KM.bind 𝟙 ≡⟨⟩ - bind 𝟙 ≡⟨⟩ - joinT X ∘ Rfmap 𝟙 ≡⟨ cong (λ φ → _ ∘ φ) R.isIdentity ⟩ - joinT X ∘ 𝟙 ≡⟨ ℂ.rightIdentity ⟩ + KM.bind identity ≡⟨⟩ + bind identity ≡⟨⟩ + joinT X ∘ Rfmap identity ≡⟨ cong (λ φ → _ ∘ φ) R.isIdentity ⟩ + joinT X ∘ identity ≡⟨ ℂ.rightIdentity ⟩ joinT X ∎ fmapEq : ∀ {A B} → KM.fmap {A} {B} ≡ Rfmap @@ -161,7 +161,7 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where Rfmap (f >>> pureT B) >>> joinT B ≡⟨ cong (λ φ → φ >>> joinT B) R.isDistributive ⟩ Rfmap f >>> Rfmap (pureT B) >>> joinT B ≡⟨ ℂ.isAssociative ⟩ joinT B ∘ Rfmap (pureT B) ∘ Rfmap f ≡⟨ cong (λ φ → φ ∘ Rfmap f) (proj₂ isInverse) ⟩ - 𝟙 ∘ Rfmap f ≡⟨ ℂ.leftIdentity ⟩ + identity ∘ Rfmap f ≡⟨ ℂ.leftIdentity ⟩ Rfmap f ∎ ) @@ -183,8 +183,8 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where joinTEq = funExt (λ X → begin M.RawMonad.joinT (backRaw (forth m)) X ≡⟨⟩ KM.join ≡⟨⟩ - joinT X ∘ Rfmap 𝟙 ≡⟨ cong (λ φ → joinT X ∘ φ) R.isIdentity ⟩ - joinT X ∘ 𝟙 ≡⟨ ℂ.rightIdentity ⟩ + joinT X ∘ Rfmap identity ≡⟨ cong (λ φ → joinT X ∘ φ) R.isIdentity ⟩ + joinT X ∘ identity ≡⟨ ℂ.rightIdentity ⟩ joinT X ∎) joinNTEq : (λ i → NaturalTransformation F[ Req i ∘ Req i ] (Req i)) diff --git a/src/Cat/Category/Monad/Kleisli.agda b/src/Cat/Category/Monad/Kleisli.agda index bf79a5f..dc40f1c 100644 --- a/src/Cat/Category/Monad/Kleisli.agda +++ b/src/Cat/Category/Monad/Kleisli.agda @@ -12,11 +12,13 @@ open import Cat.Categories.Fun -- "A monad in the Kleisli form" [voe] module Cat.Category.Monad.Kleisli {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where -open import Cat.Category.NaturalTransformation ℂ ℂ hiding (propIsNatural) +open import Cat.Category.NaturalTransformation ℂ ℂ + using (NaturalTransformation ; Transformation ; Natural) + private ℓ = ℓa ⊔ ℓb module ℂ = Category ℂ - open ℂ using (Arrow ; 𝟙 ; Object ; _∘_ ; _>>>_) + open ℂ using (Arrow ; identity ; Object ; _∘_ ; _>>>_) -- | Data for a monad. -- @@ -40,7 +42,7 @@ record RawMonad : Set ℓ where -- | Flattening nested monads. join : {A : Object} → ℂ [ omap (omap A) , omap A ] - join = bind 𝟙 + join = bind identity ------------------ -- * Monad laws -- @@ -49,7 +51,7 @@ record RawMonad : Set ℓ where -- There may be better names than what I've chosen here. IsIdentity = {X : Object} - → bind pure ≡ 𝟙 {omap X} + → bind pure ≡ identity {omap X} IsNatural = {X Y : Object} (f : ℂ [ X , omap Y ]) → pure >>> (bind f) ≡ f IsDistributive = {X Y Z : Object} (g : ℂ [ Y , omap Z ]) (f : ℂ [ X , omap Y ]) @@ -67,7 +69,7 @@ record RawMonad : Set ℓ where IsNaturalForeign = {X : Object} → join {X} ∘ fmap join ≡ join ∘ join IsInverse : Set _ - IsInverse = {X : Object} → join {X} ∘ pure ≡ 𝟙 × join {X} ∘ fmap pure ≡ 𝟙 + IsInverse = {X : Object} → join {X} ∘ pure ≡ identity × join {X} ∘ fmap pure ≡ identity record IsMonad (raw : RawMonad) : Set ℓ where open RawMonad raw public @@ -100,9 +102,9 @@ record IsMonad (raw : RawMonad) : Set ℓ where isFunctorR : IsFunctor ℂ ℂ rawR IsFunctor.isIdentity isFunctorR = begin - bind (pure ∘ 𝟙) ≡⟨ cong bind (ℂ.rightIdentity) ⟩ - bind pure ≡⟨ isIdentity ⟩ - 𝟙 ∎ + bind (pure ∘ identity) ≡⟨ cong bind (ℂ.rightIdentity) ⟩ + bind pure ≡⟨ isIdentity ⟩ + identity ∎ IsFunctor.isDistributive isFunctorR {f = f} {g} = begin bind (pure ∘ (g ∘ f)) ≡⟨⟩ @@ -137,29 +139,29 @@ record IsMonad (raw : RawMonad) : Set ℓ where joinN : Natural R² R joinT joinN f = begin join ∘ R².fmap f ≡⟨⟩ - bind 𝟙 ∘ R².fmap f ≡⟨⟩ - R².fmap f >>> bind 𝟙 ≡⟨⟩ - fmap (fmap f) >>> bind 𝟙 ≡⟨⟩ - fmap (bind (f >>> pure)) >>> bind 𝟙 ≡⟨⟩ - bind (bind (f >>> pure) >>> pure) >>> bind 𝟙 + bind identity ∘ R².fmap f ≡⟨⟩ + R².fmap f >>> bind identity ≡⟨⟩ + fmap (fmap f) >>> bind identity ≡⟨⟩ + fmap (bind (f >>> pure)) >>> bind identity ≡⟨⟩ + bind (bind (f >>> pure) >>> pure) >>> bind identity ≡⟨ isDistributive _ _ ⟩ - bind ((bind (f >>> pure) >>> pure) >=> 𝟙) + bind ((bind (f >>> pure) >>> pure) >=> identity) ≡⟨⟩ - bind ((bind (f >>> pure) >>> pure) >>> bind 𝟙) + bind ((bind (f >>> pure) >>> pure) >>> bind identity) ≡⟨ cong bind ℂ.isAssociative ⟩ - bind (bind (f >>> pure) >>> (pure >>> bind 𝟙)) + bind (bind (f >>> pure) >>> (pure >>> bind identity)) ≡⟨ cong (λ φ → bind (bind (f >>> pure) >>> φ)) (isNatural _) ⟩ - bind (bind (f >>> pure) >>> 𝟙) + bind (bind (f >>> pure) >>> identity) ≡⟨ cong bind ℂ.leftIdentity ⟩ bind (bind (f >>> pure)) ≡⟨ cong bind (sym ℂ.rightIdentity) ⟩ - bind (𝟙 >>> bind (f >>> pure)) ≡⟨⟩ - bind (𝟙 >=> (f >>> pure)) + bind (identity >>> bind (f >>> pure)) ≡⟨⟩ + bind (identity >=> (f >>> pure)) ≡⟨ sym (isDistributive _ _) ⟩ - bind 𝟙 >>> bind (f >>> pure) ≡⟨⟩ - bind 𝟙 >>> fmap f ≡⟨⟩ - bind 𝟙 >>> R.fmap f ≡⟨⟩ - R.fmap f ∘ bind 𝟙 ≡⟨⟩ + bind identity >>> bind (f >>> pure) ≡⟨⟩ + bind identity >>> fmap f ≡⟨⟩ + bind identity >>> R.fmap f ≡⟨⟩ + R.fmap f ∘ bind identity ≡⟨⟩ R.fmap f ∘ join ∎ pureNT : NaturalTransformation R⁰ R @@ -173,20 +175,20 @@ record IsMonad (raw : RawMonad) : Set ℓ where isNaturalForeign : IsNaturalForeign isNaturalForeign = begin fmap join >>> join ≡⟨⟩ - bind (join >>> pure) >>> bind 𝟙 + bind (join >>> pure) >>> bind identity ≡⟨ isDistributive _ _ ⟩ - bind ((join >>> pure) >>> bind 𝟙) + bind ((join >>> pure) >>> bind identity) ≡⟨ cong bind ℂ.isAssociative ⟩ - bind (join >>> (pure >>> bind 𝟙)) + bind (join >>> (pure >>> bind identity)) ≡⟨ cong (λ φ → bind (join >>> φ)) (isNatural _) ⟩ - bind (join >>> 𝟙) + bind (join >>> identity) ≡⟨ cong bind ℂ.leftIdentity ⟩ bind join ≡⟨⟩ - bind (bind 𝟙) + bind (bind identity) ≡⟨ cong bind (sym ℂ.rightIdentity) ⟩ - bind (𝟙 >>> bind 𝟙) ≡⟨⟩ - bind (𝟙 >=> 𝟙) ≡⟨ sym (isDistributive _ _) ⟩ - bind 𝟙 >>> bind 𝟙 ≡⟨⟩ + bind (identity >>> bind identity) ≡⟨⟩ + bind (identity >=> identity) ≡⟨ sym (isDistributive _ _) ⟩ + bind identity >>> bind identity ≡⟨⟩ join >>> join ∎ isInverse : IsInverse @@ -194,21 +196,21 @@ record IsMonad (raw : RawMonad) : Set ℓ where where inv-l = begin pure >>> join ≡⟨⟩ - pure >>> bind 𝟙 ≡⟨ isNatural _ ⟩ - 𝟙 ∎ + pure >>> bind identity ≡⟨ isNatural _ ⟩ + identity ∎ inv-r = begin fmap pure >>> join ≡⟨⟩ - bind (pure >>> pure) >>> bind 𝟙 + bind (pure >>> pure) >>> bind identity ≡⟨ isDistributive _ _ ⟩ - bind ((pure >>> pure) >=> 𝟙) ≡⟨⟩ - bind ((pure >>> pure) >>> bind 𝟙) + bind ((pure >>> pure) >=> identity) ≡⟨⟩ + bind ((pure >>> pure) >>> bind identity) ≡⟨ cong bind ℂ.isAssociative ⟩ - bind (pure >>> (pure >>> bind 𝟙)) + bind (pure >>> (pure >>> bind identity)) ≡⟨ cong (λ φ → bind (pure >>> φ)) (isNatural _) ⟩ - bind (pure >>> 𝟙) + bind (pure >>> identity) ≡⟨ cong bind ℂ.leftIdentity ⟩ bind pure ≡⟨ isIdentity ⟩ - 𝟙 ∎ + identity ∎ record Monad : Set ℓ where field diff --git a/src/Cat/Category/Monad/Monoidal.agda b/src/Cat/Category/Monad/Monoidal.agda index 69f3865..56319c2 100644 --- a/src/Cat/Category/Monad/Monoidal.agda +++ b/src/Cat/Category/Monad/Monoidal.agda @@ -16,8 +16,10 @@ module Cat.Category.Monad.Monoidal {ℓa ℓb : Level} (ℂ : Category ℓa ℓb private ℓ = ℓa ⊔ ℓb -open Category ℂ using (Object ; Arrow ; 𝟙 ; _∘_) +open Category ℂ using (Object ; Arrow ; identity ; _∘_) open import Cat.Category.NaturalTransformation ℂ ℂ + using (NaturalTransformation ; Transformation ; Natural) + record RawMonad : Set ℓ where field R : EndoFunctor ℂ @@ -47,8 +49,8 @@ record RawMonad : Set ℓ where → joinT X ∘ Rfmap (joinT X) ≡ joinT X ∘ joinT (Romap X) IsInverse : Set _ IsInverse = {X : Object} - → joinT X ∘ pureT (Romap X) ≡ 𝟙 - × joinT X ∘ Rfmap (pureT X) ≡ 𝟙 + → joinT X ∘ pureT (Romap X) ≡ identity + × joinT X ∘ Rfmap (pureT X) ≡ identity IsNatural = ∀ {X Y} f → joinT Y ∘ Rfmap f ∘ pureT X ≡ f IsDistributive = ∀ {X Y Z} (g : Arrow Y (Romap Z)) (f : Arrow X (Romap Y)) → joinT Z ∘ Rfmap g ∘ (joinT Y ∘ Rfmap f) @@ -70,7 +72,7 @@ record IsMonad (raw : RawMonad) : Set ℓ where joinT Y ∘ (R.fmap f ∘ pureT X) ≡⟨ cong (λ φ → joinT Y ∘ φ) (sym (pureN f)) ⟩ joinT Y ∘ (pureT (R.omap Y) ∘ f) ≡⟨ ℂ.isAssociative ⟩ joinT Y ∘ pureT (R.omap Y) ∘ f ≡⟨ cong (λ φ → φ ∘ f) (proj₁ isInverse) ⟩ - 𝟙 ∘ f ≡⟨ ℂ.leftIdentity ⟩ + identity ∘ f ≡⟨ ℂ.leftIdentity ⟩ f ∎ isDistributive : IsDistributive diff --git a/src/Cat/Category/NaturalTransformation.agda b/src/Cat/Category/NaturalTransformation.agda index a478aee..0b4d784 100644 --- a/src/Cat/Category/NaturalTransformation.agda +++ b/src/Cat/Category/NaturalTransformation.agda @@ -31,7 +31,7 @@ module Cat.Category.NaturalTransformation {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : Category ℓd ℓd') where -open Category using (Object ; 𝟙) +open Category using (Object) private module ℂ = Category ℂ module 𝔻 = Category 𝔻 @@ -63,14 +63,14 @@ module _ (F G : Functor ℂ 𝔻) where NaturalTransformation≡ eq = lemSig propIsNatural _ _ eq identityTrans : (F : Functor ℂ 𝔻) → Transformation F F -identityTrans F C = 𝟙 𝔻 +identityTrans F C = 𝔻.identity identityNatural : (F : Functor ℂ 𝔻) → Natural F F (identityTrans F) identityNatural F {A = A} {B = B} f = begin 𝔻 [ identityTrans F B ∘ F→ f ] ≡⟨⟩ - 𝔻 [ 𝟙 𝔻 ∘ F→ f ] ≡⟨ 𝔻.leftIdentity ⟩ + 𝔻 [ 𝔻.identity ∘ F→ f ] ≡⟨ 𝔻.leftIdentity ⟩ F→ f ≡⟨ sym 𝔻.rightIdentity ⟩ - 𝔻 [ F→ f ∘ 𝟙 𝔻 ] ≡⟨⟩ + 𝔻 [ F→ f ∘ 𝔻.identity ] ≡⟨⟩ 𝔻 [ F→ f ∘ identityTrans F A ] ∎ where module F = Functor F diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 03f6c4a..e956377 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -134,7 +134,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} ( ℂ [ ya ∘ xy ] ≡ xa) × ℂ [ yb ∘ xy ] ≡ xb } - ; 𝟙 = λ{ {A , f , g} → ℂ.𝟙 {A} , ℂ.rightIdentity , ℂ.rightIdentity} + ; identity = λ{ {A , f , g} → ℂ.identity {A} , ℂ.rightIdentity , ℂ.rightIdentity} ; _∘_ = λ { {A , a0 , a1} {B , b0 , b1} {C , c0 , c1} (f , f0 , f1) (g , g0 , g1) → (f ℂ.∘ g) , (begin @@ -169,24 +169,24 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} s0 = ℂ.isAssociative {f = f} {g} {h} - isIdentity : IsIdentity 𝟙 + isIdentity : IsIdentity identity isIdentity {AA@(A , a0 , a1)} {BB@(B , b0 , b1)} {f , f0 , f1} = leftIdentity , rightIdentity where - leftIdentity : 𝟙 ∘ (f , f0 , f1) ≡ (f , f0 , f1) + leftIdentity : identity ∘ (f , f0 , f1) ≡ (f , f0 , f1) leftIdentity i = l i , lemPropF propEqs l {proj₂ L} {proj₂ R} i where - L = 𝟙 ∘ (f , f0 , f1) + L = identity ∘ (f , f0 , f1) R : Arrow AA BB R = f , f0 , f1 l : proj₁ L ≡ proj₁ R l = ℂ.leftIdentity - rightIdentity : (f , f0 , f1) ∘ 𝟙 ≡ (f , f0 , f1) + rightIdentity : (f , f0 , f1) ∘ identity ≡ (f , f0 , f1) rightIdentity i = l i , lemPropF propEqs l {proj₂ L} {proj₂ R} i where - L = (f , f0 , f1) ∘ 𝟙 + L = (f , f0 , f1) ∘ identity R : Arrow AA BB R = (f , f0 , f1) - l : ℂ [ f ∘ ℂ.𝟙 ] ≡ f + l : ℂ [ f ∘ ℂ.identity ] ≡ f l = ℂ.rightIdentity arrowsAreSets : ArrowsAreSets diff --git a/src/Cat/Category/Yoneda.agda b/src/Cat/Category/Yoneda.agda index 1efc90e..afea823 100644 --- a/src/Cat/Category/Yoneda.agda +++ b/src/Cat/Category/Yoneda.agda @@ -52,7 +52,7 @@ module _ {ℓ : Level} {ℂ : Category ℓ ℓ} where isIdentity : IsIdentity isIdentity {c} = lemSig prp _ _ eq where - eq : (λ C x → ℂ [ ℂ.𝟙 ∘ x ]) ≡ identityTrans (presheaf c) + eq : (λ C x → ℂ [ ℂ.identity ∘ x ]) ≡ identityTrans (presheaf c) eq = funExt λ A → funExt λ B → ℂ.leftIdentity prp = F.naturalIsProp _ _ {F = presheaf c} {presheaf c} From 467c5d9c0cd41bd3c0f9205da0495b0fe3860f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 3 Apr 2018 12:40:20 +0200 Subject: [PATCH 20/93] [WIP] Propositionality of products --- src/Cat/Category/Product.agda | 80 +++++++++++++++++------------------ src/Cat/Prelude.agda | 6 +++ 2 files changed, 44 insertions(+), 42 deletions(-) diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index e956377..c25bec4 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -69,8 +69,14 @@ module _ {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} {A B : Category.Object module y = IsProduct y module _ {X : Object} (f : ℂ [ X , A ]) (g : ℂ [ X , B ]) where + module _ (f×g : Arrow X y.object) where + help : isProp (∀{y} → (ℂ [ y.proj₁ ∘ y ] ≡ f) P.× (ℂ [ y.proj₂ ∘ y ] ≡ g) → f×g ≡ y) + help = propPiImpl (λ _ → propPi (λ _ → arrowsAreSets _ _)) + + res = ∃-unique (x.ump f g) (y.ump f g) + prodAux : x.ump f g ≡ y.ump f g - prodAux = {!!} + prodAux = lemSig ((λ f×g → propSig (propSig (arrowsAreSets _ _) λ _ → arrowsAreSets _ _) (λ _ → help f×g))) _ _ res propIsProduct' : x ≡ y propIsProduct' i = record { ump = λ f g → prodAux f g i } @@ -84,42 +90,6 @@ module _ {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} {A B : Category.Object q : (λ i → IsProduct ℂ A B (p i)) [ Product.isProduct x ≡ Product.isProduct y ] q = lemPropF propIsProduct p -module _ {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} {A B : Category.Object ℂ} where - open Category ℂ - private - module _ (x y : HasProducts ℂ) where - private - module x = HasProducts x - module y = HasProducts y - module _ (A B : Object) where - module pX = Product (x.product A B) - module pY = Product (y.product A B) - objEq : pX.object ≡ pY.object - objEq = {!!} - proj₁Eq : (λ i → ℂ [ objEq i , A ]) [ pX.proj₁ ≡ pY.proj₁ ] - proj₁Eq = {!!} - proj₂Eq : (λ i → ℂ [ objEq i , B ]) [ pX.proj₂ ≡ pY.proj₂ ] - proj₂Eq = {!!} - rawEq : pX.raw ≡ pY.raw - RawProduct.object (rawEq i) = objEq i - RawProduct.proj₁ (rawEq i) = {!!} - RawProduct.proj₂ (rawEq i) = {!!} - - isEq : (λ i → IsProduct ℂ A B (rawEq i)) [ pX.isProduct ≡ pY.isProduct ] - isEq = {!!} - - appEq : x.product A B ≡ y.product A B - appEq = Product≡ rawEq - - productEq : x.product ≡ y.product - productEq i = λ A B → appEq A B i - - propHasProducts' : x ≡ y - propHasProducts' i = record { product = productEq i } - - propHasProducts : isProp (HasProducts ℂ) - propHasProducts = propHasProducts' - module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} (let module ℂ = Category ℂ) {A B : ℂ.Object} where @@ -212,12 +182,17 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} -- b : b0 ≡ b1 -- b = {!!} + open Univalence isIdentity + + univalent : Univalent + univalent {A , a0 , a1} {B , b0 , b1} = {!!} + isCat : IsCategory raw isCat = record { isAssociative = isAssocitaive ; isIdentity = isIdentity ; arrowsAreSets = arrowsAreSets - ; univalent = {!!} + ; univalent = univalent } cat : Category _ _ @@ -296,13 +271,34 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} t {Xx} = Xo , contractible ve-re : ∀ x → g (f x) ≡ x ve-re x = Propositionality.propTerminal _ _ - re-ve : ∀ x → f (g x) ≡ x - re-ve x = {!!} + re-ve : ∀ p → f (g p) ≡ p + re-ve p = Product≡ e + where + module p = Product p + -- RawProduct does not have eta-equality. + e : Product.raw (f (g p)) ≡ Product.raw p + RawProduct.object (e i) = p.object + RawProduct.proj₁ (e i) = p.proj₁ + RawProduct.proj₂ (e i) = p.proj₂ inv : AreInverses f g inv = record { verso-recto = funExt ve-re ; recto-verso = funExt re-ve } - thm : isProp (Product ℂ A B) - thm = equivPreservesNType {n = ⟨-1⟩} lemma Propositionality.propTerminal + propProduct : isProp (Product ℂ A B) + propProduct = equivPreservesNType {n = ⟨-1⟩} lemma Propositionality.propTerminal + +module _ {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} {A B : Category.Object ℂ} where + open Category ℂ + private + module _ (x y : HasProducts ℂ) where + private + module x = HasProducts x + module y = HasProducts y + + productEq : x.product ≡ y.product + productEq = funExt λ A → funExt λ B → Try0.propProduct _ _ + + propHasProducts : isProp (HasProducts ℂ) + propHasProducts x y i = record { product = productEq x y i } diff --git a/src/Cat/Prelude.agda b/src/Cat/Prelude.agda index 036d2c7..abe1ae4 100644 --- a/src/Cat/Prelude.agda +++ b/src/Cat/Prelude.agda @@ -56,6 +56,12 @@ module _ (ℓ : Level) where syntax ∃!-syntax (λ x → B) = ∃![ x ] B +module _ {ℓa ℓb} {A : Set ℓa} {P : A → Set ℓb} (f g : ∃! P) where + open Σ (proj₂ f) renaming (proj₂ to u) + + ∃-unique : proj₁ f ≡ proj₁ g + ∃-unique = u (proj₁ (proj₂ g)) + module _ {ℓa ℓb : Level} {A : Set ℓa} {B : A → Set ℓb} {a b : Σ A B} (proj₁≡ : (λ _ → A) [ proj₁ a ≡ proj₁ b ]) (proj₂≡ : (λ i → B (proj₁≡ i)) [ proj₂ a ≡ proj₂ b ]) where From 1e5fb7d50a3e3255ad779812e16f36cc733885c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 3 Apr 2018 14:46:36 +0200 Subject: [PATCH 21/93] [WIP] Arrows are sets in special product category --- src/Cat/Category/Product.agda | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index c25bec4..c22e4b4 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -160,27 +160,31 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} l = ℂ.rightIdentity arrowsAreSets : ArrowsAreSets - arrowsAreSets {X , x0 , x1} {Y , y0 , y1} (f , f0 , f1) (g , g0 , g1) p q = {!!} + arrowsAreSets {X , x0 , x1} {Y , y0 , y1} (f , f0 , f1) (g , g0 , g1) p q = pq where - prop : ∀ {X Y} (x y : ℂ.Arrow X Y) → isProp (x ≡ y) - prop = ℂ.arrowsAreSets + -- prop : ∀ {X Y} (x y : ℂ.Arrow X Y) → isProp (x ≡ y) + -- prop = ℂ.arrowsAreSets a0 a1 : f ≡ g a0 i = proj₁ (p i) a1 i = proj₁ (q i) a : a0 ≡ a1 a = ℂ.arrowsAreSets _ _ a0 a1 - res : p ≡ q - res i j = a i j , {!b i j!} , {!!} - where - -- b0 b1 : (λ j → (ℂ [ y0 ∘ a i j ]) ≡ x0) [ f0 ≡ g0 ] - -- b0 = lemPropF (λ x → prop (ℂ [ y0 ∘ x ]) x0) (a i) - -- b1 = lemPropF (λ x → prop (ℂ [ y0 ∘ x ]) x0) (a i) - b0 : (λ j → (ℂ [ y0 ∘ a0 j ]) ≡ x0) [ f0 ≡ g0 ] - b0 = lemPropF (λ x → prop (ℂ [ y0 ∘ x ]) x0) a0 - b1 : (λ j → (ℂ [ y0 ∘ a1 j ]) ≡ x0) [ f0 ≡ g0 ] - b1 = lemPropF (λ x → prop (ℂ [ y0 ∘ x ]) x0) a1 - -- b : b0 ≡ b1 - -- b = {!!} + module _ (i : I) where + r : f ≡ g + r = a i + module _ (j : I) where + prop0 : isProp (ℂ [ y0 ∘ r j ] ≡ x0) + prop0 = ℂ.arrowsAreSets _ _ + prop1 : isProp (ℂ [ y1 ∘ r j ] ≡ x1) + prop1 = ℂ.arrowsAreSets _ _ + prop : isProp (ℂ [ y0 ∘ r j ] ≡ x0 × ℂ [ y1 ∘ r j ] ≡ x1) + prop = propSig prop0 (λ _ → prop1) + helper : (b0 b1 : (ℂ [ y0 ∘ r j ]) ≡ x0 × (ℂ [ y1 ∘ r j ]) ≡ x1) → b0 ≡ b1 + helper _ _ = lemPropF (λ _ → prop) p + b : (ℂ [ y0 ∘ r j ]) ≡ x0 × (ℂ [ y1 ∘ r j ]) ≡ x1 + b = {!!} + pq : p ≡ q + pq i j = a i j , b i j open Univalence isIdentity From 172287f0a7d7e9dadaab2fa03b49258845a1d521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 3 Apr 2018 15:23:11 +0200 Subject: [PATCH 22/93] [QED] The ad-hoc product category has hom-sets that are h-sets --- src/Cat/Category.agda | 6 +++++ src/Cat/Category/Product.agda | 46 +++++++++++++++-------------------- src/Cat/Prelude.agda | 2 +- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 2576ee2..0ee54dd 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -199,6 +199,12 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc univalent≃ : Univalent≃ univalent≃ = _ , univalent + module _ {A B : Object} where + open import Cat.Equivalence using (module Equiv≃) + + iso-to-id : (A ≅ B) → (A ≡ B) + iso-to-id = fst (Equiv≃.toIso _ _ univalent) + -- | All projections are propositions. module Propositionality where propIsAssociative : isProp IsAssociative diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index c22e4b4..0e25ba2 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -160,36 +160,30 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} l = ℂ.rightIdentity arrowsAreSets : ArrowsAreSets - arrowsAreSets {X , x0 , x1} {Y , y0 , y1} (f , f0 , f1) (g , g0 , g1) p q = pq - where - -- prop : ∀ {X Y} (x y : ℂ.Arrow X Y) → isProp (x ≡ y) - -- prop = ℂ.arrowsAreSets - a0 a1 : f ≡ g - a0 i = proj₁ (p i) - a1 i = proj₁ (q i) - a : a0 ≡ a1 - a = ℂ.arrowsAreSets _ _ a0 a1 - module _ (i : I) where - r : f ≡ g - r = a i - module _ (j : I) where - prop0 : isProp (ℂ [ y0 ∘ r j ] ≡ x0) - prop0 = ℂ.arrowsAreSets _ _ - prop1 : isProp (ℂ [ y1 ∘ r j ] ≡ x1) - prop1 = ℂ.arrowsAreSets _ _ - prop : isProp (ℂ [ y0 ∘ r j ] ≡ x0 × ℂ [ y1 ∘ r j ] ≡ x1) - prop = propSig prop0 (λ _ → prop1) - helper : (b0 b1 : (ℂ [ y0 ∘ r j ]) ≡ x0 × (ℂ [ y1 ∘ r j ]) ≡ x1) → b0 ≡ b1 - helper _ _ = lemPropF (λ _ → prop) p - b : (ℂ [ y0 ∘ r j ]) ≡ x0 × (ℂ [ y1 ∘ r j ]) ≡ x1 - b = {!!} - pq : p ≡ q - pq i j = a i j , b i j + arrowsAreSets {X , x0 , x1} {Y , y0 , y1} + = sigPresNType {n = ⟨0⟩} ℂ.arrowsAreSets λ a → propSet (propEqs _) open Univalence isIdentity univalent : Univalent - univalent {A , a0 , a1} {B , b0 , b1} = {!!} + univalent {X , x} {Y , y} = {!res!} + where + open import Cat.Equivalence as E hiding (_≅_) + open import Cubical.Univalence + module _ (c : (X , x) ≅ (Y , y)) where + -- module _ (c : _ ≅ _) where + c0 : X ℂ.≅ Y + c0 = {!!} + f0 : X ≡ Y + f0 = ℂ.iso-to-id c0 + f1 : PathP (λ i → ℂ.Arrow (f0 i) A × ℂ.Arrow (f0 i) B) x y + f1 = {!!} + f : (X , x) ≡ (Y , y) + f i = f0 i , f1 i + iso : E.Isomorphism (id-to-iso (X , x) (Y , y)) + iso = f , record { verso-recto = {!!} ; recto-verso = {!!} } + res : isEquiv ((X , x) ≡ (Y , y)) ((X , x) ≅ (Y , y)) (id-to-iso (X , x) (Y , y)) + res = Equiv≃.fromIso _ _ iso isCat : IsCategory raw isCat = record diff --git a/src/Cat/Prelude.agda b/src/Cat/Prelude.agda index abe1ae4..370b300 100644 --- a/src/Cat/Prelude.agda +++ b/src/Cat/Prelude.agda @@ -28,7 +28,7 @@ open import Cubical.NType.Properties propIsContr : {ℓ : Level} → {A : Set ℓ} → isProp (isContr A) propIsContr = propHasLevel ⟨-2⟩ -open import Cubical.Sigma using (setSig ; sigPresSet) public +open import Cubical.Sigma using (setSig ; sigPresSet ; sigPresNType) public module _ (ℓ : Level) where -- FIXME Ask if we can push upstream. From f66d180ec301cbe1313e1720c4d2a54a6e6b8b57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 4 Apr 2018 11:27:03 +0200 Subject: [PATCH 23/93] [WIP] Stronger lemma for univalence --- src/Cat/Category.agda | 52 +++++++++++++++++++++++++++++++++-- src/Cat/Category/Product.agda | 27 ++++++++++++++---- 2 files changed, 72 insertions(+), 7 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 0ee54dd..cb0340c 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -131,6 +131,55 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where Univalent[Contr] : Set _ Univalent[Contr] = ∀ A → isContr (Σ[ X ∈ Object ] A ≅ X) + private + module _ (A : Object) where + postulate + -- It may be that we need something weaker than this, in that there + -- may be some other lemmas available to us. + -- For instance, `need0` should be available to us when we prove `need1`. + need0 : ∀ Y → A ≡ Y + need1 : (f : Arrow A A) → identity ≡ f + + c : Σ Object (A ≅_) + c = A , idIso A + + module _ (y : Σ Object (A ≅_)) where + open Σ y renaming (proj₁ to Y ; proj₂ to isoY) + q : A ≡ Y + q = need0 Y + + -- Some error with primComp + isoAY : A ≅ Y + isoAY = {!id-to-iso A Y q!} + + lem : PathP (λ i → A ≅ q i) (idIso A) isoY + lem = d* isoAY + where + D : (Y : Object) → (A ≡ Y) → Set _ + D Y p = (A≅Y : A ≅ Y) → PathP (λ i → A ≅ p i) (idIso A) A≅Y + d : D A refl + d A≅Y i = a0 i , a1 i , a2 i + where + open Σ A≅Y renaming (proj₁ to f ; proj₂ to iso-f) + open Σ iso-f renaming (proj₁ to f~ ; proj₂ to areInv) + a0 : identity ≡ f + a0 = need1 f + a1 : identity ≡ f~ + a1 = need1 f~ + -- we do have this! + postulate + prop : ∀ {A B} (fg : Arrow A B × Arrow B A) → isProp (IsInverseOf (fst fg) (snd fg)) + a2 : PathP (λ i → IsInverseOf (a0 i) (a1 i)) isIdentity areInv + a2 = lemPropF prop λ i → a0 i , a1 i + d* : D Y q + d* = pathJ D d Y q + + p : (A , idIso A) ≡ (Y , isoY) + p i = need0 Y i , lem i + + univ-lem : isContr (Σ Object (A ≅_)) + univ-lem = c , p + -- From: Thierry Coquand -- Date: Wed, Mar 21, 2018 at 3:12 PM -- @@ -312,7 +361,7 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc res i = fp i , cp i propInitial : isProp Initial - propInitial Xi Yi = {!!} + propInitial Xi Yi = res where open Σ Xi renaming (proj₁ to X ; proj₂ to Xii) open Σ Yi renaming (proj₁ to Y ; proj₂ to Yii) @@ -342,7 +391,6 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc res : Xi ≡ Yi res i = p0 i , p1 i - -- | Propositionality of being a category module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where open RawCategory ℂ diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 0e25ba2..a811ecd 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -172,16 +172,33 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} open import Cubical.Univalence module _ (c : (X , x) ≅ (Y , y)) where -- module _ (c : _ ≅ _) where + open Σ c renaming (proj₁ to f_c ; proj₂ to inv_c) + open Σ inv_c renaming (proj₁ to g_c ; proj₂ to ainv_c) + open Σ ainv_c renaming (proj₁ to left ; proj₂ to right) c0 : X ℂ.≅ Y - c0 = {!!} + c0 = proj₁ f_c , proj₁ g_c , (λ i → proj₁ (left i)) , (λ i → proj₁ (right i)) f0 : X ≡ Y f0 = ℂ.iso-to-id c0 - f1 : PathP (λ i → ℂ.Arrow (f0 i) A × ℂ.Arrow (f0 i) B) x y - f1 = {!!} + module _ {A : ℂ.Object} (α : ℂ.Arrow X A) where + coedom : ℂ.Arrow Y A + coedom = coe (λ i → ℂ.Arrow (f0 i) A) α + coex : ℂ.Arrow Y A × ℂ.Arrow Y B + coex = coe (λ i → ℂ.Arrow (f0 i) A × ℂ.Arrow (f0 i) B) x + f1 : PathP (λ i → ℂ.Arrow (f0 i) A × ℂ.Arrow (f0 i) B) x coex + f1 = {!sym!} + f2 : coex ≡ y + f2 = {!!} f : (X , x) ≡ (Y , y) - f i = f0 i , f1 i + f i = f0 i , {!f1 i!} + prp : isSet (ℂ.Object × ℂ.Arrow Y A × ℂ.Arrow Y B) + prp = setSig {sA = {!!}} {(λ _ → setSig {sA = ℂ.arrowsAreSets} {λ _ → ℂ.arrowsAreSets})} + ve-re : (p : (X , x) ≡ (Y , y)) → f (id-to-iso _ _ p) ≡ p + -- ve-re p i j = {!ℂ.arrowsAreSets!} , ℂ.arrowsAreSets _ _ (let k = proj₁ (proj₂ (p i)) in {!!}) {!!} {!!} {!!} , {!!} + ve-re p = let k = prp {!!} {!!} {!!} {!p!} in {!!} + re-ve : (iso : (X , x) ≅ (Y , y)) → id-to-iso _ _ (f iso) ≡ iso + re-ve = {!!} iso : E.Isomorphism (id-to-iso (X , x) (Y , y)) - iso = f , record { verso-recto = {!!} ; recto-verso = {!!} } + iso = f , record { verso-recto = funExt ve-re ; recto-verso = funExt re-ve } res : isEquiv ((X , x) ≡ (Y , y)) ((X , x) ≅ (Y , y)) (id-to-iso (X , x) (Y , y)) res = Equiv≃.fromIso _ _ iso From 84f88ac2ae8d5a1ec1ba32716633f2d8e220c63e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 4 Apr 2018 12:01:29 +0200 Subject: [PATCH 24/93] Change what is needed --- src/Cat/Category.agda | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index cb0340c..9c1ee7c 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -137,8 +137,11 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where -- It may be that we need something weaker than this, in that there -- may be some other lemmas available to us. -- For instance, `need0` should be available to us when we prove `need1`. - need0 : ∀ Y → A ≡ Y - need1 : (f : Arrow A A) → identity ≡ f + need0 : (s : Σ Object (A ≅_)) → (open Σ s renaming (proj₁ to Y) using ()) → A ≡ Y + need2 : (iso : A ≅ A) + → (open Σ iso renaming (proj₁ to f ; proj₂ to iso-f)) + → (open Σ iso-f renaming (proj₁ to f~ ; proj₂ to areInv)) + → (identity , identity) ≡ (f , f~) c : Σ Object (A ≅_) c = A , idIso A @@ -146,7 +149,7 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where module _ (y : Σ Object (A ≅_)) where open Σ y renaming (proj₁ to Y ; proj₂ to isoY) q : A ≡ Y - q = need0 Y + q = need0 y -- Some error with primComp isoAY : A ≅ Y @@ -162,20 +165,23 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where where open Σ A≅Y renaming (proj₁ to f ; proj₂ to iso-f) open Σ iso-f renaming (proj₁ to f~ ; proj₂ to areInv) + aaa : (identity , identity) ≡ (f , f~) + aaa = need2 A≅Y a0 : identity ≡ f - a0 = need1 f + a0 i = fst (aaa i) a1 : identity ≡ f~ - a1 = need1 f~ + a1 i = snd (aaa i) -- we do have this! + -- I just need to rearrange the proofs a bit. postulate prop : ∀ {A B} (fg : Arrow A B × Arrow B A) → isProp (IsInverseOf (fst fg) (snd fg)) a2 : PathP (λ i → IsInverseOf (a0 i) (a1 i)) isIdentity areInv - a2 = lemPropF prop λ i → a0 i , a1 i + a2 = lemPropF prop aaa d* : D Y q d* = pathJ D d Y q p : (A , idIso A) ≡ (Y , isoY) - p i = need0 Y i , lem i + p i = q i , lem i univ-lem : isContr (Σ Object (A ≅_)) univ-lem = c , p From d78965d73f0e73756fb30a2997021d1fe45c27f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 4 Apr 2018 17:45:36 +0200 Subject: [PATCH 25/93] Try to use lemma for proving univalence of product-category thing --- src/Cat/Categories/Sets.agda | 30 --------- src/Cat/Category.agda | 14 +++-- src/Cat/Category/Product.agda | 115 ++++++++++++++++++++++++++++++++-- 3 files changed, 119 insertions(+), 40 deletions(-) diff --git a/src/Cat/Categories/Sets.agda b/src/Cat/Categories/Sets.agda index 8536870..ab094c9 100644 --- a/src/Cat/Categories/Sets.agda +++ b/src/Cat/Categories/Sets.agda @@ -27,36 +27,6 @@ sym≃ = Equivalence.symmetry infixl 10 _⊙_ -module _ {ℓ : Level} {A : Set ℓ} {a : A} where - id-coe : coe refl a ≡ a - id-coe = begin - coe refl a ≡⟨⟩ - pathJ (λ y x → A) _ A refl ≡⟨ pathJprop {x = a} (λ y x → A) _ ⟩ - _ ≡⟨ pathJprop {x = a} (λ y x → A) _ ⟩ - a ∎ - -module _ {ℓ : Level} {A B : Set ℓ} {a : A} where - inv-coe : (p : A ≡ B) → coe (sym p) (coe p a) ≡ a - inv-coe p = - let - D : (y : Set ℓ) → _ ≡ y → Set _ - D _ q = coe (sym q) (coe q a) ≡ a - d : D A refl - d = begin - coe (sym refl) (coe refl a) ≡⟨⟩ - coe refl (coe refl a) ≡⟨ id-coe ⟩ - coe refl a ≡⟨ id-coe ⟩ - a ∎ - in pathJ D d B p - inv-coe' : (p : B ≡ A) → coe p (coe (sym p) a) ≡ a - inv-coe' p = - let - D : (y : Set ℓ) → _ ≡ y → Set _ - D _ q = coe (sym q) (coe q a) ≡ a - k : coe p (coe (sym p) a) ≡ a - k = pathJ D (trans id-coe id-coe) B (sym p) - in k - module _ (ℓ : Level) where private SetsRaw : RawCategory (lsuc ℓ) ℓ diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 9c1ee7c..5c497b9 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -132,16 +132,16 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where Univalent[Contr] = ∀ A → isContr (Σ[ X ∈ Object ] A ≅ X) private - module _ (A : Object) where - postulate + module _ (A : Object) -- It may be that we need something weaker than this, in that there -- may be some other lemmas available to us. -- For instance, `need0` should be available to us when we prove `need1`. - need0 : (s : Σ Object (A ≅_)) → (open Σ s renaming (proj₁ to Y) using ()) → A ≡ Y - need2 : (iso : A ≅ A) + (need0 : (s : Σ Object (A ≅_)) → (open Σ s renaming (proj₁ to Y) using ()) → A ≡ Y) + (need2 : (iso : A ≅ A) → (open Σ iso renaming (proj₁ to f ; proj₂ to iso-f)) → (open Σ iso-f renaming (proj₁ to f~ ; proj₂ to areInv)) → (identity , identity) ≡ (f , f~) + ) where c : Σ Object (A ≅_) c = A , idIso A @@ -186,6 +186,12 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where univ-lem : isContr (Σ Object (A ≅_)) univ-lem = c , p + univalence-lemma + : (∀ {A} → (s : Σ Object (_≅_ A)) → A ≡ fst s) + → (∀ {A} → (iso : A ≅ A) → (identity , identity) ≡ (fst iso , fst (snd iso))) + → Univalent[Contr] + univalence-lemma s u A = univ-lem A s u + -- From: Thierry Coquand -- Date: Wed, Mar 21, 2018 at 3:12 PM -- diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index a811ecd..44fb0ef 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -99,13 +99,13 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} raw : RawCategory _ _ raw = record { Object = Σ[ X ∈ ℂ.Object ] ℂ.Arrow X A × ℂ.Arrow X B - ; Arrow = λ{ (X , xa , xb) (Y , ya , yb) - → Σ[ xy ∈ ℂ.Arrow X Y ] - ( ℂ [ ya ∘ xy ] ≡ xa) - × ℂ [ yb ∘ xy ] ≡ xb + ; Arrow = λ{ (X , x0 , x1) (Y , y0 , y1) + → Σ[ f ∈ ℂ.Arrow X Y ] + ℂ [ y0 ∘ f ] ≡ x0 + × ℂ [ y1 ∘ f ] ≡ x1 } - ; identity = λ{ {A , f , g} → ℂ.identity {A} , ℂ.rightIdentity , ℂ.rightIdentity} - ; _∘_ = λ { {A , a0 , a1} {B , b0 , b1} {C , c0 , c1} (f , f0 , f1) (g , g0 , g1) + ; identity = λ{ {X , f , g} → ℂ.identity {X} , ℂ.rightIdentity , ℂ.rightIdentity} + ; _∘_ = λ { {_ , a0 , a1} {_ , b0 , b1} {_ , c0 , c1} (f , f0 , f1) (g , g0 , g1) → (f ℂ.∘ g) , (begin ℂ [ c0 ∘ ℂ [ f ∘ g ] ] ≡⟨ ℂ.isAssociative ⟩ @@ -165,6 +165,109 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} open Univalence isIdentity + module _ (A : Object) where + c : Σ Object (A ≅_) + c = A , {!!} + univalent[Contr] : isContr (Σ Object (A ≅_)) + univalent[Contr] = {!!} , {!!} + + univalent' : Univalent[Contr] + univalent' = univalence-lemma p q + where + module _ {𝕏 : Object} where + open Σ 𝕏 renaming (proj₁ to X ; proj₂ to x0x1) + open Σ x0x1 renaming (proj₁ to x0 ; proj₂ to x1) + -- x0 : X → A in ℂ + -- x1 : X → B in ℂ + module _ (𝕐-isoY : Σ Object (𝕏 ≅_)) where + open Σ 𝕐-isoY renaming (proj₁ to 𝕐  ; proj₂ to isoY) + open Σ 𝕐 renaming (proj₁ to Y ; proj₂ to y0y1) + open Σ y0y1  renaming (proj₁ to y0 ; proj₂ to y1) + open Σ isoY  renaming (proj₁ to 𝓯 ; proj₂ to iso-𝓯) + open Σ iso-𝓯  renaming (proj₁ to 𝓯~ ; proj₂ to inv-𝓯) + open Σ 𝓯  renaming (proj₁ to f ; proj₂ to inv-f) + open Σ 𝓯~  renaming (proj₁ to f~ ; proj₂ to inv-f~) + open Σ inv-𝓯  renaming (proj₁ to left ; proj₂ to right) + -- y0 : Y → A in ℂ + -- y1 : Y → B in ℂ + -- f : X → Y in ℂ + -- inv-f : ℂ [ y0 ∘ f ] ≡ x0 × ℂ [ y1 ∘ f ] ≡ x1 + -- left : 𝓯~ ∘ 𝓯 ≡ identity + -- left~ : 𝓯 ∘ 𝓯~ ≡ identity + isoℂ : X ℂ.≅ Y + isoℂ + = f + , f~ + , ( begin + ℂ [ f~ ∘ f ] ≡⟨ (λ i → proj₁ (left i)) ⟩ + ℂ.identity ∎ + ) + , ( begin + ℂ [ f ∘ f~ ] ≡⟨ (λ i → proj₁ (right i)) ⟩ + ℂ.identity ∎ + ) + p0 : X ≡ Y + p0 = ℂ.iso-to-id isoℂ + -- I note `left2` and right2` here as a reminder. + left2 : PathP + (λ i → ℂ [ x0 ∘ proj₁ (left i) ] ≡ x0 × ℂ [ x1 ∘ proj₁ (left i) ] ≡ x1) + (proj₂ (𝓯~ ∘ 𝓯)) (proj₂ identity) + left2 i = proj₂ (left i) + right2 : PathP + (λ i → ℂ [ y0 ∘ proj₁ (right i) ] ≡ y0 × ℂ [ y1 ∘ proj₁ (right i) ] ≡ y1) + (proj₂ (𝓯 ∘ 𝓯~)) (proj₂ identity) + right2 i = proj₂ (right i) + -- My idea: + -- + -- x0, x1 and y0 and y1 are product arrows as in the diagram + -- + -- X + -- ↙ ↘ + -- A ⇣ ⇡ B + -- ↖ ↗ + -- Y (All hail unicode) + -- + -- The dotted lines indicate the unique product arrows. Since they are + -- unique they necessarily be each others inverses. Alas, more than + -- this we must show that they are actually (heterogeneously) + -- identical as in `p1`: + p1 : PathP (λ i → ℂ.Arrow (p0 i) A × ℂ.Arrow (p0 i) B) x0x1 y0y1 + p1 = {!!} + where + -- This, however, should probably somehow follow from them being + -- inverses on objects that are propositionally equal cf. `p0`. + helper : {A B : Object} {f : Arrow A B} {g : Arrow B A} + → IsInverseOf f g + → (p : A ≡ B) + → PathP (λ i → Arrow (p i) (p (~ i))) f g + helper = {!!} + + p : (X , x0x1) ≡ (Y , y0y1) + p i = p0 i , {!!} + module _ (iso : 𝕏 ≅ 𝕏) where + open Σ iso renaming (proj₁ to 𝓯 ; proj₂ to inv-𝓯) + open Σ inv-𝓯 renaming (proj₁ to 𝓯~) using () + open Σ 𝓯 renaming (proj₁ to f ; proj₂ to inv-f) + open Σ 𝓯~ renaming (proj₁ to f~ ; proj₂ to inv-f~) + q0' : ℂ.identity ≡ f + q0' i = {!!} + prop : ∀ x → isProp (ℂ [ x0 ∘ x ] ≡ x0 × ℂ [ x1 ∘ x ] ≡ x1) + prop x = propSig + ( ℂ.arrowsAreSets (ℂ [ x0 ∘ x ]) x0) + (λ _ → ℂ.arrowsAreSets (ℂ [ x1 ∘ x ]) x1) + q0'' : PathP (λ i → ℂ [ x0 ∘ q0' i ] ≡ x0 × ℂ [ x1 ∘ q0' i ] ≡ x1) (proj₂ identity) inv-f + q0'' = lemPropF prop q0' + q0 : identity ≡ 𝓯 + q0 i = q0' i , q0'' i + q1' : ℂ.identity ≡ f~ + q1' = {!!} + q1'' : PathP (λ i → (ℂ [ x0 ∘ q1' i ]) ≡ x0 × (ℂ [ x1 ∘ q1' i ]) ≡ x1) (proj₂ identity) inv-f~ + q1'' = lemPropF prop q1' + q1 : identity ≡ 𝓯~ + q1 i = q1' i , {!!} + q : (identity , identity) ≡ (𝓯 , 𝓯~) + q i = q0 i , q1 i + univalent : Univalent univalent {X , x} {Y , y} = {!res!} where From 8276deb4aac1edad24ed9abf321a442fda02dde0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 5 Apr 2018 10:41:56 +0200 Subject: [PATCH 26/93] Rename proj. to fst and snd --- src/Cat/Categories/Cat.agda | 46 +++--- src/Cat/Categories/CwF.agda | 18 +-- src/Cat/Categories/Fam.agda | 14 +- src/Cat/Categories/Fun.agda | 14 +- src/Cat/Categories/Rel.agda | 2 +- src/Cat/Categories/Sets.agda | 91 ++++++----- src/Cat/Category.agda | 56 ++++--- src/Cat/Category/Exponential.agda | 2 +- src/Cat/Category/Monad.agda | 8 +- src/Cat/Category/Monad/Kleisli.agda | 8 +- src/Cat/Category/Monad/Monoidal.agda | 14 +- src/Cat/Category/Monad/Voevodsky.agda | 2 +- src/Cat/Category/NaturalTransformation.agda | 6 +- src/Cat/Category/Product.agda | 159 +++++++++++--------- src/Cat/Prelude.agda | 19 +-- 15 files changed, 238 insertions(+), 221 deletions(-) diff --git a/src/Cat/Categories/Cat.agda b/src/Cat/Categories/Cat.agda index a5d986e..da421e9 100644 --- a/src/Cat/Categories/Cat.agda +++ b/src/Cat/Categories/Cat.agda @@ -3,7 +3,7 @@ module Cat.Categories.Cat where -open import Cat.Prelude renaming (proj₁ to fst ; proj₂ to snd) +open import Cat.Prelude renaming (fst to fst ; snd to snd) open import Cat.Category open import Cat.Category.Functor @@ -83,16 +83,16 @@ module CatProduct {ℓ ℓ' : Level} (ℂ 𝔻 : Category ℓ ℓ') where object : Category ℓ ℓ' Category.raw object = rawProduct - proj₁ : Functor object ℂ - proj₁ = record + fstF : Functor object ℂ + fstF = record { raw = record { omap = fst ; fmap = fst } ; isFunctor = record { isIdentity = refl ; isDistributive = refl } } - proj₂ : Functor object 𝔻 - proj₂ = record + sndF : Functor object 𝔻 + sndF = record { raw = record { omap = snd ; fmap = snd } ; isFunctor = record @@ -116,19 +116,19 @@ module CatProduct {ℓ ℓ' : Level} (ℂ 𝔻 : Category ℓ ℓ') where open module x₁ = Functor x₁ open module x₂ = Functor x₂ - isUniqL : F[ proj₁ ∘ x ] ≡ x₁ + isUniqL : F[ fstF ∘ x ] ≡ x₁ isUniqL = Functor≡ refl - isUniqR : F[ proj₂ ∘ x ] ≡ x₂ + isUniqR : F[ sndF ∘ x ] ≡ x₂ isUniqR = Functor≡ refl - isUniq : F[ proj₁ ∘ x ] ≡ x₁ × F[ proj₂ ∘ x ] ≡ x₂ + isUniq : F[ fstF ∘ x ] ≡ x₁ × F[ sndF ∘ x ] ≡ x₂ isUniq = isUniqL , isUniqR - isProduct : ∃![ x ] (F[ proj₁ ∘ x ] ≡ x₁ × F[ proj₂ ∘ x ] ≡ x₂) + isProduct : ∃![ x ] (F[ fstF ∘ x ] ≡ x₁ × F[ sndF ∘ x ] ≡ x₂) isProduct = x , isUniq , uq where - module _ {y : Functor X object} (eq : F[ proj₁ ∘ y ] ≡ x₁ × F[ proj₂ ∘ y ] ≡ x₂) where + module _ {y : Functor X object} (eq : F[ fstF ∘ y ] ≡ x₁ × F[ sndF ∘ y ] ≡ x₂) where omapEq : Functor.omap x ≡ Functor.omap y omapEq = {!!} -- fmapEq : (λ i → {!{A B : ?} → Arrow A B → 𝔻 [ ? A , ? B ]!}) [ Functor.fmap x ≡ Functor.fmap y ] @@ -148,8 +148,8 @@ module _ {ℓ ℓ' : Level} (unprovable : IsCategory (RawCat ℓ ℓ')) where rawProduct : RawProduct Catℓ ℂ 𝔻 RawProduct.object rawProduct = P.object - RawProduct.proj₁ rawProduct = P.proj₁ - RawProduct.proj₂ rawProduct = P.proj₂ + RawProduct.fst rawProduct = P.fstF + RawProduct.snd rawProduct = P.sndF isProduct : IsProduct Catℓ _ _ rawProduct IsProduct.ump isProduct = P.isProduct @@ -182,8 +182,8 @@ module CatExponential {ℓ : Level} (ℂ 𝔻 : Category ℓ ℓ) where object = Fun module _ {dom cod : Functor ℂ 𝔻 × ℂ.Object} where - open Σ dom renaming (proj₁ to F ; proj₂ to A) - open Σ cod renaming (proj₁ to G ; proj₂ to B) + open Σ dom renaming (fst to F ; snd to A) + open Σ cod renaming (fst to G ; snd to B) private module F = Functor F module G = Functor G @@ -200,7 +200,7 @@ module CatExponential {ℓ : Level} (ℂ 𝔻 : Category ℓ ℓ) where open CatProduct renaming (object to _⊗_) using () module _ {c : Functor ℂ 𝔻 × ℂ.Object} where - open Σ c renaming (proj₁ to F ; proj₂ to C) + open Σ c renaming (fst to F ; snd to C) ident : fmap {c} {c} (identityNT F , ℂ.identity {A = snd c}) ≡ 𝔻.identity ident = begin @@ -214,9 +214,9 @@ module CatExponential {ℓ : Level} (ℂ 𝔻 : Category ℓ ℓ) where module F = Functor F module _ {F×A G×B H×C : Functor ℂ 𝔻 × ℂ.Object} where - open Σ F×A renaming (proj₁ to F ; proj₂ to A) - open Σ G×B renaming (proj₁ to G ; proj₂ to B) - open Σ H×C renaming (proj₁ to H ; proj₂ to C) + open Σ F×A renaming (fst to F ; snd to A) + open Σ G×B renaming (fst to G ; snd to B) + open Σ H×C renaming (fst to H ; snd to C) private module F = Functor F module G = Functor G @@ -225,14 +225,14 @@ module CatExponential {ℓ : Level} (ℂ 𝔻 : Category ℓ ℓ) where module _ {θ×f : NaturalTransformation F G × ℂ [ A , B ]} {η×g : NaturalTransformation G H × ℂ [ B , C ]} where - open Σ θ×f renaming (proj₁ to θNT ; proj₂ to f) - open Σ θNT renaming (proj₁ to θ ; proj₂ to θNat) - open Σ η×g renaming (proj₁ to ηNT ; proj₂ to g) - open Σ ηNT renaming (proj₁ to η ; proj₂ to ηNat) + open Σ θ×f renaming (fst to θNT ; snd to f) + open Σ θNT renaming (fst to θ ; snd to θNat) + open Σ η×g renaming (fst to ηNT ; snd to g) + open Σ ηNT renaming (fst to η ; snd to ηNat) private ηθNT : NaturalTransformation F H ηθNT = NT[_∘_] {F} {G} {H} ηNT θNT - open Σ ηθNT renaming (proj₁ to ηθ ; proj₂ to ηθNat) + open Σ ηθNT renaming (fst to ηθ ; snd to ηθNat) isDistributive : 𝔻 [ 𝔻 [ η C ∘ θ C ] ∘ F.fmap ( ℂ [ g ∘ f ] ) ] diff --git a/src/Cat/Categories/CwF.agda b/src/Cat/Categories/CwF.agda index 45dbf2b..1a491ec 100644 --- a/src/Cat/Categories/CwF.agda +++ b/src/Cat/Categories/CwF.agda @@ -25,21 +25,21 @@ module _ {ℓa ℓb : Level} where private module T = Functor T Type : (Γ : ℂ.Object) → Set ℓa - Type Γ = proj₁ (proj₁ (T.omap Γ)) + Type Γ = fst (fst (T.omap Γ)) module _ {Γ : ℂ.Object} {A : Type Γ} where -- module _ {A B : Object ℂ} {γ : ℂ [ A , B ]} where - -- k : Σ (proj₁ (omap T B) → proj₁ (omap T A)) + -- k : Σ (fst (omap T B) → fst (omap T A)) -- (λ f → - -- {x : proj₁ (omap T B)} → - -- proj₂ (omap T B) x → proj₂ (omap T A) (f x)) + -- {x : fst (omap T B)} → + -- snd (omap T B) x → snd (omap T A) (f x)) -- k = T.fmap γ - -- k₁ : proj₁ (omap T B) → proj₁ (omap T A) - -- k₁ = proj₁ k - -- k₂ : ({x : proj₁ (omap T B)} → - -- proj₂ (omap T B) x → proj₂ (omap T A) (k₁ x)) - -- k₂ = proj₂ k + -- k₁ : fst (omap T B) → fst (omap T A) + -- k₁ = fst k + -- k₂ : ({x : fst (omap T B)} → + -- snd (omap T B) x → snd (omap T A) (k₁ x)) + -- k₂ = snd k record ContextComprehension : Set (ℓa ⊔ ℓb) where field diff --git a/src/Cat/Categories/Fam.agda b/src/Cat/Categories/Fam.agda index ff4fafc..897d6e0 100644 --- a/src/Cat/Categories/Fam.agda +++ b/src/Cat/Categories/Fam.agda @@ -8,12 +8,12 @@ open import Cat.Category module _ (ℓa ℓb : Level) where private - Object = Σ[ hA ∈ hSet ℓa ] (proj₁ hA → hSet ℓb) + Object = Σ[ hA ∈ hSet ℓa ] (fst hA → hSet ℓb) Arr : Object → Object → Set (ℓa ⊔ ℓb) - Arr ((A , _) , B) ((A' , _) , B') = Σ[ f ∈ (A → A') ] ({x : A} → proj₁ (B x) → proj₁ (B' (f x))) + Arr ((A , _) , B) ((A' , _) , B') = Σ[ f ∈ (A → A') ] ({x : A} → fst (B x) → fst (B' (f x))) identity : {A : Object} → Arr A A - proj₁ identity = λ x → x - proj₂ identity = λ b → b + fst identity = λ x → x + snd identity = λ b → b _∘_ : {a b c : Object} → Arr b c → Arr a b → Arr a c (g , g') ∘ (f , f') = g Function.∘ f , g' Function.∘ f' @@ -47,11 +47,11 @@ module _ (ℓa ℓb : Level) where {sA = setPi λ _ → hB} {sB = λ f → let - helpr : isSet ((a : A) → proj₁ (famA a) → proj₁ (famB (f a))) - helpr = setPi λ a → setPi λ _ → proj₂ (famB (f a)) + helpr : isSet ((a : A) → fst (famA a) → fst (famB (f a))) + helpr = setPi λ a → setPi λ _ → snd (famB (f a)) -- It's almost like above, but where the first argument is -- implicit. - res : isSet ({a : A} → proj₁ (famA a) → proj₁ (famB (f a))) + res : isSet ({a : A} → fst (famA a) → fst (famB (f a))) res = {!!} in res } diff --git a/src/Cat/Categories/Fun.agda b/src/Cat/Categories/Fun.agda index 1cd2e0a..63e6f1b 100644 --- a/src/Cat/Categories/Fun.agda +++ b/src/Cat/Categories/Fun.agda @@ -29,16 +29,16 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C center : Σ[ G ∈ Object ] (F ≅ G) center = F , id-to-iso F F refl - open Σ center renaming (proj₂ to isoF) + open Σ center renaming (snd to isoF) module _ (cG : Σ[ G ∈ Object ] (F ≅ G)) where - open Σ cG renaming (proj₁ to G ; proj₂ to isoG) + open Σ cG renaming (fst to G ; snd to isoG) module G = Functor G - open Σ isoG renaming (proj₁ to θNT ; proj₂ to invθNT) - open Σ invθNT renaming (proj₁ to ηNT ; proj₂ to areInv) - open Σ θNT renaming (proj₁ to θ ; proj₂ to θN) - open Σ ηNT renaming (proj₁ to η ; proj₂ to ηN) - open Σ areInv renaming (proj₁ to ve-re ; proj₂ to re-ve) + open Σ isoG renaming (fst to θNT ; snd to invθNT) + open Σ invθNT renaming (fst to ηNT ; snd to areInv) + open Σ θNT renaming (fst to θ ; snd to θN) + open Σ ηNT renaming (fst to η ; snd to ηN) + open Σ areInv renaming (fst to ve-re ; snd to re-ve) -- f ~ Transformation G G -- f : (X : ℂ.Object) → 𝔻 [ G.omap X , G.omap X ] diff --git a/src/Cat/Categories/Rel.agda b/src/Cat/Categories/Rel.agda index 73d4bff..e4e9edc 100644 --- a/src/Cat/Categories/Rel.agda +++ b/src/Cat/Categories/Rel.agda @@ -1,7 +1,7 @@ {-# OPTIONS --cubical --allow-unsolved-metas #-} module Cat.Categories.Rel where -open import Cat.Prelude renaming (proj₁ to fst ; proj₂ to snd) +open import Cat.Prelude renaming (fst to fst ; snd to snd) open import Function open import Cat.Category diff --git a/src/Cat/Categories/Sets.agda b/src/Cat/Categories/Sets.agda index ab094c9..683192b 100644 --- a/src/Cat/Categories/Sets.agda +++ b/src/Cat/Categories/Sets.agda @@ -2,8 +2,7 @@ {-# OPTIONS --allow-unsolved-metas --cubical --caching #-} module Cat.Categories.Sets where -open import Cat.Prelude hiding (_≃_) -import Data.Product +open import Cat.Prelude as P hiding (_≃_) open import Function using (_∘_ ; _∘′_) @@ -38,8 +37,8 @@ module _ (ℓ : Level) where open RawCategory SetsRaw hiding (_∘_) isIdentity : IsIdentity Function.id - proj₁ isIdentity = funExt λ _ → refl - proj₂ isIdentity = funExt λ _ → refl + fst isIdentity = funExt λ _ → refl + snd isIdentity = funExt λ _ → refl open Univalence (λ {A} {B} {f} → isIdentity {A} {B} {f}) @@ -48,14 +47,14 @@ module _ (ℓ : Level) where isIso = Eqv.Isomorphism module _ {hA hB : hSet ℓ} where - open Σ hA renaming (proj₁ to A ; proj₂ to sA) - open Σ hB renaming (proj₁ to B ; proj₂ to sB) + open Σ hA renaming (fst to A ; snd to sA) + open Σ hB renaming (fst to B ; snd to sB) lem1 : (f : A → B) → isSet A → isSet B → isProp (isIso f) lem1 f sA sB = res where module _ (x y : isIso f) where - module x = Σ x renaming (proj₁ to inverse ; proj₂ to areInverses) - module y = Σ y renaming (proj₁ to inverse ; proj₂ to areInverses) + module x = Σ x renaming (fst to inverse ; snd to areInverses) + module y = Σ y renaming (fst to inverse ; snd to areInverses) module xA = AreInverses x.areInverses module yA = AreInverses y.areInverses -- I had a lot of difficulty using the corresponding proof where @@ -88,24 +87,24 @@ module _ (ℓ : Level) where res i = 1eq i , 2eq i module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where lem2 : ((x : A) → isProp (P x)) → (p q : Σ A P) - → (p ≡ q) ≃ (proj₁ p ≡ proj₁ q) + → (p ≡ q) ≃ (fst p ≡ fst q) lem2 pA p q = fromIsomorphism iso where - f : ∀ {p q} → p ≡ q → proj₁ p ≡ proj₁ q - f e i = proj₁ (e i) - g : ∀ {p q} → proj₁ p ≡ proj₁ q → p ≡ q + f : ∀ {p q} → p ≡ q → fst p ≡ fst q + f e i = fst (e i) + g : ∀ {p q} → fst p ≡ fst q → p ≡ q g {p} {q} = lemSig pA p q ve-re : (e : p ≡ q) → (g ∘ f) e ≡ e ve-re = pathJ (\ q (e : p ≡ q) → (g ∘ f) e ≡ e) - (\ i j → p .proj₁ , propSet (pA (p .proj₁)) (p .proj₂) (p .proj₂) (λ i → (g {p} {p} ∘ f) (λ i₁ → p) i .proj₂) (λ i → p .proj₂) i j ) q - re-ve : (e : proj₁ p ≡ proj₁ q) → (f {p} {q} ∘ g {p} {q}) e ≡ e + (\ i j → p .fst , propSet (pA (p .fst)) (p .snd) (p .snd) (λ i → (g {p} {p} ∘ f) (λ i₁ → p) i .snd) (λ i → p .snd) i j ) q + re-ve : (e : fst p ≡ fst q) → (f {p} {q} ∘ g {p} {q}) e ≡ e re-ve e = refl inv : AreInverses (f {p} {q}) (g {p} {q}) inv = record { verso-recto = funExt ve-re ; recto-verso = funExt re-ve } - iso : (p ≡ q) Eqv.≅ (proj₁ p ≡ proj₁ q) + iso : (p ≡ q) Eqv.≅ (fst p ≡ fst q) iso = f , g , inv lem3 : ∀ {ℓc} {Q : A → Set (ℓc ⊔ ℓb)} @@ -119,37 +118,37 @@ module _ (ℓ : Level) where where k : Eqv.Isomorphism _ k = Equiv≃.toIso _ _ (_≃_.isEqv (eA a)) - open Σ k renaming (proj₁ to g') + open Σ k renaming (fst to g') ve-re : (x : Σ A P) → (g ∘ f) x ≡ x - ve-re x i = proj₁ x , eq i + ve-re x i = fst x , eq i where - eq : proj₂ ((g ∘ f) x) ≡ proj₂ x + eq : snd ((g ∘ f) x) ≡ snd x eq = begin - proj₂ ((g ∘ f) x) ≡⟨⟩ - proj₂ (g (f (a , pA))) ≡⟨⟩ + snd ((g ∘ f) x) ≡⟨⟩ + snd (g (f (a , pA))) ≡⟨⟩ g' (_≃_.eqv (eA a) pA) ≡⟨ lem ⟩ pA ∎ where - open Σ x renaming (proj₁ to a ; proj₂ to pA) + open Σ x renaming (fst to a ; snd to pA) k : Eqv.Isomorphism _ k = Equiv≃.toIso _ _ (_≃_.isEqv (eA a)) - open Σ k renaming (proj₁ to g' ; proj₂ to inv) + open Σ k renaming (fst to g' ; snd to inv) module A = AreInverses inv -- anti-funExt lem : (g' ∘ (_≃_.eqv (eA a))) pA ≡ pA lem i = A.verso-recto i pA re-ve : (x : Σ A Q) → (f ∘ g) x ≡ x - re-ve x i = proj₁ x , eq i + re-ve x i = fst x , eq i where - open Σ x renaming (proj₁ to a ; proj₂ to qA) + open Σ x renaming (fst to a ; snd to qA) eq = begin - proj₂ ((f ∘ g) x) ≡⟨⟩ + snd ((f ∘ g) x) ≡⟨⟩ _≃_.eqv (eA a) (g' qA) ≡⟨ (λ i → A.recto-verso i qA) ⟩ qA ∎ where k : Eqv.Isomorphism _ k = Equiv≃.toIso _ _ (_≃_.isEqv (eA a)) - open Σ k renaming (proj₁ to g' ; proj₂ to inv) + open Σ k renaming (fst to g' ; snd to inv) module A = AreInverses inv inv : AreInverses f g inv = record @@ -183,8 +182,8 @@ module _ (ℓ : Level) where in fromIsomorphism iso module _ {hA hB : Object} where - open Σ hA renaming (proj₁ to A ; proj₂ to sA) - open Σ hB renaming (proj₁ to B ; proj₂ to sB) + open Σ hA renaming (fst to A ; snd to sA) + open Σ hB renaming (fst to B ; snd to sB) -- lem3 and the equivalence from lem4 step0 : Σ (A → B) isIso ≃ Σ (A → B) (isEquiv A B) @@ -236,7 +235,7 @@ module _ (ℓ : Level) where univ≃ = trivial? ⊙ step0 ⊙ step1 ⊙ step2 module _ (hA : Object) where - open Σ hA renaming (proj₁ to A) + open Σ hA renaming (fst to A) eq1 : (Σ[ hB ∈ Object ] hA ≅ hB) ≡ (Σ[ hB ∈ Object ] hA ≡ hB) eq1 = ua (lem3 (\ hB → univ≃)) @@ -245,7 +244,7 @@ module _ (ℓ : Level) where univalent[Contr] = subst {P = isContr} (sym eq1) tres where module _ (y : Σ[ hB ∈ Object ] hA ≡ hB) where - open Σ y renaming (proj₁ to hB ; proj₂ to hA≡hB) + open Σ y renaming (fst to hB ; snd to hA≡hB) qres : (hA , refl) ≡ (hB , hA≡hB) qres = contrSingl hA≡hB @@ -273,8 +272,8 @@ module _ {ℓ : Level} where open import Cubical.Sigma module _ (hA hB : Object) where - open Σ hA renaming (proj₁ to A ; proj₂ to sA) - open Σ hB renaming (proj₁ to B ; proj₂ to sB) + open Σ hA renaming (fst to A ; snd to sA) + open Σ hB renaming (fst to B ; snd to sB) private productObject : Object @@ -285,30 +284,30 @@ module _ {ℓ : Level} where _&&&_ x = f x , g x module _ (hX : Object) where - open Σ hX renaming (proj₁ to X) + open Σ hX renaming (fst to X) module _ (f : X → A ) (g : X → B) where - ump : proj₁ Function.∘′ (f &&& g) ≡ f × proj₂ Function.∘′ (f &&& g) ≡ g - proj₁ ump = refl - proj₂ ump = refl + ump : fst Function.∘′ (f &&& g) ≡ f × snd Function.∘′ (f &&& g) ≡ g + fst ump = refl + snd ump = refl rawProduct : RawProduct 𝓢 hA hB RawProduct.object rawProduct = productObject - RawProduct.proj₁ rawProduct = Data.Product.proj₁ - RawProduct.proj₂ rawProduct = Data.Product.proj₂ + RawProduct.fst rawProduct = fst + RawProduct.snd rawProduct = snd isProduct : IsProduct 𝓢 _ _ rawProduct IsProduct.ump isProduct {X = hX} f g = f &&& g , ump hX f g , λ eq → funExt (umpUniq eq) where - open Σ hX renaming (proj₁ to X) using () - module _ {y : X → A × B} (eq : proj₁ Function.∘′ y ≡ f × proj₂ Function.∘′ y ≡ g) (x : X) where - p1 : proj₁ ((f &&& g) x) ≡ proj₁ (y x) + open Σ hX renaming (fst to X) using () + module _ {y : X → A × B} (eq : fst Function.∘′ y ≡ f × snd Function.∘′ y ≡ g) (x : X) where + p1 : fst ((f &&& g) x) ≡ fst (y x) p1 = begin - proj₁ ((f &&& g) x) ≡⟨⟩ - f x ≡⟨ (λ i → sym (proj₁ eq) i x) ⟩ - proj₁ (y x) ∎ - p2 : proj₂ ((f &&& g) x) ≡ proj₂ (y x) - p2 = λ i → sym (proj₂ eq) i x + fst ((f &&& g) x) ≡⟨⟩ + f x ≡⟨ (λ i → sym (fst eq) i x) ⟩ + fst (y x) ∎ + p2 : snd ((f &&& g) x) ≡ snd (y x) + p2 = λ i → sym (snd eq) i x umpUniq : (f &&& g) x ≡ y x umpUniq i = p1 i , p2 i diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 5c497b9..a847eb9 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -29,12 +29,8 @@ module Cat.Category where open import Cat.Prelude - renaming - ( proj₁ to fst - ; proj₂ to snd - ) -import Function +import Function ------------------ -- * Categories -- @@ -136,10 +132,10 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where -- It may be that we need something weaker than this, in that there -- may be some other lemmas available to us. -- For instance, `need0` should be available to us when we prove `need1`. - (need0 : (s : Σ Object (A ≅_)) → (open Σ s renaming (proj₁ to Y) using ()) → A ≡ Y) + (need0 : (s : Σ Object (A ≅_)) → (open Σ s renaming (fst to Y) using ()) → A ≡ Y) (need2 : (iso : A ≅ A) - → (open Σ iso renaming (proj₁ to f ; proj₂ to iso-f)) - → (open Σ iso-f renaming (proj₁ to f~ ; proj₂ to areInv)) + → (open Σ iso renaming (fst to f ; snd to iso-f)) + → (open Σ iso-f renaming (fst to f~ ; snd to areInv)) → (identity , identity) ≡ (f , f~) ) where @@ -147,7 +143,7 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where c = A , idIso A module _ (y : Σ Object (A ≅_)) where - open Σ y renaming (proj₁ to Y ; proj₂ to isoY) + open Σ y renaming (fst to Y ; snd to isoY) q : A ≡ Y q = need0 y @@ -163,8 +159,8 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where d : D A refl d A≅Y i = a0 i , a1 i , a2 i where - open Σ A≅Y renaming (proj₁ to f ; proj₂ to iso-f) - open Σ iso-f renaming (proj₁ to f~ ; proj₂ to areInv) + open Σ A≅Y renaming (fst to f ; snd to iso-f) + open Σ iso-f renaming (fst to f~ ; snd to areInv) aaa : (identity , identity) ≡ (f , f~) aaa = need2 A≅Y a0 : identity ≡ f @@ -309,8 +305,8 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc propIsTerminal T x y i {X} = res X i where module _ (X : Object) where - open Σ (x {X}) renaming (proj₁ to fx ; proj₂ to cx) - open Σ (y {X}) renaming (proj₁ to fy ; proj₂ to cy) + open Σ (x {X}) renaming (fst to fx ; snd to cx) + open Σ (y {X}) renaming (fst to fy ; snd to cy) fp : fx ≡ fy fp = cx fy prop : (x : Arrow X T) → isProp (∀ f → x ≡ f) @@ -328,10 +324,10 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc propTerminal : isProp Terminal propTerminal Xt Yt = res where - open Σ Xt renaming (proj₁ to X ; proj₂ to Xit) - open Σ Yt renaming (proj₁ to Y ; proj₂ to Yit) - open Σ (Xit {Y}) renaming (proj₁ to Y→X) using () - open Σ (Yit {X}) renaming (proj₁ to X→Y) using () + open Σ Xt renaming (fst to X ; snd to Xit) + open Σ Yt renaming (fst to Y ; snd to Yit) + open Σ (Xit {Y}) renaming (fst to Y→X) using () + open Σ (Yit {X}) renaming (fst to X→Y) using () open import Cat.Equivalence hiding (_≅_) -- Need to show `left` and `right`, what we know is that the arrows are -- unique. Well, I know that if I compose these two arrows they must give @@ -361,8 +357,8 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc propIsInitial I x y i {X} = res X i where module _ (X : Object) where - open Σ (x {X}) renaming (proj₁ to fx ; proj₂ to cx) - open Σ (y {X}) renaming (proj₁ to fy ; proj₂ to cy) + open Σ (x {X}) renaming (fst to fx ; snd to cx) + open Σ (y {X}) renaming (fst to fy ; snd to cy) fp : fx ≡ fy fp = cx fy prop : (x : Arrow I X) → isProp (∀ f → x ≡ f) @@ -375,10 +371,10 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc propInitial : isProp Initial propInitial Xi Yi = res where - open Σ Xi renaming (proj₁ to X ; proj₂ to Xii) - open Σ Yi renaming (proj₁ to Y ; proj₂ to Yii) - open Σ (Xii {Y}) renaming (proj₁ to Y→X) using () - open Σ (Yii {X}) renaming (proj₁ to X→Y) using () + open Σ Xi renaming (fst to X ; snd to Xii) + open Σ Yi renaming (fst to Y ; snd to Yii) + open Σ (Xii {Y}) renaming (fst to Y→X) using () + open Σ (Yii {X}) renaming (fst to X→Y) using () open import Cat.Equivalence hiding (_≅_) -- Need to show `left` and `right`, what we know is that the arrows are -- unique. Well, I know that if I compose these two arrows they must give @@ -508,7 +504,7 @@ module Opposite {ℓa ℓb : Level} where open import Cat.Equivalence as Equivalence hiding (_≅_) k : Equivalence.Isomorphism (ℂ.id-to-iso A B) k = Equiv≃.toIso _ _ ℂ.univalent - open Σ k renaming (proj₁ to f ; proj₂ to inv) + open Σ k renaming (fst to f ; snd to inv) open AreInverses inv _⊙_ = Function._∘_ @@ -531,12 +527,12 @@ module Opposite {ℓa ℓb : Level} where where l = id-to-iso A B p r = flopDem (ℂ.id-to-iso A B p) - open Σ l renaming (proj₁ to l-obv ; proj₂ to l-areInv) - open Σ l-areInv renaming (proj₁ to l-invs ; proj₂ to l-iso) - open Σ l-iso renaming (proj₁ to l-l ; proj₂ to l-r) - open Σ r renaming (proj₁ to r-obv ; proj₂ to r-areInv) - open Σ r-areInv renaming (proj₁ to r-invs ; proj₂ to r-iso) - open Σ r-iso renaming (proj₁ to r-l ; proj₂ to r-r) + open Σ l renaming (fst to l-obv ; snd to l-areInv) + open Σ l-areInv renaming (fst to l-invs ; snd to l-iso) + open Σ l-iso renaming (fst to l-l ; snd to l-r) + open Σ r renaming (fst to r-obv ; snd to r-areInv) + open Σ r-areInv renaming (fst to r-invs ; snd to r-iso) + open Σ r-iso renaming (fst to r-l ; snd to r-r) l-obv≡r-obv : l-obv ≡ r-obv l-obv≡r-obv = refl l-invs≡r-invs : l-invs ≡ r-invs diff --git a/src/Cat/Category/Exponential.agda b/src/Cat/Category/Exponential.agda index 4b4f017..46aa1c0 100644 --- a/src/Cat/Category/Exponential.agda +++ b/src/Cat/Category/Exponential.agda @@ -30,7 +30,7 @@ module _ {ℓ ℓ'} (ℂ : Category ℓ ℓ') {{hasProducts : HasProducts ℂ}} {{isExponential}} : IsExponential obj eval transpose : (A : Object) → ℂ [ A × B , C ] → ℂ [ A , obj ] - transpose A f = proj₁ (isExponential A f) + transpose A f = fst (isExponential A f) record HasExponentials {ℓ ℓ' : Level} (ℂ : Category ℓ ℓ') {{_ : HasProducts ℂ}} : Set (ℓ ⊔ ℓ') where open Category ℂ diff --git a/src/Cat/Category/Monad.agda b/src/Cat/Category/Monad.agda index 6383ab0..5b3c657 100644 --- a/src/Cat/Category/Monad.agda +++ b/src/Cat/Category/Monad.agda @@ -52,7 +52,7 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where private module MI = M.IsMonad m forthIsMonad : K.IsMonad (forthRaw raw) - K.IsMonad.isIdentity forthIsMonad = proj₂ MI.isInverse + K.IsMonad.isIdentity forthIsMonad = snd MI.isInverse K.IsMonad.isNatural forthIsMonad = MI.isNatural K.IsMonad.isDistributive forthIsMonad = MI.isDistributive @@ -83,11 +83,11 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where where inv-l = begin joinT X ∘ pureT (R.omap X) ≡⟨⟩ - join ∘ pure ≡⟨ proj₁ isInverse ⟩ + join ∘ pure ≡⟨ fst isInverse ⟩ identity ∎ inv-r = begin joinT X ∘ R.fmap (pureT X) ≡⟨⟩ - join ∘ fmap pure ≡⟨ proj₂ isInverse ⟩ + join ∘ fmap pure ≡⟨ snd isInverse ⟩ identity ∎ back : K.Monad → M.Monad @@ -160,7 +160,7 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where Rfmap (f >>> pureT B) >>> joinT B ≡⟨⟩ Rfmap (f >>> pureT B) >>> joinT B ≡⟨ cong (λ φ → φ >>> joinT B) R.isDistributive ⟩ Rfmap f >>> Rfmap (pureT B) >>> joinT B ≡⟨ ℂ.isAssociative ⟩ - joinT B ∘ Rfmap (pureT B) ∘ Rfmap f ≡⟨ cong (λ φ → φ ∘ Rfmap f) (proj₂ isInverse) ⟩ + joinT B ∘ Rfmap (pureT B) ∘ Rfmap f ≡⟨ cong (λ φ → φ ∘ Rfmap f) (snd isInverse) ⟩ identity ∘ Rfmap f ≡⟨ ℂ.leftIdentity ⟩ Rfmap f ∎ ) diff --git a/src/Cat/Category/Monad/Kleisli.agda b/src/Cat/Category/Monad/Kleisli.agda index dc40f1c..1faf079 100644 --- a/src/Cat/Category/Monad/Kleisli.agda +++ b/src/Cat/Category/Monad/Kleisli.agda @@ -165,12 +165,12 @@ record IsMonad (raw : RawMonad) : Set ℓ where R.fmap f ∘ join ∎ pureNT : NaturalTransformation R⁰ R - proj₁ pureNT = pureT - proj₂ pureNT = pureN + fst pureNT = pureT + snd pureNT = pureN joinNT : NaturalTransformation R² R - proj₁ joinNT = joinT - proj₂ joinNT = joinN + fst joinNT = joinT + snd joinNT = joinN isNaturalForeign : IsNaturalForeign isNaturalForeign = begin diff --git a/src/Cat/Category/Monad/Monoidal.agda b/src/Cat/Category/Monad/Monoidal.agda index 56319c2..707ea07 100644 --- a/src/Cat/Category/Monad/Monoidal.agda +++ b/src/Cat/Category/Monad/Monoidal.agda @@ -29,14 +29,14 @@ record RawMonad : Set ℓ where -- Note that `pureT` and `joinT` differs from their definition in the -- kleisli formulation only by having an explicit parameter. pureT : Transformation Functors.identity R - pureT = proj₁ pureNT + pureT = fst pureNT pureN : Natural Functors.identity R pureT - pureN = proj₂ pureNT + pureN = snd pureNT joinT : Transformation F[ R ∘ R ] R - joinT = proj₁ joinNT + joinT = fst joinNT joinN : Natural F[ R ∘ R ] R joinT - joinN = proj₂ joinNT + joinN = snd joinNT Romap = Functor.omap R Rfmap = Functor.fmap R @@ -71,7 +71,7 @@ record IsMonad (raw : RawMonad) : Set ℓ where joinT Y ∘ R.fmap f ∘ pureT X ≡⟨ sym ℂ.isAssociative ⟩ joinT Y ∘ (R.fmap f ∘ pureT X) ≡⟨ cong (λ φ → joinT Y ∘ φ) (sym (pureN f)) ⟩ joinT Y ∘ (pureT (R.omap Y) ∘ f) ≡⟨ ℂ.isAssociative ⟩ - joinT Y ∘ pureT (R.omap Y) ∘ f ≡⟨ cong (λ φ → φ ∘ f) (proj₁ isInverse) ⟩ + joinT Y ∘ pureT (R.omap Y) ∘ f ≡⟨ cong (λ φ → φ ∘ f) (fst isInverse) ⟩ identity ∘ f ≡⟨ ℂ.leftIdentity ⟩ f ∎ @@ -129,8 +129,8 @@ private where xX = x {X} yX = y {X} - e1 = Category.arrowsAreSets ℂ _ _ (proj₁ xX) (proj₁ yX) - e2 = Category.arrowsAreSets ℂ _ _ (proj₂ xX) (proj₂ yX) + e1 = Category.arrowsAreSets ℂ _ _ (fst xX) (fst yX) + e2 = Category.arrowsAreSets ℂ _ _ (snd xX) (snd yX) open IsMonad propIsMonad : (raw : _) → isProp (IsMonad raw) diff --git a/src/Cat/Category/Monad/Voevodsky.agda b/src/Cat/Category/Monad/Voevodsky.agda index 6563cb8..3c6bad6 100644 --- a/src/Cat/Category/Monad/Voevodsky.agda +++ b/src/Cat/Category/Monad/Voevodsky.agda @@ -124,7 +124,7 @@ module voe {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where -- | to talk about voevodsky's construction. module _ (omap : Omap ℂ ℂ) (pure : {X : Object} → Arrow X (omap X)) where private - module E = AreInverses (Monoidal≅Kleisli ℂ .proj₂ .proj₂) + module E = AreInverses (Monoidal≅Kleisli ℂ .snd .snd) Monoidal→Kleisli : M.Monad → K.Monad Monoidal→Kleisli = E.obverse diff --git a/src/Cat/Category/NaturalTransformation.agda b/src/Cat/Category/NaturalTransformation.agda index 0b4d784..01eff6d 100644 --- a/src/Cat/Category/NaturalTransformation.agda +++ b/src/Cat/Category/NaturalTransformation.agda @@ -58,7 +58,7 @@ module _ (F G : Functor ℂ 𝔻) where propIsNatural θ x y i {A} {B} f = 𝔻.arrowsAreSets _ _ (x f) (y f) i NaturalTransformation≡ : {α β : NaturalTransformation} - → (eq₁ : α .proj₁ ≡ β .proj₁) + → (eq₁ : α .fst ≡ β .fst) → α ≡ β NaturalTransformation≡ eq = lemSig propIsNatural _ _ eq @@ -88,8 +88,8 @@ module _ {F G H : Functor ℂ 𝔻} where T[ θ ∘ η ] C = 𝔻 [ θ C ∘ η C ] NT[_∘_] : NaturalTransformation G H → NaturalTransformation F G → NaturalTransformation F H - proj₁ NT[ (θ , _) ∘ (η , _) ] = T[ θ ∘ η ] - proj₂ NT[ (θ , θNat) ∘ (η , ηNat) ] {A} {B} f = begin + fst NT[ (θ , _) ∘ (η , _) ] = T[ θ ∘ η ] + snd NT[ (θ , θNat) ∘ (η , ηNat) ] {A} {B} f = begin 𝔻 [ T[ θ ∘ η ] B ∘ F.fmap f ] ≡⟨⟩ 𝔻 [ 𝔻 [ θ B ∘ η B ] ∘ F.fmap f ] ≡⟨ sym 𝔻.isAssociative ⟩ 𝔻 [ θ B ∘ 𝔻 [ η B ∘ F.fmap f ] ] ≡⟨ cong (λ φ → 𝔻 [ θ B ∘ φ ]) (ηNat f) ⟩ diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 44fb0ef..ac5ac14 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -2,8 +2,8 @@ module Cat.Category.Product where open import Cubical.NType.Properties -open import Cat.Prelude hiding (_×_ ; proj₁ ; proj₂) -import Data.Product as P +open import Cat.Prelude as P hiding (_×_ ; fst ; snd) +-- module P = Cat.Prelude open import Cat.Category @@ -16,8 +16,8 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where no-eta-equality field object : Object - proj₁ : ℂ [ object , A ] - proj₂ : ℂ [ object , B ] + fst : ℂ [ object , A ] + snd : ℂ [ object , B ] -- FIXME Not sure this is actually a proposition - so this name is -- misleading. @@ -25,12 +25,12 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where open RawProduct raw public field ump : ∀ {X : Object} (f : ℂ [ X , A ]) (g : ℂ [ X , B ]) - → ∃![ f×g ] (ℂ [ proj₁ ∘ f×g ] ≡ f P.× ℂ [ proj₂ ∘ f×g ] ≡ g) + → ∃![ f×g ] (ℂ [ fst ∘ f×g ] ≡ f P.× ℂ [ snd ∘ f×g ] ≡ g) -- | Arrow product _P[_×_] : ∀ {X} → (π₁ : ℂ [ X , A ]) (π₂ : ℂ [ X , B ]) → ℂ [ X , object ] - _P[_×_] π₁ π₂ = P.proj₁ (ump π₁ π₂) + _P[_×_] π₁ π₂ = P.fst (ump π₁ π₂) record Product : Set (ℓa ⊔ ℓb) where field @@ -51,8 +51,8 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where -- The product mentioned in awodey in Def 6.1 is not the regular product of -- arrows. It's a "parallel" product module _ {A A' B B' : Object} where - open Product - open Product (product A B) hiding (_P[_×_]) renaming (proj₁ to fst ; proj₂ to snd) + open Product using (_P[_×_]) + open Product (product A B) hiding (_P[_×_]) renaming (fst to fst ; snd to snd) _|×|_ : ℂ [ A , A' ] → ℂ [ B , B' ] → ℂ [ A × B , A' × B' ] f |×| g = product A' B' P[ ℂ [ f ∘ fst ] @@ -70,7 +70,7 @@ module _ {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} {A B : Category.Object module _ {X : Object} (f : ℂ [ X , A ]) (g : ℂ [ X , B ]) where module _ (f×g : Arrow X y.object) where - help : isProp (∀{y} → (ℂ [ y.proj₁ ∘ y ] ≡ f) P.× (ℂ [ y.proj₂ ∘ y ] ≡ g) → f×g ≡ y) + help : isProp (∀{y} → (ℂ [ y.fst ∘ y ] ≡ f) P.× (ℂ [ y.snd ∘ y ] ≡ g) → f×g ≡ y) help = propPiImpl (λ _ → propPi (λ _ → arrowsAreSets _ _)) res = ∃-unique (x.ump f g) (y.ump f g) @@ -93,7 +93,7 @@ module _ {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} {A B : Category.Object module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} (let module ℂ = Category ℂ) {A B : ℂ.Object} where - open import Data.Product + open P module _ where raw : RawCategory _ _ @@ -130,12 +130,12 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} isAssocitaive : IsAssociative isAssocitaive {A'@(A , a0 , a1)} {B , _} {C , c0 , c1} {D'@(D , d0 , d1)} {ff@(f , f0 , f1)} {gg@(g , g0 , g1)} {hh@(h , h0 , h1)} i - = s0 i , lemPropF propEqs s0 {proj₂ l} {proj₂ r} i + = s0 i , lemPropF propEqs s0 {P.snd l} {P.snd r} i where l = hh ∘ (gg ∘ ff) r = hh ∘ gg ∘ ff -- s0 : h ℂ.∘ (g ℂ.∘ f) ≡ h ℂ.∘ g ℂ.∘ f - s0 : proj₁ l ≡ proj₁ r + s0 : fst l ≡ fst r s0 = ℂ.isAssociative {f = f} {g} {h} @@ -143,15 +143,15 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} isIdentity {AA@(A , a0 , a1)} {BB@(B , b0 , b1)} {f , f0 , f1} = leftIdentity , rightIdentity where leftIdentity : identity ∘ (f , f0 , f1) ≡ (f , f0 , f1) - leftIdentity i = l i , lemPropF propEqs l {proj₂ L} {proj₂ R} i + leftIdentity i = l i , lemPropF propEqs l {snd L} {snd R} i where L = identity ∘ (f , f0 , f1) R : Arrow AA BB R = f , f0 , f1 - l : proj₁ L ≡ proj₁ R + l : fst L ≡ fst R l = ℂ.leftIdentity rightIdentity : (f , f0 , f1) ∘ identity ≡ (f , f0 , f1) - rightIdentity i = l i , lemPropF propEqs l {proj₂ L} {proj₂ R} i + rightIdentity i = l i , lemPropF propEqs l {snd L} {snd R} i where L = (f , f0 , f1) ∘ identity R : Arrow AA BB @@ -165,29 +165,50 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} open Univalence isIdentity - module _ (A : Object) where - c : Σ Object (A ≅_) - c = A , {!!} - univalent[Contr] : isContr (Σ Object (A ≅_)) - univalent[Contr] = {!!} , {!!} + -- module _ (X : Object) where + -- center : Σ Object (X ≅_) + -- center = X , idIso X + + -- module _ (y : Σ Object (X ≅_)) where + -- open Σ y renaming (fst to Y ; snd to X≅Y) + + -- contractible : (X , idIso X) ≡ (Y , X≅Y) + -- contractible = {!!} + + -- univalent[Contr] : isContr (Σ Object (X ≅_)) + -- univalent[Contr] = center , contractible + -- module _ (y : Σ Object (X ≡_)) where + -- open Σ y renaming (fst to Y ; snd to p) + -- a0 : X ≡ Y + -- a0 = {!!} + -- a1 : PathP (λ i → X ≡ a0 i) refl p + -- a1 = {!!} + -- where + -- P : (Z : Object) → X ≡ Z → Set _ + -- P Z p = PathP (λ i → X ≡ Z) + + -- alt' : (X , refl) ≡ y + -- alt' i = a0 i , a1 i + -- alt : isContr (Σ Object (X ≡_)) + -- alt = (X , refl) , alt' univalent' : Univalent[Contr] univalent' = univalence-lemma p q where module _ {𝕏 : Object} where - open Σ 𝕏 renaming (proj₁ to X ; proj₂ to x0x1) - open Σ x0x1 renaming (proj₁ to x0 ; proj₂ to x1) + open Σ 𝕏 renaming (fst to X ; snd to x0x1) + open Σ x0x1 renaming (fst to x0 ; snd to x1) -- x0 : X → A in ℂ -- x1 : X → B in ℂ module _ (𝕐-isoY : Σ Object (𝕏 ≅_)) where - open Σ 𝕐-isoY renaming (proj₁ to 𝕐  ; proj₂ to isoY) - open Σ 𝕐 renaming (proj₁ to Y ; proj₂ to y0y1) - open Σ y0y1  renaming (proj₁ to y0 ; proj₂ to y1) - open Σ isoY  renaming (proj₁ to 𝓯 ; proj₂ to iso-𝓯) - open Σ iso-𝓯  renaming (proj₁ to 𝓯~ ; proj₂ to inv-𝓯) - open Σ 𝓯  renaming (proj₁ to f ; proj₂ to inv-f) - open Σ 𝓯~  renaming (proj₁ to f~ ; proj₂ to inv-f~) - open Σ inv-𝓯  renaming (proj₁ to left ; proj₂ to right) + open Σ 𝕐-isoY renaming (fst to 𝕐  ; snd to isoY) + open Σ 𝕐 renaming (fst to Y ; snd to y0y1) + open Σ y0y1  renaming (fst to y0 ; snd to y1) + open Σ isoY  renaming (fst to 𝓯 ; snd to iso-𝓯) + open Σ iso-𝓯  renaming (fst to 𝓯~ ; snd to inv-𝓯) + open Σ 𝓯  renaming (fst to f ; snd to inv-f) + open Σ 𝓯~  renaming (fst to f~ ; snd to inv-f~) + open Σ inv-𝓯  renaming (fst to left ; snd to right) -- y0 : Y → A in ℂ -- y1 : Y → B in ℂ -- f : X → Y in ℂ @@ -199,24 +220,24 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} = f , f~ , ( begin - ℂ [ f~ ∘ f ] ≡⟨ (λ i → proj₁ (left i)) ⟩ + ℂ [ f~ ∘ f ] ≡⟨ (λ i → fst (left i)) ⟩ ℂ.identity ∎ ) , ( begin - ℂ [ f ∘ f~ ] ≡⟨ (λ i → proj₁ (right i)) ⟩ + ℂ [ f ∘ f~ ] ≡⟨ (λ i → fst (right i)) ⟩ ℂ.identity ∎ ) p0 : X ≡ Y p0 = ℂ.iso-to-id isoℂ -- I note `left2` and right2` here as a reminder. left2 : PathP - (λ i → ℂ [ x0 ∘ proj₁ (left i) ] ≡ x0 × ℂ [ x1 ∘ proj₁ (left i) ] ≡ x1) - (proj₂ (𝓯~ ∘ 𝓯)) (proj₂ identity) - left2 i = proj₂ (left i) + (λ i → ℂ [ x0 ∘ fst (left i) ] ≡ x0 × ℂ [ x1 ∘ fst (left i) ] ≡ x1) + (snd (𝓯~ ∘ 𝓯)) (snd identity) + left2 i = snd (left i) right2 : PathP - (λ i → ℂ [ y0 ∘ proj₁ (right i) ] ≡ y0 × ℂ [ y1 ∘ proj₁ (right i) ] ≡ y1) - (proj₂ (𝓯 ∘ 𝓯~)) (proj₂ identity) - right2 i = proj₂ (right i) + (λ i → ℂ [ y0 ∘ fst (right i) ] ≡ y0 × ℂ [ y1 ∘ fst (right i) ] ≡ y1) + (snd (𝓯 ∘ 𝓯~)) (snd identity) + right2 i = snd (right i) -- My idea: -- -- x0, x1 and y0 and y1 are product arrows as in the diagram @@ -245,23 +266,23 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} p : (X , x0x1) ≡ (Y , y0y1) p i = p0 i , {!!} module _ (iso : 𝕏 ≅ 𝕏) where - open Σ iso renaming (proj₁ to 𝓯 ; proj₂ to inv-𝓯) - open Σ inv-𝓯 renaming (proj₁ to 𝓯~) using () - open Σ 𝓯 renaming (proj₁ to f ; proj₂ to inv-f) - open Σ 𝓯~ renaming (proj₁ to f~ ; proj₂ to inv-f~) + open Σ iso renaming (fst to 𝓯 ; snd to inv-𝓯) + open Σ inv-𝓯 renaming (fst to 𝓯~) using () + open Σ 𝓯 renaming (fst to f ; snd to inv-f) + open Σ 𝓯~ renaming (fst to f~ ; snd to inv-f~) q0' : ℂ.identity ≡ f q0' i = {!!} prop : ∀ x → isProp (ℂ [ x0 ∘ x ] ≡ x0 × ℂ [ x1 ∘ x ] ≡ x1) prop x = propSig ( ℂ.arrowsAreSets (ℂ [ x0 ∘ x ]) x0) (λ _ → ℂ.arrowsAreSets (ℂ [ x1 ∘ x ]) x1) - q0'' : PathP (λ i → ℂ [ x0 ∘ q0' i ] ≡ x0 × ℂ [ x1 ∘ q0' i ] ≡ x1) (proj₂ identity) inv-f + q0'' : PathP (λ i → ℂ [ x0 ∘ q0' i ] ≡ x0 × ℂ [ x1 ∘ q0' i ] ≡ x1) (snd identity) inv-f q0'' = lemPropF prop q0' q0 : identity ≡ 𝓯 q0 i = q0' i , q0'' i q1' : ℂ.identity ≡ f~ q1' = {!!} - q1'' : PathP (λ i → (ℂ [ x0 ∘ q1' i ]) ≡ x0 × (ℂ [ x1 ∘ q1' i ]) ≡ x1) (proj₂ identity) inv-f~ + q1'' : PathP (λ i → (ℂ [ x0 ∘ q1' i ]) ≡ x0 × (ℂ [ x1 ∘ q1' i ]) ≡ x1) (snd identity) inv-f~ q1'' = lemPropF prop q1' q1 : identity ≡ 𝓯~ q1 i = q1' i , {!!} @@ -275,11 +296,11 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} open import Cubical.Univalence module _ (c : (X , x) ≅ (Y , y)) where -- module _ (c : _ ≅ _) where - open Σ c renaming (proj₁ to f_c ; proj₂ to inv_c) - open Σ inv_c renaming (proj₁ to g_c ; proj₂ to ainv_c) - open Σ ainv_c renaming (proj₁ to left ; proj₂ to right) + open Σ c renaming (fst to f_c ; snd to inv_c) + open Σ inv_c renaming (fst to g_c ; snd to ainv_c) + open Σ ainv_c renaming (fst to left ; snd to right) c0 : X ℂ.≅ Y - c0 = proj₁ f_c , proj₁ g_c , (λ i → proj₁ (left i)) , (λ i → proj₁ (right i)) + c0 = fst f_c , fst g_c , (λ i → fst (left i)) , (λ i → fst (right i)) f0 : X ≡ Y f0 = ℂ.iso-to-id c0 module _ {A : ℂ.Object} (α : ℂ.Arrow X A) where @@ -296,7 +317,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} prp : isSet (ℂ.Object × ℂ.Arrow Y A × ℂ.Arrow Y B) prp = setSig {sA = {!!}} {(λ _ → setSig {sA = ℂ.arrowsAreSets} {λ _ → ℂ.arrowsAreSets})} ve-re : (p : (X , x) ≡ (Y , y)) → f (id-to-iso _ _ p) ≡ p - -- ve-re p i j = {!ℂ.arrowsAreSets!} , ℂ.arrowsAreSets _ _ (let k = proj₁ (proj₂ (p i)) in {!!}) {!!} {!!} {!!} , {!!} + -- ve-re p i j = {!ℂ.arrowsAreSets!} , ℂ.arrowsAreSets _ _ (let k = fst (snd (p i)) in {!!}) {!!} {!!} {!!} , {!!} ve-re p = let k = prp {!!} {!!} {!!} {!p!} in {!!} re-ve : (iso : (X , x) ≅ (Y , y)) → id-to-iso _ _ (f iso) ≡ iso re-ve = {!!} @@ -332,17 +353,17 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} rawP : RawProduct ℂ A B rawP = record { object = X - ; proj₁ = x0 - ; proj₂ = x1 + ; fst = x0 + ; snd = x1 } - -- open RawProduct rawP renaming (proj₁ to x0 ; proj₂ to x1) + -- open RawProduct rawP renaming (fst to x0 ; snd to x1) module _ {Y : ℂ.Object} (p0 : ℂ [ Y , A ]) (p1 : ℂ [ Y , B ]) where uy : isContr (Arrow (Y , p0 , p1) (X , x0 , x1)) uy = uniq {Y , p0 , p1} - open Σ uy renaming (proj₁ to Y→X ; proj₂ to contractible) - open Σ Y→X renaming (proj₁ to p0×p1 ; proj₂ to cond) + open Σ uy renaming (fst to Y→X ; snd to contractible) + open Σ Y→X renaming (fst to p0×p1 ; snd to cond) ump : ∃![ f×g ] (ℂ [ x0 ∘ f×g ] ≡ p0 P.× ℂ [ x1 ∘ f×g ] ≡ p1) - ump = p0×p1 , cond , λ {y} x → let k = contractible (y , x) in λ i → proj₁ (k i) + ump = p0×p1 , cond , λ {y} x → let k = contractible (y , x) in λ i → fst (k i) isP : IsProduct ℂ A B rawP isP = record { ump = ump } p : Product ℂ A B @@ -356,31 +377,31 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} module p = Product p module isp = IsProduct p.isProduct o : Object - o = p.object , p.proj₁ , p.proj₂ + o = p.object , p.fst , p.snd module _ {Xx : Object} where - open Σ Xx renaming (proj₁ to X ; proj₂ to x) + open Σ Xx renaming (fst to X ; snd to x) ℂXo : ℂ [ X , isp.object ] - ℂXo = isp._P[_×_] (proj₁ x) (proj₂ x) - ump = p.ump (proj₁ x) (proj₂ x) - Xoo = proj₁ (proj₂ ump) + ℂXo = isp._P[_×_] (fst x) (snd x) + ump = p.ump (fst x) (snd x) + Xoo = fst (snd ump) Xo : Arrow Xx o Xo = ℂXo , Xoo contractible : ∀ y → Xo ≡ y contractible (y , yy) = res where k : ℂXo ≡ y - k = proj₂ (proj₂ ump) (yy) + k = snd (snd ump) (yy) prp : ∀ a → isProp - ( (ℂ [ p.proj₁ ∘ a ] ≡ proj₁ x) - × (ℂ [ p.proj₂ ∘ a ] ≡ proj₂ x) + ( (ℂ [ p.fst ∘ a ] ≡ fst x) + × (ℂ [ p.snd ∘ a ] ≡ snd x) ) prp ab ac ad i - = ℂ.arrowsAreSets _ _ (proj₁ ac) (proj₁ ad) i - , ℂ.arrowsAreSets _ _ (proj₂ ac) (proj₂ ad) i + = ℂ.arrowsAreSets _ _ (fst ac) (fst ad) i + , ℂ.arrowsAreSets _ _ (snd ac) (snd ad) i h : ( λ i - → ℂ [ p.proj₁ ∘ k i ] ≡ proj₁ x - × ℂ [ p.proj₂ ∘ k i ] ≡ proj₂ x + → ℂ [ p.fst ∘ k i ] ≡ fst x + × ℂ [ p.snd ∘ k i ] ≡ snd x ) [ Xoo ≡ yy ] h = lemPropF prp k res : (ℂXo , Xoo) ≡ (y , yy) @@ -396,8 +417,8 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} -- RawProduct does not have eta-equality. e : Product.raw (f (g p)) ≡ Product.raw p RawProduct.object (e i) = p.object - RawProduct.proj₁ (e i) = p.proj₁ - RawProduct.proj₂ (e i) = p.proj₂ + RawProduct.fst (e i) = p.fst + RawProduct.snd (e i) = p.snd inv : AreInverses f g inv = record { verso-recto = funExt ve-re diff --git a/src/Cat/Prelude.agda b/src/Cat/Prelude.agda index 370b300..7a239d5 100644 --- a/src/Cat/Prelude.agda +++ b/src/Cat/Prelude.agda @@ -3,10 +3,11 @@ module Cat.Prelude where open import Agda.Primitive public -- FIXME Use: --- open import Agda.Builtin.Sigma public +open import Agda.Builtin.Sigma public -- Rather than open import Data.Product public renaming (∃! to ∃!≈) + using (_×_ ; Σ-syntax ; swap) -- TODO Import Data.Function under appropriate names. @@ -46,7 +47,7 @@ module _ (ℓ : Level) where -- * Utilities -- ----------------- --- | Unique existensials. +-- | Unique existentials. ∃! : ∀ {a b} {A : Set a} → (A → Set b) → Set (a ⊔ b) ∃! = ∃!≈ _≡_ @@ -57,15 +58,15 @@ module _ (ℓ : Level) where syntax ∃!-syntax (λ x → B) = ∃![ x ] B module _ {ℓa ℓb} {A : Set ℓa} {P : A → Set ℓb} (f g : ∃! P) where - open Σ (proj₂ f) renaming (proj₂ to u) + open Σ (snd f) renaming (snd to u) - ∃-unique : proj₁ f ≡ proj₁ g - ∃-unique = u (proj₁ (proj₂ g)) + ∃-unique : fst f ≡ fst g + ∃-unique = u (fst (snd g)) module _ {ℓa ℓb : Level} {A : Set ℓa} {B : A → Set ℓb} {a b : Σ A B} - (proj₁≡ : (λ _ → A) [ proj₁ a ≡ proj₁ b ]) - (proj₂≡ : (λ i → B (proj₁≡ i)) [ proj₂ a ≡ proj₂ b ]) where + (fst≡ : (λ _ → A) [ fst a ≡ fst b ]) + (snd≡ : (λ i → B (fst≡ i)) [ snd a ≡ snd b ]) where Σ≡ : a ≡ b - proj₁ (Σ≡ i) = proj₁≡ i - proj₂ (Σ≡ i) = proj₂≡ i + fst (Σ≡ i) = fst≡ i + snd (Σ≡ i) = snd≡ i From 6c5b68a8ac9030f22dd8e2ded09ebcbd3ce45a33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 5 Apr 2018 14:37:25 +0200 Subject: [PATCH 27/93] Add notion of pre-category --- src/Cat/Categories/Cat.agda | 16 ++- src/Cat/Categories/Fam.agda | 46 ++++---- src/Cat/Categories/Free.agda | 10 +- src/Cat/Categories/Fun.agda | 82 +++++++------- src/Cat/Categories/Rel.agda | 16 +-- src/Cat/Categories/Sets.agda | 25 +++-- src/Cat/Category.agda | 202 ++++++++++++++++++++-------------- src/Cat/Category/Product.agda | 86 ++++++++------- 8 files changed, 272 insertions(+), 211 deletions(-) diff --git a/src/Cat/Categories/Cat.agda b/src/Cat/Categories/Cat.agda index da421e9..55d717c 100644 --- a/src/Cat/Categories/Cat.agda +++ b/src/Cat/Categories/Cat.agda @@ -72,16 +72,20 @@ module CatProduct {ℓ ℓ' : Level} (ℂ 𝔻 : Category ℓ ℓ') where = Σ≡ (fst ℂ.isIdentity) (fst 𝔻.isIdentity) , Σ≡ (snd ℂ.isIdentity) (snd 𝔻.isIdentity) + isPreCategory : IsPreCategory rawProduct + IsPreCategory.isAssociative isPreCategory = Σ≡ ℂ.isAssociative 𝔻.isAssociative + IsPreCategory.isIdentity isPreCategory = isIdentity + IsPreCategory.arrowsAreSets isPreCategory = arrowsAreSets + postulate univalent : Univalence.Univalent isIdentity - instance - isCategory : IsCategory rawProduct - IsCategory.isAssociative isCategory = Σ≡ ℂ.isAssociative 𝔻.isAssociative - IsCategory.isIdentity isCategory = isIdentity - IsCategory.arrowsAreSets isCategory = arrowsAreSets - IsCategory.univalent isCategory = univalent + + isCategory : IsCategory rawProduct + IsCategory.isPreCategory isCategory = isPreCategory + IsCategory.univalent isCategory = univalent object : Category ℓ ℓ' Category.raw object = rawProduct + Category.isCategory object = isCategory fstF : Functor object ℂ fstF = record diff --git a/src/Cat/Categories/Fam.agda b/src/Cat/Categories/Fam.agda index 897d6e0..e90838c 100644 --- a/src/Cat/Categories/Fam.agda +++ b/src/Cat/Categories/Fam.agda @@ -35,29 +35,31 @@ module _ (ℓa ℓb : Level) where open import Cubical.NType.Properties open import Cubical.Sigma - instance - isCategory : IsCategory RawFam - isCategory = record - { isAssociative = λ {A} {B} {C} {D} {f} {g} {h} → isAssociative {A} {B} {C} {D} {f} {g} {h} - ; isIdentity = λ {A} {B} {f} → isIdentity {A} {B} {f = f} - ; arrowsAreSets = λ { - {((A , hA) , famA)} - {((B , hB) , famB)} - → setSig - {sA = setPi λ _ → hB} - {sB = λ f → - let - helpr : isSet ((a : A) → fst (famA a) → fst (famB (f a))) - helpr = setPi λ a → setPi λ _ → snd (famB (f a)) - -- It's almost like above, but where the first argument is - -- implicit. - res : isSet ({a : A} → fst (famA a) → fst (famB (f a))) - res = {!!} - in res - } - } - ; univalent = {!!} + + isPreCategory : IsPreCategory RawFam + IsPreCategory.isAssociative isPreCategory + {A} {B} {C} {D} {f} {g} {h} = isAssociative {A} {B} {C} {D} {f} {g} {h} + IsPreCategory.isIdentity isPreCategory + {A} {B} {f} = isIdentity {A} {B} {f = f} + IsPreCategory.arrowsAreSets isPreCategory + {(A , hA) , famA} {(B , hB) , famB} + = setSig + {sA = setPi λ _ → hB} + {sB = λ f → + let + helpr : isSet ((a : A) → fst (famA a) → fst (famB (f a))) + helpr = setPi λ a → setPi λ _ → snd (famB (f a)) + -- It's almost like above, but where the first argument is + -- implicit. + res : isSet ({a : A} → fst (famA a) → fst (famB (f a))) + res = {!!} + in res } + isCategory : IsCategory RawFam + IsCategory.isPreCategory isCategory = isPreCategory + IsCategory.univalent isCategory = {!!} + Fam : Category (lsuc (ℓa ⊔ ℓb)) (ℓa ⊔ ℓb) Category.raw Fam = RawFam + Category.isCategory Fam = isCategory diff --git a/src/Cat/Categories/Free.agda b/src/Cat/Categories/Free.agda index 29d6bbe..d004467 100644 --- a/src/Cat/Categories/Free.agda +++ b/src/Cat/Categories/Free.agda @@ -61,6 +61,12 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where arrowsAreSets : isSet (Path ℂ.Arrow A B) arrowsAreSets a b p q = {!!} + isPreCategory : IsPreCategory RawFree + IsPreCategory.isAssociative isPreCategory {f = f} {g} {h} = isAssociative {r = f} {g} {h} + IsPreCategory.isIdentity isPreCategory = isIdentity + IsPreCategory.arrowsAreSets isPreCategory = arrowsAreSets + + module _ {A B : ℂ.Object} where eqv : isEquiv (A ≡ B) (A ≅ B) (Univalence.id-to-iso isIdentity A B) eqv = {!!} @@ -68,9 +74,7 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where univalent = eqv isCategory : IsCategory RawFree - IsCategory.isAssociative isCategory {f = f} {g} {h} = isAssociative {r = f} {g} {h} - IsCategory.isIdentity isCategory = isIdentity - IsCategory.arrowsAreSets isCategory = arrowsAreSets + IsCategory.isPreCategory isCategory = isPreCategory IsCategory.univalent isCategory = univalent Free : Category _ _ diff --git a/src/Cat/Categories/Fun.agda b/src/Cat/Categories/Fun.agda index 63e6f1b..60ee5e7 100644 --- a/src/Cat/Categories/Fun.agda +++ b/src/Cat/Categories/Fun.agda @@ -10,20 +10,28 @@ import Cat.Category.NaturalTransformation module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : Category ℓd ℓd') where open NaturalTransformation ℂ 𝔻 public hiding (module Properties) - open NaturalTransformation.Properties ℂ 𝔻 private module ℂ = Category ℂ module 𝔻 = Category 𝔻 - -- Functor categories. Objects are functors, arrows are natural transformations. - raw : RawCategory (ℓc ⊔ ℓc' ⊔ ℓd ⊔ ℓd') (ℓc ⊔ ℓc' ⊔ ℓd') - RawCategory.Object raw = Functor ℂ 𝔻 - RawCategory.Arrow raw = NaturalTransformation - RawCategory.identity raw {F} = identity F - RawCategory._∘_ raw {F} {G} {H} = NT[_∘_] {F} {G} {H} + module _ where + -- Functor categories. Objects are functors, arrows are natural transformations. + raw : RawCategory (ℓc ⊔ ℓc' ⊔ ℓd ⊔ ℓd') (ℓc ⊔ ℓc' ⊔ ℓd') + RawCategory.Object raw = Functor ℂ 𝔻 + RawCategory.Arrow raw = NaturalTransformation + RawCategory.identity raw {F} = identity F + RawCategory._∘_ raw {F} {G} {H} = NT[_∘_] {F} {G} {H} - open RawCategory raw hiding (identity) - open Univalence (λ {A} {B} {f} → isIdentity {F = A} {B} {f}) + module _ where + open RawCategory raw hiding (identity) + open NaturalTransformation.Properties ℂ 𝔻 + + isPreCategory : IsPreCategory raw + IsPreCategory.isAssociative isPreCategory {A} {B} {C} {D} = isAssociative {A} {B} {C} {D} + IsPreCategory.isIdentity isPreCategory {A} {B} = isIdentity {A} {B} + IsPreCategory.arrowsAreSets isPreCategory {F} {G} = naturalTransformationIsSet {F} {G} + + open IsPreCategory isPreCategory hiding (identity) module _ (F : Functor ℂ 𝔻) where center : Σ[ G ∈ Object ] (F ≅ G) @@ -167,17 +175,15 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C re-ve : (x : A ≡ B) → reverse (obverse x) ≡ x re-ve = {!!} - done : isEquiv (A ≡ B) (A ≅ B) (Univalence.id-to-iso (λ { {A} {B} → isIdentity {F = A} {B}}) A B) + done : isEquiv (A ≡ B) (A ≅ B) (id-to-iso A B) done = {!gradLemma obverse reverse ve-re re-ve!} - -- univalent : Univalent - -- univalent = done + univalent : Univalent + univalent = {!done!} isCategory : IsCategory raw - IsCategory.isAssociative isCategory {A} {B} {C} {D} = isAssociative {A} {B} {C} {D} - IsCategory.isIdentity isCategory {A} {B} = isIdentity {A} {B} - IsCategory.arrowsAreSets isCategory {F} {G} = naturalTransformationIsSet {F} {G} - IsCategory.univalent isCategory = {!!} + IsCategory.isPreCategory isCategory = isPreCategory + IsCategory.univalent isCategory = univalent Fun : Category (ℓc ⊔ ℓc' ⊔ ℓd ⊔ ℓd') (ℓc ⊔ ℓc' ⊔ ℓd') Category.raw Fun = raw @@ -199,26 +205,26 @@ module _ {ℓ ℓ' : Level} (ℂ : Category ℓ ℓ') where ; _∘_ = λ {F G H} → NT[_∘_] {F = F} {G = G} {H = H} } - isCategory : IsCategory raw - isCategory = record - { isAssociative = - λ{ {A} {B} {C} {D} {f} {g} {h} - → F.isAssociative {A} {B} {C} {D} {f} {g} {h} - } - ; isIdentity = - λ{ {A} {B} {f} - → F.isIdentity {A} {B} {f} - } - ; arrowsAreSets = - λ{ {A} {B} - → F.arrowsAreSets {A} {B} - } - ; univalent = - λ{ {A} {B} - → F.univalent {A} {B} - } - } + -- isCategory : IsCategory raw + -- isCategory = record + -- { isAssociative = + -- λ{ {A} {B} {C} {D} {f} {g} {h} + -- → F.isAssociative {A} {B} {C} {D} {f} {g} {h} + -- } + -- ; isIdentity = + -- λ{ {A} {B} {f} + -- → F.isIdentity {A} {B} {f} + -- } + -- ; arrowsAreSets = + -- λ{ {A} {B} + -- → F.arrowsAreSets {A} {B} + -- } + -- ; univalent = + -- λ{ {A} {B} + -- → F.univalent {A} {B} + -- } + -- } - Presh : Category (ℓ ⊔ lsuc ℓ') (ℓ ⊔ ℓ') - Category.raw Presh = raw - Category.isCategory Presh = isCategory + -- Presh : Category (ℓ ⊔ lsuc ℓ') (ℓ ⊔ ℓ') + -- Category.raw Presh = raw + -- Category.isCategory Presh = isCategory diff --git a/src/Cat/Categories/Rel.agda b/src/Cat/Categories/Rel.agda index e4e9edc..6b08717 100644 --- a/src/Cat/Categories/Rel.agda +++ b/src/Cat/Categories/Rel.agda @@ -157,10 +157,12 @@ RawRel = record ; _∘_ = λ {A B C} S R → λ {( a , c ) → Σ[ b ∈ B ] ( (a , b) ∈ R × (b , c) ∈ S )} } -RawIsCategoryRel : IsCategory RawRel -RawIsCategoryRel = record - { isAssociative = funExt is-isAssociative - ; isIdentity = funExt ident-l , funExt ident-r - ; arrowsAreSets = {!!} - ; univalent = {!!} - } +isPreCategory : IsPreCategory RawRel + +IsPreCategory.isAssociative isPreCategory = funExt is-isAssociative +IsPreCategory.isIdentity isPreCategory = funExt ident-l , funExt ident-r +IsPreCategory.arrowsAreSets isPreCategory = {!!} + +Rel : PreCategory _ _ +PreCategory.raw Rel = RawRel +PreCategory.isPreCategory Rel = isPreCategory diff --git a/src/Cat/Categories/Sets.agda b/src/Cat/Categories/Sets.agda index 683192b..a323481 100644 --- a/src/Cat/Categories/Sets.agda +++ b/src/Cat/Categories/Sets.agda @@ -34,16 +34,23 @@ module _ (ℓ : Level) where RawCategory.identity SetsRaw = Function.id RawCategory._∘_ SetsRaw = Function._∘′_ - open RawCategory SetsRaw hiding (_∘_) + module _ where + private + open RawCategory SetsRaw hiding (_∘_) - isIdentity : IsIdentity Function.id - fst isIdentity = funExt λ _ → refl - snd isIdentity = funExt λ _ → refl + isIdentity : IsIdentity Function.id + fst isIdentity = funExt λ _ → refl + snd isIdentity = funExt λ _ → refl - open Univalence (λ {A} {B} {f} → isIdentity {A} {B} {f}) + arrowsAreSets : ArrowsAreSets + arrowsAreSets {B = (_ , s)} = setPi λ _ → s - arrowsAreSets : ArrowsAreSets - arrowsAreSets {B = (_ , s)} = setPi λ _ → s + isPreCat : IsPreCategory SetsRaw + IsPreCategory.isAssociative isPreCat = refl + IsPreCategory.isIdentity isPreCat {A} {B} = isIdentity {A} {B} + IsPreCategory.arrowsAreSets isPreCat {A} {B} = arrowsAreSets {A} {B} + + open IsPreCategory isPreCat hiding (_∘_) isIso = Eqv.Isomorphism module _ {hA hB : hSet ℓ} where @@ -255,9 +262,7 @@ module _ (ℓ : Level) where univalent = from[Contr] univalent[Contr] SetsIsCategory : IsCategory SetsRaw - IsCategory.isAssociative SetsIsCategory = refl - IsCategory.isIdentity SetsIsCategory {A} {B} = isIdentity {A} {B} - IsCategory.arrowsAreSets SetsIsCategory {A} {B} = arrowsAreSets {A} {B} + IsCategory.isPreCategory SetsIsCategory = isPreCat IsCategory.univalent SetsIsCategory = univalent 𝓢𝓮𝓽 Sets : Category (lsuc ℓ) ℓ diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index a847eb9..b182e02 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -203,15 +203,13 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where -- -- Sans `univalent` this would be what is referred to as a pre-category in -- [HoTT]. -record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc (ℓa ⊔ ℓb)) where +record IsPreCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc (ℓa ⊔ ℓb)) where open RawCategory ℂ public field isAssociative : IsAssociative isIdentity : IsIdentity identity arrowsAreSets : ArrowsAreSets open Univalence isIdentity public - field - univalent : Univalent leftIdentity : {A B : Object} {f : Arrow A B} → identity ∘ f ≡ f leftIdentity {A} {B} {f} = fst (isIdentity {A = A} {B} {f}) @@ -251,6 +249,83 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc iso→epi×mono : Isomorphism f → Epimorphism {X = X} f × Monomorphism {X = X} f iso→epi×mono iso = iso→epi iso , iso→mono iso + propIsAssociative : isProp IsAssociative + propIsAssociative x y i = arrowsAreSets _ _ x y i + + propIsIdentity : ∀ {f : ∀ {A} → Arrow A A} → isProp (IsIdentity f) + propIsIdentity a b i + = arrowsAreSets _ _ (fst a) (fst b) i + , arrowsAreSets _ _ (snd a) (snd b) i + + propArrowIsSet : isProp (∀ {A B} → isSet (Arrow A B)) + propArrowIsSet a b i = isSetIsProp a b i + + propIsInverseOf : ∀ {A B f g} → isProp (IsInverseOf {A} {B} f g) + propIsInverseOf x y = λ i → + let + h : fst x ≡ fst y + h = arrowsAreSets _ _ (fst x) (fst y) + hh : snd x ≡ snd y + hh = arrowsAreSets _ _ (snd x) (snd y) + in h i , hh i + + module _ {A B : Object} {f : Arrow A B} where + isoIsProp : isProp (Isomorphism f) + isoIsProp a@(g , η , ε) a'@(g' , η' , ε') = + lemSig (λ g → propIsInverseOf) a a' geq + where + geq : g ≡ g' + geq = begin + g ≡⟨ sym rightIdentity ⟩ + g ∘ identity ≡⟨ cong (λ φ → g ∘ φ) (sym ε') ⟩ + g ∘ (f ∘ g') ≡⟨ isAssociative ⟩ + (g ∘ f) ∘ g' ≡⟨ cong (λ φ → φ ∘ g') η ⟩ + identity ∘ g' ≡⟨ leftIdentity ⟩ + g' ∎ + + propIsInitial : ∀ I → isProp (IsInitial I) + propIsInitial I x y i {X} = res X i + where + module _ (X : Object) where + open Σ (x {X}) renaming (fst to fx ; snd to cx) + open Σ (y {X}) renaming (fst to fy ; snd to cy) + fp : fx ≡ fy + fp = cx fy + prop : (x : Arrow I X) → isProp (∀ f → x ≡ f) + prop x = propPi (λ y → arrowsAreSets x y) + cp : (λ i → ∀ f → fp i ≡ f) [ cx ≡ cy ] + cp = lemPropF prop fp + res : (fx , cx) ≡ (fy , cy) + res i = fp i , cp i + + propIsTerminal : ∀ T → isProp (IsTerminal T) + propIsTerminal T x y i {X} = res X i + where + module _ (X : Object) where + open Σ (x {X}) renaming (fst to fx ; snd to cx) + open Σ (y {X}) renaming (fst to fy ; snd to cy) + fp : fx ≡ fy + fp = cx fy + prop : (x : Arrow X T) → isProp (∀ f → x ≡ f) + prop x = propPi (λ y → arrowsAreSets x y) + cp : (λ i → ∀ f → fp i ≡ f) [ cx ≡ cy ] + cp = lemPropF prop fp + res : (fx , cx) ≡ (fy , cy) + res i = fp i , cp i + +record PreCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where + field + raw : RawCategory ℓa ℓb + isPreCategory : IsPreCategory raw + open IsPreCategory isPreCategory public + +record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc (ℓa ⊔ ℓb)) where + field + isPreCategory : IsPreCategory ℂ + open IsPreCategory isPreCategory public + field + univalent : Univalent + -- | The formulation of univalence expressed with _≃_ is trivially admissable - -- just "forget" the equivalence. univalent≃ : Univalent≃ @@ -264,58 +339,9 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc -- | All projections are propositions. module Propositionality where - propIsAssociative : isProp IsAssociative - propIsAssociative x y i = arrowsAreSets _ _ x y i - - propIsIdentity : ∀ {f : ∀ {A} → Arrow A A} → isProp (IsIdentity f) - propIsIdentity a b i - = arrowsAreSets _ _ (fst a) (fst b) i - , arrowsAreSets _ _ (snd a) (snd b) i - - propArrowIsSet : isProp (∀ {A B} → isSet (Arrow A B)) - propArrowIsSet a b i = isSetIsProp a b i - - propIsInverseOf : ∀ {A B f g} → isProp (IsInverseOf {A} {B} f g) - propIsInverseOf x y = λ i → - let - h : fst x ≡ fst y - h = arrowsAreSets _ _ (fst x) (fst y) - hh : snd x ≡ snd y - hh = arrowsAreSets _ _ (snd x) (snd y) - in h i , hh i - - module _ {A B : Object} {f : Arrow A B} where - isoIsProp : isProp (Isomorphism f) - isoIsProp a@(g , η , ε) a'@(g' , η' , ε') = - lemSig (λ g → propIsInverseOf) a a' geq - where - geq : g ≡ g' - geq = begin - g ≡⟨ sym rightIdentity ⟩ - g ∘ identity ≡⟨ cong (λ φ → g ∘ φ) (sym ε') ⟩ - g ∘ (f ∘ g') ≡⟨ isAssociative ⟩ - (g ∘ f) ∘ g' ≡⟨ cong (λ φ → φ ∘ g') η ⟩ - identity ∘ g' ≡⟨ leftIdentity ⟩ - g' ∎ - propUnivalent : isProp Univalent propUnivalent a b i = propPi (λ iso → propIsContr) a b i - propIsTerminal : ∀ T → isProp (IsTerminal T) - propIsTerminal T x y i {X} = res X i - where - module _ (X : Object) where - open Σ (x {X}) renaming (fst to fx ; snd to cx) - open Σ (y {X}) renaming (fst to fy ; snd to cy) - fp : fx ≡ fy - fp = cx fy - prop : (x : Arrow X T) → isProp (∀ f → x ≡ f) - prop x = propPi (λ y → arrowsAreSets x y) - cp : (λ i → ∀ f → fp i ≡ f) [ cx ≡ cy ] - cp = lemPropF prop fp - res : (fx , cx) ≡ (fy , cy) - res i = fp i , cp i - -- | Terminal objects are propositional - a.k.a uniqueness of terminal -- | objects. -- @@ -353,20 +379,6 @@ record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc res i = p0 i , p1 i -- Merely the dual of the above statement. - propIsInitial : ∀ I → isProp (IsInitial I) - propIsInitial I x y i {X} = res X i - where - module _ (X : Object) where - open Σ (x {X}) renaming (fst to fx ; snd to cx) - open Σ (y {X}) renaming (fst to fy ; snd to cy) - fp : fx ≡ fy - fp = cx fy - prop : (x : Arrow I X) → isProp (∀ f → x ≡ f) - prop x = propPi (λ y → arrowsAreSets x y) - cp : (λ i → ∀ f → fp i ≡ f) [ cx ≡ cy ] - cp = lemPropF prop fp - res : (fx , cx) ≡ (fy , cy) - res i = fp i , cp i propInitial : isProp Initial propInitial Xi Yi = res @@ -404,6 +416,23 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where open RawCategory ℂ open Univalence private + module _ (x y : IsPreCategory ℂ) where + module x = IsPreCategory x + module y = IsPreCategory y + -- In a few places I use the result of propositionality of the various + -- projections of `IsCategory` - Here I arbitrarily chose to use this + -- result from `x : IsCategory C`. I don't know which (if any) possibly + -- adverse effects this may have. + -- module Prop = X.Propositionality + + propIsPreCategory : x ≡ y + IsPreCategory.isAssociative (propIsPreCategory i) + = x.propIsAssociative x.isAssociative y.isAssociative i + IsPreCategory.isIdentity (propIsPreCategory i) + = x.propIsIdentity x.isIdentity y.isIdentity i + IsPreCategory.arrowsAreSets (propIsPreCategory i) + = x.propArrowIsSet x.arrowsAreSets y.arrowsAreSets i + module _ (x y : IsCategory ℂ) where module X = IsCategory x module Y = IsCategory y @@ -414,7 +443,7 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where module Prop = X.Propositionality isIdentity : (λ _ → IsIdentity identity) [ X.isIdentity ≡ Y.isIdentity ] - isIdentity = Prop.propIsIdentity X.isIdentity Y.isIdentity + isIdentity = X.propIsIdentity X.isIdentity Y.isIdentity U : ∀ {a : IsIdentity identity} → (λ _ → IsIdentity identity) [ X.isIdentity ≡ a ] @@ -434,10 +463,13 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where eqUni : U isIdentity Y.univalent eqUni = helper Y.univalent done : x ≡ y - IsCategory.isAssociative (done i) = Prop.propIsAssociative X.isAssociative Y.isAssociative i - IsCategory.isIdentity (done i) = isIdentity i - IsCategory.arrowsAreSets (done i) = Prop.propArrowIsSet X.arrowsAreSets Y.arrowsAreSets i + IsCategory.isPreCategory (done i) + = propIsPreCategory X.isPreCategory Y.isPreCategory i IsCategory.univalent (done i) = eqUni i + -- IsCategory.isAssociative (done i) = Prop.propIsAssociative X.isAssociative Y.isAssociative i + -- IsCategory.isIdentity (done i) = isIdentity i + -- IsCategory.arrowsAreSets (done i) = Prop.propArrowIsSet X.arrowsAreSets Y.arrowsAreSets i + -- IsCategory.univalent (done i) = eqUni i propIsCategory : isProp (IsCategory ℂ) propIsCategory = done @@ -486,19 +518,25 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where module Opposite {ℓa ℓb : Level} where module _ (ℂ : Category ℓa ℓb) where private - module ℂ = Category ℂ - opRaw : RawCategory ℓa ℓb - RawCategory.Object opRaw = ℂ.Object - RawCategory.Arrow opRaw = Function.flip ℂ.Arrow - RawCategory.identity opRaw = ℂ.identity - RawCategory._∘_ opRaw = Function.flip ℂ._∘_ + module _ where + module ℂ = Category ℂ + opRaw : RawCategory ℓa ℓb + RawCategory.Object opRaw = ℂ.Object + RawCategory.Arrow opRaw = Function.flip ℂ.Arrow + RawCategory.identity opRaw = ℂ.identity + RawCategory._∘_ opRaw = Function.flip ℂ._∘_ - open RawCategory opRaw + open RawCategory opRaw - isIdentity : IsIdentity identity - isIdentity = swap ℂ.isIdentity + isIdentity : IsIdentity identity + isIdentity = swap ℂ.isIdentity - open Univalence isIdentity + isPreCategory : IsPreCategory opRaw + IsPreCategory.isAssociative isPreCategory = sym ℂ.isAssociative + IsPreCategory.isIdentity isPreCategory = isIdentity + IsPreCategory.arrowsAreSets isPreCategory = ℂ.arrowsAreSets + + open IsPreCategory isPreCategory module _ {A B : ℂ.Object} where open import Cat.Equivalence as Equivalence hiding (_≅_) @@ -571,9 +609,7 @@ module Opposite {ℓa ℓb : Level} where univalent = Equiv≃.fromIso _ _ h isCategory : IsCategory opRaw - IsCategory.isAssociative isCategory = sym ℂ.isAssociative - IsCategory.isIdentity isCategory = isIdentity - IsCategory.arrowsAreSets isCategory = ℂ.arrowsAreSets + IsCategory.isPreCategory isCategory = isPreCategory IsCategory.univalent isCategory = univalent opposite : Category ℓa ℓb diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index ac5ac14..9a77477 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -122,48 +122,54 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} } } - open RawCategory raw + module _ where + open RawCategory raw - propEqs : ∀ {X' : Object}{Y' : Object} (let X , xa , xb = X') (let Y , ya , yb = Y') - → (xy : ℂ.Arrow X Y) → isProp (ℂ [ ya ∘ xy ] ≡ xa × ℂ [ yb ∘ xy ] ≡ xb) - propEqs xs = propSig (ℂ.arrowsAreSets _ _) (\ _ → ℂ.arrowsAreSets _ _) + propEqs : ∀ {X' : Object}{Y' : Object} (let X , xa , xb = X') (let Y , ya , yb = Y') + → (xy : ℂ.Arrow X Y) → isProp (ℂ [ ya ∘ xy ] ≡ xa × ℂ [ yb ∘ xy ] ≡ xb) + propEqs xs = propSig (ℂ.arrowsAreSets _ _) (\ _ → ℂ.arrowsAreSets _ _) - isAssocitaive : IsAssociative - isAssocitaive {A'@(A , a0 , a1)} {B , _} {C , c0 , c1} {D'@(D , d0 , d1)} {ff@(f , f0 , f1)} {gg@(g , g0 , g1)} {hh@(h , h0 , h1)} i - = s0 i , lemPropF propEqs s0 {P.snd l} {P.snd r} i - where - l = hh ∘ (gg ∘ ff) - r = hh ∘ gg ∘ ff - -- s0 : h ℂ.∘ (g ℂ.∘ f) ≡ h ℂ.∘ g ℂ.∘ f - s0 : fst l ≡ fst r - s0 = ℂ.isAssociative {f = f} {g} {h} - - - isIdentity : IsIdentity identity - isIdentity {AA@(A , a0 , a1)} {BB@(B , b0 , b1)} {f , f0 , f1} = leftIdentity , rightIdentity - where - leftIdentity : identity ∘ (f , f0 , f1) ≡ (f , f0 , f1) - leftIdentity i = l i , lemPropF propEqs l {snd L} {snd R} i + isAssociative : IsAssociative + isAssociative {A'@(A , a0 , a1)} {B , _} {C , c0 , c1} {D'@(D , d0 , d1)} {ff@(f , f0 , f1)} {gg@(g , g0 , g1)} {hh@(h , h0 , h1)} i + = s0 i , lemPropF propEqs s0 {P.snd l} {P.snd r} i where - L = identity ∘ (f , f0 , f1) - R : Arrow AA BB - R = f , f0 , f1 - l : fst L ≡ fst R - l = ℂ.leftIdentity - rightIdentity : (f , f0 , f1) ∘ identity ≡ (f , f0 , f1) - rightIdentity i = l i , lemPropF propEqs l {snd L} {snd R} i + l = hh ∘ (gg ∘ ff) + r = hh ∘ gg ∘ ff + -- s0 : h ℂ.∘ (g ℂ.∘ f) ≡ h ℂ.∘ g ℂ.∘ f + s0 : fst l ≡ fst r + s0 = ℂ.isAssociative {f = f} {g} {h} + + + isIdentity : IsIdentity identity + isIdentity {AA@(A , a0 , a1)} {BB@(B , b0 , b1)} {f , f0 , f1} = leftIdentity , rightIdentity where - L = (f , f0 , f1) ∘ identity - R : Arrow AA BB - R = (f , f0 , f1) - l : ℂ [ f ∘ ℂ.identity ] ≡ f - l = ℂ.rightIdentity + leftIdentity : identity ∘ (f , f0 , f1) ≡ (f , f0 , f1) + leftIdentity i = l i , lemPropF propEqs l {snd L} {snd R} i + where + L = identity ∘ (f , f0 , f1) + R : Arrow AA BB + R = f , f0 , f1 + l : fst L ≡ fst R + l = ℂ.leftIdentity + rightIdentity : (f , f0 , f1) ∘ identity ≡ (f , f0 , f1) + rightIdentity i = l i , lemPropF propEqs l {snd L} {snd R} i + where + L = (f , f0 , f1) ∘ identity + R : Arrow AA BB + R = (f , f0 , f1) + l : ℂ [ f ∘ ℂ.identity ] ≡ f + l = ℂ.rightIdentity - arrowsAreSets : ArrowsAreSets - arrowsAreSets {X , x0 , x1} {Y , y0 , y1} - = sigPresNType {n = ⟨0⟩} ℂ.arrowsAreSets λ a → propSet (propEqs _) + arrowsAreSets : ArrowsAreSets + arrowsAreSets {X , x0 , x1} {Y , y0 , y1} + = sigPresNType {n = ⟨0⟩} ℂ.arrowsAreSets λ a → propSet (propEqs _) - open Univalence isIdentity + isPreCat : IsPreCategory raw + IsPreCategory.isAssociative isPreCat = isAssociative + IsPreCategory.isIdentity isPreCat = isIdentity + IsPreCategory.arrowsAreSets isPreCat = arrowsAreSets + + open IsPreCategory isPreCat -- module _ (X : Object) where -- center : Σ Object (X ≅_) @@ -327,12 +333,8 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} res = Equiv≃.fromIso _ _ iso isCat : IsCategory raw - isCat = record - { isAssociative = isAssocitaive - ; isIdentity = isIdentity - ; arrowsAreSets = arrowsAreSets - ; univalent = univalent - } + IsCategory.isPreCategory isCat = isPreCat + IsCategory.univalent isCat = univalent cat : Category _ _ cat = record From b5f89322ac3c4992598d1915bb9c714eb44bdcb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 5 Apr 2018 15:13:59 +0200 Subject: [PATCH 28/93] Add notion of strict category --- src/Cat/Category.agda | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index b182e02..fcae234 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -319,6 +319,14 @@ record PreCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where isPreCategory : IsPreCategory raw open IsPreCategory isPreCategory public +-- Definition 9.6.1 in [HoTT] +record StrictCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where + field + preCategory : PreCategory ℓa ℓb + open PreCategory preCategory + field + objectsAreSets : isSet Object + record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc (ℓa ⊔ ℓb)) where field isPreCategory : IsPreCategory ℂ From e69ace21a0ec47798e9d51bc8e78df0ed403bfc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 5 Apr 2018 15:21:54 +0200 Subject: [PATCH 29/93] Rename id-to-iso to idToIso --- BACKLOG.md | 2 +- src/Cat/Categories/Free.agda | 2 +- src/Cat/Categories/Fun.agda | 4 ++-- src/Cat/Category.agda | 38 +++++++++++++++++------------------ src/Cat/Category/Product.agda | 8 ++++---- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/BACKLOG.md b/BACKLOG.md index 91d6b63..7e18b07 100644 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -6,7 +6,7 @@ Prove postulates in `Cat.Wishlist`: Prove that these two formulations of univalence are equivalent: - ∀ A B → isEquiv (A ≡ B) (A ≅ B) (id-to-iso A B) + ∀ A B → isEquiv (A ≡ B) (A ≅ B) (idToIso A B) ∀ A → isContr (Σ[ X ∈ Object ] A ≅ X) Prove univalence for the category of diff --git a/src/Cat/Categories/Free.agda b/src/Cat/Categories/Free.agda index d004467..e6aa4c7 100644 --- a/src/Cat/Categories/Free.agda +++ b/src/Cat/Categories/Free.agda @@ -67,7 +67,7 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where IsPreCategory.arrowsAreSets isPreCategory = arrowsAreSets module _ {A B : ℂ.Object} where - eqv : isEquiv (A ≡ B) (A ≅ B) (Univalence.id-to-iso isIdentity A B) + eqv : isEquiv (A ≡ B) (A ≅ B) (Univalence.idToIso isIdentity A B) eqv = {!!} univalent : Univalent diff --git a/src/Cat/Categories/Fun.agda b/src/Cat/Categories/Fun.agda index 60ee5e7..be37dcb 100644 --- a/src/Cat/Categories/Fun.agda +++ b/src/Cat/Categories/Fun.agda @@ -35,7 +35,7 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C module _ (F : Functor ℂ 𝔻) where center : Σ[ G ∈ Object ] (F ≅ G) - center = F , id-to-iso F F refl + center = F , idToIso F F refl open Σ center renaming (snd to isoF) @@ -175,7 +175,7 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C re-ve : (x : A ≡ B) → reverse (obverse x) ≡ x re-ve = {!!} - done : isEquiv (A ≡ B) (A ≅ B) (id-to-iso A B) + done : isEquiv (A ≡ B) (A ≅ B) (idToIso A B) done = {!gradLemma obverse reverse ve-re re-ve!} univalent : Univalent diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index fcae234..b006f69 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -114,11 +114,11 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where -- | Extract an isomorphism from an equality -- -- [HoTT §9.1.4] - id-to-iso : (A B : Object) → A ≡ B → A ≅ B - id-to-iso A B eq = transp (\ i → A ≅ eq i) (idIso A) + idToIso : (A B : Object) → A ≡ B → A ≅ B + idToIso A B eq = transp (\ i → A ≅ eq i) (idIso A) Univalent : Set (ℓa ⊔ ℓb) - Univalent = {A B : Object} → isEquiv (A ≡ B) (A ≅ B) (id-to-iso A B) + Univalent = {A B : Object} → isEquiv (A ≡ B) (A ≅ B) (idToIso A B) -- A perhaps more readable version of univalence: Univalent≃ = {A B : Object} → (A ≡ B) ≃ (A ≅ B) @@ -149,7 +149,7 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where -- Some error with primComp isoAY : A ≅ Y - isoAY = {!id-to-iso A Y q!} + isoAY = {!idToIso A Y q!} lem : PathP (λ i → A ≅ q i) (idIso A) isoY lem = d* isoAY @@ -548,7 +548,7 @@ module Opposite {ℓa ℓb : Level} where module _ {A B : ℂ.Object} where open import Cat.Equivalence as Equivalence hiding (_≅_) - k : Equivalence.Isomorphism (ℂ.id-to-iso A B) + k : Equivalence.Isomorphism (ℂ.idToIso A B) k = Equiv≃.toIso _ _ ℂ.univalent open Σ k renaming (fst to f ; snd to inv) open AreInverses inv @@ -568,11 +568,11 @@ module Opposite {ℓa ℓb : Level} where -- Shouldn't be necessary to use `arrowsAreSets` here, but we have it, -- so why not? - lem : (p : A ≡ B) → id-to-iso A B p ≡ flopDem (ℂ.id-to-iso A B p) + lem : (p : A ≡ B) → idToIso A B p ≡ flopDem (ℂ.idToIso A B p) lem p i = l≡r i where - l = id-to-iso A B p - r = flopDem (ℂ.id-to-iso A B p) + l = idToIso A B p + r = flopDem (ℂ.idToIso A B p) open Σ l renaming (fst to l-obv ; snd to l-areInv) open Σ l-areInv renaming (fst to l-invs ; snd to l-iso) open Σ l-iso renaming (fst to l-l ; snd to l-r) @@ -593,27 +593,27 @@ module Opposite {ℓa ℓb : Level} where ff : A ≅ B → A ≡ B ff = f ⊙ flipDem - -- inv : AreInverses (ℂ.id-to-iso A B) f - invv : AreInverses (id-to-iso A B) ff - -- recto-verso : ℂ.id-to-iso A B ∘ f ≡ idFun (A ℂ.≅ B) + -- inv : AreInverses (ℂ.idToIso A B) f + invv : AreInverses (idToIso A B) ff + -- recto-verso : ℂ.idToIso A B ∘ f ≡ idFun (A ℂ.≅ B) invv = record { verso-recto = funExt (λ x → begin - (ff ⊙ id-to-iso A B) x ≡⟨⟩ - (f ⊙ flipDem ⊙ id-to-iso A B) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → f ⊙ flipDem ⊙ φ) (funExt lem)) ⟩ - (f ⊙ flipDem ⊙ flopDem ⊙ ℂ.id-to-iso A B) x ≡⟨⟩ - (f ⊙ ℂ.id-to-iso A B) x ≡⟨ (λ i → verso-recto i x) ⟩ + (ff ⊙ idToIso A B) x ≡⟨⟩ + (f ⊙ flipDem ⊙ idToIso A B) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → f ⊙ flipDem ⊙ φ) (funExt lem)) ⟩ + (f ⊙ flipDem ⊙ flopDem ⊙ ℂ.idToIso A B) x ≡⟨⟩ + (f ⊙ ℂ.idToIso A B) x ≡⟨ (λ i → verso-recto i x) ⟩ x ∎) ; recto-verso = funExt (λ x → begin - (id-to-iso A B ⊙ f ⊙ flipDem) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → φ ⊙ f ⊙ flipDem) (funExt lem)) ⟩ - (flopDem ⊙ ℂ.id-to-iso A B ⊙ f ⊙ flipDem) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → flopDem ⊙ φ ⊙ flipDem) recto-verso) ⟩ + (idToIso A B ⊙ f ⊙ flipDem) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → φ ⊙ f ⊙ flipDem) (funExt lem)) ⟩ + (flopDem ⊙ ℂ.idToIso A B ⊙ f ⊙ flipDem) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → flopDem ⊙ φ ⊙ flipDem) recto-verso) ⟩ (flopDem ⊙ flipDem) x ≡⟨⟩ x ∎) } - h : Equivalence.Isomorphism (id-to-iso A B) + h : Equivalence.Isomorphism (idToIso A B) h = ff , invv univalent : isEquiv (A ≡ B) (A ≅ B) - (Univalence.id-to-iso (swap ℂ.isIdentity) A B) + (Univalence.idToIso (swap ℂ.isIdentity) A B) univalent = Equiv≃.fromIso _ _ h isCategory : IsCategory opRaw diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 9a77477..c65adeb 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -322,14 +322,14 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} f i = f0 i , {!f1 i!} prp : isSet (ℂ.Object × ℂ.Arrow Y A × ℂ.Arrow Y B) prp = setSig {sA = {!!}} {(λ _ → setSig {sA = ℂ.arrowsAreSets} {λ _ → ℂ.arrowsAreSets})} - ve-re : (p : (X , x) ≡ (Y , y)) → f (id-to-iso _ _ p) ≡ p + ve-re : (p : (X , x) ≡ (Y , y)) → f (idToIso _ _ p) ≡ p -- ve-re p i j = {!ℂ.arrowsAreSets!} , ℂ.arrowsAreSets _ _ (let k = fst (snd (p i)) in {!!}) {!!} {!!} {!!} , {!!} ve-re p = let k = prp {!!} {!!} {!!} {!p!} in {!!} - re-ve : (iso : (X , x) ≅ (Y , y)) → id-to-iso _ _ (f iso) ≡ iso + re-ve : (iso : (X , x) ≅ (Y , y)) → idToIso _ _ (f iso) ≡ iso re-ve = {!!} - iso : E.Isomorphism (id-to-iso (X , x) (Y , y)) + iso : E.Isomorphism (idToIso (X , x) (Y , y)) iso = f , record { verso-recto = funExt ve-re ; recto-verso = funExt re-ve } - res : isEquiv ((X , x) ≡ (Y , y)) ((X , x) ≅ (Y , y)) (id-to-iso (X , x) (Y , y)) + res : isEquiv ((X , x) ≡ (Y , y)) ((X , x) ≅ (Y , y)) (idToIso (X , x) (Y , y)) res = Equiv≃.fromIso _ _ iso isCat : IsCategory raw From be56027c3798659c5c07c688fa5e7c470dab6e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 5 Apr 2018 15:23:05 +0200 Subject: [PATCH 30/93] Remove bad lemma for showing univalence --- src/Cat/Category.agda | 61 ---------------------- src/Cat/Category/Product.agda | 97 ----------------------------------- 2 files changed, 158 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index b006f69..135e1a7 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -127,67 +127,6 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where Univalent[Contr] : Set _ Univalent[Contr] = ∀ A → isContr (Σ[ X ∈ Object ] A ≅ X) - private - module _ (A : Object) - -- It may be that we need something weaker than this, in that there - -- may be some other lemmas available to us. - -- For instance, `need0` should be available to us when we prove `need1`. - (need0 : (s : Σ Object (A ≅_)) → (open Σ s renaming (fst to Y) using ()) → A ≡ Y) - (need2 : (iso : A ≅ A) - → (open Σ iso renaming (fst to f ; snd to iso-f)) - → (open Σ iso-f renaming (fst to f~ ; snd to areInv)) - → (identity , identity) ≡ (f , f~) - ) where - - c : Σ Object (A ≅_) - c = A , idIso A - - module _ (y : Σ Object (A ≅_)) where - open Σ y renaming (fst to Y ; snd to isoY) - q : A ≡ Y - q = need0 y - - -- Some error with primComp - isoAY : A ≅ Y - isoAY = {!idToIso A Y q!} - - lem : PathP (λ i → A ≅ q i) (idIso A) isoY - lem = d* isoAY - where - D : (Y : Object) → (A ≡ Y) → Set _ - D Y p = (A≅Y : A ≅ Y) → PathP (λ i → A ≅ p i) (idIso A) A≅Y - d : D A refl - d A≅Y i = a0 i , a1 i , a2 i - where - open Σ A≅Y renaming (fst to f ; snd to iso-f) - open Σ iso-f renaming (fst to f~ ; snd to areInv) - aaa : (identity , identity) ≡ (f , f~) - aaa = need2 A≅Y - a0 : identity ≡ f - a0 i = fst (aaa i) - a1 : identity ≡ f~ - a1 i = snd (aaa i) - -- we do have this! - -- I just need to rearrange the proofs a bit. - postulate - prop : ∀ {A B} (fg : Arrow A B × Arrow B A) → isProp (IsInverseOf (fst fg) (snd fg)) - a2 : PathP (λ i → IsInverseOf (a0 i) (a1 i)) isIdentity areInv - a2 = lemPropF prop aaa - d* : D Y q - d* = pathJ D d Y q - - p : (A , idIso A) ≡ (Y , isoY) - p i = q i , lem i - - univ-lem : isContr (Σ Object (A ≅_)) - univ-lem = c , p - - univalence-lemma - : (∀ {A} → (s : Σ Object (_≅_ A)) → A ≡ fst s) - → (∀ {A} → (iso : A ≅ A) → (identity , identity) ≡ (fst iso , fst (snd iso))) - → Univalent[Contr] - univalence-lemma s u A = univ-lem A s u - -- From: Thierry Coquand -- Date: Wed, Mar 21, 2018 at 3:12 PM -- diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index c65adeb..ed49dac 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -198,103 +198,6 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} -- alt : isContr (Σ Object (X ≡_)) -- alt = (X , refl) , alt' - univalent' : Univalent[Contr] - univalent' = univalence-lemma p q - where - module _ {𝕏 : Object} where - open Σ 𝕏 renaming (fst to X ; snd to x0x1) - open Σ x0x1 renaming (fst to x0 ; snd to x1) - -- x0 : X → A in ℂ - -- x1 : X → B in ℂ - module _ (𝕐-isoY : Σ Object (𝕏 ≅_)) where - open Σ 𝕐-isoY renaming (fst to 𝕐  ; snd to isoY) - open Σ 𝕐 renaming (fst to Y ; snd to y0y1) - open Σ y0y1  renaming (fst to y0 ; snd to y1) - open Σ isoY  renaming (fst to 𝓯 ; snd to iso-𝓯) - open Σ iso-𝓯  renaming (fst to 𝓯~ ; snd to inv-𝓯) - open Σ 𝓯  renaming (fst to f ; snd to inv-f) - open Σ 𝓯~  renaming (fst to f~ ; snd to inv-f~) - open Σ inv-𝓯  renaming (fst to left ; snd to right) - -- y0 : Y → A in ℂ - -- y1 : Y → B in ℂ - -- f : X → Y in ℂ - -- inv-f : ℂ [ y0 ∘ f ] ≡ x0 × ℂ [ y1 ∘ f ] ≡ x1 - -- left : 𝓯~ ∘ 𝓯 ≡ identity - -- left~ : 𝓯 ∘ 𝓯~ ≡ identity - isoℂ : X ℂ.≅ Y - isoℂ - = f - , f~ - , ( begin - ℂ [ f~ ∘ f ] ≡⟨ (λ i → fst (left i)) ⟩ - ℂ.identity ∎ - ) - , ( begin - ℂ [ f ∘ f~ ] ≡⟨ (λ i → fst (right i)) ⟩ - ℂ.identity ∎ - ) - p0 : X ≡ Y - p0 = ℂ.iso-to-id isoℂ - -- I note `left2` and right2` here as a reminder. - left2 : PathP - (λ i → ℂ [ x0 ∘ fst (left i) ] ≡ x0 × ℂ [ x1 ∘ fst (left i) ] ≡ x1) - (snd (𝓯~ ∘ 𝓯)) (snd identity) - left2 i = snd (left i) - right2 : PathP - (λ i → ℂ [ y0 ∘ fst (right i) ] ≡ y0 × ℂ [ y1 ∘ fst (right i) ] ≡ y1) - (snd (𝓯 ∘ 𝓯~)) (snd identity) - right2 i = snd (right i) - -- My idea: - -- - -- x0, x1 and y0 and y1 are product arrows as in the diagram - -- - -- X - -- ↙ ↘ - -- A ⇣ ⇡ B - -- ↖ ↗ - -- Y (All hail unicode) - -- - -- The dotted lines indicate the unique product arrows. Since they are - -- unique they necessarily be each others inverses. Alas, more than - -- this we must show that they are actually (heterogeneously) - -- identical as in `p1`: - p1 : PathP (λ i → ℂ.Arrow (p0 i) A × ℂ.Arrow (p0 i) B) x0x1 y0y1 - p1 = {!!} - where - -- This, however, should probably somehow follow from them being - -- inverses on objects that are propositionally equal cf. `p0`. - helper : {A B : Object} {f : Arrow A B} {g : Arrow B A} - → IsInverseOf f g - → (p : A ≡ B) - → PathP (λ i → Arrow (p i) (p (~ i))) f g - helper = {!!} - - p : (X , x0x1) ≡ (Y , y0y1) - p i = p0 i , {!!} - module _ (iso : 𝕏 ≅ 𝕏) where - open Σ iso renaming (fst to 𝓯 ; snd to inv-𝓯) - open Σ inv-𝓯 renaming (fst to 𝓯~) using () - open Σ 𝓯 renaming (fst to f ; snd to inv-f) - open Σ 𝓯~ renaming (fst to f~ ; snd to inv-f~) - q0' : ℂ.identity ≡ f - q0' i = {!!} - prop : ∀ x → isProp (ℂ [ x0 ∘ x ] ≡ x0 × ℂ [ x1 ∘ x ] ≡ x1) - prop x = propSig - ( ℂ.arrowsAreSets (ℂ [ x0 ∘ x ]) x0) - (λ _ → ℂ.arrowsAreSets (ℂ [ x1 ∘ x ]) x1) - q0'' : PathP (λ i → ℂ [ x0 ∘ q0' i ] ≡ x0 × ℂ [ x1 ∘ q0' i ] ≡ x1) (snd identity) inv-f - q0'' = lemPropF prop q0' - q0 : identity ≡ 𝓯 - q0 i = q0' i , q0'' i - q1' : ℂ.identity ≡ f~ - q1' = {!!} - q1'' : PathP (λ i → (ℂ [ x0 ∘ q1' i ]) ≡ x0 × (ℂ [ x1 ∘ q1' i ]) ≡ x1) (snd identity) inv-f~ - q1'' = lemPropF prop q1' - q1 : identity ≡ 𝓯~ - q1 i = q1' i , {!!} - q : (identity , identity) ≡ (𝓯 , 𝓯~) - q i = q0 i , q1 i - univalent : Univalent univalent {X , x} {Y , y} = {!res!} where From bbe94606479123f66bd44ee0c014e9e0aaba8df1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 5 Apr 2018 20:41:14 +0200 Subject: [PATCH 31/93] Provide composition of isEquiv's --- src/Cat/Category.agda | 16 +-- src/Cat/Equivalence.agda | 212 ++++++++++++++++++++++++++++++++++----- src/Cat/Prelude.agda | 3 +- 3 files changed, 194 insertions(+), 37 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 135e1a7..09ac382 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -189,24 +189,16 @@ record IsPreCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (ls iso→epi×mono iso = iso→epi iso , iso→mono iso propIsAssociative : isProp IsAssociative - propIsAssociative x y i = arrowsAreSets _ _ x y i + propIsAssociative = propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl λ _ → arrowsAreSets _ _)))))) propIsIdentity : ∀ {f : ∀ {A} → Arrow A A} → isProp (IsIdentity f) - propIsIdentity a b i - = arrowsAreSets _ _ (fst a) (fst b) i - , arrowsAreSets _ _ (snd a) (snd b) i + propIsIdentity = propPiImpl (λ _ → propPiImpl λ _ → propPiImpl (λ _ → propSig (arrowsAreSets _ _) λ _ → arrowsAreSets _ _)) propArrowIsSet : isProp (∀ {A B} → isSet (Arrow A B)) - propArrowIsSet a b i = isSetIsProp a b i + propArrowIsSet = propPiImpl λ _ → propPiImpl (λ _ → isSetIsProp) propIsInverseOf : ∀ {A B f g} → isProp (IsInverseOf {A} {B} f g) - propIsInverseOf x y = λ i → - let - h : fst x ≡ fst y - h = arrowsAreSets _ _ (fst x) (fst y) - hh : snd x ≡ snd y - hh = arrowsAreSets _ _ (snd x) (snd y) - in h i , hh i + propIsInverseOf = propSig (arrowsAreSets _ _) (λ _ → arrowsAreSets _ _) module _ {A B : Object} {f : Arrow A B} where isoIsProp : isProp (Isomorphism f) diff --git a/src/Cat/Equivalence.agda b/src/Cat/Equivalence.agda index b63e4ec..7d976af 100644 --- a/src/Cat/Equivalence.agda +++ b/src/Cat/Equivalence.agda @@ -7,6 +7,8 @@ open import Cubical.PathPrelude hiding (inverse ; _≃_) open import Cubical.PathPrelude using (isEquiv ; isContr ; fiber) public open import Cubical.GradLemma +open import Cat.Prelude using (lemPropF ; setPi ; lemSig ; propSet) + module _ {ℓa ℓb : Level} where private ℓ = ℓa ⊔ ℓb @@ -55,6 +57,50 @@ module _ {ℓ : Level} {A B : Set ℓ} {f : A → B} re-ve : f ∘ g ≡ idFun B re-ve = s (f ∘ g) (idFun B) (recto-verso x) (recto-verso y) i +module _ {ℓ : Level} {A B : Set ℓ} (f : A → B) + (sA : isSet A) (sB : isSet B) where + + propIsIso : isProp (Isomorphism f) + propIsIso = res + where + module _ (x y : Isomorphism f) where + module x = Σ x renaming (fst to inverse ; snd to areInverses) + module y = Σ y renaming (fst to inverse ; snd to areInverses) + module xA = AreInverses x.areInverses + module yA = AreInverses y.areInverses + -- I had a lot of difficulty using the corresponding proof where + -- AreInverses is defined. This is sadly a bit anti-modular. The + -- reason for my troubles is probably related to the type of objects + -- being hSet's rather than sets. + p : ∀ {f} g → isProp (AreInverses {A = A} {B} f g) + p {f} g xx yy i = record + { verso-recto = ve-re + ; recto-verso = re-ve + } + where + module xxA = AreInverses xx + module yyA = AreInverses yy + setPiB : ∀ {X : Set ℓ} → isSet (X → B) + setPiB = setPi (λ _ → sB) + setPiA : ∀ {X : Set ℓ} → isSet (X → A) + setPiA = setPi (λ _ → sA) + ve-re : g ∘ f ≡ idFun _ + ve-re = setPiA _ _ xxA.verso-recto yyA.verso-recto i + re-ve : f ∘ g ≡ idFun _ + re-ve = setPiB _ _ xxA.recto-verso yyA.recto-verso i + 1eq : x.inverse ≡ y.inverse + 1eq = begin + x.inverse ≡⟨⟩ + x.inverse ∘ idFun _ ≡⟨ cong (λ φ → x.inverse ∘ φ) (sym yA.recto-verso) ⟩ + x.inverse ∘ (f ∘ y.inverse) ≡⟨⟩ + (x.inverse ∘ f) ∘ y.inverse ≡⟨ cong (λ φ → φ ∘ y.inverse) xA.verso-recto ⟩ + idFun _ ∘ y.inverse ≡⟨⟩ + y.inverse ∎ + 2eq : (λ i → AreInverses f (1eq i)) [ x.areInverses ≡ y.areInverses ] + 2eq = lemPropF p 1eq + res : x ≡ y + res i = 1eq i , 2eq i + -- In HoTT they generalize an equivalence to have the following 3 properties: module _ {ℓa ℓb ℓ : Level} (A : Set ℓa) (B : Set ℓb) where record Equiv (iseqv : (A → B) → Set ℓ) : Set (ℓa ⊔ ℓb ⊔ ℓ) where @@ -132,7 +178,7 @@ module _ {ℓa ℓb ℓ : Level} (A : Set ℓa) (B : Set ℓb) where module _ {ℓa ℓb : Level} (A : Set ℓa) (B : Set ℓb) where -- A wrapper around PathPrelude.≃ - open Cubical.PathPrelude using (_≃_ ; isEquiv) + open Cubical.PathPrelude using (_≃_) private module _ {obverse : A → B} (e : isEquiv A B obverse) where inverse : B → A @@ -202,6 +248,37 @@ module _ {ℓa ℓb : Level} (A : Set ℓa) (B : Set ℓb) where module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where open Cubical.PathPrelude using (_≃_) + module _ {ℓc : Level} {C : Set ℓc} {f : A → B} {g : B → C} where + + composeIsomorphism : Isomorphism f → Isomorphism g → Isomorphism (g ∘ f) + composeIsomorphism a b = f~ ∘ g~ , inv + where + open Σ a renaming (fst to f~ ; snd to inv-a) + module A = AreInverses inv-a + open Σ b renaming (fst to g~ ; snd to inv-b) + module B = AreInverses inv-b + inv : AreInverses (g ∘ f) (f~ ∘ g~) + inv = record + { verso-recto = begin + (f~ ∘ g~) ∘ (g ∘ f) ≡⟨⟩ + f~ ∘ (g~ ∘ g) ∘ f  ≡⟨ cong (λ φ → f~ ∘ φ ∘ f) B.verso-recto ⟩ + f~ ∘ idFun _ ∘ f   ≡⟨⟩ + f~ ∘ f ≡⟨ A.verso-recto ⟩ + idFun A  ∎ + ; recto-verso = begin + (g ∘ f) ∘ (f~ ∘ g~) ≡⟨⟩ + g ∘ (f ∘ f~) ∘ g~  ≡⟨ cong (λ φ → g ∘ φ ∘ g~) A.recto-verso ⟩ + g ∘ g~ ≡⟨ B.recto-verso ⟩ + idFun C  ∎ + } + + composeIsEquiv : isEquiv A B f → isEquiv B C g → isEquiv A C (g ∘ f) + composeIsEquiv a b = Equiv≃.fromIso A C (composeIsomorphism a' b') + where + a' = Equiv≃.toIso A B a + b' = Equiv≃.toIso B C b + + -- Gives the quasi inverse from an equivalence. module Equivalence (e : A ≃ B) where open Equiv≃ A B public @@ -212,31 +289,10 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where open AreInverses (snd iso) public composeIso : {ℓc : Level} {C : Set ℓc} → (B ≅ C) → A ≅ C - composeIso {C = C} (g , g' , iso-g) = g ∘ obverse , inverse ∘ g' , inv - where - module iso-g = AreInverses iso-g - inv : AreInverses (g ∘ obverse) (inverse ∘ g') - AreInverses.verso-recto inv = begin - (inverse ∘ g') ∘ (g ∘ obverse) ≡⟨⟩ - (inverse ∘ (g' ∘ g) ∘ obverse) - ≡⟨ cong (λ φ → φ ∘ obverse) (cong (λ φ → inverse ∘ φ) iso-g.verso-recto) ⟩ - (inverse ∘ idFun B ∘ obverse) ≡⟨⟩ - (inverse ∘ obverse) ≡⟨ verso-recto ⟩ - idFun A ∎ - AreInverses.recto-verso inv = begin - g ∘ obverse ∘ inverse ∘ g' - ≡⟨ cong (λ φ → φ ∘ g') (cong (λ φ → g ∘ φ) recto-verso) ⟩ - g ∘ idFun B ∘ g' ≡⟨⟩ - g ∘ g' ≡⟨ iso-g.recto-verso ⟩ - idFun C ∎ + composeIso {C = C} (g , iso-g) = g ∘ obverse , composeIsomorphism iso iso-g compose : {ℓc : Level} {C : Set ℓc} → (B ≃ C) → A ≃ C - compose {C = C} e = A≃C.fromIsomorphism is - where - module B≃C = Equiv≃ B C - module A≃C = Equiv≃ A C - is : A ≅ C - is = composeIso (B≃C.toIsomorphism e) + compose (f , isEquiv) = f ∘ obverse , composeIsEquiv (snd e) isEquiv symmetryIso : B ≅ A symmetryIso @@ -288,3 +344,111 @@ module NoEta {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where toIsomorphism : A ≃ B → A ≅ B toIsomorphism (_≃_.con f eqv) = f , Equiv≃.toIso _ _ eqv + +-- A few results that I have not generalized to work with both the eta and no-eta variable of ≃ +module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where + open NoEta + open import Cubical.Univalence using (_≃_) + + -- Equality on sigma's whose second component is a proposition is equivalent + -- to equality on their first components. + equivPropSig : ((x : A) → isProp (P x)) → (p q : Σ A P) + → (p ≡ q) ≃ (fst p ≡ fst q) + equivPropSig pA p q = fromIsomorphism iso + where + f : ∀ {p q} → p ≡ q → fst p ≡ fst q + f e i = fst (e i) + g : ∀ {p q} → fst p ≡ fst q → p ≡ q + g {p} {q} = lemSig pA p q + ve-re : (e : p ≡ q) → (g ∘ f) e ≡ e + ve-re = pathJ (\ q (e : p ≡ q) → (g ∘ f) e ≡ e) + (\ i j → p .fst , propSet (pA (p .fst)) (p .snd) (p .snd) (λ i → (g {p} {p} ∘ f) (λ i₁ → p) i .snd) (λ i → p .snd) i j ) q + re-ve : (e : fst p ≡ fst q) → (f {p} {q} ∘ g {p} {q}) e ≡ e + re-ve e = refl + inv : AreInverses (f {p} {q}) (g {p} {q}) + inv = record + { verso-recto = funExt ve-re + ; recto-verso = funExt re-ve + } + iso : (p ≡ q) ≅ (fst p ≡ fst q) + iso = f , g , inv + + -- Sigma that are equivalent on all points in the second projection are + -- equivalent. + equivSigSnd : ∀ {ℓc} {Q : A → Set (ℓc ⊔ ℓb)} + → ((a : A) → P a ≃ Q a) → Σ A P ≃ Σ A Q + equivSigSnd {Q = Q} eA = res + where + f : Σ A P → Σ A Q + f (a , pA) = a , _≃_.eqv (eA a) pA + g : Σ A Q → Σ A P + g (a , qA) = a , g' qA + where + k : Isomorphism _ + k = Equiv≃.toIso _ _ (_≃_.isEqv (eA a)) + open Σ k renaming (fst to g') + ve-re : (x : Σ A P) → (g ∘ f) x ≡ x + ve-re x i = fst x , eq i + where + eq : snd ((g ∘ f) x) ≡ snd x + eq = begin + snd ((g ∘ f) x) ≡⟨⟩ + snd (g (f (a , pA))) ≡⟨⟩ + g' (_≃_.eqv (eA a) pA) ≡⟨ lem ⟩ + pA ∎ + where + open Σ x renaming (fst to a ; snd to pA) + k : Isomorphism _ + k = Equiv≃.toIso _ _ (_≃_.isEqv (eA a)) + open Σ k renaming (fst to g' ; snd to inv) + module A = AreInverses inv + -- anti-funExt + lem : (g' ∘ (_≃_.eqv (eA a))) pA ≡ pA + lem i = A.verso-recto i pA + re-ve : (x : Σ A Q) → (f ∘ g) x ≡ x + re-ve x i = fst x , eq i + where + open Σ x renaming (fst to a ; snd to qA) + eq = begin + snd ((f ∘ g) x) ≡⟨⟩ + _≃_.eqv (eA a) (g' qA) ≡⟨ (λ i → A.recto-verso i qA) ⟩ + qA ∎ + where + k : Isomorphism _ + k = Equiv≃.toIso _ _ (_≃_.isEqv (eA a)) + open Σ k renaming (fst to g' ; snd to inv) + module A = AreInverses inv + inv : AreInverses f g + inv = record + { verso-recto = funExt ve-re + ; recto-verso = funExt re-ve + } + iso : Σ A P ≅ Σ A Q + iso = f , g , inv + res : Σ A P ≃ Σ A Q + res = fromIsomorphism iso + +module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where + open NoEta + open import Cubical.Univalence using (_≃_) + -- Equivalence is equivalent to isomorphism when the domain and codomain of + -- the equivalence is a set. + equivSetIso : isSet A → isSet B → (f : A → B) + → isEquiv A B f ≃ Isomorphism f + equivSetIso sA sB f = + let + obv : isEquiv A B f → Isomorphism f + obv = Equiv≃.toIso A B + inv : Isomorphism f → isEquiv A B f + inv = Equiv≃.fromIso A B + re-ve : (x : isEquiv A B f) → (inv ∘ obv) x ≡ x + re-ve = Equiv≃.inverse-from-to-iso A B + ve-re : (x : Isomorphism f) → (obv ∘ inv) x ≡ x + ve-re = Equiv≃.inverse-to-from-iso A B sA sB + iso : isEquiv A B f ≅ Isomorphism f + iso = obv , inv , + record + { verso-recto = funExt re-ve + ; recto-verso = funExt ve-re + } + in fromIsomorphism iso diff --git a/src/Cat/Prelude.agda b/src/Cat/Prelude.agda index 7a239d5..e18cb72 100644 --- a/src/Cat/Prelude.agda +++ b/src/Cat/Prelude.agda @@ -23,7 +23,8 @@ open import Cubical.NType open import Cubical.NType.Properties using ( lemPropF ; lemSig ; lemSigP ; isSetIsProp - ; propPi ; propHasLevel ; setPi ; propSet) + ; propPi ; propPiImpl ; propHasLevel ; setPi ; propSet + ; propSig) public propIsContr : {ℓ : Level} → {A : Set ℓ} → isProp (isContr A) From 5db1a1e791e9433d2608dae844c6f6378a238242 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 5 Apr 2018 20:41:36 +0200 Subject: [PATCH 32/93] Report-stuff --- doc/implementation.tex | 291 +++++++++++++++++++++++++++++++++++++++++ doc/macros.tex | 2 + doc/main.tex | 2 + 3 files changed, 295 insertions(+) create mode 100644 doc/implementation.tex diff --git a/doc/implementation.tex b/doc/implementation.tex new file mode 100644 index 0000000..b250cc1 --- /dev/null +++ b/doc/implementation.tex @@ -0,0 +1,291 @@ +\section{Implementation} +This implementation formalizes the following concepts: +% +\begin{itemize} +\item Core categorical concepts +\subitem Categories +\subitem Functors +\subitem Products +\subitem Exponentials +\subitem Cartesian closed categories +\subitem Natural transformations +\subitem Yoneda embedding +\subitem Monads +\subsubitem Monoidal monads +\subsubitem Kleisli monads +\subsubitem Voevodsky's construction +\item Category of \ldots +\subitem Homotopy sets +\subitem Categories +\subitem Relations +\subitem Functors +\subitem Free category +\end{itemize} +% +Since it is useful to distinguish between types with more or less (homotopical) +structure I have followed the following design-principle: I have split concepts +up into things that represent ``data'' and ``laws'' about this data. The idea is +that we can provide a proof that the laws are mere propositions. As an example a +category is defined to have two members: `raw` which is a collection of the data +and `isCategory` which asserts some laws about that data. + +This allows me to reason about things in a more mathematical way, where one can +reason about two categories by simply focusing on the data. This is acheived by +creating a function embodying the ``equality principle'' for a given type. + +\subsubsection{Categories} +The data for a category consist of objects, morphisms (or arrows as I will refer +to them henceforth), the identity arrow and composition of arrows. + +Another record encapsulates some laws about this data: associativity of +composition, identity law for the identity morphism. These are standard +requirements for being a category as can be found in standard mathematical +expositions on the topic. We, however, impose one further requirement on what it +means to be a category, namely that the type of arrows form a set. We could +relax this requirement, this would give us the notion of higher categorier +(\cite[p. 307]{hott-2013}). For the purpose of this project, however, this +report will restrict itself to 1-categories. + +Raw categories satisfying these properties are called a pre-categories. + +As a further requirement to be a proper category we require it to be univalent. +This requirement is quite similiar to univalence for types, but we let +isomorphism of objects play the role of equivalence of types. The univalence +criterion is: +% +$$ +\isEquiv\ (A \cong B)\ (A \equiv B)\ \idToIso_{A\ B} +$$ +% +Note that this is a stronger requirement than: +% +$$ +(A \cong B) \simeq (A \equiv B) +$$ +% +Which is permissable simply by ``forgetting'' that $\idToIso_{A\ B}$ plays the +role of the equivalence. + +With all this in place it is now possible to prove that all the laws are indeed +mere propositions. Most of the proofs simply use the fact that the type of +arrows are sets. This is because most of the laws are a collection of equations +between arrows in the category. And since such a proof does not have any +content, two witnesses must be the same. All the proofs are really quite +mechanical. Lets have a look at one of them: The identity law states that: +% +$$ +\prod_{A\ B \tp \Object} \prod_{f \tp A \to B} \id \comp f \equiv f \x f \id \equiv f +$$ +% +There are multiple ways to prove this. Perhaps one of the more intuitive proofs +is by way of the following `combinators': +% +$$ +\mathit{propPi} \tp \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\prod_{a \tp A} P\ a\right) +$$ +% +I.e.; pi-types preserve propositionality when the co-domain is always a +proposition. +% +$$ +\mathit{propSig} \tp \isProp\ A \to \left(\prod_{a : A} \isProp\ (P\ a)\right) \to \isProp\ \left(\sum_{a \tp A} P\ a\right) +$$ +% +I.e.; sigma-types preserve propositionality whenever it's first component is a +proposition, and it's second component is always a proposition for all points of +in the left type. + +Defines the basic notion of a category. This definition +closely follows that of [HoTT]: That is, the standard definition of a category +(data; objects, arrows, composition and identity, laws; preservation of identity +and composition) plus the extra condition that it is univalent - namely that you +can get an equality of two objects from an isomorphism. + +\subsubsection{Functors} +Defines the notion of a functor - also split up into data and laws. + +Propositionality for being a functor. + +Composition of functors and the identity functor. + +\subsubsection{Products} +Definition of what it means for an object to be a product in a given category. + +Definition of what it means for a category to have all products. + +\WIP{} Prove propositionality for being a product and having products. + +\subsubsection{Exponentials} +Definition of what it means to be an exponential object. + +Definition of what it means for a category to have all exponential objects. + +\subsubsection{Cartesian closed categories} +Definition of what it means for a category to be cartesian closed; namely that +it has all products and all exponentials. + +\subsubsection{Natural transformations} +Definition of transformations\footnote{Maybe this is a name I made up for a + family of morphisms} and the naturality condition for these. + +Proof that naturality is a mere proposition and the accompanying equality +principle. Proof that natural transformations are homotopic sets. + +The identity natural transformation. + +\subsubsection{Yoneda embedding} + +The yoneda embedding is typically presented in terms of the category of +categories (cf. Awodey) \emph however this is not stricly needed - all we need +is what would be the exponential object in that category - this happens to be +functors and so this is how we define the yoneda embedding. + +\subsubsection{Monads} + +Defines an equivalence between these two formulations of a monad: + +\subsubsubsection{Monoidal monads} + +Defines the standard monoidal representation of a monad: + +An endofunctor with two natural transformations (called ``pure'' and ``join'') +and some laws about these natural transformations. + +Propositionality proofs and equality principle is provided. + +\subsubsubsection{Kleisli monads} + +A presentation of monads perhaps more familiar to a functional programer: + +A map on objects and two maps on morphisms (called ``pure'' and ``bind'') and +some laws about these maps. + +Propositionality proofs and equality principle is provided. + +\subsubsubsection{Voevodsky's construction} + +Provides construction 2.3 as presented in an unpublished paper by Vladimir +Voevodsky. This construction is similiar to the equivalence provided for the two +preceding formulations +\footnote{ TODO: I would like to include in the thesis some motivation for why + this construction is particularly interesting.} + +\subsubsection{Homotopy sets} +The typical category of sets where the objects are modelled by an Agda set +(henceforth ``$\Type$'') at a given level is not a valid category in this cubical +settings, we need to restrict the types to be those that are homotopy sets. Thus +the objects of this category are: +% +$$\hSet_\ell \defeq \sum_{A \tp \MCU_\ell} \isSet\ A$$ +% +The definition of univalence for categories I have defined is: +% +$$\isEquiv\ (\hA \equiv \hB)\ (\hA \cong \hB)\ \idToIso$$ +% +Where $\hA and \hB$ denote objects in the category. Note that this is stronger +than +% +$$(\hA \equiv \hB) \simeq (\hA \cong \hB)$$ +% +Because we require that the equivalence is constructed from the witness to: +% +$$\id \comp f \equiv f \x f \comp \id \equiv f$$ +% +And indeed univalence does not follow immediately from univalence for types: +% +$$(A \equiv B) \simeq (A \simeq B)$$ +% +Because $A\ B \tp \Type$ whereas $\hA\ \hB \tp \hSet$. + +For this reason I have shown that this category satisfies the following +equivalent formulation of being univalent: +% +$$\prod_{A \tp hSet} \isContr \left( \sum_{X \tp hSet} A \cong X \right)$$ +% +But I have not shown that it is indeed equivalent to my former definition. +\subsubsection{Categories} +Note that this category does in fact not exist. In stead I provide the +definition of the ``raw'' category as well as some of the laws. + +Furthermore I provide some helpful lemmas about this raw category. For instance +I have shown what would be the exponential object in such a category. + +These lemmas can be used to provide the actual exponential object in a context +where we have a witness to this being a category. This is useful if this library +is later extended to talk about higher categories. + +\subsubsection{Functors} +The category of functors and natural transformations. An immediate corrolary is +the set of presheaf categories. + +\WIP{} I have not shown that the category of functors is univalent. + +\subsubsection{Relations} +The category of relations. \WIP{} I have not shown that this category is +univalent. Not sure I intend to do so either. + +\subsubsection{Free category} +The free category of a category. \WIP{} I have not shown that this category is +univalent. + +\subsection{Current Challenges} +Besides the items marked \WIP{} above I still feel a bit unsure about what to +include in my report. Most of my work so far has been specifically about +developing this library. Some ideas: +% +\begin{itemize} +\item + Modularity properties +\item + Compare with setoid-approach to solve similiar problems. +\item + How to structure an implementation to best deal with types that have no + structure (propositions) and those that do (sets and everything above) +\end{itemize} +% +\subsection{Ideas for future developments} +\subsubsection{Higher categories} +I only have a notion of (1-)categories. Perhaps it would be nice to also +formalize higher categories. + +\subsubsection{Hierarchy of concepts related to monads} +In Haskell the type-class Monad sits in a hierarchy atop the notion of a functor +and applicative functors. There's probably a similiar notion in the +category-theoretic approach to developing this. + +As I have already defined monads from these two perspectives, it would be +interesting to take this idea even further and actually show how monads are +related to applicative functors and functors. I'm not entirely sure how this +would look in Agda though. + +\subsubsection{Use formulation on the standard library} +I also thought it would be interesting to use this library to show certain +properties about functors, applicative functors and monads used in the Agda +Standard library. So I went ahead and tried to show that agda's standard +library's notion of a functor (along with suitable laws) is equivalent to my +formulation (in the category of homotopic sets). I ran into two problems here, +however; the first one is that the standard library's notion of a functor is +indexed by the object map: +% +$$ +\Functor \tp (\Type \to \Type) \to \Type +$$ +% +Where $\Functor\ F$ has the member: +% +$$ +\fmap \tp (A \to B) \to F A \to F B +$$ +% +Whereas the object map in my definition is existentially quantified: +% +$$ +\Functor \tp \Type +$$ +% +And $\Functor$ has these members: +\begin{align*} +F & \tp \Type \to \Type \\ +\fmap & \tp (A \to B) \to F A \to F B\} +\end{align*} +% diff --git a/doc/macros.tex b/doc/macros.tex index 9384ae6..aed408f 100644 --- a/doc/macros.tex +++ b/doc/macros.tex @@ -30,6 +30,8 @@ \newcommand{\tp}{\,\mathord{:}\,} \newcommand\hA{\mathit{hA}} \newcommand\hB{\mathit{hB}} +\newcommand\Object{\mathit{Object}} \newcommand\Functor{\mathit{Functor}} +\newcommand\isProp{\mathit{isProp}} \newcommand{\subsubsubsection}[1]{\textbf{#1}} \newcommand{\WIP}{\textbf{WIP}} diff --git a/doc/main.tex b/doc/main.tex index e2542f7..478ec30 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -18,6 +18,8 @@ \input{report.tex} +\input{implementation.tex} + \bibliographystyle{plainnat} \nocite{cubical-demo} \nocite{coquand-2013} From 23b562a8739a5ab91856f8c21799c4d6c070a9b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 6 Apr 2018 16:54:00 +0200 Subject: [PATCH 33/93] Provide preorder instance for some things - more work on product cat --- src/Cat/Categories/Rel.agda | 2 +- src/Cat/Category.agda | 37 ++++++ src/Cat/Category/Monad.agda | 2 +- src/Cat/Category/Monoid.agda | 38 +++--- src/Cat/Category/Product.agda | 235 ++++++++++++++++++++-------------- src/Cat/Equivalence.agda | 24 +++- src/Cat/Prelude.agda | 14 ++ 7 files changed, 233 insertions(+), 119 deletions(-) diff --git a/src/Cat/Categories/Rel.agda b/src/Cat/Categories/Rel.agda index 6b08717..3c7648c 100644 --- a/src/Cat/Categories/Rel.agda +++ b/src/Cat/Categories/Rel.agda @@ -1,7 +1,7 @@ {-# OPTIONS --cubical --allow-unsolved-metas #-} module Cat.Categories.Rel where -open import Cat.Prelude renaming (fst to fst ; snd to snd) +open import Cat.Prelude hiding (Rel) open import Function open import Cat.Category diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 09ac382..dfbbc17 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -120,6 +120,15 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where Univalent : Set (ℓa ⊔ ℓb) Univalent = {A B : Object} → isEquiv (A ≡ B) (A ≅ B) (idToIso A B) + import Cat.Equivalence as E + open E public using () renaming (Isomorphism to TypeIsomorphism) + open E using (module Equiv≃) + open Equiv≃ using (fromIso) + + univalenceFromIsomorphism : {A B : Object} + → TypeIsomorphism (idToIso A B) → isEquiv (A ≡ B) (A ≅ B) (idToIso A B) + univalenceFromIsomorphism = fromIso _ _ + -- A perhaps more readable version of univalence: Univalent≃ = {A B : Object} → (A ≡ B) ≃ (A ≅ B) @@ -244,6 +253,34 @@ record IsPreCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (ls res : (fx , cx) ≡ (fy , cy) res i = fp i , cp i + module _ where + private + trans≅ : Transitive _≅_ + trans≅ (f , f~ , f-inv) (g , g~ , g-inv) + = g ∘ f + , f~ ∘ g~ + , ( begin + (f~ ∘ g~) ∘ (g ∘ f) ≡⟨ isAssociative ⟩ + (f~ ∘ g~) ∘ g ∘ f ≡⟨ cong (λ φ → φ ∘ f) (sym isAssociative) ⟩ + f~ ∘ (g~ ∘ g) ∘ f ≡⟨ cong (λ φ → f~ ∘ φ ∘ f) (fst g-inv) ⟩ + f~ ∘ identity ∘ f ≡⟨ cong (λ φ → φ ∘ f) rightIdentity ⟩ + f~ ∘ f ≡⟨ fst f-inv ⟩ + identity ∎ + ) + , ( begin + g ∘ f ∘ (f~ ∘ g~) ≡⟨ isAssociative ⟩ + g ∘ f ∘ f~ ∘ g~ ≡⟨ cong (λ φ → φ ∘ g~) (sym isAssociative) ⟩ + g ∘ (f ∘ f~) ∘ g~ ≡⟨ cong (λ φ → g ∘ φ ∘ g~) (snd f-inv) ⟩ + g ∘ identity ∘ g~ ≡⟨ cong (λ φ → φ ∘ g~) rightIdentity ⟩ + g ∘ g~ ≡⟨ snd g-inv ⟩ + identity ∎ + ) + isPreorder : IsPreorder _≅_ + isPreorder = record { isEquivalence = equalityIsEquivalence ; reflexive = idToIso _ _ ; trans = trans≅ } + + preorder≅ : Preorder _ _ _ + preorder≅ = record { Carrier = Object ; _≈_ = _≡_ ; _∼_ = _≅_ ; isPreorder = isPreorder } + record PreCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where field raw : RawCategory ℓa ℓb diff --git a/src/Cat/Category/Monad.agda b/src/Cat/Category/Monad.agda index 5b3c657..387dc75 100644 --- a/src/Cat/Category/Monad.agda +++ b/src/Cat/Category/Monad.agda @@ -29,7 +29,7 @@ import Cat.Category.Monad.Kleisli open import Cat.Categories.Fun module Monoidal = Cat.Category.Monad.Monoidal -module Kleisli = Cat.Category.Monad.Kleisli +module Kleisli = Cat.Category.Monad.Kleisli -- | The monoidal- and kleisli presentation of monads are equivalent. module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where diff --git a/src/Cat/Category/Monoid.agda b/src/Cat/Category/Monoid.agda index 75eaa68..e813005 100644 --- a/src/Cat/Category/Monoid.agda +++ b/src/Cat/Category/Monoid.agda @@ -1,3 +1,4 @@ +{-# OPTIONS --allow-unsolved-metas #-} module Cat.Category.Monoid where open import Agda.Primitive @@ -6,9 +7,10 @@ open import Cat.Category open import Cat.Category.Product open import Cat.Category.Functor import Cat.Categories.Cat as Cat +open import Cat.Prelude hiding (_×_ ; empty) -- TODO: Incorrect! -module _ (ℓa ℓb : Level) where +module _ {ℓa ℓb : Level} where private ℓ = lsuc (ℓa ⊔ ℓb) @@ -21,30 +23,34 @@ module _ (ℓa ℓb : Level) where _×_ : ∀ {ℓa ℓb} → Category ℓa ℓb → Category ℓa ℓb → Category ℓa ℓb ℂ × 𝔻 = Cat.CatProduct.object ℂ 𝔻 - record RawMonoidalCategory : Set ℓ where + record RawMonoidalCategory (ℂ : Category ℓa ℓb) : Set ℓ where + open Category ℂ public hiding (IsAssociative) field - category : Category ℓa ℓb - open Category category public - field - {{hasProducts}} : HasProducts category empty : Object -- aka. tensor product, monoidal product. - append : Functor (category × category) category - open HasProducts hasProducts public + append : Functor (ℂ × ℂ) ℂ - record MonoidalCategory : Set ℓ where + module F = Functor append + + _⊗_ = append + mappend = F.fmap + + IsAssociative : Set _ + IsAssociative = {A B : Object} → (f g h : Arrow A A) → mappend ({!mappend!} , {!mappend!}) ≡ mappend (f , mappend (g , h)) + + record MonoidalCategory (ℂ : Category ℓa ℓb) : Set ℓ where field - raw : RawMonoidalCategory + raw : RawMonoidalCategory ℂ open RawMonoidalCategory raw public -module _ {ℓa ℓb : Level} (ℂ : MonoidalCategory ℓa ℓb) where +module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) {monoidal : MonoidalCategory ℂ} {hasProducts : HasProducts ℂ} where private ℓ = ℓa ⊔ ℓb - open MonoidalCategory ℂ public + open MonoidalCategory monoidal public hiding (mappend) + open HasProducts hasProducts - record Monoid : Set ℓ where + record MonoidalObject (M : Object) : Set ℓ where field - carrier : Object - mempty : Arrow empty carrier - mappend : Arrow (carrier × carrier) carrier + mempty : Arrow empty M + mappend : Arrow (M × M) M diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index ed49dac..9def8a2 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -123,46 +123,47 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} } module _ where - open RawCategory raw + private + open RawCategory raw - propEqs : ∀ {X' : Object}{Y' : Object} (let X , xa , xb = X') (let Y , ya , yb = Y') - → (xy : ℂ.Arrow X Y) → isProp (ℂ [ ya ∘ xy ] ≡ xa × ℂ [ yb ∘ xy ] ≡ xb) - propEqs xs = propSig (ℂ.arrowsAreSets _ _) (\ _ → ℂ.arrowsAreSets _ _) + propEqs : ∀ {X' : Object}{Y' : Object} (let X , xa , xb = X') (let Y , ya , yb = Y') + → (xy : ℂ.Arrow X Y) → isProp (ℂ [ ya ∘ xy ] ≡ xa × ℂ [ yb ∘ xy ] ≡ xb) + propEqs xs = propSig (ℂ.arrowsAreSets _ _) (\ _ → ℂ.arrowsAreSets _ _) - isAssociative : IsAssociative - isAssociative {A'@(A , a0 , a1)} {B , _} {C , c0 , c1} {D'@(D , d0 , d1)} {ff@(f , f0 , f1)} {gg@(g , g0 , g1)} {hh@(h , h0 , h1)} i - = s0 i , lemPropF propEqs s0 {P.snd l} {P.snd r} i - where - l = hh ∘ (gg ∘ ff) - r = hh ∘ gg ∘ ff - -- s0 : h ℂ.∘ (g ℂ.∘ f) ≡ h ℂ.∘ g ℂ.∘ f - s0 : fst l ≡ fst r - s0 = ℂ.isAssociative {f = f} {g} {h} - - - isIdentity : IsIdentity identity - isIdentity {AA@(A , a0 , a1)} {BB@(B , b0 , b1)} {f , f0 , f1} = leftIdentity , rightIdentity - where - leftIdentity : identity ∘ (f , f0 , f1) ≡ (f , f0 , f1) - leftIdentity i = l i , lemPropF propEqs l {snd L} {snd R} i + isAssociative : IsAssociative + isAssociative {A'@(A , a0 , a1)} {B , _} {C , c0 , c1} {D'@(D , d0 , d1)} {ff@(f , f0 , f1)} {gg@(g , g0 , g1)} {hh@(h , h0 , h1)} i + = s0 i , lemPropF propEqs s0 {P.snd l} {P.snd r} i where - L = identity ∘ (f , f0 , f1) - R : Arrow AA BB - R = f , f0 , f1 - l : fst L ≡ fst R - l = ℂ.leftIdentity - rightIdentity : (f , f0 , f1) ∘ identity ≡ (f , f0 , f1) - rightIdentity i = l i , lemPropF propEqs l {snd L} {snd R} i - where - L = (f , f0 , f1) ∘ identity - R : Arrow AA BB - R = (f , f0 , f1) - l : ℂ [ f ∘ ℂ.identity ] ≡ f - l = ℂ.rightIdentity + l = hh ∘ (gg ∘ ff) + r = hh ∘ gg ∘ ff + -- s0 : h ℂ.∘ (g ℂ.∘ f) ≡ h ℂ.∘ g ℂ.∘ f + s0 : fst l ≡ fst r + s0 = ℂ.isAssociative {f = f} {g} {h} - arrowsAreSets : ArrowsAreSets - arrowsAreSets {X , x0 , x1} {Y , y0 , y1} - = sigPresNType {n = ⟨0⟩} ℂ.arrowsAreSets λ a → propSet (propEqs _) + + isIdentity : IsIdentity identity + isIdentity {AA@(A , a0 , a1)} {BB@(B , b0 , b1)} {f , f0 , f1} = leftIdentity , rightIdentity + where + leftIdentity : identity ∘ (f , f0 , f1) ≡ (f , f0 , f1) + leftIdentity i = l i , lemPropF propEqs l {snd L} {snd R} i + where + L = identity ∘ (f , f0 , f1) + R : Arrow AA BB + R = f , f0 , f1 + l : fst L ≡ fst R + l = ℂ.leftIdentity + rightIdentity : (f , f0 , f1) ∘ identity ≡ (f , f0 , f1) + rightIdentity i = l i , lemPropF propEqs l {snd L} {snd R} i + where + L = (f , f0 , f1) ∘ identity + R : Arrow AA BB + R = (f , f0 , f1) + l : ℂ [ f ∘ ℂ.identity ] ≡ f + l = ℂ.rightIdentity + + arrowsAreSets : ArrowsAreSets + arrowsAreSets {X , x0 , x1} {Y , y0 , y1} + = sigPresNType {n = ⟨0⟩} ℂ.arrowsAreSets λ a → propSet (propEqs _) isPreCat : IsPreCategory raw IsPreCategory.isAssociative isPreCat = isAssociative @@ -171,69 +172,106 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} open IsPreCategory isPreCat - -- module _ (X : Object) where - -- center : Σ Object (X ≅_) - -- center = X , idIso X - - -- module _ (y : Σ Object (X ≅_)) where - -- open Σ y renaming (fst to Y ; snd to X≅Y) - - -- contractible : (X , idIso X) ≡ (Y , X≅Y) - -- contractible = {!!} - - -- univalent[Contr] : isContr (Σ Object (X ≅_)) - -- univalent[Contr] = center , contractible - -- module _ (y : Σ Object (X ≡_)) where - -- open Σ y renaming (fst to Y ; snd to p) - -- a0 : X ≡ Y - -- a0 = {!!} - -- a1 : PathP (λ i → X ≡ a0 i) refl p - -- a1 = {!!} - -- where - -- P : (Z : Object) → X ≡ Z → Set _ - -- P Z p = PathP (λ i → X ≡ Z) - - -- alt' : (X , refl) ≡ y - -- alt' i = a0 i , a1 i - -- alt : isContr (Σ Object (X ≡_)) - -- alt = (X , refl) , alt' - univalent : Univalent - univalent {X , x} {Y , y} = {!res!} + univalent {(X , xa , xb)} {(Y , ya , yb)} = univalenceFromIsomorphism res where - open import Cat.Equivalence as E hiding (_≅_) - open import Cubical.Univalence - module _ (c : (X , x) ≅ (Y , y)) where - -- module _ (c : _ ≅ _) where - open Σ c renaming (fst to f_c ; snd to inv_c) - open Σ inv_c renaming (fst to g_c ; snd to ainv_c) - open Σ ainv_c renaming (fst to left ; snd to right) - c0 : X ℂ.≅ Y - c0 = fst f_c , fst g_c , (λ i → fst (left i)) , (λ i → fst (right i)) - f0 : X ≡ Y - f0 = ℂ.iso-to-id c0 - module _ {A : ℂ.Object} (α : ℂ.Arrow X A) where - coedom : ℂ.Arrow Y A - coedom = coe (λ i → ℂ.Arrow (f0 i) A) α - coex : ℂ.Arrow Y A × ℂ.Arrow Y B - coex = coe (λ i → ℂ.Arrow (f0 i) A × ℂ.Arrow (f0 i) B) x - f1 : PathP (λ i → ℂ.Arrow (f0 i) A × ℂ.Arrow (f0 i) B) x coex - f1 = {!sym!} - f2 : coex ≡ y - f2 = {!!} - f : (X , x) ≡ (Y , y) - f i = f0 i , {!f1 i!} - prp : isSet (ℂ.Object × ℂ.Arrow Y A × ℂ.Arrow Y B) - prp = setSig {sA = {!!}} {(λ _ → setSig {sA = ℂ.arrowsAreSets} {λ _ → ℂ.arrowsAreSets})} - ve-re : (p : (X , x) ≡ (Y , y)) → f (idToIso _ _ p) ≡ p - -- ve-re p i j = {!ℂ.arrowsAreSets!} , ℂ.arrowsAreSets _ _ (let k = fst (snd (p i)) in {!!}) {!!} {!!} {!!} , {!!} - ve-re p = let k = prp {!!} {!!} {!!} {!p!} in {!!} - re-ve : (iso : (X , x) ≅ (Y , y)) → idToIso _ _ (f iso) ≡ iso - re-ve = {!!} - iso : E.Isomorphism (idToIso (X , x) (Y , y)) - iso = f , record { verso-recto = funExt ve-re ; recto-verso = funExt re-ve } - res : isEquiv ((X , x) ≡ (Y , y)) ((X , x) ≅ (Y , y)) (idToIso (X , x) (Y , y)) - res = Equiv≃.fromIso _ _ iso + open import Cat.Equivalence using (composeIso) renaming (_≅_ to _≈_) + -- open import Relation.Binary.PreorderReasoning (Cat.Equivalence.preorder≅ {!!}) using () + -- renaming + -- ( _∼⟨_⟩_ to _≈⟨_⟩_ + -- ; begin_ to begin!_ + -- ; _∎ to _∎! ) + -- lawl + -- : ((X , xa , xb) ≡ (Y , ya , yb)) + -- ≈ (Σ[ iso ∈ (X ℂ.≅ Y) ] let p = ℂ.iso-to-id iso in (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)) + -- lawl = {!begin! ? ≈⟨ ? ⟩ ? ∎!!} + -- Problem with the above approach: Preorders only work for heterogeneous equaluties. + + -- (X , xa , xb) ≡ (Y , ya , yb) + -- ≅ + -- Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb) + -- ≅ + -- Σ (X ℂ.≅ Y) (λ iso + -- → let p = ℂ.iso-to-id iso + -- in + -- ( PathP (λ i → ℂ.Arrow (p i) A) xa ya) + -- × PathP (λ i → ℂ.Arrow (p i) B) xb yb + -- ) + -- ≅ + -- (X , xa , xb) ≅ (Y , ya , yb) + step0 + : ((X , xa , xb) ≡ (Y , ya , yb)) + ≈ (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)) + step0 + = (λ p → (λ i → fst (p i)) , (λ i → fst (snd (p i))) , (λ i → snd (snd (p i)))) + , (λ x → λ i → fst x i , (fst (snd x) i) , (snd (snd x) i)) + , record + { verso-recto = {!!} + ; recto-verso = {!!} + } + step1 + : (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)) + ≈ Σ (X ℂ.≅ Y) (λ iso + → let p = ℂ.iso-to-id iso + in + ( PathP (λ i → ℂ.Arrow (p i) A) xa ya) + × PathP (λ i → ℂ.Arrow (p i) B) xb yb + ) + step1 + = (λ{ (p , x) → (ℂ.idToIso _ _ p) , {!snd x!}}) + -- Goal is: + -- + -- φ x + -- + -- where `x` is + -- + -- ℂ.iso-to-id (ℂ.idToIso _ _ p) + -- + -- I have `φ p` in scope, but surely `p` and `x` are the same - though + -- perhaps not definitonally. + , (λ{ (iso , x) → ℂ.iso-to-id iso , x}) + , record { verso-recto = {!!} ; recto-verso = {!!} } + lemA : {A B : Object} {f g : Arrow A B} → fst f ≡ fst g → f ≡ g + lemA {A} {B} {f = f} {g} p i = p i , h i + where + h : PathP (λ i → + (ℂ [ fst (snd B) ∘ p i ]) ≡ fst (snd A) × + (ℂ [ snd (snd B) ∘ p i ]) ≡ snd (snd A) + ) (snd f) (snd g) + h = lemPropF (λ a → propSig + (ℂ.arrowsAreSets (ℂ [ fst (snd B) ∘ a ]) (fst (snd A))) + λ _ → ℂ.arrowsAreSets (ℂ [ snd (snd B) ∘ a ]) (snd (snd A))) + p + step2 + : Σ (X ℂ.≅ Y) (λ iso + → let p = ℂ.iso-to-id iso + in + ( PathP (λ i → ℂ.Arrow (p i) A) xa ya) + × PathP (λ i → ℂ.Arrow (p i) B) xb yb + ) + ≈ ((X , xa , xb) ≅ (Y , ya , yb)) + step2 + = ( λ{ ((f , f~ , inv-f) , x) + → ( f , {!!}) + , ( (f~ , {!!}) + , lemA {!!} + , lemA {!!} + ) + } + ) + , (λ x → {!!}) + , {!!} + -- One thing to watch out for here is that the isomorphisms going forwards + -- must compose to give idToIso + iso + : ((X , xa , xb) ≡ (Y , ya , yb)) + ≈ ((X , xa , xb) ≅ (Y , ya , yb)) + iso = step0 ⊙ step1 ⊙ step2 + where + infixl 5 _⊙_ + _⊙_ = composeIso + res : TypeIsomorphism (idToIso (X , xa , xb) (Y , ya , yb)) + res = {!snd iso!} isCat : IsCategory raw IsCategory.isPreCategory isCat = isPreCat @@ -346,3 +384,6 @@ module _ {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} {A B : Category.Object propHasProducts : isProp (HasProducts ℂ) propHasProducts x y i = record { product = productEq x y i } + +fmap≡ : {A : Set} {a0 a1 : A} {B : Set} → (f : A → B) → Path a0 a1 → Path (f a0) (f a1) +fmap≡ = cong diff --git a/src/Cat/Equivalence.agda b/src/Cat/Equivalence.agda index 7d976af..a7386b1 100644 --- a/src/Cat/Equivalence.agda +++ b/src/Cat/Equivalence.agda @@ -7,7 +7,7 @@ open import Cubical.PathPrelude hiding (inverse ; _≃_) open import Cubical.PathPrelude using (isEquiv ; isContr ; fiber) public open import Cubical.GradLemma -open import Cat.Prelude using (lemPropF ; setPi ; lemSig ; propSet) +open import Cat.Prelude using (lemPropF ; setPi ; lemSig ; propSet ; Preorder ; equalityIsEquivalence) module _ {ℓa ℓb : Level} where private @@ -278,6 +278,8 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where a' = Equiv≃.toIso A B a b' = Equiv≃.toIso B C b + composeIso : {ℓc : Level} {C : Set ℓc} → (A ≅ B) → (B ≅ C) → A ≅ C + composeIso {C = C} (f , iso-f) (g , iso-g) = g ∘ f , composeIsomorphism iso-f iso-g -- Gives the quasi inverse from an equivalence. module Equivalence (e : A ≃ B) where @@ -288,9 +290,6 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where open AreInverses (snd iso) public - composeIso : {ℓc : Level} {C : Set ℓc} → (B ≅ C) → A ≅ C - composeIso {C = C} (g , iso-g) = g ∘ obverse , composeIsomorphism iso iso-g - compose : {ℓc : Level} {C : Set ℓc} → (B ≃ C) → A ≃ C compose (f , isEquiv) = f ∘ obverse , composeIsEquiv (snd e) isEquiv @@ -308,6 +307,23 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where where module B≃A = Equiv≃ B A +preorder≅ : (ℓ : Level) → Preorder _ _ _ +preorder≅ ℓ = record + { Carrier = Set ℓ ; _≈_ = _≡_ ; _∼_ = _≅_ + ; isPreorder = record + { isEquivalence = equalityIsEquivalence + ; reflexive = λ p + → coe p + , coe (sym p) + -- I believe I stashed the proof of this somewhere. + , record + { verso-recto = {!refl!} + ; recto-verso = {!!} + } + ; trans = composeIso + } + } + module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where open import Cubical.PathPrelude renaming (_≃_ to _≃η_) open import Cubical.Univalence using (_≃_) diff --git a/src/Cat/Prelude.agda b/src/Cat/Prelude.agda index e18cb72..a01dc25 100644 --- a/src/Cat/Prelude.agda +++ b/src/Cat/Prelude.agda @@ -71,3 +71,17 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {B : A → Set ℓb} {a b : Σ A B} Σ≡ : a ≡ b fst (Σ≡ i) = fst≡ i snd (Σ≡ i) = snd≡ i + +import Relation.Binary +open Relation.Binary public using (Preorder ; Transitive ; IsEquivalence ; Rel) + +equalityIsEquivalence : {ℓ : Level} {A : Set ℓ} → IsEquivalence {A = A} _≡_ +IsEquivalence.refl equalityIsEquivalence = refl +IsEquivalence.sym equalityIsEquivalence = sym +IsEquivalence.trans equalityIsEquivalence = trans + +IsPreorder + : {a ℓ : Level} {A : Set a} + → (_∼_ : Rel A ℓ) -- The relation. + → Set _ +IsPreorder _~_ = Relation.Binary.IsPreorder _≡_ _~_ From 36d92c7ceb86b9c2b52a0e310bc3de567b9e3387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 6 Apr 2018 17:09:15 +0200 Subject: [PATCH 34/93] Make the category an index of PreCategory --- src/Cat/Categories/Rel.agda | 3 +- src/Cat/Category.agda | 456 +++++++++++++++++------------------- 2 files changed, 222 insertions(+), 237 deletions(-) diff --git a/src/Cat/Categories/Rel.agda b/src/Cat/Categories/Rel.agda index 3c7648c..71630e4 100644 --- a/src/Cat/Categories/Rel.agda +++ b/src/Cat/Categories/Rel.agda @@ -163,6 +163,5 @@ IsPreCategory.isAssociative isPreCategory = funExt is-isAssociative IsPreCategory.isIdentity isPreCategory = funExt ident-l , funExt ident-r IsPreCategory.arrowsAreSets isPreCategory = {!!} -Rel : PreCategory _ _ -PreCategory.raw Rel = RawRel +Rel : PreCategory RawRel PreCategory.isPreCategory Rel = isPreCategory diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index dfbbc17..7c316e9 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -142,252 +142,242 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where -- This is not so straight-forward so you can assume it postulate from[Contr] : Univalent[Contr] → Univalent --- | The mere proposition of being a category. --- --- Also defines a few lemmas: --- --- iso-is-epi : Isomorphism f → Epimorphism {X = X} f --- iso-is-mono : Isomorphism f → Monomorphism {X = X} f --- --- Sans `univalent` this would be what is referred to as a pre-category in --- [HoTT]. -record IsPreCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc (ℓa ⊔ ℓb)) where - open RawCategory ℂ public - field - isAssociative : IsAssociative - isIdentity : IsIdentity identity - arrowsAreSets : ArrowsAreSets - open Univalence isIdentity public +module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where + record IsPreCategory : Set (lsuc (ℓa ⊔ ℓb)) where + open RawCategory ℂ public + field + isAssociative : IsAssociative + isIdentity : IsIdentity identity + arrowsAreSets : ArrowsAreSets + open Univalence isIdentity public - leftIdentity : {A B : Object} {f : Arrow A B} → identity ∘ f ≡ f - leftIdentity {A} {B} {f} = fst (isIdentity {A = A} {B} {f}) + leftIdentity : {A B : Object} {f : Arrow A B} → identity ∘ f ≡ f + leftIdentity {A} {B} {f} = fst (isIdentity {A = A} {B} {f}) - rightIdentity : {A B : Object} {f : Arrow A B} → f ∘ identity ≡ f - rightIdentity {A} {B} {f} = snd (isIdentity {A = A} {B} {f}) + rightIdentity : {A B : Object} {f : Arrow A B} → f ∘ identity ≡ f + rightIdentity {A} {B} {f} = snd (isIdentity {A = A} {B} {f}) - ------------ - -- Lemmas -- - ------------ + ------------ + -- Lemmas -- + ------------ - -- | Relation between iso- epi- and mono- morphisms. - module _ {A B : Object} {X : Object} (f : Arrow A B) where - iso→epi : Isomorphism f → Epimorphism {X = X} f - iso→epi (f- , left-inv , right-inv) g₀ g₁ eq = begin - g₀ ≡⟨ sym rightIdentity ⟩ - g₀ ∘ identity ≡⟨ cong (_∘_ g₀) (sym right-inv) ⟩ - g₀ ∘ (f ∘ f-) ≡⟨ isAssociative ⟩ - (g₀ ∘ f) ∘ f- ≡⟨ cong (λ φ → φ ∘ f-) eq ⟩ - (g₁ ∘ f) ∘ f- ≡⟨ sym isAssociative ⟩ - g₁ ∘ (f ∘ f-) ≡⟨ cong (_∘_ g₁) right-inv ⟩ - g₁ ∘ identity ≡⟨ rightIdentity ⟩ - g₁ ∎ + -- | Relation between iso- epi- and mono- morphisms. + module _ {A B : Object} {X : Object} (f : Arrow A B) where + iso→epi : Isomorphism f → Epimorphism {X = X} f + iso→epi (f- , left-inv , right-inv) g₀ g₁ eq = begin + g₀ ≡⟨ sym rightIdentity ⟩ + g₀ ∘ identity ≡⟨ cong (_∘_ g₀) (sym right-inv) ⟩ + g₀ ∘ (f ∘ f-) ≡⟨ isAssociative ⟩ + (g₀ ∘ f) ∘ f- ≡⟨ cong (λ φ → φ ∘ f-) eq ⟩ + (g₁ ∘ f) ∘ f- ≡⟨ sym isAssociative ⟩ + g₁ ∘ (f ∘ f-) ≡⟨ cong (_∘_ g₁) right-inv ⟩ + g₁ ∘ identity ≡⟨ rightIdentity ⟩ + g₁ ∎ - iso→mono : Isomorphism f → Monomorphism {X = X} f - iso→mono (f- , left-inv , right-inv) g₀ g₁ eq = - begin - g₀ ≡⟨ sym leftIdentity ⟩ - identity ∘ g₀ ≡⟨ cong (λ φ → φ ∘ g₀) (sym left-inv) ⟩ - (f- ∘ f) ∘ g₀ ≡⟨ sym isAssociative ⟩ - f- ∘ (f ∘ g₀) ≡⟨ cong (_∘_ f-) eq ⟩ - f- ∘ (f ∘ g₁) ≡⟨ isAssociative ⟩ - (f- ∘ f) ∘ g₁ ≡⟨ cong (λ φ → φ ∘ g₁) left-inv ⟩ - identity ∘ g₁ ≡⟨ leftIdentity ⟩ - g₁ ∎ + iso→mono : Isomorphism f → Monomorphism {X = X} f + iso→mono (f- , left-inv , right-inv) g₀ g₁ eq = + begin + g₀ ≡⟨ sym leftIdentity ⟩ + identity ∘ g₀ ≡⟨ cong (λ φ → φ ∘ g₀) (sym left-inv) ⟩ + (f- ∘ f) ∘ g₀ ≡⟨ sym isAssociative ⟩ + f- ∘ (f ∘ g₀) ≡⟨ cong (_∘_ f-) eq ⟩ + f- ∘ (f ∘ g₁) ≡⟨ isAssociative ⟩ + (f- ∘ f) ∘ g₁ ≡⟨ cong (λ φ → φ ∘ g₁) left-inv ⟩ + identity ∘ g₁ ≡⟨ leftIdentity ⟩ + g₁ ∎ - iso→epi×mono : Isomorphism f → Epimorphism {X = X} f × Monomorphism {X = X} f - iso→epi×mono iso = iso→epi iso , iso→mono iso + iso→epi×mono : Isomorphism f → Epimorphism {X = X} f × Monomorphism {X = X} f + iso→epi×mono iso = iso→epi iso , iso→mono iso - propIsAssociative : isProp IsAssociative - propIsAssociative = propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl λ _ → arrowsAreSets _ _)))))) + propIsAssociative : isProp IsAssociative + propIsAssociative = propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl λ _ → arrowsAreSets _ _)))))) - propIsIdentity : ∀ {f : ∀ {A} → Arrow A A} → isProp (IsIdentity f) - propIsIdentity = propPiImpl (λ _ → propPiImpl λ _ → propPiImpl (λ _ → propSig (arrowsAreSets _ _) λ _ → arrowsAreSets _ _)) + propIsIdentity : ∀ {f : ∀ {A} → Arrow A A} → isProp (IsIdentity f) + propIsIdentity = propPiImpl (λ _ → propPiImpl λ _ → propPiImpl (λ _ → propSig (arrowsAreSets _ _) λ _ → arrowsAreSets _ _)) - propArrowIsSet : isProp (∀ {A B} → isSet (Arrow A B)) - propArrowIsSet = propPiImpl λ _ → propPiImpl (λ _ → isSetIsProp) + propArrowIsSet : isProp (∀ {A B} → isSet (Arrow A B)) + propArrowIsSet = propPiImpl λ _ → propPiImpl (λ _ → isSetIsProp) - propIsInverseOf : ∀ {A B f g} → isProp (IsInverseOf {A} {B} f g) - propIsInverseOf = propSig (arrowsAreSets _ _) (λ _ → arrowsAreSets _ _) + propIsInverseOf : ∀ {A B f g} → isProp (IsInverseOf {A} {B} f g) + propIsInverseOf = propSig (arrowsAreSets _ _) (λ _ → arrowsAreSets _ _) - module _ {A B : Object} {f : Arrow A B} where - isoIsProp : isProp (Isomorphism f) - isoIsProp a@(g , η , ε) a'@(g' , η' , ε') = - lemSig (λ g → propIsInverseOf) a a' geq + module _ {A B : Object} {f : Arrow A B} where + isoIsProp : isProp (Isomorphism f) + isoIsProp a@(g , η , ε) a'@(g' , η' , ε') = + lemSig (λ g → propIsInverseOf) a a' geq + where + geq : g ≡ g' + geq = begin + g ≡⟨ sym rightIdentity ⟩ + g ∘ identity ≡⟨ cong (λ φ → g ∘ φ) (sym ε') ⟩ + g ∘ (f ∘ g') ≡⟨ isAssociative ⟩ + (g ∘ f) ∘ g' ≡⟨ cong (λ φ → φ ∘ g') η ⟩ + identity ∘ g' ≡⟨ leftIdentity ⟩ + g' ∎ + + propIsInitial : ∀ I → isProp (IsInitial I) + propIsInitial I x y i {X} = res X i + where + module _ (X : Object) where + open Σ (x {X}) renaming (fst to fx ; snd to cx) + open Σ (y {X}) renaming (fst to fy ; snd to cy) + fp : fx ≡ fy + fp = cx fy + prop : (x : Arrow I X) → isProp (∀ f → x ≡ f) + prop x = propPi (λ y → arrowsAreSets x y) + cp : (λ i → ∀ f → fp i ≡ f) [ cx ≡ cy ] + cp = lemPropF prop fp + res : (fx , cx) ≡ (fy , cy) + res i = fp i , cp i + + propIsTerminal : ∀ T → isProp (IsTerminal T) + propIsTerminal T x y i {X} = res X i + where + module _ (X : Object) where + open Σ (x {X}) renaming (fst to fx ; snd to cx) + open Σ (y {X}) renaming (fst to fy ; snd to cy) + fp : fx ≡ fy + fp = cx fy + prop : (x : Arrow X T) → isProp (∀ f → x ≡ f) + prop x = propPi (λ y → arrowsAreSets x y) + cp : (λ i → ∀ f → fp i ≡ f) [ cx ≡ cy ] + cp = lemPropF prop fp + res : (fx , cx) ≡ (fy , cy) + res i = fp i , cp i + + module _ where + private + trans≅ : Transitive _≅_ + trans≅ (f , f~ , f-inv) (g , g~ , g-inv) + = g ∘ f + , f~ ∘ g~ + , ( begin + (f~ ∘ g~) ∘ (g ∘ f) ≡⟨ isAssociative ⟩ + (f~ ∘ g~) ∘ g ∘ f ≡⟨ cong (λ φ → φ ∘ f) (sym isAssociative) ⟩ + f~ ∘ (g~ ∘ g) ∘ f ≡⟨ cong (λ φ → f~ ∘ φ ∘ f) (fst g-inv) ⟩ + f~ ∘ identity ∘ f ≡⟨ cong (λ φ → φ ∘ f) rightIdentity ⟩ + f~ ∘ f ≡⟨ fst f-inv ⟩ + identity ∎ + ) + , ( begin + g ∘ f ∘ (f~ ∘ g~) ≡⟨ isAssociative ⟩ + g ∘ f ∘ f~ ∘ g~ ≡⟨ cong (λ φ → φ ∘ g~) (sym isAssociative) ⟩ + g ∘ (f ∘ f~) ∘ g~ ≡⟨ cong (λ φ → g ∘ φ ∘ g~) (snd f-inv) ⟩ + g ∘ identity ∘ g~ ≡⟨ cong (λ φ → φ ∘ g~) rightIdentity ⟩ + g ∘ g~ ≡⟨ snd g-inv ⟩ + identity ∎ + ) + isPreorder : IsPreorder _≅_ + isPreorder = record { isEquivalence = equalityIsEquivalence ; reflexive = idToIso _ _ ; trans = trans≅ } + + preorder≅ : Preorder _ _ _ + preorder≅ = record { Carrier = Object ; _≈_ = _≡_ ; _∼_ = _≅_ ; isPreorder = isPreorder } + + record PreCategory : Set (lsuc (ℓa ⊔ ℓb)) where + field + isPreCategory : IsPreCategory + open IsPreCategory isPreCategory public + + -- Definition 9.6.1 in [HoTT] + record StrictCategory : Set (lsuc (ℓa ⊔ ℓb)) where + field + preCategory : PreCategory + open PreCategory preCategory + field + objectsAreSets : isSet Object + + record IsCategory : Set (lsuc (ℓa ⊔ ℓb)) where + field + isPreCategory : IsPreCategory + open IsPreCategory isPreCategory public + field + univalent : Univalent + + -- | The formulation of univalence expressed with _≃_ is trivially admissable - + -- just "forget" the equivalence. + univalent≃ : Univalent≃ + univalent≃ = _ , univalent + + module _ {A B : Object} where + open import Cat.Equivalence using (module Equiv≃) + + iso-to-id : (A ≅ B) → (A ≡ B) + iso-to-id = fst (Equiv≃.toIso _ _ univalent) + + -- | All projections are propositions. + module Propositionality where + propUnivalent : isProp Univalent + propUnivalent a b i = propPi (λ iso → propIsContr) a b i + + -- | Terminal objects are propositional - a.k.a uniqueness of terminal + -- | objects. + -- + -- Having two terminal objects induces an isomorphism between them - and + -- because of univalence this is equivalent to equality. + propTerminal : isProp Terminal + propTerminal Xt Yt = res where - geq : g ≡ g' - geq = begin - g ≡⟨ sym rightIdentity ⟩ - g ∘ identity ≡⟨ cong (λ φ → g ∘ φ) (sym ε') ⟩ - g ∘ (f ∘ g') ≡⟨ isAssociative ⟩ - (g ∘ f) ∘ g' ≡⟨ cong (λ φ → φ ∘ g') η ⟩ - identity ∘ g' ≡⟨ leftIdentity ⟩ - g' ∎ + open Σ Xt renaming (fst to X ; snd to Xit) + open Σ Yt renaming (fst to Y ; snd to Yit) + open Σ (Xit {Y}) renaming (fst to Y→X) using () + open Σ (Yit {X}) renaming (fst to X→Y) using () + open import Cat.Equivalence hiding (_≅_) + -- Need to show `left` and `right`, what we know is that the arrows are + -- unique. Well, I know that if I compose these two arrows they must give + -- the identity, since also the identity is the unique such arrow (by X + -- and Y both being terminal objects.) + Xprop : isProp (Arrow X X) + Xprop f g = trans (sym (snd Xit f)) (snd Xit g) + Yprop : isProp (Arrow Y Y) + Yprop f g = trans (sym (snd Yit f)) (snd Yit g) + left : Y→X ∘ X→Y ≡ identity + left = Xprop _ _ + right : X→Y ∘ Y→X ≡ identity + right = Yprop _ _ + iso : X ≅ Y + iso = X→Y , Y→X , left , right + fromIso : X ≅ Y → X ≡ Y + fromIso = fst (Equiv≃.toIso (X ≡ Y) (X ≅ Y) univalent) + p0 : X ≡ Y + p0 = fromIso iso + p1 : (λ i → IsTerminal (p0 i)) [ Xit ≡ Yit ] + p1 = lemPropF propIsTerminal p0 + res : Xt ≡ Yt + res i = p0 i , p1 i - propIsInitial : ∀ I → isProp (IsInitial I) - propIsInitial I x y i {X} = res X i - where - module _ (X : Object) where - open Σ (x {X}) renaming (fst to fx ; snd to cx) - open Σ (y {X}) renaming (fst to fy ; snd to cy) - fp : fx ≡ fy - fp = cx fy - prop : (x : Arrow I X) → isProp (∀ f → x ≡ f) - prop x = propPi (λ y → arrowsAreSets x y) - cp : (λ i → ∀ f → fp i ≡ f) [ cx ≡ cy ] - cp = lemPropF prop fp - res : (fx , cx) ≡ (fy , cy) - res i = fp i , cp i + -- Merely the dual of the above statement. - propIsTerminal : ∀ T → isProp (IsTerminal T) - propIsTerminal T x y i {X} = res X i - where - module _ (X : Object) where - open Σ (x {X}) renaming (fst to fx ; snd to cx) - open Σ (y {X}) renaming (fst to fy ; snd to cy) - fp : fx ≡ fy - fp = cx fy - prop : (x : Arrow X T) → isProp (∀ f → x ≡ f) - prop x = propPi (λ y → arrowsAreSets x y) - cp : (λ i → ∀ f → fp i ≡ f) [ cx ≡ cy ] - cp = lemPropF prop fp - res : (fx , cx) ≡ (fy , cy) - res i = fp i , cp i + propInitial : isProp Initial + propInitial Xi Yi = res + where + open Σ Xi renaming (fst to X ; snd to Xii) + open Σ Yi renaming (fst to Y ; snd to Yii) + open Σ (Xii {Y}) renaming (fst to Y→X) using () + open Σ (Yii {X}) renaming (fst to X→Y) using () + open import Cat.Equivalence hiding (_≅_) + -- Need to show `left` and `right`, what we know is that the arrows are + -- unique. Well, I know that if I compose these two arrows they must give + -- the identity, since also the identity is the unique such arrow (by X + -- and Y both being terminal objects.) + Xprop : isProp (Arrow X X) + Xprop f g = trans (sym (snd Xii f)) (snd Xii g) + Yprop : isProp (Arrow Y Y) + Yprop f g = trans (sym (snd Yii f)) (snd Yii g) + left : Y→X ∘ X→Y ≡ identity + left = Yprop _ _ + right : X→Y ∘ Y→X ≡ identity + right = Xprop _ _ + iso : X ≅ Y + iso = Y→X , X→Y , right , left + fromIso : X ≅ Y → X ≡ Y + fromIso = fst (Equiv≃.toIso (X ≡ Y) (X ≅ Y) univalent) + p0 : X ≡ Y + p0 = fromIso iso + p1 : (λ i → IsInitial (p0 i)) [ Xii ≡ Yii ] + p1 = lemPropF propIsInitial p0 + res : Xi ≡ Yi + res i = p0 i , p1 i - module _ where - private - trans≅ : Transitive _≅_ - trans≅ (f , f~ , f-inv) (g , g~ , g-inv) - = g ∘ f - , f~ ∘ g~ - , ( begin - (f~ ∘ g~) ∘ (g ∘ f) ≡⟨ isAssociative ⟩ - (f~ ∘ g~) ∘ g ∘ f ≡⟨ cong (λ φ → φ ∘ f) (sym isAssociative) ⟩ - f~ ∘ (g~ ∘ g) ∘ f ≡⟨ cong (λ φ → f~ ∘ φ ∘ f) (fst g-inv) ⟩ - f~ ∘ identity ∘ f ≡⟨ cong (λ φ → φ ∘ f) rightIdentity ⟩ - f~ ∘ f ≡⟨ fst f-inv ⟩ - identity ∎ - ) - , ( begin - g ∘ f ∘ (f~ ∘ g~) ≡⟨ isAssociative ⟩ - g ∘ f ∘ f~ ∘ g~ ≡⟨ cong (λ φ → φ ∘ g~) (sym isAssociative) ⟩ - g ∘ (f ∘ f~) ∘ g~ ≡⟨ cong (λ φ → g ∘ φ ∘ g~) (snd f-inv) ⟩ - g ∘ identity ∘ g~ ≡⟨ cong (λ φ → φ ∘ g~) rightIdentity ⟩ - g ∘ g~ ≡⟨ snd g-inv ⟩ - identity ∎ - ) - isPreorder : IsPreorder _≅_ - isPreorder = record { isEquivalence = equalityIsEquivalence ; reflexive = idToIso _ _ ; trans = trans≅ } - - preorder≅ : Preorder _ _ _ - preorder≅ = record { Carrier = Object ; _≈_ = _≡_ ; _∼_ = _≅_ ; isPreorder = isPreorder } - -record PreCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where - field - raw : RawCategory ℓa ℓb - isPreCategory : IsPreCategory raw - open IsPreCategory isPreCategory public - --- Definition 9.6.1 in [HoTT] -record StrictCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where - field - preCategory : PreCategory ℓa ℓb - open PreCategory preCategory - field - objectsAreSets : isSet Object - -record IsCategory {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) : Set (lsuc (ℓa ⊔ ℓb)) where - field - isPreCategory : IsPreCategory ℂ - open IsPreCategory isPreCategory public - field - univalent : Univalent - - -- | The formulation of univalence expressed with _≃_ is trivially admissable - - -- just "forget" the equivalence. - univalent≃ : Univalent≃ - univalent≃ = _ , univalent - - module _ {A B : Object} where - open import Cat.Equivalence using (module Equiv≃) - - iso-to-id : (A ≅ B) → (A ≡ B) - iso-to-id = fst (Equiv≃.toIso _ _ univalent) - - -- | All projections are propositions. - module Propositionality where - propUnivalent : isProp Univalent - propUnivalent a b i = propPi (λ iso → propIsContr) a b i - - -- | Terminal objects are propositional - a.k.a uniqueness of terminal - -- | objects. - -- - -- Having two terminal objects induces an isomorphism between them - and - -- because of univalence this is equivalent to equality. - propTerminal : isProp Terminal - propTerminal Xt Yt = res - where - open Σ Xt renaming (fst to X ; snd to Xit) - open Σ Yt renaming (fst to Y ; snd to Yit) - open Σ (Xit {Y}) renaming (fst to Y→X) using () - open Σ (Yit {X}) renaming (fst to X→Y) using () - open import Cat.Equivalence hiding (_≅_) - -- Need to show `left` and `right`, what we know is that the arrows are - -- unique. Well, I know that if I compose these two arrows they must give - -- the identity, since also the identity is the unique such arrow (by X - -- and Y both being terminal objects.) - Xprop : isProp (Arrow X X) - Xprop f g = trans (sym (snd Xit f)) (snd Xit g) - Yprop : isProp (Arrow Y Y) - Yprop f g = trans (sym (snd Yit f)) (snd Yit g) - left : Y→X ∘ X→Y ≡ identity - left = Xprop _ _ - right : X→Y ∘ Y→X ≡ identity - right = Yprop _ _ - iso : X ≅ Y - iso = X→Y , Y→X , left , right - fromIso : X ≅ Y → X ≡ Y - fromIso = fst (Equiv≃.toIso (X ≡ Y) (X ≅ Y) univalent) - p0 : X ≡ Y - p0 = fromIso iso - p1 : (λ i → IsTerminal (p0 i)) [ Xit ≡ Yit ] - p1 = lemPropF propIsTerminal p0 - res : Xt ≡ Yt - res i = p0 i , p1 i - - -- Merely the dual of the above statement. - - propInitial : isProp Initial - propInitial Xi Yi = res - where - open Σ Xi renaming (fst to X ; snd to Xii) - open Σ Yi renaming (fst to Y ; snd to Yii) - open Σ (Xii {Y}) renaming (fst to Y→X) using () - open Σ (Yii {X}) renaming (fst to X→Y) using () - open import Cat.Equivalence hiding (_≅_) - -- Need to show `left` and `right`, what we know is that the arrows are - -- unique. Well, I know that if I compose these two arrows they must give - -- the identity, since also the identity is the unique such arrow (by X - -- and Y both being terminal objects.) - Xprop : isProp (Arrow X X) - Xprop f g = trans (sym (snd Xii f)) (snd Xii g) - Yprop : isProp (Arrow Y Y) - Yprop f g = trans (sym (snd Yii f)) (snd Yii g) - left : Y→X ∘ X→Y ≡ identity - left = Yprop _ _ - right : X→Y ∘ Y→X ≡ identity - right = Xprop _ _ - iso : X ≅ Y - iso = Y→X , X→Y , right , left - fromIso : X ≅ Y → X ≡ Y - fromIso = fst (Equiv≃.toIso (X ≡ Y) (X ≅ Y) univalent) - p0 : X ≡ Y - p0 = fromIso iso - p1 : (λ i → IsInitial (p0 i)) [ Xii ≡ Yii ] - p1 = lemPropF propIsInitial p0 - res : Xi ≡ Yi - res i = p0 i , p1 i - --- | Propositionality of being a category module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where open RawCategory ℂ open Univalence @@ -442,10 +432,6 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where IsCategory.isPreCategory (done i) = propIsPreCategory X.isPreCategory Y.isPreCategory i IsCategory.univalent (done i) = eqUni i - -- IsCategory.isAssociative (done i) = Prop.propIsAssociative X.isAssociative Y.isAssociative i - -- IsCategory.isIdentity (done i) = isIdentity i - -- IsCategory.arrowsAreSets (done i) = Prop.propArrowIsSet X.arrowsAreSets Y.arrowsAreSets i - -- IsCategory.univalent (done i) = eqUni i propIsCategory : isProp (IsCategory ℂ) propIsCategory = done From 69689e7b2a8a29a39f6c6cb7b5a3c7e337dae3e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 6 Apr 2018 18:27:24 +0200 Subject: [PATCH 35/93] Use a single version of \simeq --- src/Cat/Categories/Fam.agda | 3 - src/Cat/Categories/Fun.agda | 1 - src/Cat/Categories/Sets.agda | 79 ++++++++---------------- src/Cat/Category.agda | 35 +++++------ src/Cat/Category/Functor.agda | 1 - src/Cat/Category/Product.agda | 6 +- src/Cat/Equivalence.agda | 113 ++++++++++++++-------------------- src/Cat/Prelude.agda | 2 +- 8 files changed, 91 insertions(+), 149 deletions(-) diff --git a/src/Cat/Categories/Fam.agda b/src/Cat/Categories/Fam.agda index e90838c..dd5c757 100644 --- a/src/Cat/Categories/Fam.agda +++ b/src/Cat/Categories/Fam.agda @@ -33,9 +33,6 @@ module _ (ℓa ℓb : Level) where isIdentity : IsIdentity λ { {A} → identity {A} } isIdentity = (Σ≡ refl refl) , Σ≡ refl refl - open import Cubical.NType.Properties - open import Cubical.Sigma - isPreCategory : IsPreCategory RawFam IsPreCategory.isAssociative isPreCategory {A} {B} {C} {D} {f} {g} {h} = isAssociative {A} {B} {C} {D} {f} {g} {h} diff --git a/src/Cat/Categories/Fun.agda b/src/Cat/Categories/Fun.agda index be37dcb..48ee817 100644 --- a/src/Cat/Categories/Fun.agda +++ b/src/Cat/Categories/Fun.agda @@ -78,7 +78,6 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C F[ F ∘ G~ ] ≡⟨ prop1 ⟩ idFunctor ∎ - open import Cubical.Univalence p0 : F ≡ G p0 = begin F ≡⟨ sym Functors.rightIdentity ⟩ diff --git a/src/Cat/Categories/Sets.agda b/src/Cat/Categories/Sets.agda index a323481..7870fc0 100644 --- a/src/Cat/Categories/Sets.agda +++ b/src/Cat/Categories/Sets.agda @@ -2,21 +2,15 @@ {-# OPTIONS --allow-unsolved-metas --cubical --caching #-} module Cat.Categories.Sets where -open import Cat.Prelude as P hiding (_≃_) +open import Cat.Prelude as P open import Function using (_∘_ ; _∘′_) -open import Cubical.Univalence using (univalence ; con ; _≃_ ; idtoeqv ; ua) - open import Cat.Category open import Cat.Category.Functor open import Cat.Category.Product open import Cat.Wishlist -open import Cat.Equivalence as Eqv using (AreInverses ; module Equiv≃ ; module NoEta) - -open NoEta - -module Equivalence = Equivalence′ +open import Cat.Equivalence renaming (_≅_ to _≈_) _⊙_ : {ℓa ℓb ℓc : Level} {A : Set ℓa} {B : Set ℓb} {C : Set ℓc} → (A ≃ B) → (B ≃ C) → A ≃ C eqA ⊙ eqB = Equivalence.compose eqA eqB @@ -52,7 +46,7 @@ module _ (ℓ : Level) where open IsPreCategory isPreCat hiding (_∘_) - isIso = Eqv.Isomorphism + isIso = TypeIsomorphism module _ {hA hB : hSet ℓ} where open Σ hA renaming (fst to A ; snd to sA) open Σ hB renaming (fst to B ; snd to sB) @@ -95,7 +89,7 @@ module _ (ℓ : Level) where module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where lem2 : ((x : A) → isProp (P x)) → (p q : Σ A P) → (p ≡ q) ≃ (fst p ≡ fst q) - lem2 pA p q = fromIsomorphism iso + lem2 pA p q = fromIsomorphism _ _ iso where f : ∀ {p q} → p ≡ q → fst p ≡ fst q f e i = fst (e i) @@ -111,7 +105,7 @@ module _ (ℓ : Level) where { verso-recto = funExt ve-re ; recto-verso = funExt re-ve } - iso : (p ≡ q) Eqv.≅ (fst p ≡ fst q) + iso : (p ≡ q) ≈ (fst p ≡ fst q) iso = f , g , inv lem3 : ∀ {ℓc} {Q : A → Set (ℓc ⊔ ℓb)} @@ -119,12 +113,12 @@ module _ (ℓ : Level) where lem3 {Q = Q} eA = res where f : Σ A P → Σ A Q - f (a , pA) = a , _≃_.eqv (eA a) pA + f (a , pA) = a , fst (eA a) pA g : Σ A Q → Σ A P g (a , qA) = a , g' qA where - k : Eqv.Isomorphism _ - k = Equiv≃.toIso _ _ (_≃_.isEqv (eA a)) + k : TypeIsomorphism _ + k = toIso _ _ (snd (eA a)) open Σ k renaming (fst to g') ve-re : (x : Σ A P) → (g ∘ f) x ≡ x ve-re x i = fst x , eq i @@ -133,16 +127,16 @@ module _ (ℓ : Level) where eq = begin snd ((g ∘ f) x) ≡⟨⟩ snd (g (f (a , pA))) ≡⟨⟩ - g' (_≃_.eqv (eA a) pA) ≡⟨ lem ⟩ + g' (fst (eA a) pA) ≡⟨ lem ⟩ pA ∎ where open Σ x renaming (fst to a ; snd to pA) - k : Eqv.Isomorphism _ - k = Equiv≃.toIso _ _ (_≃_.isEqv (eA a)) + k : TypeIsomorphism _ + k = toIso _ _ (snd (eA a)) open Σ k renaming (fst to g' ; snd to inv) module A = AreInverses inv -- anti-funExt - lem : (g' ∘ (_≃_.eqv (eA a))) pA ≡ pA + lem : (g' ∘ (fst (eA a))) pA ≡ pA lem i = A.verso-recto i pA re-ve : (x : Σ A Q) → (f ∘ g) x ≡ x re-ve x i = fst x , eq i @@ -150,11 +144,11 @@ module _ (ℓ : Level) where open Σ x renaming (fst to a ; snd to qA) eq = begin snd ((f ∘ g) x) ≡⟨⟩ - _≃_.eqv (eA a) (g' qA) ≡⟨ (λ i → A.recto-verso i qA) ⟩ + fst (eA a) (g' qA) ≡⟨ (λ i → A.recto-verso i qA) ⟩ qA ∎ where - k : Eqv.Isomorphism _ - k = Equiv≃.toIso _ _ (_≃_.isEqv (eA a)) + k : TypeIsomorphism _ + k = toIso _ _ (snd (eA a)) open Σ k renaming (fst to g' ; snd to inv) module A = AreInverses inv inv : AreInverses f g @@ -162,10 +156,10 @@ module _ (ℓ : Level) where { verso-recto = funExt ve-re ; recto-verso = funExt re-ve } - iso : Σ A P Eqv.≅ Σ A Q + iso : Σ A P ≈ Σ A Q iso = f , g , inv res : Σ A P ≃ Σ A Q - res = fromIsomorphism iso + res = fromIsomorphism _ _ iso module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where lem4 : isSet A → isSet B → (f : A → B) @@ -173,20 +167,20 @@ module _ (ℓ : Level) where lem4 sA sB f = let obv : isEquiv A B f → isIso f - obv = Equiv≃.toIso A B + obv = toIso A B inv : isIso f → isEquiv A B f - inv = Equiv≃.fromIso A B + inv = fromIso A B re-ve : (x : isEquiv A B f) → (inv ∘ obv) x ≡ x - re-ve = Equiv≃.inverse-from-to-iso A B + re-ve = inverse-from-to-iso A B ve-re : (x : isIso f) → (obv ∘ inv) x ≡ x - ve-re = Equiv≃.inverse-to-from-iso A B sA sB - iso : isEquiv A B f Eqv.≅ isIso f + ve-re = inverse-to-from-iso A B sA sB + iso : isEquiv A B f ≈ isIso f iso = obv , inv , record { verso-recto = funExt re-ve ; recto-verso = funExt ve-re } - in fromIsomorphism iso + in fromIsomorphism _ _ iso module _ {hA hB : Object} where open Σ hA renaming (fst to A ; snd to sA) @@ -198,33 +192,15 @@ module _ (ℓ : Level) where -- univalence step1 : Σ (A → B) (isEquiv A B) ≃ (A ≡ B) - step1 = hh ⊙ h - where - h : (A ≃ B) ≃ (A ≡ B) - h = sym≃ (univalence {A = A} {B}) - obv : Σ (A → B) (isEquiv A B) → A ≃ B - obv = Eqv.deEta - inv : A ≃ B → Σ (A → B) (isEquiv A B) - inv = Eqv.doEta - re-ve : (x : _) → (inv ∘ obv) x ≡ x - re-ve x = refl - -- Because _≃_ does not have eta equality! - ve-re : (x : _) → (obv ∘ inv) x ≡ x - ve-re (con eqv isEqv) i = con eqv isEqv - areInv : AreInverses obv inv - areInv = record { verso-recto = funExt re-ve ; recto-verso = funExt ve-re } - eqv : Σ (A → B) (isEquiv A B) Eqv.≅ (A ≃ B) - eqv = obv , inv , areInv - hh : Σ (A → B) (isEquiv A B) ≃ (A ≃ B) - hh = fromIsomorphism eqv + step1 = sym≃ univalence -- lem2 with propIsSet step2 : (A ≡ B) ≃ (hA ≡ hB) step2 = sym≃ (lem2 (λ A → isSetIsProp) hA hB) -- Go from an isomorphism on sets to an isomorphism on homotopic sets - trivial? : (hA ≅ hB) ≃ (A Eqv.≅ B) - trivial? = sym≃ (fromIsomorphism res) + trivial? : (hA ≅ hB) ≃ (A ≈ B) + trivial? = sym≃ (fromIsomorphism _ _ res) where fwd : Σ (A → B) isIso → hA ≅ hB fwd (f , g , inv) = f , g , inv.toPair @@ -232,7 +208,7 @@ module _ (ℓ : Level) where module inv = AreInverses inv bwd : hA ≅ hB → Σ (A → B) isIso bwd (f , g , x , y) = f , g , record { verso-recto = x ; recto-verso = y } - res : Σ (A → B) isIso Eqv.≅ (hA ≅ hB) + res : Σ (A → B) isIso ≈ (hA ≅ hB) res = fwd , bwd , record { verso-recto = refl ; recto-verso = refl } conclusion : (hA ≅ hB) ≃ (hA ≡ hB) @@ -274,7 +250,6 @@ module _ {ℓ : Level} where private 𝓢 = 𝓢𝓮𝓽 ℓ open Category 𝓢 - open import Cubical.Sigma module _ (hA hB : Object) where open Σ hA renaming (fst to A ; snd to sA) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 7c316e9..254f024 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -29,6 +29,7 @@ module Cat.Category where open import Cat.Prelude +open import Cat.Equivalence as Equivalence renaming (_≅_ to _≈_ ; Isomorphism to TypeIsomorphism) hiding (preorder≅) import Function @@ -122,8 +123,6 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where import Cat.Equivalence as E open E public using () renaming (Isomorphism to TypeIsomorphism) - open E using (module Equiv≃) - open Equiv≃ using (fromIso) univalenceFromIsomorphism : {A B : Object} → TypeIsomorphism (idToIso A B) → isEquiv (A ≡ B) (A ≅ B) (idToIso A B) @@ -299,10 +298,8 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where univalent≃ = _ , univalent module _ {A B : Object} where - open import Cat.Equivalence using (module Equiv≃) - iso-to-id : (A ≅ B) → (A ≡ B) - iso-to-id = fst (Equiv≃.toIso _ _ univalent) + iso-to-id = fst (toIso _ _ univalent) -- | All projections are propositions. module Propositionality where @@ -321,7 +318,6 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where open Σ Yt renaming (fst to Y ; snd to Yit) open Σ (Xit {Y}) renaming (fst to Y→X) using () open Σ (Yit {X}) renaming (fst to X→Y) using () - open import Cat.Equivalence hiding (_≅_) -- Need to show `left` and `right`, what we know is that the arrows are -- unique. Well, I know that if I compose these two arrows they must give -- the identity, since also the identity is the unique such arrow (by X @@ -336,10 +332,10 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where right = Yprop _ _ iso : X ≅ Y iso = X→Y , Y→X , left , right - fromIso : X ≅ Y → X ≡ Y - fromIso = fst (Equiv≃.toIso (X ≡ Y) (X ≅ Y) univalent) + fromIso' : X ≅ Y → X ≡ Y + fromIso' = fst (toIso (X ≡ Y) (X ≅ Y) univalent) p0 : X ≡ Y - p0 = fromIso iso + p0 = fromIso' iso p1 : (λ i → IsTerminal (p0 i)) [ Xit ≡ Yit ] p1 = lemPropF propIsTerminal p0 res : Xt ≡ Yt @@ -354,7 +350,6 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where open Σ Yi renaming (fst to Y ; snd to Yii) open Σ (Xii {Y}) renaming (fst to Y→X) using () open Σ (Yii {X}) renaming (fst to X→Y) using () - open import Cat.Equivalence hiding (_≅_) -- Need to show `left` and `right`, what we know is that the arrows are -- unique. Well, I know that if I compose these two arrows they must give -- the identity, since also the identity is the unique such arrow (by X @@ -369,10 +364,10 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where right = Xprop _ _ iso : X ≅ Y iso = Y→X , X→Y , right , left - fromIso : X ≅ Y → X ≡ Y - fromIso = fst (Equiv≃.toIso (X ≡ Y) (X ≅ Y) univalent) + fromIso' : X ≅ Y → X ≡ Y + fromIso' = fst (toIso (X ≡ Y) (X ≅ Y) univalent) p0 : X ≡ Y - p0 = fromIso iso + p0 = fromIso' iso p1 : (λ i → IsInitial (p0 i)) [ Xii ≡ Yii ] p1 = lemPropF propIsInitial p0 res : Xi ≡ Yi @@ -436,9 +431,12 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where propIsCategory : isProp (IsCategory ℂ) propIsCategory = done + -- | Univalent categories -- -- Just bundles up the data with witnesses inhabiting the propositions. + +-- Question: Should I remove the type `Category`? record Category (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where field raw : RawCategory ℓa ℓb @@ -459,10 +457,8 @@ module _ {ℓa ℓb : Level} {ℂ 𝔻 : Category ℓa ℓb} where isCategoryEq = lemPropF propIsCategory rawEq Category≡ : ℂ ≡ 𝔻 - Category≡ i = record - { raw = rawEq i - ; isCategory = isCategoryEq i - } + Category.raw (Category≡ i) = rawEq i + Category.isCategory (Category≡ i) = isCategoryEq i -- | Syntax for arrows- and composition in a given category. module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where @@ -501,9 +497,8 @@ module Opposite {ℓa ℓb : Level} where open IsPreCategory isPreCategory module _ {A B : ℂ.Object} where - open import Cat.Equivalence as Equivalence hiding (_≅_) k : Equivalence.Isomorphism (ℂ.idToIso A B) - k = Equiv≃.toIso _ _ ℂ.univalent + k = toIso _ _ ℂ.univalent open Σ k renaming (fst to f ; snd to inv) open AreInverses inv @@ -568,7 +563,7 @@ module Opposite {ℓa ℓb : Level} where h = ff , invv univalent : isEquiv (A ≡ B) (A ≅ B) (Univalence.idToIso (swap ℂ.isIdentity) A B) - univalent = Equiv≃.fromIso _ _ h + univalent = fromIso _ _ h isCategory : IsCategory opRaw IsCategory.isPreCategory isCategory = isPreCategory diff --git a/src/Cat/Category/Functor.agda b/src/Cat/Category/Functor.agda index c4a7346..08dcafa 100644 --- a/src/Cat/Category/Functor.agda +++ b/src/Cat/Category/Functor.agda @@ -5,7 +5,6 @@ open import Cat.Prelude open import Function open import Cubical -open import Cubical.NType.Properties using (lemPropF) open import Cat.Category diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 9def8a2..536467b 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -1,8 +1,8 @@ {-# OPTIONS --allow-unsolved-metas --cubical #-} module Cat.Category.Product where -open import Cubical.NType.Properties open import Cat.Prelude as P hiding (_×_ ; fst ; snd) +open import Cat.Equivalence hiding (_≅_) -- module P = Cat.Prelude open import Cat.Category @@ -285,10 +285,8 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} open Category cat - open import Cat.Equivalence - lemma : Terminal ≃ Product ℂ A B - lemma = Equiv≃.fromIsomorphism Terminal (Product ℂ A B) (f , g , inv) + lemma = fromIsomorphism Terminal (Product ℂ A B) (f , g , inv) where f : Terminal → Product ℂ A B f ((X , x0 , x1) , uniq) = p diff --git a/src/Cat/Equivalence.agda b/src/Cat/Equivalence.agda index a7386b1..43a25e4 100644 --- a/src/Cat/Equivalence.agda +++ b/src/Cat/Equivalence.agda @@ -3,11 +3,26 @@ module Cat.Equivalence where open import Cubical.Primitives open import Cubical.FromStdLib renaming (ℓ-max to _⊔_) +-- FIXME: Don't hide ≃ open import Cubical.PathPrelude hiding (inverse ; _≃_) open import Cubical.PathPrelude using (isEquiv ; isContr ; fiber) public open import Cubical.GradLemma -open import Cat.Prelude using (lemPropF ; setPi ; lemSig ; propSet ; Preorder ; equalityIsEquivalence) +open import Cat.Prelude using (lemPropF ; setPi ; lemSig ; propSet ; Preorder ; equalityIsEquivalence ; _≃_) + +import Cubical.Univalence as U + +module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where + open Cubical.PathPrelude + deEta : A ≃ B → A U.≃ B + deEta (a , b) = U.con a b + doEta : A U.≃ B → A ≃ B + doEta (U.con eqv isEqv) = eqv , isEqv + +module _ {ℓ : Level} {A B : Set ℓ} where + open Cubical.PathPrelude + ua : A ≃ B → A ≡ B + ua (f , isEqv) = U.ua (U.con f isEqv) module _ {ℓa ℓb : Level} where private @@ -242,8 +257,7 @@ module _ {ℓa ℓb : Level} (A : Set ℓa) (B : Set ℓb) where where import Cubical.NType.Properties as P - module Equiv≃ where - open Equiv ≃isEquiv public + open Equiv ≃isEquiv public module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where open Cubical.PathPrelude using (_≃_) @@ -273,20 +287,19 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where } composeIsEquiv : isEquiv A B f → isEquiv B C g → isEquiv A C (g ∘ f) - composeIsEquiv a b = Equiv≃.fromIso A C (composeIsomorphism a' b') + composeIsEquiv a b = fromIso A C (composeIsomorphism a' b') where - a' = Equiv≃.toIso A B a - b' = Equiv≃.toIso B C b + a' = toIso A B a + b' = toIso B C b composeIso : {ℓc : Level} {C : Set ℓc} → (A ≅ B) → (B ≅ C) → A ≅ C composeIso {C = C} (f , iso-f) (g , iso-g) = g ∘ f , composeIsomorphism iso-f iso-g -- Gives the quasi inverse from an equivalence. module Equivalence (e : A ≃ B) where - open Equiv≃ A B public private iso : Isomorphism (fst e) - iso = snd (toIsomorphism e) + iso = snd (toIsomorphism _ _ e) open AreInverses (snd iso) public @@ -303,9 +316,7 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where } symmetry : B ≃ A - symmetry = B≃A.fromIsomorphism symmetryIso - where - module B≃A = Equiv≃ B A + symmetry = fromIsomorphism _ _ symmetryIso preorder≅ : (ℓ : Level) → Preorder _ _ _ preorder≅ ℓ = record @@ -323,54 +334,24 @@ preorder≅ ℓ = record ; trans = composeIso } } - -module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where - open import Cubical.PathPrelude renaming (_≃_ to _≃η_) - open import Cubical.Univalence using (_≃_) - - doEta : A ≃ B → A ≃η B - doEta (_≃_.con eqv isEqv) = eqv , isEqv - - deEta : A ≃η B → A ≃ B - deEta (eqv , isEqv) = _≃_.con eqv isEqv - -module NoEta {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where - open import Cubical.PathPrelude renaming (_≃_ to _≃η_) - open import Cubical.Univalence using (_≃_) - - module Equivalence′ (e : A ≃ B) where - open Equivalence (doEta e) hiding - ( toIsomorphism ; fromIsomorphism ; _~_ - ; compose ; symmetryIso ; symmetry ) public - - compose : {ℓc : Level} {C : Set ℓc} → (B ≃ C) → A ≃ C - compose ee = deEta (Equivalence.compose (doEta e) (doEta ee)) - - symmetry : B ≃ A - symmetry = deEta (Equivalence.symmetry (doEta e)) - - -- fromIso : {f : A → B} → Isomorphism f → isEquiv f - -- fromIso = ? - - -- toIso : {f : A → B} → isEquiv f → Isomorphism f - -- toIso = ? - - fromIsomorphism : A ≅ B → A ≃ B - fromIsomorphism (f , iso) = _≃_.con f (Equiv≃.fromIso _ _ iso) - - toIsomorphism : A ≃ B → A ≅ B - toIsomorphism (_≃_.con f eqv) = f , Equiv≃.toIso _ _ eqv +module _ {ℓ : Level} {A B : Set ℓ} where + univalence : (A ≡ B) ≃ (A ≃ B) + univalence = Equivalence.compose u' aux + where + u : (A ≡ B) U.≃ (A U.≃ B) + u = U.univalence + u' : (A ≡ B) ≃ (A U.≃ B) + u' = doEta u + aux : (A U.≃ B) ≃ (A ≃ B) + aux = fromIsomorphism _ _ (doEta , deEta , record { verso-recto = funExt (λ{ (U.con _ _) → refl}) ; recto-verso = refl }) -- A few results that I have not generalized to work with both the eta and no-eta variable of ≃ module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where - open NoEta - open import Cubical.Univalence using (_≃_) - -- Equality on sigma's whose second component is a proposition is equivalent -- to equality on their first components. equivPropSig : ((x : A) → isProp (P x)) → (p q : Σ A P) → (p ≡ q) ≃ (fst p ≡ fst q) - equivPropSig pA p q = fromIsomorphism iso + equivPropSig pA p q = fromIsomorphism _ _ iso where f : ∀ {p q} → p ≡ q → fst p ≡ fst q f e i = fst (e i) @@ -396,12 +377,12 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where equivSigSnd {Q = Q} eA = res where f : Σ A P → Σ A Q - f (a , pA) = a , _≃_.eqv (eA a) pA + f (a , pA) = a , fst (eA a) pA g : Σ A Q → Σ A P g (a , qA) = a , g' qA where k : Isomorphism _ - k = Equiv≃.toIso _ _ (_≃_.isEqv (eA a)) + k = toIso _ _ (snd (eA a)) open Σ k renaming (fst to g') ve-re : (x : Σ A P) → (g ∘ f) x ≡ x ve-re x i = fst x , eq i @@ -410,16 +391,16 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where eq = begin snd ((g ∘ f) x) ≡⟨⟩ snd (g (f (a , pA))) ≡⟨⟩ - g' (_≃_.eqv (eA a) pA) ≡⟨ lem ⟩ + g' (fst (eA a) pA) ≡⟨ lem ⟩ pA ∎ where open Σ x renaming (fst to a ; snd to pA) k : Isomorphism _ - k = Equiv≃.toIso _ _ (_≃_.isEqv (eA a)) + k = toIso _ _ (snd (eA a)) open Σ k renaming (fst to g' ; snd to inv) module A = AreInverses inv -- anti-funExt - lem : (g' ∘ (_≃_.eqv (eA a))) pA ≡ pA + lem : (g' ∘ (fst (eA a))) pA ≡ pA lem i = A.verso-recto i pA re-ve : (x : Σ A Q) → (f ∘ g) x ≡ x re-ve x i = fst x , eq i @@ -427,11 +408,11 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where open Σ x renaming (fst to a ; snd to qA) eq = begin snd ((f ∘ g) x) ≡⟨⟩ - _≃_.eqv (eA a) (g' qA) ≡⟨ (λ i → A.recto-verso i qA) ⟩ + fst (eA a) (g' qA) ≡⟨ (λ i → A.recto-verso i qA) ⟩ qA ∎ where k : Isomorphism _ - k = Equiv≃.toIso _ _ (_≃_.isEqv (eA a)) + k = toIso _ _ (snd (eA a)) open Σ k renaming (fst to g' ; snd to inv) module A = AreInverses inv inv : AreInverses f g @@ -442,11 +423,9 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where iso : Σ A P ≅ Σ A Q iso = f , g , inv res : Σ A P ≃ Σ A Q - res = fromIsomorphism iso + res = fromIsomorphism _ _ iso module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where - open NoEta - open import Cubical.Univalence using (_≃_) -- Equivalence is equivalent to isomorphism when the domain and codomain of -- the equivalence is a set. equivSetIso : isSet A → isSet B → (f : A → B) @@ -454,17 +433,17 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where equivSetIso sA sB f = let obv : isEquiv A B f → Isomorphism f - obv = Equiv≃.toIso A B + obv = toIso A B inv : Isomorphism f → isEquiv A B f - inv = Equiv≃.fromIso A B + inv = fromIso A B re-ve : (x : isEquiv A B f) → (inv ∘ obv) x ≡ x - re-ve = Equiv≃.inverse-from-to-iso A B + re-ve = inverse-from-to-iso A B ve-re : (x : Isomorphism f) → (obv ∘ inv) x ≡ x - ve-re = Equiv≃.inverse-to-from-iso A B sA sB + ve-re = inverse-to-from-iso A B sA sB iso : isEquiv A B f ≅ Isomorphism f iso = obv , inv , record { verso-recto = funExt re-ve ; recto-verso = funExt ve-re } - in fromIsomorphism iso + in fromIsomorphism _ _ iso diff --git a/src/Cat/Prelude.agda b/src/Cat/Prelude.agda index a01dc25..0646bf5 100644 --- a/src/Cat/Prelude.agda +++ b/src/Cat/Prelude.agda @@ -24,7 +24,7 @@ open import Cubical.NType.Properties using ( lemPropF ; lemSig ; lemSigP ; isSetIsProp ; propPi ; propPiImpl ; propHasLevel ; setPi ; propSet - ; propSig) + ; propSig ; equivPreservesNType) public propIsContr : {ℓ : Level} → {A : Set ℓ} → isProp (isContr A) From 472dbba84de9b5a24752c70ba0c6eba628570df7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Mon, 9 Apr 2018 16:03:02 +0200 Subject: [PATCH 36/93] Update backlog --- BACKLOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/BACKLOG.md b/BACKLOG.md index 7e18b07..9a72a1d 100644 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -10,13 +10,16 @@ Prove that these two formulations of univalence are equivalent: ∀ A → isContr (Σ[ X ∈ Object ] A ≅ X) Prove univalence for the category of - * the opposite category * functors and natural transformations Prove: * `isProp (Product ...)` * `isProp (HasProducts ...)` +Rename composition in categories + +In stead of using AreInverses, just use a sigma-type + Ideas for future work --------------------- From 735b25de2388b80bf034a73fc93d63cb11e5d121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Mon, 9 Apr 2018 16:03:43 +0200 Subject: [PATCH 37/93] Simplify proof and move propUnivalent to a more general setting --- src/Cat/Category.agda | 63 +++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 254f024..abc7830 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -141,6 +141,9 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where -- This is not so straight-forward so you can assume it postulate from[Contr] : Univalent[Contr] → Univalent + propUnivalent : isProp Univalent + propUnivalent a b i = propPi (λ iso → propIsContr) a b i + module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where record IsPreCategory : Set (lsuc (ℓa ⊔ ℓb)) where open RawCategory ℂ public @@ -192,7 +195,8 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where propIsAssociative = propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl (λ _ → propPiImpl λ _ → arrowsAreSets _ _)))))) propIsIdentity : ∀ {f : ∀ {A} → Arrow A A} → isProp (IsIdentity f) - propIsIdentity = propPiImpl (λ _ → propPiImpl λ _ → propPiImpl (λ _ → propSig (arrowsAreSets _ _) λ _ → arrowsAreSets _ _)) + propIsIdentity {id} = propPiImpl (λ _ → propPiImpl λ _ → propPiImpl (λ f → + propSig (arrowsAreSets (id ∘ f) f) λ _ → arrowsAreSets (f ∘ id) f)) propArrowIsSet : isProp (∀ {A B} → isSet (Arrow A B)) propArrowIsSet = propPiImpl λ _ → propPiImpl (λ _ → isSetIsProp) @@ -303,9 +307,6 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where -- | All projections are propositions. module Propositionality where - propUnivalent : isProp Univalent - propUnivalent a b i = propPi (λ iso → propIsContr) a b i - -- | Terminal objects are propositional - a.k.a uniqueness of terminal -- | objects. -- @@ -403,30 +404,28 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where -- adverse effects this may have. module Prop = X.Propositionality - isIdentity : (λ _ → IsIdentity identity) [ X.isIdentity ≡ Y.isIdentity ] - isIdentity = X.propIsIdentity X.isIdentity Y.isIdentity + isIdentity= : (λ _ → IsIdentity identity) [ X.isIdentity ≡ Y.isIdentity ] + isIdentity= = X.propIsIdentity X.isIdentity Y.isIdentity + + isPreCategory= : X.isPreCategory ≡ Y.isPreCategory + isPreCategory= = propIsPreCategory X.isPreCategory Y.isPreCategory + + private + p = cong IsPreCategory.isIdentity isPreCategory= + + univalent= : (λ i → Univalent (p i)) + [ X.univalent ≡ Y.univalent ] + univalent= = lemPropF + {A = IsIdentity identity} + {B = Univalent} + propUnivalent + {a0 = X.isIdentity} + {a1 = Y.isIdentity} + p - U : ∀ {a : IsIdentity identity} - → (λ _ → IsIdentity identity) [ X.isIdentity ≡ a ] - → (b : Univalent a) - → Set _ - U eqwal univ = - (λ i → Univalent (eqwal i)) - [ X.univalent ≡ univ ] - P : (y : IsIdentity identity) - → (λ _ → IsIdentity identity) [ X.isIdentity ≡ y ] → Set _ - P y eq = ∀ (univ : Univalent y) → U eq univ - p : ∀ (b' : Univalent X.isIdentity) - → (λ _ → Univalent X.isIdentity) [ X.univalent ≡ b' ] - p univ = Prop.propUnivalent X.univalent univ - helper : P Y.isIdentity isIdentity - helper = pathJ P p Y.isIdentity isIdentity - eqUni : U isIdentity Y.univalent - eqUni = helper Y.univalent done : x ≡ y - IsCategory.isPreCategory (done i) - = propIsPreCategory X.isPreCategory Y.isPreCategory i - IsCategory.univalent (done i) = eqUni i + IsCategory.isPreCategory (done i) = isPreCategory= i + IsCategory.univalent (done i) = univalent= i propIsCategory : isProp (IsCategory ℂ) propIsCategory = done @@ -454,7 +453,7 @@ module _ {ℓa ℓb : Level} {ℂ 𝔻 : Category ℓa ℓb} where module _ (rawEq : ℂ.raw ≡ 𝔻.raw) where private isCategoryEq : (λ i → IsCategory (rawEq i)) [ ℂ.isCategory ≡ 𝔻.isCategory ] - isCategoryEq = lemPropF propIsCategory rawEq + isCategoryEq = lemPropF {A = RawCategory _ _} {B = IsCategory} propIsCategory rawEq Category≡ : ℂ ≡ 𝔻 Category.raw (Category≡ i) = rawEq i @@ -482,16 +481,13 @@ module Opposite {ℓa ℓb : Level} where RawCategory.Object opRaw = ℂ.Object RawCategory.Arrow opRaw = Function.flip ℂ.Arrow RawCategory.identity opRaw = ℂ.identity - RawCategory._∘_ opRaw = Function.flip ℂ._∘_ + RawCategory._∘_ opRaw = ℂ._>>>_ open RawCategory opRaw - isIdentity : IsIdentity identity - isIdentity = swap ℂ.isIdentity - isPreCategory : IsPreCategory opRaw IsPreCategory.isAssociative isPreCategory = sym ℂ.isAssociative - IsPreCategory.isIdentity isPreCategory = isIdentity + IsPreCategory.isIdentity isPreCategory = swap ℂ.isIdentity IsPreCategory.arrowsAreSets isPreCategory = ℂ.arrowsAreSets open IsPreCategory isPreCategory @@ -512,9 +508,6 @@ module Opposite {ℓa ℓb : Level} where flopDem : A ℂ.≅ B → A ≅ B flopDem (f , g , inv) = g , f , inv - flipInv : ∀ {x} → (flipDem ⊙ flopDem) x ≡ x - flipInv = refl - -- Shouldn't be necessary to use `arrowsAreSets` here, but we have it, -- so why not? lem : (p : A ≡ B) → idToIso A B p ≡ flopDem (ℂ.idToIso A B p) From 04144db606c9418db73bb1a0c7d8d2b2f5091281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Mon, 9 Apr 2018 18:02:39 +0200 Subject: [PATCH 38/93] Simplifications and renaming --- src/Cat/Category.agda | 80 +++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 49 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index abc7830..bb26526 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -121,9 +121,6 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where Univalent : Set (ℓa ⊔ ℓb) Univalent = {A B : Object} → isEquiv (A ≡ B) (A ≅ B) (idToIso A B) - import Cat.Equivalence as E - open E public using () renaming (Isomorphism to TypeIsomorphism) - univalenceFromIsomorphism : {A B : Object} → TypeIsomorphism (idToIso A B) → isEquiv (A ≡ B) (A ≅ B) (idToIso A B) univalenceFromIsomorphism = fromIso _ _ @@ -305,6 +302,9 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where iso-to-id : (A ≅ B) → (A ≡ B) iso-to-id = fst (toIso _ _ univalent) + asTypeIso : TypeIsomorphism (idToIso A B) + asTypeIso = toIso _ _ univalent + -- | All projections are propositions. module Propositionality where -- | Terminal objects are propositional - a.k.a uniqueness of terminal @@ -333,10 +333,8 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where right = Yprop _ _ iso : X ≅ Y iso = X→Y , Y→X , left , right - fromIso' : X ≅ Y → X ≡ Y - fromIso' = fst (toIso (X ≡ Y) (X ≅ Y) univalent) p0 : X ≡ Y - p0 = fromIso' iso + p0 = iso-to-id iso p1 : (λ i → IsTerminal (p0 i)) [ Xit ≡ Yit ] p1 = lemPropF propIsTerminal p0 res : Xt ≡ Yt @@ -365,14 +363,8 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where right = Xprop _ _ iso : X ≅ Y iso = Y→X , X→Y , right , left - fromIso' : X ≅ Y → X ≡ Y - fromIso' = fst (toIso (X ≡ Y) (X ≅ Y) univalent) - p0 : X ≡ Y - p0 = fromIso' iso - p1 : (λ i → IsInitial (p0 i)) [ Xii ≡ Yii ] - p1 = lemPropF propIsInitial p0 res : Xi ≡ Yi - res i = p0 i , p1 i + res = lemSig propIsInitial _ _ (iso-to-id iso) module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where open RawCategory ℂ @@ -495,72 +487,62 @@ module Opposite {ℓa ℓb : Level} where module _ {A B : ℂ.Object} where k : Equivalence.Isomorphism (ℂ.idToIso A B) k = toIso _ _ ℂ.univalent - open Σ k renaming (fst to f ; snd to inv) - open AreInverses inv + open Σ k renaming (fst to η ; snd to inv-η) + open AreInverses inv-η _⊙_ = Function._∘_ infixr 9 _⊙_ - -- f : A ℂ.≅ B → A ≡ B - flipDem : A ≅ B → A ℂ.≅ B - flipDem (f , g , inv) = g , f , inv + genericly : {ℓa ℓb ℓc : Level} {a : Set ℓa} {b : Set ℓb} {c : Set ℓc} + → a × b × c → b × a × c + genericly (a , b , c) = (b , a , c) - flopDem : A ℂ.≅ B → A ≅ B - flopDem (f , g , inv) = g , f , inv + shuffle : A ≅ B → A ℂ.≅ B + shuffle (f , g , inv) = g , f , inv + + shuffle~ : A ℂ.≅ B → A ≅ B + shuffle~ (f , g , inv) = g , f , inv -- Shouldn't be necessary to use `arrowsAreSets` here, but we have it, -- so why not? - lem : (p : A ≡ B) → idToIso A B p ≡ flopDem (ℂ.idToIso A B p) - lem p i = l≡r i + lem : (p : A ≡ B) → idToIso A B p ≡ shuffle~ (ℂ.idToIso A B p) + lem p = Σ≡ refl (Σ≡ refl (Σ≡ (ℂ.arrowsAreSets _ _ l-l r-l) (ℂ.arrowsAreSets _ _ l-r r-r))) where l = idToIso A B p - r = flopDem (ℂ.idToIso A B p) + r = shuffle~ (ℂ.idToIso A B p) open Σ l renaming (fst to l-obv ; snd to l-areInv) open Σ l-areInv renaming (fst to l-invs ; snd to l-iso) open Σ l-iso renaming (fst to l-l ; snd to l-r) open Σ r renaming (fst to r-obv ; snd to r-areInv) open Σ r-areInv renaming (fst to r-invs ; snd to r-iso) open Σ r-iso renaming (fst to r-l ; snd to r-r) - l-obv≡r-obv : l-obv ≡ r-obv - l-obv≡r-obv = refl - l-invs≡r-invs : l-invs ≡ r-invs - l-invs≡r-invs = refl - l-l≡r-l : l-l ≡ r-l - l-l≡r-l = ℂ.arrowsAreSets _ _ l-l r-l - l-r≡r-r : l-r ≡ r-r - l-r≡r-r = ℂ.arrowsAreSets _ _ l-r r-r - l≡r : l ≡ r - l≡r i = l-obv≡r-obv i , l-invs≡r-invs i , l-l≡r-l i , l-r≡r-r i - ff : A ≅ B → A ≡ B - ff = f ⊙ flipDem + ζ : A ≅ B → A ≡ B + ζ = η ⊙ shuffle -- inv : AreInverses (ℂ.idToIso A B) f - invv : AreInverses (idToIso A B) ff + inv-ζ : AreInverses (idToIso A B) ζ -- recto-verso : ℂ.idToIso A B ∘ f ≡ idFun (A ℂ.≅ B) - invv = record + inv-ζ = record { verso-recto = funExt (λ x → begin - (ff ⊙ idToIso A B) x ≡⟨⟩ - (f ⊙ flipDem ⊙ idToIso A B) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → f ⊙ flipDem ⊙ φ) (funExt lem)) ⟩ - (f ⊙ flipDem ⊙ flopDem ⊙ ℂ.idToIso A B) x ≡⟨⟩ - (f ⊙ ℂ.idToIso A B) x ≡⟨ (λ i → verso-recto i x) ⟩ + (ζ ⊙ idToIso A B) x ≡⟨⟩ + (η ⊙ shuffle ⊙ idToIso A B) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → η ⊙ shuffle ⊙ φ) (funExt lem)) ⟩ + (η ⊙ shuffle ⊙ shuffle~ ⊙ ℂ.idToIso A B) x ≡⟨⟩ + (η ⊙ ℂ.idToIso A B) x ≡⟨ (λ i → verso-recto i x) ⟩ x ∎) ; recto-verso = funExt (λ x → begin - (idToIso A B ⊙ f ⊙ flipDem) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → φ ⊙ f ⊙ flipDem) (funExt lem)) ⟩ - (flopDem ⊙ ℂ.idToIso A B ⊙ f ⊙ flipDem) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → flopDem ⊙ φ ⊙ flipDem) recto-verso) ⟩ - (flopDem ⊙ flipDem) x ≡⟨⟩ + (idToIso A B ⊙ η ⊙ shuffle) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → φ ⊙ η ⊙ shuffle) (funExt lem)) ⟩ + (shuffle~ ⊙ ℂ.idToIso A B ⊙ η ⊙ shuffle) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → shuffle~ ⊙ φ ⊙ shuffle) recto-verso) ⟩ + (shuffle~ ⊙ shuffle) x ≡⟨⟩ x ∎) } h : Equivalence.Isomorphism (idToIso A B) - h = ff , invv - univalent : isEquiv (A ≡ B) (A ≅ B) - (Univalence.idToIso (swap ℂ.isIdentity) A B) - univalent = fromIso _ _ h + h = ζ , inv-ζ isCategory : IsCategory opRaw IsCategory.isPreCategory isCategory = isPreCategory - IsCategory.univalent isCategory = univalent + IsCategory.univalent isCategory = univalenceFromIsomorphism h opposite : Category ℓa ℓb Category.raw opposite = opRaw From 8c6e327b1ca138786347fdb27698fd5d69f351ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Mon, 9 Apr 2018 18:02:54 +0200 Subject: [PATCH 39/93] Write stuff about implementation in report --- doc/implementation.tex | 602 ++++++++++++++++++++++++++++++----------- doc/macros.tex | 33 ++- doc/main.tex | 8 +- 3 files changed, 470 insertions(+), 173 deletions(-) diff --git a/doc/implementation.tex b/doc/implementation.tex index b250cc1..79981d9 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -74,7 +74,7 @@ content, two witnesses must be the same. All the proofs are really quite mechanical. Lets have a look at one of them: The identity law states that: % $$ -\prod_{A\ B \tp \Object} \prod_{f \tp A \to B} \id \comp f \equiv f \x f \id \equiv f +\prod_{A\ B \tp \Object} \prod_{f \tp A \to B} \id \comp f \equiv f \x f \comp \id \equiv f $$ % There are multiple ways to prove this. Perhaps one of the more intuitive proofs @@ -88,204 +88,480 @@ I.e.; pi-types preserve propositionality when the co-domain is always a proposition. % $$ -\mathit{propSig} \tp \isProp\ A \to \left(\prod_{a : A} \isProp\ (P\ a)\right) \to \isProp\ \left(\sum_{a \tp A} P\ a\right) +\mathit{propSig} \tp \isProp\ A \to \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\sum_{a \tp A} P\ a\right) $$ % I.e.; sigma-types preserve propositionality whenever it's first component is a proposition, and it's second component is always a proposition for all points of in the left type. -Defines the basic notion of a category. This definition -closely follows that of [HoTT]: That is, the standard definition of a category -(data; objects, arrows, composition and identity, laws; preservation of identity -and composition) plus the extra condition that it is univalent - namely that you -can get an equality of two objects from an isomorphism. +So the proof goes like this: We `eliminate' the 3 function abstractions by +applying $\propPi$ three times, then we eliminate the (non-dependent) sigma-type +by applying $\propSig$ and are thus left with the two proof-obligations: +$\isProp\ (\id \comp f \equiv f)$ and $\isProp\ (f \comp \id \equiv f)$ which +follows from the type of arrows being a set. -\subsubsection{Functors} -Defines the notion of a functor - also split up into data and laws. +This example illustrates nicely how we can use these combinators to reason about +`canonical' types like $\sum$ and $\prod$. Similiar combinators can be defined +at the other homotopic levels. These combinators are however not applicable in +situations where we want to reason about other types - e.g. types we've defined +ourselves. For instance, after we've proven that all the projections of +pre-categories are propositions, we would like to bundle this up to show that +the type of pre-categories is also a proposition. Since pre-categories are not +formulates with a chain of sigma-types we wont have any combinators available to +help us here. In stead we'll use the path-type directly. -Propositionality for being a functor. - -Composition of functors and the identity functor. - -\subsubsection{Products} -Definition of what it means for an object to be a product in a given category. - -Definition of what it means for a category to have all products. - -\WIP{} Prove propositionality for being a product and having products. - -\subsubsection{Exponentials} -Definition of what it means to be an exponential object. - -Definition of what it means for a category to have all exponential objects. - -\subsubsection{Cartesian closed categories} -Definition of what it means for a category to be cartesian closed; namely that -it has all products and all exponentials. - -\subsubsection{Natural transformations} -Definition of transformations\footnote{Maybe this is a name I made up for a - family of morphisms} and the naturality condition for these. - -Proof that naturality is a mere proposition and the accompanying equality -principle. Proof that natural transformations are homotopic sets. - -The identity natural transformation. - -\subsubsection{Yoneda embedding} - -The yoneda embedding is typically presented in terms of the category of -categories (cf. Awodey) \emph however this is not stricly needed - all we need -is what would be the exponential object in that category - this happens to be -functors and so this is how we define the yoneda embedding. - -\subsubsection{Monads} - -Defines an equivalence between these two formulations of a monad: - -\subsubsubsection{Monoidal monads} - -Defines the standard monoidal representation of a monad: - -An endofunctor with two natural transformations (called ``pure'' and ``join'') -and some laws about these natural transformations. - -Propositionality proofs and equality principle is provided. - -\subsubsubsection{Kleisli monads} - -A presentation of monads perhaps more familiar to a functional programer: - -A map on objects and two maps on morphisms (called ``pure'' and ``bind'') and -some laws about these maps. - -Propositionality proofs and equality principle is provided. - -\subsubsubsection{Voevodsky's construction} - -Provides construction 2.3 as presented in an unpublished paper by Vladimir -Voevodsky. This construction is similiar to the equivalence provided for the two -preceding formulations -\footnote{ TODO: I would like to include in the thesis some motivation for why - this construction is particularly interesting.} - -\subsubsection{Homotopy sets} -The typical category of sets where the objects are modelled by an Agda set -(henceforth ``$\Type$'') at a given level is not a valid category in this cubical -settings, we need to restrict the types to be those that are homotopy sets. Thus -the objects of this category are: +What we want to prove is: % -$$\hSet_\ell \defeq \sum_{A \tp \MCU_\ell} \isSet\ A$$ +$$ +\isProp\ \IsPreCategory +$$ % -The definition of univalence for categories I have defined is: +Which is judgmentally the same as % -$$\isEquiv\ (\hA \equiv \hB)\ (\hA \cong \hB)\ \idToIso$$ +$$ +\prod_{a\ b \tp \IsPreCategory} a \equiv b +$$ % -Where $\hA and \hB$ denote objects in the category. Note that this is stronger -than +So let $a\ b \tp \IsPreCategory$ be given. To prove the equality $a \equiv b$ is +to give a continuous path from the index-type into path-space - in this case +$\IsPreCategory$. This path must satisfy being being judgmentally the same as +$a$ at the left endpoint and $b$ at the right endpoint. I.e. a function $I \to +\IsPreCategory$. We know we can form a continuous path between all projections +of $a$ and $b$, this follows from the type of all the projections being mere +propositions. For instance, the path between $\isIdentity_a$ and $\isIdentity_b$ +is simply formed by: % -$$(\hA \equiv \hB) \simeq (\hA \cong \hB)$$ +$$ +\propIsIdentity\ \isIdentity_a\ \isIdentity_b \tp \isIdentity_a \equiv \isIdentity_b +$$ % -Because we require that the equivalence is constructed from the witness to: +So to give the continuous function $I \to \IsPreCategory$ that is our goal we +introduce $i \tp I$ and proceed by constructing an element of $\IsPreCategory$ +by using that all the projections are propositions to generate paths between all +projections. Once we have such a path e.g. $p : \isIdentity_a \equiv +\isIdentity_b$ we can elimiate it with $i$ and thus obtaining $p\ i \tp +\isIdentity_{p\ i}$ and this element satisfies exactly that it corresponds to +the corresponding projections at either endpoint. Thus the element we construct +at $i$ becomes: % -$$\id \comp f \equiv f \x f \comp \id \equiv f$$ +\begin{align*} + & \{\ \mathit{propIsAssociative}\ \mathit{isAssociative}_x\ + \mathit{isAssociative}_y\ i \\ + & ,\ \mathit{propIsIdentity}\ \mathit{isIdentity}_x\ + \mathit{isIdentity}_y\ i \\ + & ,\ \mathit{propArrowsAreSets}\ \mathit{arrowsAreSets}_x\ + \mathit{arrowsAreSets}_y\ i \\ + & \} +\end{align*} % -And indeed univalence does not follow immediately from univalence for types: -% -$$(A \equiv B) \simeq (A \simeq B)$$ -% -Because $A\ B \tp \Type$ whereas $\hA\ \hB \tp \hSet$. +I've found that this to be a general pattern when proving things in homotopy +type theory, namely that you have to wrap and unwrap equalities at different +levels. It is worth noting that proving this theorem with the regular inductive +equality type would already not be possible, since we at least need +extensionality (the projections are all $\prod$-types). Assuming we had +functional extensionality available to us as an axiom, we would use functional +extensionality (in reverse?) to retreive the equalities in $a$ and $b$, +pattern-match on them to see that they are both $\mathit{refl}$ and then close +the proof with $\mathit{refl}$. Of course this theorem is not so interesting in +the setting of ITT since we know a priori that equality proofs are unique. -For this reason I have shown that this category satisfies the following -equivalent formulation of being univalent: +The situation is a bit more complicated when we have a dependent type. For +instance, when we want to show that $\IsCategory$ is a mere proposition. +$\IsCategory$ is a record with two fields, a witness to being a pre-category and +the univalence condition. Recall that the univalence condition is indexed by the +identity-proof. So if we follow the same recipe as above, let $a\ b \tp +\IsCategory$, to show them equal, we now need to give two paths. One homogenous: % -$$\prod_{A \tp hSet} \isContr \left( \sum_{X \tp hSet} A \cong X \right)$$ +$$ +p_{\isPreCategory} \tp \isPreCategory_a \equiv \isPreCategory_b +$$ % -But I have not shown that it is indeed equivalent to my former definition. -\subsubsection{Categories} -Note that this category does in fact not exist. In stead I provide the -definition of the ``raw'' category as well as some of the laws. +and one heterogeneous: +% +$$ +Path\ (\Gl i \to Univalent_{p\ i})\ \isPreCategory_a\ \isPreCategory_b +$$ +% +Which depends on the choice of $p_{\isPreCategory}$. The first of these we can +provide since, as we have shown, $\IsPreCategory$ is a proposition. However, +even though $\Univalent$ is also a proposition, we cannot use this directly to +show the latter. This is becasue $\isProp$ talks about non-dependent paths. To +`promote' this to a dependent path we can use another useful combinator; +$\lemPropF$. Given a type $A \tp \MCU$ and a type family on $A$; $B : A \to +\MCU$. Let $P$ be a proposition indexed by an element of $A$ and say we have a +path between some two elements in $A$; $p : a_0 \equiv a_1$ then we can built a +heterogeneous path between any two $b$'s at the endpoints: +% +$$ +Path\ (\Gl i \to B\ (p\ i))\ b0\ b1 +$$ +% +where $b_0 \tp B a_0$ and $b_1 \tp B\ a_1$. This is quite a mouthful, but the +example at present should serve as an illustration. In this case $A = +\mathit{IsIdentity}\ \mathit{identity}$ and $B = \mathit{Univalent}$ we've shown +that being a category is a proposition, a result that holds for any choice of +identity proof. Finally we must provide a proof that the identity proofs at $a$ +and $b$ are indeed the same, this we can extract from $p_{\isPreCategory}$ by +applying using congruence of paths: $\congruence\ \mathit{isIdentity}\ +p_{\isPreCategory}$ -Furthermore I provide some helpful lemmas about this raw category. For instance -I have shown what would be the exponential object in such a category. +When we have a proper category we can make precise the notion of ``identifying +isomorphic types'' (TODO cite awodey here). That is, we can construct the +function: +% +$$ +\isoToId \tp (A \cong B) \to (A \equiv B) +$$ +% +One application of this, and a perhaps somewhat surprising result, is that +terminal objects are propositional. Intuitively; they do not have any +interesting structure. The proof of this follows from the usual observation that +any two terminal objects are isomorphic. The proof is omitted here, but the +curious reader can check the implementation for the details. (TODO: The proof is +a bit fun, should I include it?) -These lemmas can be used to provide the actual exponential object in a context -where we have a witness to this being a category. This is useful if this library -is later extended to talk about higher categories. +In the following I will demonstrate how to instantiate a category and +subsequently why the result above is very useful to have when equating +categories (TODO: This promise is not fulfilled immediately as I digress and +talk about equivalences). So let us define the notion of the opposite category. +This is arguably one of the simplest constructions of a category one can give. +Let $\bC$ be a category, we then define a new category called the opposite of +$\bC$; $\overline{\bC}$. It has the same objects and the same identity, an arrow +from $A$ to $B$ in this category corresponds to an arrow from $B$ to $A$ in the +underlying category. Function composition will then be reverse function +composition from the underlying category. -\subsubsection{Functors} -The category of functors and natural transformations. An immediate corrolary is -the set of presheaf categories. +Showing that this forms a pre-category is rather straightforward. I'll state the +laws in terms of the underlying category $\bC$: +% +$$ +h >>> (g >>> f) \equiv h >>> g >>> f +$$ +% +Since $>>>$ is reverse function composition this is just the symmetric version +of associativity. +% +$$ +\matit{identity} >>> f \equiv f \x f >>> identity \equiv f +$$ +This is just the swapped version of identity. -\WIP{} I have not shown that the category of functors is univalent. +Finally, that the arrows form sets just follows by flipping the order of the +arguments. Or in other words since $\Hom_{A\ B}$ is a set for all $A\ B \tp +\Object$ then so is $\Hom_{B\ A}$. -\subsubsection{Relations} -The category of relations. \WIP{} I have not shown that this category is -univalent. Not sure I intend to do so either. +Now, to show that this category is univalent is not as trivial. So I will +digress at this point and talk about equivalences. We will return to this category in section ????. -\subsubsection{Free category} -The free category of a category. \WIP{} I have not shown that this category is -univalent. - -\subsection{Current Challenges} -Besides the items marked \WIP{} above I still feel a bit unsure about what to -include in my report. Most of my work so far has been specifically about -developing this library. Some ideas: +\subsection{Equivalences} +The usual notion of a function $f : A \to B$ having an inverses is: +% +$$ +\sum_{g : B \to A} f \comp g \equiv \identity_{B} \x g \comp f \equiv \identity_{A} +$$ +% +This is defined in \cite[p. 129]{hott-2013} and is referred to as the a +quasi-inverse. At the same place \cite{hott-2013} gives an ``interface'' for +what an equivalence $\isequiv : (A \to B) \to \MCU$ must supply: % \begin{itemize} \item - Modularity properties + $\qinv\ f \to \isequiv\ f$ \item - Compare with setoid-approach to solve similiar problems. + $\isequiv\ f \to \qinv\ f$ \item - How to structure an implementation to best deal with types that have no - structure (propositions) and those that do (sets and everything above) + $\isequiv\ f$ is a proposition \end{itemize} % -\subsection{Ideas for future developments} -\subsubsection{Higher categories} -I only have a notion of (1-)categories. Perhaps it would be nice to also -formalize higher categories. +Having such an interface us to both 1) think rather abstractly about how to work +with equivalences and 2) to use ad-hoc definitions of equivalences. The specific +instantiation of $\isequiv$ as defined in \cite{cubical} is: +% +$$ +isEquiv\ f \defeq \prod_{b : B} \isContr\ (\fiber\ f\ b) +$$ +where +$$ +\fiber\ f\ b \defeq \sum_{a \tp A} b \equiv f\ a +$$ +% +I give it's definition here mainly for completeness, because as I stated we can +move away from this specific instantiation and think about it more abstractly +once we have shown that this definition actually works as an equivalence. -\subsubsection{Hierarchy of concepts related to monads} -In Haskell the type-class Monad sits in a hierarchy atop the notion of a functor -and applicative functors. There's probably a similiar notion in the -category-theoretic approach to developing this. +The first function from the list of requirements we will call +$\mathit{fromIsomorphism}$, this is known as $\mathit{gradLemma}$ in +\cite{cubical} the second one we will refer to as $\mathit{toIsmorphism}$. It's +implementation can be found in the sources. Likewise the proof that this +equivalence is propositional can be found in my implementation. -As I have already defined monads from these two perspectives, it would be -interesting to take this idea even further and actually show how monads are -related to applicative functors and functors. I'm not entirely sure how this -would look in Agda though. +So another way to provide a proof that a category is univalent is to give give +an inverse to $\idToIso\ A\ B$. I want to stress here that the notion of an +inverse at this point is conflated. There is the notion of an inverse in the +context of a category (where the concept of functions are generalized to arrows) +and, as here, an inverse as a regular type-theoretic function. This is +particularly confusing because the function that one must give the inverse to +has the type +% +$$ +(A \cong B) \to (A \equiv B) +$$ +% +where $\cong$ refers to ismorphism \emph{in the category}! -\subsubsection{Use formulation on the standard library} -I also thought it would be interesting to use this library to show certain -properties about functors, applicative functors and monads used in the Agda -Standard library. So I went ahead and tried to show that agda's standard -library's notion of a functor (along with suitable laws) is equivalent to my -formulation (in the category of homotopic sets). I ran into two problems here, -however; the first one is that the standard library's notion of a functor is -indexed by the object map: +TODO: There is a lot more to say about equivalences! + +\subsection{Categories contd.} +Back from this aside, we can now show that the opposite category is also +univalent simply by showing that $\idToIso \tp (A \equiv B) \to (A \cong B)$ is +an isomorphism (seen as a function). Dually we have that $\idToIso_{\bC} \tp (A +\equiv B) \to (A \cong_{\bC} B)$ is an isomorphism. Let us denote it's inverse +as $\eta \tp (A \cong_{\bC} B) \to (A \equiv B)$. If we squint we can see what +we need is a way to go between $\cong$ and $\cong_{\bC}$, well, an inhabitant of +$A \cong B$ is simply a pair of arrows $f$ being the isomorphism and $g$ it's +inverse. In the present category $g$ will play the role of the isomorphism and +$f$ will be the inverse. Similarly we can go in the opposite direction. These +two functions are obviously inverses. Name them $\mathit{shuffle} \tp (A \cong +B) \to (A \cong_{\bC} B)$ and $\mathit{shuffle}^{-1} : (A \cong_{\bC} B) \to (A +\cong B)$ respectively. + +As the inverse of $\idToIso$ we will pick $\zeta \defeq \eta \comp +\mathit{shuffle}$. The proof that they are inverses go as follows: % -$$ -\Functor \tp (\Type \to \Type) \to \Type -$$ -% -Where $\Functor\ F$ has the member: -% -$$ -\fmap \tp (A \to B) \to F A \to F B -$$ -% -Whereas the object map in my definition is existentially quantified: -% -$$ -\Functor \tp \Type -$$ -% -And $\Functor$ has these members: \begin{align*} -F & \tp \Type \to \Type \\ -\fmap & \tp (A \to B) \to F A \to F B\} +\zeta \comp \idToIso & \equiv +\eta \comp \shuffle \comp \idToIso +&& \text{by definition} \\ +%% ≡⟨ cong (λ φ → φ x) (cong (λ φ → η ⊙ shuffle ⊙ φ) (funExt lem)) ⟩ \\ +% +& \equiv +\eta \comp \shuffle \comp \inv{\shuffle} \comp \idToIso +&& \text{lemma} \\ +%% ≡⟨⟩ \\ +& \equiv +\eta \comp \idToIso_{\bC} +&& \text{$\shuffle$ is an isomorphism} \\ +%% ≡⟨ (λ i → verso-recto i x) ⟩ \\ +& \equiv +\identity +&& \text{$\eta$ is an ismorphism} \\ \end{align*} % +The other direction is analogous. + +The lemma used in this proof show that $\idToIso \equiv \inv{\shuffle} \comp +\idToIso_{\bC}$ it's a rather straight-forward proof since being-an-inverse-of +is a proposition. + +So, in conclusion, we've shown that the opposite category is indeed a category. +We can now proceed to show that this construction is an involution, namely: +% +$$ +\prod_{\bC : \Category} \left(\bC^T\right)^T \equiv \bC +$$ +% +As we've seen the laws in $\left(\bC^T\right)^T$ get quite involved.\footnote{We + haven't even seen the full story because we've used this `interface' for + equivalences.} Luckily they being a category is a proposition, so we need not +concern ourselves with this bit when proving the above. We can use the equality +principle for categories that lets us prove an equality just by giving an +equality on the data-part. So, given a category $\bC$ what we must provide is +the following proof: +% +$$ +\mathit{raw}\ \left(\bC^T\right)^T \equiv \mathit{raw}\ \bC +$$ +% +And these are judgmentally the same. I remind the reader that the left-hand side +is constructed by flipping the arrows, an action that is certainly an +involution. + +%% \subsubsection{Functors} +%% Defines the notion of a functor - also split up into data and laws. + +%% Propositionality for being a functor. + +%% Composition of functors and the identity functor. + +%% \subsubsection{Products} +%% Definition of what it means for an object to be a product in a given category. + +%% Definition of what it means for a category to have all products. + +%% \WIP{} Prove propositionality for being a product and having products. + +%% \subsubsection{Exponentials} +%% Definition of what it means to be an exponential object. + +%% Definition of what it means for a category to have all exponential objects. + +%% \subsubsection{Cartesian closed categories} +%% Definition of what it means for a category to be cartesian closed; namely that +%% it has all products and all exponentials. + +%% \subsubsection{Natural transformations} +%% Definition of transformations\footnote{Maybe this is a name I made up for a +%% family of morphisms} and the naturality condition for these. + +%% Proof that naturality is a mere proposition and the accompanying equality +%% principle. Proof that natural transformations are homotopic sets. + +%% The identity natural transformation. + +%% \subsubsection{Yoneda embedding} + +%% The yoneda embedding is typically presented in terms of the category of +%% categories (cf. Awodey) \emph however this is not stricly needed - all we need +%% is what would be the exponential object in that category - this happens to be +%% functors and so this is how we define the yoneda embedding. + +%% \subsubsection{Monads} + +%% Defines an equivalence between these two formulations of a monad: + +%% \subsubsubsection{Monoidal monads} + +%% Defines the standard monoidal representation of a monad: + +%% An endofunctor with two natural transformations (called ``pure'' and ``join'') +%% and some laws about these natural transformations. + +%% Propositionality proofs and equality principle is provided. + +%% \subsubsubsection{Kleisli monads} + +%% A presentation of monads perhaps more familiar to a functional programer: + +%% A map on objects and two maps on morphisms (called ``pure'' and ``bind'') and +%% some laws about these maps. + +%% Propositionality proofs and equality principle is provided. + +%% \subsubsubsection{Voevodsky's construction} + +%% Provides construction 2.3 as presented in an unpublished paper by Vladimir +%% Voevodsky. This construction is similiar to the equivalence provided for the two +%% preceding formulations +%% \footnote{ TODO: I would like to include in the thesis some motivation for why +%% this construction is particularly interesting.} + +%% \subsubsection{Homotopy sets} +%% The typical category of sets where the objects are modelled by an Agda set +%% (henceforth ``$\Type$'') at a given level is not a valid category in this cubical +%% settings, we need to restrict the types to be those that are homotopy sets. Thus +%% the objects of this category are: +%% % +%% $$\hSet_\ell \defeq \sum_{A \tp \MCU_\ell} \isSet\ A$$ +%% % +%% The definition of univalence for categories I have defined is: +%% % +%% $$\isEquiv\ (\hA \equiv \hB)\ (\hA \cong \hB)\ \idToIso$$ +%% % +%% Where $\hA and \hB$ denote objects in the category. Note that this is stronger +%% than +%% % +%% $$(\hA \equiv \hB) \simeq (\hA \cong \hB)$$ +%% % +%% Because we require that the equivalence is constructed from the witness to: +%% % +%% $$\id \comp f \equiv f \x f \comp \id \equiv f$$ +%% % +%% And indeed univalence does not follow immediately from univalence for types: +%% % +%% $$(A \equiv B) \simeq (A \simeq B)$$ +%% % +%% Because $A\ B \tp \Type$ whereas $\hA\ \hB \tp \hSet$. + +%% For this reason I have shown that this category satisfies the following +%% equivalent formulation of being univalent: +%% % +%% $$\prod_{A \tp hSet} \isContr \left( \sum_{X \tp hSet} A \cong X \right)$$ +%% % +%% But I have not shown that it is indeed equivalent to my former definition. +%% \subsubsection{Categories} +%% Note that this category does in fact not exist. In stead I provide the +%% definition of the ``raw'' category as well as some of the laws. + +%% Furthermore I provide some helpful lemmas about this raw category. For instance +%% I have shown what would be the exponential object in such a category. + +%% These lemmas can be used to provide the actual exponential object in a context +%% where we have a witness to this being a category. This is useful if this library +%% is later extended to talk about higher categories. + +%% \subsubsection{Functors} +%% The category of functors and natural transformations. An immediate corrolary is +%% the set of presheaf categories. + +%% \WIP{} I have not shown that the category of functors is univalent. + +%% \subsubsection{Relations} +%% The category of relations. \WIP{} I have not shown that this category is +%% univalent. Not sure I intend to do so either. + +%% \subsubsection{Free category} +%% The free category of a category. \WIP{} I have not shown that this category is +%% univalent. + +%% \subsection{Current Challenges} +%% Besides the items marked \WIP{} above I still feel a bit unsure about what to +%% include in my report. Most of my work so far has been specifically about +%% developing this library. Some ideas: +%% % +%% \begin{itemize} +%% \item +%% Modularity properties +%% \item +%% Compare with setoid-approach to solve similiar problems. +%% \item +%% How to structure an implementation to best deal with types that have no +%% structure (propositions) and those that do (sets and everything above) +%% \end{itemize} +%% % +%% \subsection{Ideas for future developments} +%% \subsubsection{Higher categories} +%% I only have a notion of (1-)categories. Perhaps it would be nice to also +%% formalize higher categories. + +%% \subsubsection{Hierarchy of concepts related to monads} +%% In Haskell the type-class Monad sits in a hierarchy atop the notion of a functor +%% and applicative functors. There's probably a similiar notion in the +%% category-theoretic approach to developing this. + +%% As I have already defined monads from these two perspectives, it would be +%% interesting to take this idea even further and actually show how monads are +%% related to applicative functors and functors. I'm not entirely sure how this +%% would look in Agda though. + +%% \subsubsection{Use formulation on the standard library} +%% I also thought it would be interesting to use this library to show certain +%% properties about functors, applicative functors and monads used in the Agda +%% Standard library. So I went ahead and tried to show that agda's standard +%% library's notion of a functor (along with suitable laws) is equivalent to my +%% formulation (in the category of homotopic sets). I ran into two problems here, +%% however; the first one is that the standard library's notion of a functor is +%% indexed by the object map: +%% % +%% $$ +%% \Functor \tp (\Type \to \Type) \to \Type +%% $$ +%% % +%% Where $\Functor\ F$ has the member: +%% % +%% $$ +%% \fmap \tp (A \to B) \to F A \to F B +%% $$ +%% % +%% Whereas the object map in my definition is existentially quantified: +%% % +%% $$ +%% \Functor \tp \Type +%% $$ +%% % +%% And $\Functor$ has these members: +%% \begin{align*} +%% F & \tp \Type \to \Type \\ +%% \fmap & \tp (A \to B) \to F A \to F B\} +%% \end{align*} +%% % diff --git a/doc/macros.tex b/doc/macros.tex index aed408f..e63ff35 100644 --- a/doc/macros.tex +++ b/doc/macros.tex @@ -1,3 +1,6 @@ +\newcommand{\subsubsubsection}[1]{\textbf{#1}} +\newcommand{\WIP}{\textbf{WIP}} + \newcommand{\coloneqq}{\mathrel{\vcenter{\baselineskip0.5ex \lineskiplimit0pt \hbox{\scriptsize.}\hbox{\scriptsize.}}}% =} @@ -21,17 +24,35 @@ \newcommand{\Set}{\mathit{Set}} \newcommand{\hSet}{\mathit{hSet}} \newcommand{\Type}{\mathcal{U}} -\newcommand{\isEquiv}{\mathit{isEquiv}} -\newcommand{\idToIso}{\mathit{idToIso}} + \newcommand{\MCU}{\UU} -\newcommand{\isSet}{\mathit{isSet}} -\newcommand{\isContr}{\mathit{isContr}} \newcommand{\id}{\mathit{id}} \newcommand{\tp}{\,\mathord{:}\,} \newcommand\hA{\mathit{hA}} \newcommand\hB{\mathit{hB}} + +\newcommand{\isEquiv}{\mathit{isEquiv}} +\newcommand{\idToIso}{\mathit{idToIso}} +\newcommand{\isSet}{\mathit{isSet}} +\newcommand{\isContr}{\mathit{isContr}} \newcommand\Object{\mathit{Object}} \newcommand\Functor{\mathit{Functor}} \newcommand\isProp{\mathit{isProp}} -\newcommand{\subsubsubsection}[1]{\textbf{#1}} -\newcommand{\WIP}{\textbf{WIP}} +\newcommand\propPi{\mathit{propPi}} +\newcommand\propSig{\mathit{propSig}} +\newcommand\PreCategory{\mathit{PreCategory}} +\newcommand\IsPreCategory{\mathit{IsPreCategory}} +\newcommand\isIdentity{\mathit{isIdentity}} +\newcommand\propIsIdentity{\mathit{propIsIdentity}} +\newcommand\IsCategory{\mathit{IsCategory}} +\newcommand\Gl{\mathit{\lambda}} +\newcommand\lemPropF{\mathit{lemPropF}} +\newcommand\isPreCategory{\mathit{isPreCategory}} +\newcommand\congruence{\mathit{cong}} +\newcommand\identity{\mathit{identity}} +\newcommand\isequiv{\mathit{isequiv}} +\newcommand\qinv{\mathit{qinv}} +\newcommand\fiber{\mathit{fiber}} +\newcommand\shuffle{\mathit{shuffle}} +\newcommand\inv[1]{#1\raisebox{1.15ex}{$\scriptscriptstyle-\!1$}} +\newcommand\isoToId{\mathit{isoToId}} diff --git a/doc/main.tex b/doc/main.tex index 478ec30..98cba0d 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -23,9 +23,9 @@ \bibliographystyle{plainnat} \nocite{cubical-demo} \nocite{coquand-2013} -\bibliography{refs} -\begin{appendices} -\input{planning.tex} -\input{halftime.tex} +%% \bibliography{refs} +%% \begin{appendices} +%% \input{planning.tex} +%% \input{halftime.tex} \end{appendices} \end{document} From fd18985e53fe90e8ae2e0abc3d67d3d94a4695f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Mon, 9 Apr 2018 18:10:39 +0200 Subject: [PATCH 40/93] Export TypeIsomorphism as an alias for Equivalence.Isomorphism --- src/Cat/Category.agda | 10 +++++++--- src/Cat/Category/Monad.agda | 3 +++ src/Cat/Category/Monad/Voevodsky.agda | 3 --- src/Cat/Category/Product.agda | 7 +++++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index bb26526..776c92a 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -29,7 +29,11 @@ module Cat.Category where open import Cat.Prelude -open import Cat.Equivalence as Equivalence renaming (_≅_ to _≈_ ; Isomorphism to TypeIsomorphism) hiding (preorder≅) +import Cat.Equivalence +open Cat.Equivalence public using () renaming (Isomorphism to TypeIsomorphism) +open Cat.Equivalence + renaming (_≅_ to _≈_) + hiding (preorder≅ ; Isomorphism) import Function @@ -485,7 +489,7 @@ module Opposite {ℓa ℓb : Level} where open IsPreCategory isPreCategory module _ {A B : ℂ.Object} where - k : Equivalence.Isomorphism (ℂ.idToIso A B) + k : TypeIsomorphism (ℂ.idToIso A B) k = toIso _ _ ℂ.univalent open Σ k renaming (fst to η ; snd to inv-η) open AreInverses inv-η @@ -537,7 +541,7 @@ module Opposite {ℓa ℓb : Level} where x ∎) } - h : Equivalence.Isomorphism (idToIso A B) + h : TypeIsomorphism (idToIso A B) h = ζ , inv-ζ isCategory : IsCategory opRaw diff --git a/src/Cat/Category/Monad.agda b/src/Cat/Category/Monad.agda index 387dc75..8ad64fa 100644 --- a/src/Cat/Category/Monad.agda +++ b/src/Cat/Category/Monad.agda @@ -209,3 +209,6 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where Monoidal≃Kleisli : M.Monad ≃ K.Monad Monoidal≃Kleisli = forth , eqv + + Monoidal≡Kleisli : M.Monad ≡ K.Monad + Monoidal≡Kleisli = ua (forth , eqv) diff --git a/src/Cat/Category/Monad/Voevodsky.agda b/src/Cat/Category/Monad/Voevodsky.agda index 3c6bad6..f4dc465 100644 --- a/src/Cat/Category/Monad/Voevodsky.agda +++ b/src/Cat/Category/Monad/Voevodsky.agda @@ -172,9 +172,6 @@ module voe {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where where t' : ((Monoidal→Kleisli ∘ Kleisli→Monoidal) ∘ §2-3.§2.toMonad {omap} {pure}) ≡ §2-3.§2.toMonad - cong-d : ∀ {ℓ} {A : Set ℓ} {ℓ'} {B : A → Set ℓ'} {x y : A} - → (f : (x : A) → B x) → (eq : x ≡ y) → PathP (\ i → B (eq i)) (f x) (f y) - cong-d f p = λ i → f (p i) t' = cong (\ φ → φ ∘ §2-3.§2.toMonad) re-ve t : (§2-fromMonad ∘ (Monoidal→Kleisli ∘ Kleisli→Monoidal) ∘ §2-3.§2.toMonad {omap} {pure}) ≡ (§2-fromMonad ∘ §2-3.§2.toMonad) diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 536467b..1985656 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -203,12 +203,15 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} : ((X , xa , xb) ≡ (Y , ya , yb)) ≈ (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)) step0 - = (λ p → (λ i → fst (p i)) , (λ i → fst (snd (p i))) , (λ i → snd (snd (p i)))) - , (λ x → λ i → fst x i , (fst (snd x) i) , (snd (snd x) i)) + = (λ p → cong fst p , cong-d (fst ⊙ snd) p , cong-d (snd ⊙ snd) p) + -- , (λ x → λ i → fst x i , (fst (snd x) i) , (snd (snd x) i)) + , (λ{ (p , q , r) → Σ≡ p λ i → q i , r i}) , record { verso-recto = {!!} ; recto-verso = {!!} } + where + open import Function renaming (_∘_ to _⊙_) step1 : (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)) ≈ Σ (X ℂ.≅ Y) (λ iso From 772e6778f3904fd1c12b79e07c5584c850e40e9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 10 Apr 2018 17:17:04 +0200 Subject: [PATCH 41/93] [WIP] Univalence in ad-hoc category in product --- src/Cat/Category.agda | 34 ++++++++--- src/Cat/Category/Product.agda | 109 ++++++++++++++++++++++++---------- 2 files changed, 106 insertions(+), 37 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 776c92a..f95603f 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -136,12 +136,25 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where Univalent[Contr] : Set _ Univalent[Contr] = ∀ A → isContr (Σ[ X ∈ Object ] A ≅ X) + Univalent[Andrea] : Set _ + Univalent[Andrea] = ∀ A B → (A ≅ B) ≃ (A ≡ B) + -- From: Thierry Coquand -- Date: Wed, Mar 21, 2018 at 3:12 PM -- -- This is not so straight-forward so you can assume it postulate from[Contr] : Univalent[Contr] → Univalent + from[Andrea] : Univalent[Andrea] → Univalent + from[Andrea] = from[Contr] Function.∘ step + where + module _ (f : Univalent[Andrea]) (A : Object) where + aux : isContr (Σ[ B ∈ Object ] A ≡ B) + aux = ? + + step : isContr (Σ Object (A ≅_)) + step = {!subst {P = isContr} {!!} aux!} + propUnivalent : isProp Univalent propUnivalent a b i = propPi (λ iso → propIsContr) a b i @@ -205,9 +218,9 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where propIsInverseOf : ∀ {A B f g} → isProp (IsInverseOf {A} {B} f g) propIsInverseOf = propSig (arrowsAreSets _ _) (λ _ → arrowsAreSets _ _) - module _ {A B : Object} {f : Arrow A B} where - isoIsProp : isProp (Isomorphism f) - isoIsProp a@(g , η , ε) a'@(g' , η' , ε') = + module _ {A B : Object} (f : Arrow A B) where + propIsomorphism : isProp (Isomorphism f) + propIsomorphism a@(g , η , ε) a'@(g' , η' , ε') = lemSig (λ g → propIsInverseOf) a a' geq where geq : g ≡ g' @@ -303,12 +316,19 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where univalent≃ = _ , univalent module _ {A B : Object} where - iso-to-id : (A ≅ B) → (A ≡ B) - iso-to-id = fst (toIso _ _ univalent) + private + iso : TypeIsomorphism (idToIso A B) + iso = toIso _ _ univalent + + isoToId : (A ≅ B) → (A ≡ B) + isoToId = fst iso asTypeIso : TypeIsomorphism (idToIso A B) asTypeIso = toIso _ _ univalent + inverse-from-to-iso' : AreInverses (idToIso A B) isoToId + inverse-from-to-iso' = snd iso + -- | All projections are propositions. module Propositionality where -- | Terminal objects are propositional - a.k.a uniqueness of terminal @@ -338,7 +358,7 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where iso : X ≅ Y iso = X→Y , Y→X , left , right p0 : X ≡ Y - p0 = iso-to-id iso + p0 = isoToId iso p1 : (λ i → IsTerminal (p0 i)) [ Xit ≡ Yit ] p1 = lemPropF propIsTerminal p0 res : Xt ≡ Yt @@ -368,7 +388,7 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where iso : X ≅ Y iso = Y→X , X→Y , right , left res : Xi ≡ Yi - res = lemSig propIsInitial _ _ (iso-to-id iso) + res = lemSig propIsInitial _ _ (isoToId iso) module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where open RawCategory ℂ diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 1985656..3aa73ba 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -1,4 +1,4 @@ -{-# OPTIONS --allow-unsolved-metas --cubical #-} +{-# OPTIONS --allow-unsolved-metas --cubical --caching #-} module Cat.Category.Product where open import Cat.Prelude as P hiding (_×_ ; fst ; snd) @@ -183,7 +183,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} -- ; _∎ to _∎! ) -- lawl -- : ((X , xa , xb) ≡ (Y , ya , yb)) - -- ≈ (Σ[ iso ∈ (X ℂ.≅ Y) ] let p = ℂ.iso-to-id iso in (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)) + -- ≈ (Σ[ iso ∈ (X ℂ.≅ Y) ] let p = ℂ.isoToId iso in (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)) -- lawl = {!begin! ? ≈⟨ ? ⟩ ? ∎!!} -- Problem with the above approach: Preorders only work for heterogeneous equaluties. @@ -192,7 +192,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} -- Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb) -- ≅ -- Σ (X ℂ.≅ Y) (λ iso - -- → let p = ℂ.iso-to-id iso + -- → let p = ℂ.isoToId iso -- in -- ( PathP (λ i → ℂ.Arrow (p i) A) xa ya) -- × PathP (λ i → ℂ.Arrow (p i) B) xb yb @@ -207,63 +207,104 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} -- , (λ x → λ i → fst x i , (fst (snd x) i) , (snd (snd x) i)) , (λ{ (p , q , r) → Σ≡ p λ i → q i , r i}) , record - { verso-recto = {!!} - ; recto-verso = {!!} + { verso-recto = funExt (λ{ p → refl}) + ; recto-verso = funExt (λ{ (p , q , r) → refl}) } where open import Function renaming (_∘_ to _⊙_) + + -- Should follow from c being univalent + iso-id-inv : {p : X ≡ Y} → p ≡ ℂ.isoToId (ℂ.idToIso X Y p) + iso-id-inv {p} = sym (λ i → AreInverses.verso-recto ℂ.inverse-from-to-iso' i p) + id-iso-inv : {iso : X ℂ.≅ Y} → iso ≡ ℂ.idToIso X Y (ℂ.isoToId iso) + id-iso-inv {iso} = sym (λ i → AreInverses.recto-verso ℂ.inverse-from-to-iso' i iso) + + lemA : {A B : Object} {f g : Arrow A B} → fst f ≡ fst g → f ≡ g + lemA {A} {B} {f = f} {g} p i = p i , h i + where + h : PathP (λ i → + (ℂ [ fst (snd B) ∘ p i ]) ≡ fst (snd A) × + (ℂ [ snd (snd B) ∘ p i ]) ≡ snd (snd A) + ) (snd f) (snd g) + h = lemPropF (λ a → propSig + (ℂ.arrowsAreSets (ℂ [ fst (snd B) ∘ a ]) (fst (snd A))) + λ _ → ℂ.arrowsAreSets (ℂ [ snd (snd B) ∘ a ]) (snd (snd A))) + p + step1 : (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)) ≈ Σ (X ℂ.≅ Y) (λ iso - → let p = ℂ.iso-to-id iso + → let p = ℂ.isoToId iso in ( PathP (λ i → ℂ.Arrow (p i) A) xa ya) × PathP (λ i → ℂ.Arrow (p i) B) xb yb ) step1 - = (λ{ (p , x) → (ℂ.idToIso _ _ p) , {!snd x!}}) + = (λ{ (p , x) + → (ℂ.idToIso _ _ p) + , let + P-l : (p : X ≡ Y) → Set _ + P-l φ = PathP (λ i → ℂ.Arrow (φ i) A) xa ya + P-r : (p : X ≡ Y) → Set _ + P-r φ = PathP (λ i → ℂ.Arrow (φ i) B) xb yb + left : P-l p + left = fst x + right : P-r p + right = snd x + in subst {P = P-l} iso-id-inv left , subst {P = P-r} iso-id-inv right + }) -- Goal is: -- -- φ x -- -- where `x` is -- - -- ℂ.iso-to-id (ℂ.idToIso _ _ p) + -- ℂ.isoToId (ℂ.idToIso _ _ p) -- -- I have `φ p` in scope, but surely `p` and `x` are the same - though -- perhaps not definitonally. - , (λ{ (iso , x) → ℂ.iso-to-id iso , x}) - , record { verso-recto = {!!} ; recto-verso = {!!} } - lemA : {A B : Object} {f g : Arrow A B} → fst f ≡ fst g → f ≡ g - lemA {A} {B} {f = f} {g} p i = p i , h i - where - h : PathP (λ i → - (ℂ [ fst (snd B) ∘ p i ]) ≡ fst (snd A) × - (ℂ [ snd (snd B) ∘ p i ]) ≡ snd (snd A) - ) (snd f) (snd g) - h = lemPropF (λ a → propSig - (ℂ.arrowsAreSets (ℂ [ fst (snd B) ∘ a ]) (fst (snd A))) - λ _ → ℂ.arrowsAreSets (ℂ [ snd (snd B) ∘ a ]) (snd (snd A))) - p + , (λ{ (iso , x) → ℂ.isoToId iso , x}) + , record + { verso-recto = funExt (λ{ (p , q , r) → Σ≡ (sym iso-id-inv) (toPathP {A = λ i → {!!}} {!!})}) + -- { verso-recto = funExt (λ{ (p , q , r) → Σ≡ (sym iso-id-inv) {!!}}) + ; recto-verso = funExt (λ x → Σ≡ (sym id-iso-inv) {!!}) + } step2 : Σ (X ℂ.≅ Y) (λ iso - → let p = ℂ.iso-to-id iso + → let p = ℂ.isoToId iso in ( PathP (λ i → ℂ.Arrow (p i) A) xa ya) × PathP (λ i → ℂ.Arrow (p i) B) xb yb ) ≈ ((X , xa , xb) ≅ (Y , ya , yb)) step2 - = ( λ{ ((f , f~ , inv-f) , x) - → ( f , {!!}) - , ( (f~ , {!!}) - , lemA {!!} - , lemA {!!} + = ( λ{ ((f , f~ , inv-f) , p , q) + → ( f , (let r = fromPathP p in {!r!}) , {!!}) + , ( (f~ , {!!} , {!!}) + , lemA (fst inv-f) + , lemA (snd inv-f) ) } ) - , (λ x → {!!}) - , {!!} + , (λ{ (f , f~ , inv-f , inv-f~) → + let + iso : X ℂ.≅ Y + iso = fst f , fst f~ , cong fst inv-f , cong fst inv-f~ + helper : PathP (λ i → ℂ.Arrow (ℂ.isoToId ? i) A) xa ya + helper = {!!} + in iso , helper , {!!}}) + , record + { verso-recto = funExt (λ x → lemSig + (λ x → propSig prop0 (λ _ → prop1)) + _ _ + (Σ≡ {!!} (ℂ.propIsomorphism _ _ _))) + ; recto-verso = funExt (λ{ (f , _) → lemSig propIsomorphism _ _ {!refl!}}) + } + where + prop0 : ∀ {x} → isProp (PathP (λ i → ℂ.Arrow (ℂ.isoToId x i) A) xa ya) + prop0 {x} = pathJ (λ y p → ∀ x → isProp (PathP (λ i → ℂ.Arrow (p i) A) xa x)) (λ x → ℂ.arrowsAreSets _ _) Y (ℂ.isoToId x) ya + prop1 : ∀ {x} → isProp (PathP (λ i → ℂ.Arrow (ℂ.isoToId x i) B) xb yb) + prop1 {x} = pathJ (λ y p → ∀ x → isProp (PathP (λ i → ℂ.Arrow (p i) B) xb x)) (λ x → ℂ.arrowsAreSets _ _) Y (ℂ.isoToId x) yb -- One thing to watch out for here is that the isomorphisms going forwards -- must compose to give idToIso iso @@ -273,8 +314,16 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} where infixl 5 _⊙_ _⊙_ = composeIso + equiv1 + : ((X , xa , xb) ≡ (Y , ya , yb)) + ≃ ((X , xa , xb) ≅ (Y , ya , yb)) + equiv1 = _ , fromIso _ _ (snd iso) + res : TypeIsomorphism (idToIso (X , xa , xb) (Y , ya , yb)) - res = {!snd iso!} + res = {!snd equiv1!} + + univalent2 : ∀ X Y → (X ≅ Y) ≃ (X ≡ Y) + univalent2 = {!!} isCat : IsCategory raw IsCategory.isPreCategory isCat = isPreCat From 6d59a8f79e542d9930cc507b378d3c9104e30190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 10 Apr 2018 17:33:22 +0200 Subject: [PATCH 42/93] Add note about proving 9.1.9 --- src/Cat/Category.agda | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index f95603f..1818c15 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -150,7 +150,7 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where where module _ (f : Univalent[Andrea]) (A : Object) where aux : isContr (Σ[ B ∈ Object ] A ≡ B) - aux = ? + aux = {!!} step : isContr (Σ Object (A ≅_)) step = {!subst {P = isContr} {!!} aux!} @@ -329,6 +329,21 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where inverse-from-to-iso' : AreInverses (idToIso A B) isoToId inverse-from-to-iso' = snd iso + -- lemma 9.1.9 in hott + module _ {a a' b b' : Object} + (p : a ≡ a') (q : b ≡ b') (f : Arrow a b) + where + private + q* : Arrow b b' + q* = fst (idToIso b b' q) + p~ : Arrow a' a + p~ = fst (snd (idToIso _ _ p)) + pq : Arrow a b ≡ Arrow a' b' + pq i = Arrow (p i) (q i) + + 9-1-9 : coe pq f ≡ q* ∘ f ∘ p~ + 9-1-9 = transpP {!!} {!!} + -- | All projections are propositions. module Propositionality where -- | Terminal objects are propositional - a.k.a uniqueness of terminal From c90b064bb012f915db4515daab9f00dcd7e25e5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 11 Apr 2018 10:58:50 +0200 Subject: [PATCH 43/93] Rename \o to <<< --- src/Cat/Categories/Cat.agda | 8 +- src/Cat/Categories/Cube.agda | 4 +- src/Cat/Categories/Fam.agda | 6 +- src/Cat/Categories/Free.agda | 2 +- src/Cat/Categories/Fun.agda | 8 +- src/Cat/Categories/Rel.agda | 2 +- src/Cat/Categories/Sets.agda | 6 +- src/Cat/Category.agda | 114 +++++++++++++-------------- src/Cat/Category/Monad.agda | 58 +++++++------- src/Cat/Category/Monad/Kleisli.agda | 79 ++++++++++--------- src/Cat/Category/Monad/Monoidal.agda | 74 ++++++++--------- src/Cat/Category/Product.agda | 18 ++--- 12 files changed, 191 insertions(+), 188 deletions(-) diff --git a/src/Cat/Categories/Cat.agda b/src/Cat/Categories/Cat.agda index 55d717c..a24abc8 100644 --- a/src/Cat/Categories/Cat.agda +++ b/src/Cat/Categories/Cat.agda @@ -18,7 +18,7 @@ module _ (ℓ ℓ' : Level) where RawCategory.Object RawCat = Category ℓ ℓ' RawCategory.Arrow RawCat = Functor RawCategory.identity RawCat = Functors.identity - RawCategory._∘_ RawCat = F[_∘_] + RawCategory._<<<_ RawCat = F[_∘_] -- NB! `ArrowsAreSets RawCat` is *not* provable. The type of functors, -- however, form a groupoid! Therefore there is no (1-)category of @@ -50,18 +50,18 @@ module CatProduct {ℓ ℓ' : Level} (ℂ 𝔻 : Category ℓ ℓ') where Arr (c , d) (c' , d') = ℂ [ c , c' ] × 𝔻 [ d , d' ] identity : {o : Obj} → Arr o o identity = ℂ.identity , 𝔻.identity - _∘_ : + _<<<_ : {a b c : Obj} → Arr b c → Arr a b → Arr a c - _∘_ = λ { (bc∈C , bc∈D) (ab∈C , ab∈D) → ℂ [ bc∈C ∘ ab∈C ] , 𝔻 [ bc∈D ∘ ab∈D ]} + _<<<_ = λ { (bc∈C , bc∈D) (ab∈C , ab∈D) → ℂ [ bc∈C ∘ ab∈C ] , 𝔻 [ bc∈D ∘ ab∈D ]} rawProduct : RawCategory ℓ ℓ' RawCategory.Object rawProduct = Obj RawCategory.Arrow rawProduct = Arr RawCategory.identity rawProduct = identity - RawCategory._∘_ rawProduct = _∘_ + RawCategory._<<<_ rawProduct = _<<<_ open RawCategory rawProduct diff --git a/src/Cat/Categories/Cube.agda b/src/Cat/Categories/Cube.agda index 5322b16..fde96b9 100644 --- a/src/Cat/Categories/Cube.agda +++ b/src/Cat/Categories/Cube.agda @@ -19,7 +19,7 @@ open import Cat.Category.Functor -- See section 6.8 in Huber's thesis for details on how to implement the -- categorical version of CTT -open Category hiding (_∘_) +open Category hiding (_<<<_) open Functor module _ {ℓ ℓ' : Level} (Ns : Set ℓ) where @@ -68,7 +68,7 @@ module _ {ℓ ℓ' : Level} (Ns : Set ℓ) where Raw.Object Rawℂ = FiniteDecidableSubset Raw.Arrow Rawℂ = Hom Raw.identity Rawℂ {o} = inj₁ , λ { (i , ii) (j , jj) eq → Σ≡ eq {!refl!} } - Raw._∘_ Rawℂ = {!!} + Raw._<<<_ Rawℂ = {!!} postulate IsCategoryℂ : IsCategory Rawℂ diff --git a/src/Cat/Categories/Fam.agda b/src/Cat/Categories/Fam.agda index dd5c757..a0b4d1d 100644 --- a/src/Cat/Categories/Fam.agda +++ b/src/Cat/Categories/Fam.agda @@ -14,15 +14,15 @@ module _ (ℓa ℓb : Level) where identity : {A : Object} → Arr A A fst identity = λ x → x snd identity = λ b → b - _∘_ : {a b c : Object} → Arr b c → Arr a b → Arr a c - (g , g') ∘ (f , f') = g Function.∘ f , g' Function.∘ f' + _<<<_ : {a b c : Object} → Arr b c → Arr a b → Arr a c + (g , g') <<< (f , f') = g Function.∘ f , g' Function.∘ f' RawFam : RawCategory (lsuc (ℓa ⊔ ℓb)) (ℓa ⊔ ℓb) RawFam = record { Object = Object ; Arrow = Arr ; identity = λ { {A} → identity {A = A}} - ; _∘_ = λ {a b c} → _∘_ {a} {b} {c} + ; _<<<_ = λ {a b c} → _<<<_ {a} {b} {c} } open RawCategory RawFam hiding (Object ; identity) diff --git a/src/Cat/Categories/Free.agda b/src/Cat/Categories/Free.agda index e6aa4c7..58b777d 100644 --- a/src/Cat/Categories/Free.agda +++ b/src/Cat/Categories/Free.agda @@ -30,7 +30,7 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where RawCategory.Object RawFree = ℂ.Object RawCategory.Arrow RawFree = Path ℂ.Arrow RawCategory.identity RawFree = empty - RawCategory._∘_ RawFree = concatenate + RawCategory._<<<_ RawFree = concatenate open RawCategory RawFree diff --git a/src/Cat/Categories/Fun.agda b/src/Cat/Categories/Fun.agda index 48ee817..da71f2c 100644 --- a/src/Cat/Categories/Fun.agda +++ b/src/Cat/Categories/Fun.agda @@ -20,7 +20,7 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C RawCategory.Object raw = Functor ℂ 𝔻 RawCategory.Arrow raw = NaturalTransformation RawCategory.identity raw {F} = identity F - RawCategory._∘_ raw {F} {G} {H} = NT[_∘_] {F} {G} {H} + RawCategory._<<<_ raw {F} {G} {H} = NT[_∘_] {F} {G} {H} module _ where open RawCategory raw hiding (identity) @@ -154,9 +154,9 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C ob = fromEq p re : Arrow B A re = fromEq (sym p) - vr : _∘_ {A = A} {B} {A} re ob ≡ identity A + vr : _<<<_ {A = A} {B} {A} re ob ≡ identity A vr = {!!} - rv : _∘_ {A = B} {A} {B} ob re ≡ identity B + rv : _<<<_ {A = B} {A} {B} ob re ≡ identity B rv = {!!} isInverse : IsInverseOf {A} {B} ob re isInverse = vr , rv @@ -201,7 +201,7 @@ module _ {ℓ ℓ' : Level} (ℂ : Category ℓ ℓ') where { Object = Presheaf ℂ ; Arrow = NaturalTransformation ; identity = λ {F} → identity F - ; _∘_ = λ {F G H} → NT[_∘_] {F = F} {G = G} {H = H} + ; _<<<_ = λ {F G H} → NT[_∘_] {F = F} {G = G} {H = H} } -- isCategory : IsCategory raw diff --git a/src/Cat/Categories/Rel.agda b/src/Cat/Categories/Rel.agda index 71630e4..71c9044 100644 --- a/src/Cat/Categories/Rel.agda +++ b/src/Cat/Categories/Rel.agda @@ -154,7 +154,7 @@ RawRel = record { Object = Set ; Arrow = λ S R → Subset (S × R) ; identity = λ {S} → Diag S - ; _∘_ = λ {A B C} S R → λ {( a , c ) → Σ[ b ∈ B ] ( (a , b) ∈ R × (b , c) ∈ S )} + ; _<<<_ = λ {A B C} S R → λ {( a , c ) → Σ[ b ∈ B ] ( (a , b) ∈ R × (b , c) ∈ S )} } isPreCategory : IsPreCategory RawRel diff --git a/src/Cat/Categories/Sets.agda b/src/Cat/Categories/Sets.agda index 7870fc0..f950339 100644 --- a/src/Cat/Categories/Sets.agda +++ b/src/Cat/Categories/Sets.agda @@ -26,11 +26,11 @@ module _ (ℓ : Level) where RawCategory.Object SetsRaw = hSet ℓ RawCategory.Arrow SetsRaw (T , _) (U , _) = T → U RawCategory.identity SetsRaw = Function.id - RawCategory._∘_ SetsRaw = Function._∘′_ + RawCategory._<<<_ SetsRaw = Function._∘′_ module _ where private - open RawCategory SetsRaw hiding (_∘_) + open RawCategory SetsRaw hiding (_<<<_) isIdentity : IsIdentity Function.id fst isIdentity = funExt λ _ → refl @@ -44,7 +44,7 @@ module _ (ℓ : Level) where IsPreCategory.isIdentity isPreCat {A} {B} = isIdentity {A} {B} IsPreCategory.arrowsAreSets isPreCat {A} {B} = arrowsAreSets {A} {B} - open IsPreCategory isPreCat hiding (_∘_) + open IsPreCategory isPreCat hiding (_<<<_) isIso = TypeIsomorphism module _ {hA hB : hSet ℓ} where diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 1818c15..6190052 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -13,7 +13,7 @@ -- Data -- ---- -- identity; the identity arrow --- _∘_; function composition +-- _<<<_; function composition -- -- Laws -- ---- @@ -52,9 +52,9 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where Object : Set ℓa Arrow : Object → Object → Set ℓb identity : {A : Object} → Arrow A A - _∘_ : {A B C : Object} → Arrow B C → Arrow A B → Arrow A C + _<<<_ : {A B C : Object} → Arrow B C → Arrow A B → Arrow A C - infixl 10 _∘_ _>>>_ + infixl 10 _<<<_ _>>>_ -- | Operations on data @@ -65,7 +65,7 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where codomain {b = b} _ = b _>>>_ : {A B C : Object} → (Arrow A B) → (Arrow B C) → Arrow A C - f >>> g = g ∘ f + f >>> g = g <<< f -- | Laws about the data @@ -73,17 +73,17 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where -- right-hand-side. IsAssociative : Set (ℓa ⊔ ℓb) IsAssociative = ∀ {A B C D} {f : Arrow A B} {g : Arrow B C} {h : Arrow C D} - → h ∘ (g ∘ f) ≡ (h ∘ g) ∘ f + → h <<< (g <<< f) ≡ (h <<< g) <<< f IsIdentity : ({A : Object} → Arrow A A) → Set (ℓa ⊔ ℓb) IsIdentity id = {A B : Object} {f : Arrow A B} - → id ∘ f ≡ f × f ∘ id ≡ f + → id <<< f ≡ f × f <<< id ≡ f ArrowsAreSets : Set (ℓa ⊔ ℓb) ArrowsAreSets = ∀ {A B : Object} → isSet (Arrow A B) IsInverseOf : ∀ {A B} → (Arrow A B) → (Arrow B A) → Set ℓb - IsInverseOf = λ f g → g ∘ f ≡ identity × f ∘ g ≡ identity + IsInverseOf = λ f g → g <<< f ≡ identity × f <<< g ≡ identity Isomorphism : ∀ {A B} → (f : Arrow A B) → Set ℓb Isomorphism {A} {B} f = Σ[ g ∈ Arrow B A ] IsInverseOf f g @@ -93,10 +93,10 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where module _ {A B : Object} where Epimorphism : {X : Object } → (f : Arrow A B) → Set ℓb - Epimorphism {X} f = (g₀ g₁ : Arrow B X) → g₀ ∘ f ≡ g₁ ∘ f → g₀ ≡ g₁ + Epimorphism {X} f = (g₀ g₁ : Arrow B X) → g₀ <<< f ≡ g₁ <<< f → g₀ ≡ g₁ Monomorphism : {X : Object} → (f : Arrow A B) → Set ℓb - Monomorphism {X} f = (g₀ g₁ : Arrow X A) → f ∘ g₀ ≡ f ∘ g₁ → g₀ ≡ g₁ + Monomorphism {X} f = (g₀ g₁ : Arrow X A) → f <<< g₀ ≡ f <<< g₁ → g₀ ≡ g₁ IsInitial : Object → Set (ℓa ⊔ ℓb) IsInitial I = {X : Object} → isContr (Arrow I X) @@ -167,10 +167,10 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where arrowsAreSets : ArrowsAreSets open Univalence isIdentity public - leftIdentity : {A B : Object} {f : Arrow A B} → identity ∘ f ≡ f + leftIdentity : {A B : Object} {f : Arrow A B} → identity <<< f ≡ f leftIdentity {A} {B} {f} = fst (isIdentity {A = A} {B} {f}) - rightIdentity : {A B : Object} {f : Arrow A B} → f ∘ identity ≡ f + rightIdentity : {A B : Object} {f : Arrow A B} → f <<< identity ≡ f rightIdentity {A} {B} {f} = snd (isIdentity {A = A} {B} {f}) ------------ @@ -181,26 +181,26 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where module _ {A B : Object} {X : Object} (f : Arrow A B) where iso→epi : Isomorphism f → Epimorphism {X = X} f iso→epi (f- , left-inv , right-inv) g₀ g₁ eq = begin - g₀ ≡⟨ sym rightIdentity ⟩ - g₀ ∘ identity ≡⟨ cong (_∘_ g₀) (sym right-inv) ⟩ - g₀ ∘ (f ∘ f-) ≡⟨ isAssociative ⟩ - (g₀ ∘ f) ∘ f- ≡⟨ cong (λ φ → φ ∘ f-) eq ⟩ - (g₁ ∘ f) ∘ f- ≡⟨ sym isAssociative ⟩ - g₁ ∘ (f ∘ f-) ≡⟨ cong (_∘_ g₁) right-inv ⟩ - g₁ ∘ identity ≡⟨ rightIdentity ⟩ - g₁ ∎ + g₀ ≡⟨ sym rightIdentity ⟩ + g₀ <<< identity ≡⟨ cong (_<<<_ g₀) (sym right-inv) ⟩ + g₀ <<< (f <<< f-) ≡⟨ isAssociative ⟩ + (g₀ <<< f) <<< f- ≡⟨ cong (λ φ → φ <<< f-) eq ⟩ + (g₁ <<< f) <<< f- ≡⟨ sym isAssociative ⟩ + g₁ <<< (f <<< f-) ≡⟨ cong (_<<<_ g₁) right-inv ⟩ + g₁ <<< identity ≡⟨ rightIdentity ⟩ + g₁ ∎ iso→mono : Isomorphism f → Monomorphism {X = X} f iso→mono (f- , left-inv , right-inv) g₀ g₁ eq = begin - g₀ ≡⟨ sym leftIdentity ⟩ - identity ∘ g₀ ≡⟨ cong (λ φ → φ ∘ g₀) (sym left-inv) ⟩ - (f- ∘ f) ∘ g₀ ≡⟨ sym isAssociative ⟩ - f- ∘ (f ∘ g₀) ≡⟨ cong (_∘_ f-) eq ⟩ - f- ∘ (f ∘ g₁) ≡⟨ isAssociative ⟩ - (f- ∘ f) ∘ g₁ ≡⟨ cong (λ φ → φ ∘ g₁) left-inv ⟩ - identity ∘ g₁ ≡⟨ leftIdentity ⟩ - g₁ ∎ + g₀ ≡⟨ sym leftIdentity ⟩ + identity <<< g₀ ≡⟨ cong (λ φ → φ <<< g₀) (sym left-inv) ⟩ + (f- <<< f) <<< g₀ ≡⟨ sym isAssociative ⟩ + f- <<< (f <<< g₀) ≡⟨ cong (_<<<_ f-) eq ⟩ + f- <<< (f <<< g₁) ≡⟨ isAssociative ⟩ + (f- <<< f) <<< g₁ ≡⟨ cong (λ φ → φ <<< g₁) left-inv ⟩ + identity <<< g₁ ≡⟨ leftIdentity ⟩ + g₁ ∎ iso→epi×mono : Isomorphism f → Epimorphism {X = X} f × Monomorphism {X = X} f iso→epi×mono iso = iso→epi iso , iso→mono iso @@ -210,7 +210,7 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where propIsIdentity : ∀ {f : ∀ {A} → Arrow A A} → isProp (IsIdentity f) propIsIdentity {id} = propPiImpl (λ _ → propPiImpl λ _ → propPiImpl (λ f → - propSig (arrowsAreSets (id ∘ f) f) λ _ → arrowsAreSets (f ∘ id) f)) + propSig (arrowsAreSets (id <<< f) f) λ _ → arrowsAreSets (f <<< id) f)) propArrowIsSet : isProp (∀ {A B} → isSet (Arrow A B)) propArrowIsSet = propPiImpl λ _ → propPiImpl (λ _ → isSetIsProp) @@ -225,12 +225,12 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where where geq : g ≡ g' geq = begin - g ≡⟨ sym rightIdentity ⟩ - g ∘ identity ≡⟨ cong (λ φ → g ∘ φ) (sym ε') ⟩ - g ∘ (f ∘ g') ≡⟨ isAssociative ⟩ - (g ∘ f) ∘ g' ≡⟨ cong (λ φ → φ ∘ g') η ⟩ - identity ∘ g' ≡⟨ leftIdentity ⟩ - g' ∎ + g ≡⟨ sym rightIdentity ⟩ + g <<< identity ≡⟨ cong (λ φ → g <<< φ) (sym ε') ⟩ + g <<< (f <<< g') ≡⟨ isAssociative ⟩ + (g <<< f) <<< g' ≡⟨ cong (λ φ → φ <<< g') η ⟩ + identity <<< g' ≡⟨ leftIdentity ⟩ + g' ∎ propIsInitial : ∀ I → isProp (IsInitial I) propIsInitial I x y i {X} = res X i @@ -266,23 +266,23 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where private trans≅ : Transitive _≅_ trans≅ (f , f~ , f-inv) (g , g~ , g-inv) - = g ∘ f - , f~ ∘ g~ + = g <<< f + , f~ <<< g~ , ( begin - (f~ ∘ g~) ∘ (g ∘ f) ≡⟨ isAssociative ⟩ - (f~ ∘ g~) ∘ g ∘ f ≡⟨ cong (λ φ → φ ∘ f) (sym isAssociative) ⟩ - f~ ∘ (g~ ∘ g) ∘ f ≡⟨ cong (λ φ → f~ ∘ φ ∘ f) (fst g-inv) ⟩ - f~ ∘ identity ∘ f ≡⟨ cong (λ φ → φ ∘ f) rightIdentity ⟩ - f~ ∘ f ≡⟨ fst f-inv ⟩ - identity ∎ + (f~ <<< g~) <<< (g <<< f) ≡⟨ isAssociative ⟩ + (f~ <<< g~) <<< g <<< f ≡⟨ cong (λ φ → φ <<< f) (sym isAssociative) ⟩ + f~ <<< (g~ <<< g) <<< f ≡⟨ cong (λ φ → f~ <<< φ <<< f) (fst g-inv) ⟩ + f~ <<< identity <<< f ≡⟨ cong (λ φ → φ <<< f) rightIdentity ⟩ + f~ <<< f ≡⟨ fst f-inv ⟩ + identity ∎ ) , ( begin - g ∘ f ∘ (f~ ∘ g~) ≡⟨ isAssociative ⟩ - g ∘ f ∘ f~ ∘ g~ ≡⟨ cong (λ φ → φ ∘ g~) (sym isAssociative) ⟩ - g ∘ (f ∘ f~) ∘ g~ ≡⟨ cong (λ φ → g ∘ φ ∘ g~) (snd f-inv) ⟩ - g ∘ identity ∘ g~ ≡⟨ cong (λ φ → φ ∘ g~) rightIdentity ⟩ - g ∘ g~ ≡⟨ snd g-inv ⟩ - identity ∎ + g <<< f <<< (f~ <<< g~) ≡⟨ isAssociative ⟩ + g <<< f <<< f~ <<< g~ ≡⟨ cong (λ φ → φ <<< g~) (sym isAssociative) ⟩ + g <<< (f <<< f~) <<< g~ ≡⟨ cong (λ φ → g <<< φ <<< g~) (snd f-inv) ⟩ + g <<< identity <<< g~ ≡⟨ cong (λ φ → φ <<< g~) rightIdentity ⟩ + g <<< g~ ≡⟨ snd g-inv ⟩ + identity ∎ ) isPreorder : IsPreorder _≅_ isPreorder = record { isEquivalence = equalityIsEquivalence ; reflexive = idToIso _ _ ; trans = trans≅ } @@ -341,7 +341,7 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where pq : Arrow a b ≡ Arrow a' b' pq i = Arrow (p i) (q i) - 9-1-9 : coe pq f ≡ q* ∘ f ∘ p~ + 9-1-9 : coe pq f ≡ q* <<< f <<< p~ 9-1-9 = transpP {!!} {!!} -- | All projections are propositions. @@ -366,9 +366,9 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where Xprop f g = trans (sym (snd Xit f)) (snd Xit g) Yprop : isProp (Arrow Y Y) Yprop f g = trans (sym (snd Yit f)) (snd Yit g) - left : Y→X ∘ X→Y ≡ identity + left : Y→X <<< X→Y ≡ identity left = Xprop _ _ - right : X→Y ∘ Y→X ≡ identity + right : X→Y <<< Y→X ≡ identity right = Yprop _ _ iso : X ≅ Y iso = X→Y , Y→X , left , right @@ -396,9 +396,9 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where Xprop f g = trans (sym (snd Xii f)) (snd Xii g) Yprop : isProp (Arrow Y Y) Yprop f g = trans (sym (snd Yii f)) (snd Yii g) - left : Y→X ∘ X→Y ≡ identity + left : Y→X <<< X→Y ≡ identity left = Yprop _ _ - right : X→Y ∘ Y→X ≡ identity + right : X→Y <<< Y→X ≡ identity right = Xprop _ _ iso : X ≅ Y iso = Y→X , X→Y , right , left @@ -497,7 +497,7 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where _[_,_] = Arrow _[_∘_] : {A B C : Object} → (g : Arrow B C) → (f : Arrow A B) → Arrow A C - _[_∘_] = _∘_ + _[_∘_] = _<<<_ -- | The opposite category -- @@ -512,7 +512,7 @@ module Opposite {ℓa ℓb : Level} where RawCategory.Object opRaw = ℂ.Object RawCategory.Arrow opRaw = Function.flip ℂ.Arrow RawCategory.identity opRaw = ℂ.identity - RawCategory._∘_ opRaw = ℂ._>>>_ + RawCategory._<<<_ opRaw = ℂ._>>>_ open RawCategory opRaw @@ -561,7 +561,7 @@ module Opposite {ℓa ℓb : Level} where -- inv : AreInverses (ℂ.idToIso A B) f inv-ζ : AreInverses (idToIso A B) ζ - -- recto-verso : ℂ.idToIso A B ∘ f ≡ idFun (A ℂ.≅ B) + -- recto-verso : ℂ.idToIso A B <<< f ≡ idFun (A ℂ.≅ B) inv-ζ = record { verso-recto = funExt (λ x → begin (ζ ⊙ idToIso A B) x ≡⟨⟩ @@ -600,7 +600,7 @@ module Opposite {ℓa ℓb : Level} where RawCategory.Object (rawInv _) = Object RawCategory.Arrow (rawInv _) = Arrow RawCategory.identity (rawInv _) = identity - RawCategory._∘_ (rawInv _) = _∘_ + RawCategory._<<<_ (rawInv _) = _<<<_ oppositeIsInvolution : opposite (opposite ℂ) ≡ ℂ oppositeIsInvolution = Category≡ rawInv diff --git a/src/Cat/Category/Monad.agda b/src/Cat/Category/Monad.agda index 8ad64fa..85b23e4 100644 --- a/src/Cat/Category/Monad.agda +++ b/src/Cat/Category/Monad.agda @@ -36,7 +36,7 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where open Cat.Category.NaturalTransformation ℂ ℂ using (NaturalTransformation ; propIsNatural) private module ℂ = Category ℂ - open ℂ using (Object ; Arrow ; identity ; _∘_ ; _>>>_) + open ℂ using (Object ; Arrow ; identity ; _<<<_ ; _>>>_) module M = Monoidal ℂ module K = Kleisli ℂ @@ -74,21 +74,21 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where backIsMonad : M.IsMonad backRaw M.IsMonad.isAssociative backIsMonad {X} = begin - joinT X ∘ R.fmap (joinT X) ≡⟨⟩ - join ∘ fmap (joinT X) ≡⟨⟩ - join ∘ fmap join ≡⟨ isNaturalForeign ⟩ - join ∘ join ≡⟨⟩ - joinT X ∘ joinT (R.omap X) ∎ + joinT X <<< R.fmap (joinT X) ≡⟨⟩ + join <<< fmap (joinT X) ≡⟨⟩ + join <<< fmap join ≡⟨ isNaturalForeign ⟩ + join <<< join ≡⟨⟩ + joinT X <<< joinT (R.omap X) ∎ M.IsMonad.isInverse backIsMonad {X} = inv-l , inv-r where inv-l = begin - joinT X ∘ pureT (R.omap X) ≡⟨⟩ - join ∘ pure ≡⟨ fst isInverse ⟩ - identity ∎ + joinT X <<< pureT (R.omap X) ≡⟨⟩ + join <<< pure ≡⟨ fst isInverse ⟩ + identity ∎ inv-r = begin - joinT X ∘ R.fmap (pureT X) ≡⟨⟩ - join ∘ fmap pure ≡⟨ snd isInverse ⟩ - identity ∎ + joinT X <<< R.fmap (pureT X) ≡⟨⟩ + join <<< fmap pure ≡⟨ snd isInverse ⟩ + identity ∎ back : K.Monad → M.Monad Monoidal.Monad.raw (back m) = backRaw m @@ -101,11 +101,11 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where → K.RawMonad.bind (forthRaw (backRaw m)) {X} {Y} ≡ K.RawMonad.bind (K.Monad.raw m) bindEq {X} {Y} = begin - K.RawMonad.bind (forthRaw (backRaw m)) ≡⟨⟩ - (λ f → join ∘ fmap f) ≡⟨⟩ + K.RawMonad.bind (forthRaw (backRaw m)) ≡⟨⟩ + (λ f → join <<< fmap f) ≡⟨⟩ (λ f → bind (f >>> pure) >>> bind identity) ≡⟨ funExt lem ⟩ - (λ f → bind f) ≡⟨⟩ - bind ∎ + (λ f → bind f) ≡⟨⟩ + bind ∎ where lem : (f : Arrow X (omap Y)) → bind (f >>> pure) >>> bind identity @@ -139,18 +139,18 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where bindEq : ∀ {X Y} {f : Arrow X (Romap Y)} → KM.bind f ≡ bind f bindEq {X} {Y} {f} = begin - KM.bind f ≡⟨⟩ - joinT Y ∘ Rfmap f ≡⟨⟩ - bind f ∎ + KM.bind f ≡⟨⟩ + joinT Y <<< Rfmap f ≡⟨⟩ + bind f ∎ joinEq : ∀ {X} → KM.join ≡ joinT X joinEq {X} = begin - KM.join ≡⟨⟩ - KM.bind identity ≡⟨⟩ - bind identity ≡⟨⟩ - joinT X ∘ Rfmap identity ≡⟨ cong (λ φ → _ ∘ φ) R.isIdentity ⟩ - joinT X ∘ identity ≡⟨ ℂ.rightIdentity ⟩ - joinT X ∎ + KM.join ≡⟨⟩ + KM.bind identity ≡⟨⟩ + bind identity ≡⟨⟩ + joinT X <<< Rfmap identity ≡⟨ cong (λ φ → _ <<< φ) R.isIdentity ⟩ + joinT X <<< identity ≡⟨ ℂ.rightIdentity ⟩ + joinT X ∎ fmapEq : ∀ {A B} → KM.fmap {A} {B} ≡ Rfmap fmapEq {A} {B} = funExt (λ f → begin @@ -160,8 +160,8 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where Rfmap (f >>> pureT B) >>> joinT B ≡⟨⟩ Rfmap (f >>> pureT B) >>> joinT B ≡⟨ cong (λ φ → φ >>> joinT B) R.isDistributive ⟩ Rfmap f >>> Rfmap (pureT B) >>> joinT B ≡⟨ ℂ.isAssociative ⟩ - joinT B ∘ Rfmap (pureT B) ∘ Rfmap f ≡⟨ cong (λ φ → φ ∘ Rfmap f) (snd isInverse) ⟩ - identity ∘ Rfmap f ≡⟨ ℂ.leftIdentity ⟩ + joinT B <<< Rfmap (pureT B) <<< Rfmap f ≡⟨ cong (λ φ → φ <<< Rfmap f) (snd isInverse) ⟩ + identity <<< Rfmap f ≡⟨ ℂ.leftIdentity ⟩ Rfmap f ∎ ) @@ -183,8 +183,8 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where joinTEq = funExt (λ X → begin M.RawMonad.joinT (backRaw (forth m)) X ≡⟨⟩ KM.join ≡⟨⟩ - joinT X ∘ Rfmap identity ≡⟨ cong (λ φ → joinT X ∘ φ) R.isIdentity ⟩ - joinT X ∘ identity ≡⟨ ℂ.rightIdentity ⟩ + joinT X <<< Rfmap identity ≡⟨ cong (λ φ → joinT X <<< φ) R.isIdentity ⟩ + joinT X <<< identity ≡⟨ ℂ.rightIdentity ⟩ joinT X ∎) joinNTEq : (λ i → NaturalTransformation F[ Req i ∘ Req i ] (Req i)) diff --git a/src/Cat/Category/Monad/Kleisli.agda b/src/Cat/Category/Monad/Kleisli.agda index 1faf079..55e9cf5 100644 --- a/src/Cat/Category/Monad/Kleisli.agda +++ b/src/Cat/Category/Monad/Kleisli.agda @@ -18,7 +18,7 @@ open import Cat.Category.NaturalTransformation ℂ ℂ private ℓ = ℓa ⊔ ℓb module ℂ = Category ℂ - open ℂ using (Arrow ; identity ; Object ; _∘_ ; _>>>_) + open ℂ using (Arrow ; identity ; Object ; _<<<_ ; _>>>_) -- | Data for a monad. -- @@ -34,7 +34,7 @@ record RawMonad : Set ℓ where -- -- This should perhaps be defined in a "Klesli-version" of functors as well? fmap : ∀ {A B} → ℂ [ A , B ] → ℂ [ omap A , omap B ] - fmap f = bind (pure ∘ f) + fmap f = bind (pure <<< f) -- | Composition of monads aka. the kleisli-arrow. _>=>_ : {A B C : Object} → ℂ [ A , omap B ] → ℂ [ B , omap C ] → ℂ [ A , omap C ] @@ -62,14 +62,14 @@ record RawMonad : Set ℓ where -- This is really a functor law. Should we have a kleisli-representation of -- functors as well and make them a super-class? Fusion = {X Y Z : Object} {g : ℂ [ Y , Z ]} {f : ℂ [ X , Y ]} - → fmap (g ∘ f) ≡ fmap g ∘ fmap f + → fmap (g <<< f) ≡ fmap g <<< fmap f -- In the ("foreign") formulation of a monad `IsNatural`'s analogue here would be: IsNaturalForeign : Set _ - IsNaturalForeign = {X : Object} → join {X} ∘ fmap join ≡ join ∘ join + IsNaturalForeign = {X : Object} → join {X} <<< fmap join ≡ join <<< join IsInverse : Set _ - IsInverse = {X : Object} → join {X} ∘ pure ≡ identity × join {X} ∘ fmap pure ≡ identity + IsInverse = {X : Object} → join {X} <<< pure ≡ identity × join {X} <<< fmap pure ≡ identity record IsMonad (raw : RawMonad) : Set ℓ where open RawMonad raw public @@ -81,18 +81,21 @@ record IsMonad (raw : RawMonad) : Set ℓ where -- | Map fusion is admissable. fusion : Fusion fusion {g = g} {f} = begin - fmap (g ∘ f) ≡⟨⟩ - bind ((f >>> g) >>> pure) ≡⟨ cong bind ℂ.isAssociative ⟩ - bind (f >>> (g >>> pure)) ≡⟨ cong (λ φ → bind (f >>> φ)) (sym (isNatural _)) ⟩ - bind (f >>> (pure >>> (bind (g >>> pure)))) ≡⟨⟩ + fmap (g <<< f) ≡⟨⟩ + bind ((f >>> g) >>> pure) ≡⟨ cong bind ℂ.isAssociative ⟩ + bind (f >>> (g >>> pure)) + ≡⟨ cong (λ φ → bind (f >>> φ)) (sym (isNatural _)) ⟩ + bind (f >>> (pure >>> (bind (g >>> pure)))) + ≡⟨⟩ bind (f >>> (pure >>> fmap g)) ≡⟨⟩ - bind ((fmap g ∘ pure) ∘ f) ≡⟨ cong bind (sym ℂ.isAssociative) ⟩ - bind (fmap g ∘ (pure ∘ f)) ≡⟨ sym distrib ⟩ - bind (pure ∘ g) ∘ bind (pure ∘ f) ≡⟨⟩ - fmap g ∘ fmap f ∎ + bind ((fmap g <<< pure) <<< f) ≡⟨ cong bind (sym ℂ.isAssociative) ⟩ + bind (fmap g <<< (pure <<< f)) ≡⟨ sym distrib ⟩ + bind (pure <<< g) <<< bind (pure <<< f) + ≡⟨⟩ + fmap g <<< fmap f ∎ where - distrib : fmap g ∘ fmap f ≡ bind (fmap g ∘ (pure ∘ f)) - distrib = isDistributive (pure ∘ g) (pure ∘ f) + distrib : fmap g <<< fmap f ≡ bind (fmap g <<< (pure <<< f)) + distrib = isDistributive (pure <<< g) (pure <<< f) -- | This formulation gives rise to the following endo-functor. private @@ -102,15 +105,15 @@ record IsMonad (raw : RawMonad) : Set ℓ where isFunctorR : IsFunctor ℂ ℂ rawR IsFunctor.isIdentity isFunctorR = begin - bind (pure ∘ identity) ≡⟨ cong bind (ℂ.rightIdentity) ⟩ - bind pure ≡⟨ isIdentity ⟩ - identity ∎ + bind (pure <<< identity) ≡⟨ cong bind (ℂ.rightIdentity) ⟩ + bind pure ≡⟨ isIdentity ⟩ + identity ∎ IsFunctor.isDistributive isFunctorR {f = f} {g} = begin - bind (pure ∘ (g ∘ f)) ≡⟨⟩ - fmap (g ∘ f) ≡⟨ fusion ⟩ - fmap g ∘ fmap f ≡⟨⟩ - bind (pure ∘ g) ∘ bind (pure ∘ f) ∎ + bind (pure <<< (g <<< f)) ≡⟨⟩ + fmap (g <<< f) ≡⟨ fusion ⟩ + fmap g <<< fmap f ≡⟨⟩ + bind (pure <<< g) <<< bind (pure <<< f) ∎ -- FIXME Naming! R : EndoFunctor ℂ @@ -129,20 +132,20 @@ record IsMonad (raw : RawMonad) : Set ℓ where pureT A = pure pureN : Natural R⁰ R pureT pureN {A} {B} f = begin - pureT B ∘ R⁰.fmap f ≡⟨⟩ - pure ∘ f ≡⟨ sym (isNatural _) ⟩ - bind (pure ∘ f) ∘ pure ≡⟨⟩ - fmap f ∘ pure ≡⟨⟩ - R.fmap f ∘ pureT A ∎ + pureT B <<< R⁰.fmap f ≡⟨⟩ + pure <<< f ≡⟨ sym (isNatural _) ⟩ + bind (pure <<< f) <<< pure ≡⟨⟩ + fmap f <<< pure ≡⟨⟩ + R.fmap f <<< pureT A ∎ joinT : Transformation R² R joinT C = join joinN : Natural R² R joinT joinN f = begin - join ∘ R².fmap f ≡⟨⟩ - bind identity ∘ R².fmap f ≡⟨⟩ - R².fmap f >>> bind identity ≡⟨⟩ - fmap (fmap f) >>> bind identity ≡⟨⟩ - fmap (bind (f >>> pure)) >>> bind identity ≡⟨⟩ + join <<< R².fmap f ≡⟨⟩ + bind identity <<< R².fmap f ≡⟨⟩ + R².fmap f >>> bind identity ≡⟨⟩ + fmap (fmap f) >>> bind identity ≡⟨⟩ + fmap (bind (f >>> pure)) >>> bind identity ≡⟨⟩ bind (bind (f >>> pure) >>> pure) >>> bind identity ≡⟨ isDistributive _ _ ⟩ bind ((bind (f >>> pure) >>> pure) >=> identity) @@ -155,14 +158,14 @@ record IsMonad (raw : RawMonad) : Set ℓ where ≡⟨ cong bind ℂ.leftIdentity ⟩ bind (bind (f >>> pure)) ≡⟨ cong bind (sym ℂ.rightIdentity) ⟩ - bind (identity >>> bind (f >>> pure)) ≡⟨⟩ + bind (identity >>> bind (f >>> pure)) ≡⟨⟩ bind (identity >=> (f >>> pure)) ≡⟨ sym (isDistributive _ _) ⟩ - bind identity >>> bind (f >>> pure) ≡⟨⟩ - bind identity >>> fmap f ≡⟨⟩ - bind identity >>> R.fmap f ≡⟨⟩ - R.fmap f ∘ bind identity ≡⟨⟩ - R.fmap f ∘ join ∎ + bind identity >>> bind (f >>> pure) ≡⟨⟩ + bind identity >>> fmap f ≡⟨⟩ + bind identity >>> R.fmap f ≡⟨⟩ + R.fmap f <<< bind identity ≡⟨⟩ + R.fmap f <<< join ∎ pureNT : NaturalTransformation R⁰ R fst pureNT = pureT diff --git a/src/Cat/Category/Monad/Monoidal.agda b/src/Cat/Category/Monad/Monoidal.agda index 707ea07..fdd739e 100644 --- a/src/Cat/Category/Monad/Monoidal.agda +++ b/src/Cat/Category/Monad/Monoidal.agda @@ -16,7 +16,7 @@ module Cat.Category.Monad.Monoidal {ℓa ℓb : Level} (ℂ : Category ℓa ℓb private ℓ = ℓa ⊔ ℓb -open Category ℂ using (Object ; Arrow ; identity ; _∘_) +open Category ℂ using (Object ; Arrow ; identity ; _<<<_) open import Cat.Category.NaturalTransformation ℂ ℂ using (NaturalTransformation ; Transformation ; Natural) @@ -42,19 +42,19 @@ record RawMonad : Set ℓ where Rfmap = Functor.fmap R bind : {X Y : Object} → ℂ [ X , Romap Y ] → ℂ [ Romap X , Romap Y ] - bind {X} {Y} f = joinT Y ∘ Rfmap f + bind {X} {Y} f = joinT Y <<< Rfmap f IsAssociative : Set _ IsAssociative = {X : Object} - → joinT X ∘ Rfmap (joinT X) ≡ joinT X ∘ joinT (Romap X) + → joinT X <<< Rfmap (joinT X) ≡ joinT X <<< joinT (Romap X) IsInverse : Set _ IsInverse = {X : Object} - → joinT X ∘ pureT (Romap X) ≡ identity - × joinT X ∘ Rfmap (pureT X) ≡ identity - IsNatural = ∀ {X Y} f → joinT Y ∘ Rfmap f ∘ pureT X ≡ f + → joinT X <<< pureT (Romap X) ≡ identity + × joinT X <<< Rfmap (pureT X) ≡ identity + IsNatural = ∀ {X Y} f → joinT Y <<< Rfmap f <<< pureT X ≡ f IsDistributive = ∀ {X Y Z} (g : Arrow Y (Romap Z)) (f : Arrow X (Romap Y)) - → joinT Z ∘ Rfmap g ∘ (joinT Y ∘ Rfmap f) - ≡ joinT Z ∘ Rfmap (joinT Z ∘ Rfmap g ∘ f) + → joinT Z <<< Rfmap g <<< (joinT Y <<< Rfmap f) + ≡ joinT Z <<< Rfmap (joinT Z <<< Rfmap g <<< f) record IsMonad (raw : RawMonad) : Set ℓ where open RawMonad raw public @@ -68,48 +68,48 @@ record IsMonad (raw : RawMonad) : Set ℓ where isNatural : IsNatural isNatural {X} {Y} f = begin - joinT Y ∘ R.fmap f ∘ pureT X ≡⟨ sym ℂ.isAssociative ⟩ - joinT Y ∘ (R.fmap f ∘ pureT X) ≡⟨ cong (λ φ → joinT Y ∘ φ) (sym (pureN f)) ⟩ - joinT Y ∘ (pureT (R.omap Y) ∘ f) ≡⟨ ℂ.isAssociative ⟩ - joinT Y ∘ pureT (R.omap Y) ∘ f ≡⟨ cong (λ φ → φ ∘ f) (fst isInverse) ⟩ - identity ∘ f ≡⟨ ℂ.leftIdentity ⟩ - f ∎ + joinT Y <<< R.fmap f <<< pureT X ≡⟨ sym ℂ.isAssociative ⟩ + joinT Y <<< (R.fmap f <<< pureT X) ≡⟨ cong (λ φ → joinT Y <<< φ) (sym (pureN f)) ⟩ + joinT Y <<< (pureT (R.omap Y) <<< f) ≡⟨ ℂ.isAssociative ⟩ + joinT Y <<< pureT (R.omap Y) <<< f ≡⟨ cong (λ φ → φ <<< f) (fst isInverse) ⟩ + identity <<< f ≡⟨ ℂ.leftIdentity ⟩ + f ∎ isDistributive : IsDistributive isDistributive {X} {Y} {Z} g f = sym aux where module R² = Functor F[ R ∘ R ] distrib3 : ∀ {A B C D} {a : Arrow C D} {b : Arrow B C} {c : Arrow A B} - → R.fmap (a ∘ b ∘ c) - ≡ R.fmap a ∘ R.fmap b ∘ R.fmap c + → R.fmap (a <<< b <<< c) + ≡ R.fmap a <<< R.fmap b <<< R.fmap c distrib3 {a = a} {b} {c} = begin - R.fmap (a ∘ b ∘ c) ≡⟨ R.isDistributive ⟩ - R.fmap (a ∘ b) ∘ R.fmap c ≡⟨ cong (_∘ _) R.isDistributive ⟩ - R.fmap a ∘ R.fmap b ∘ R.fmap c ∎ + R.fmap (a <<< b <<< c) ≡⟨ R.isDistributive ⟩ + R.fmap (a <<< b) <<< R.fmap c ≡⟨ cong (_<<< _) R.isDistributive ⟩ + R.fmap a <<< R.fmap b <<< R.fmap c ∎ aux = begin - joinT Z ∘ R.fmap (joinT Z ∘ R.fmap g ∘ f) - ≡⟨ cong (λ φ → joinT Z ∘ φ) distrib3 ⟩ - joinT Z ∘ (R.fmap (joinT Z) ∘ R.fmap (R.fmap g) ∘ R.fmap f) + joinT Z <<< R.fmap (joinT Z <<< R.fmap g <<< f) + ≡⟨ cong (λ φ → joinT Z <<< φ) distrib3 ⟩ + joinT Z <<< (R.fmap (joinT Z) <<< R.fmap (R.fmap g) <<< R.fmap f) ≡⟨⟩ - joinT Z ∘ (R.fmap (joinT Z) ∘ R².fmap g ∘ R.fmap f) - ≡⟨ cong (_∘_ (joinT Z)) (sym ℂ.isAssociative) ⟩ - joinT Z ∘ (R.fmap (joinT Z) ∘ (R².fmap g ∘ R.fmap f)) + joinT Z <<< (R.fmap (joinT Z) <<< R².fmap g <<< R.fmap f) + ≡⟨ cong (_<<<_ (joinT Z)) (sym ℂ.isAssociative) ⟩ + joinT Z <<< (R.fmap (joinT Z) <<< (R².fmap g <<< R.fmap f)) ≡⟨ ℂ.isAssociative ⟩ - (joinT Z ∘ R.fmap (joinT Z)) ∘ (R².fmap g ∘ R.fmap f) - ≡⟨ cong (λ φ → φ ∘ (R².fmap g ∘ R.fmap f)) isAssociative ⟩ - (joinT Z ∘ joinT (R.omap Z)) ∘ (R².fmap g ∘ R.fmap f) + (joinT Z <<< R.fmap (joinT Z)) <<< (R².fmap g <<< R.fmap f) + ≡⟨ cong (λ φ → φ <<< (R².fmap g <<< R.fmap f)) isAssociative ⟩ + (joinT Z <<< joinT (R.omap Z)) <<< (R².fmap g <<< R.fmap f) ≡⟨ ℂ.isAssociative ⟩ - joinT Z ∘ joinT (R.omap Z) ∘ R².fmap g ∘ R.fmap f + joinT Z <<< joinT (R.omap Z) <<< R².fmap g <<< R.fmap f ≡⟨⟩ - ((joinT Z ∘ joinT (R.omap Z)) ∘ R².fmap g) ∘ R.fmap f - ≡⟨ cong (_∘ R.fmap f) (sym ℂ.isAssociative) ⟩ - (joinT Z ∘ (joinT (R.omap Z) ∘ R².fmap g)) ∘ R.fmap f - ≡⟨ cong (λ φ → φ ∘ R.fmap f) (cong (_∘_ (joinT Z)) (joinN g)) ⟩ - (joinT Z ∘ (R.fmap g ∘ joinT Y)) ∘ R.fmap f - ≡⟨ cong (_∘ R.fmap f) ℂ.isAssociative ⟩ - joinT Z ∘ R.fmap g ∘ joinT Y ∘ R.fmap f + ((joinT Z <<< joinT (R.omap Z)) <<< R².fmap g) <<< R.fmap f + ≡⟨ cong (_<<< R.fmap f) (sym ℂ.isAssociative) ⟩ + (joinT Z <<< (joinT (R.omap Z) <<< R².fmap g)) <<< R.fmap f + ≡⟨ cong (λ φ → φ <<< R.fmap f) (cong (_<<<_ (joinT Z)) (joinN g)) ⟩ + (joinT Z <<< (R.fmap g <<< joinT Y)) <<< R.fmap f + ≡⟨ cong (_<<< R.fmap f) ℂ.isAssociative ⟩ + joinT Z <<< R.fmap g <<< joinT Y <<< R.fmap f ≡⟨ sym (Category.isAssociative ℂ) ⟩ - joinT Z ∘ R.fmap g ∘ (joinT Y ∘ R.fmap f) + joinT Z <<< R.fmap g <<< (joinT Y <<< R.fmap f) ∎ record Monad : Set ℓ where diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 3aa73ba..caa993f 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -105,8 +105,8 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} × ℂ [ y1 ∘ f ] ≡ x1 } ; identity = λ{ {X , f , g} → ℂ.identity {X} , ℂ.rightIdentity , ℂ.rightIdentity} - ; _∘_ = λ { {_ , a0 , a1} {_ , b0 , b1} {_ , c0 , c1} (f , f0 , f1) (g , g0 , g1) - → (f ℂ.∘ g) + ; _<<<_ = λ { {_ , a0 , a1} {_ , b0 , b1} {_ , c0 , c1} (f , f0 , f1) (g , g0 , g1) + → (f ℂ.<<< g) , (begin ℂ [ c0 ∘ ℂ [ f ∘ g ] ] ≡⟨ ℂ.isAssociative ⟩ ℂ [ ℂ [ c0 ∘ f ] ∘ g ] ≡⟨ cong (λ φ → ℂ [ φ ∘ g ]) f0 ⟩ @@ -134,9 +134,9 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} isAssociative {A'@(A , a0 , a1)} {B , _} {C , c0 , c1} {D'@(D , d0 , d1)} {ff@(f , f0 , f1)} {gg@(g , g0 , g1)} {hh@(h , h0 , h1)} i = s0 i , lemPropF propEqs s0 {P.snd l} {P.snd r} i where - l = hh ∘ (gg ∘ ff) - r = hh ∘ gg ∘ ff - -- s0 : h ℂ.∘ (g ℂ.∘ f) ≡ h ℂ.∘ g ℂ.∘ f + l = hh <<< (gg <<< ff) + r = hh <<< gg <<< ff + -- s0 : h ℂ.<<< (g ℂ.<<< f) ≡ h ℂ.<<< g ℂ.<<< f s0 : fst l ≡ fst r s0 = ℂ.isAssociative {f = f} {g} {h} @@ -144,18 +144,18 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} isIdentity : IsIdentity identity isIdentity {AA@(A , a0 , a1)} {BB@(B , b0 , b1)} {f , f0 , f1} = leftIdentity , rightIdentity where - leftIdentity : identity ∘ (f , f0 , f1) ≡ (f , f0 , f1) + leftIdentity : identity <<< (f , f0 , f1) ≡ (f , f0 , f1) leftIdentity i = l i , lemPropF propEqs l {snd L} {snd R} i where - L = identity ∘ (f , f0 , f1) + L = identity <<< (f , f0 , f1) R : Arrow AA BB R = f , f0 , f1 l : fst L ≡ fst R l = ℂ.leftIdentity - rightIdentity : (f , f0 , f1) ∘ identity ≡ (f , f0 , f1) + rightIdentity : (f , f0 , f1) <<< identity ≡ (f , f0 , f1) rightIdentity i = l i , lemPropF propEqs l {snd L} {snd R} i where - L = (f , f0 , f1) ∘ identity + L = (f , f0 , f1) <<< identity R : Arrow AA BB R = (f , f0 , f1) l : ℂ [ f ∘ ℂ.identity ] ≡ f From db5fb3603a5fe46c6c23680802f24bbd89b6edf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 11 Apr 2018 11:10:33 +0200 Subject: [PATCH 44/93] Banish qualified import of Function - use \o for fun-comp! --- src/Cat/Categories/Cube.agda | 1 - src/Cat/Categories/Fam.agda | 3 +-- src/Cat/Categories/Rel.agda | 1 - src/Cat/Categories/Sets.agda | 20 +++++++++----------- src/Cat/Category.agda | 25 ++++++++++--------------- src/Cat/Category/Functor.agda | 5 ++--- src/Cat/Category/Monad/Voevodsky.agda | 5 ++--- src/Cat/Category/Product.agda | 5 +---- src/Cat/Equivalence.agda | 2 -- src/Cat/Prelude.agda | 5 ++++- 10 files changed, 29 insertions(+), 43 deletions(-) diff --git a/src/Cat/Categories/Cube.agda b/src/Cat/Categories/Cube.agda index fde96b9..121cb24 100644 --- a/src/Cat/Categories/Cube.agda +++ b/src/Cat/Categories/Cube.agda @@ -7,7 +7,6 @@ open import Data.Bool hiding (T) open import Data.Sum hiding ([_,_]) open import Data.Unit open import Data.Empty -open import Function open import Relation.Nullary open import Relation.Nullary.Decidable diff --git a/src/Cat/Categories/Fam.agda b/src/Cat/Categories/Fam.agda index a0b4d1d..157b3b5 100644 --- a/src/Cat/Categories/Fam.agda +++ b/src/Cat/Categories/Fam.agda @@ -2,7 +2,6 @@ module Cat.Categories.Fam where open import Cat.Prelude -import Function open import Cat.Category @@ -15,7 +14,7 @@ module _ (ℓa ℓb : Level) where fst identity = λ x → x snd identity = λ b → b _<<<_ : {a b c : Object} → Arr b c → Arr a b → Arr a c - (g , g') <<< (f , f') = g Function.∘ f , g' Function.∘ f' + (g , g') <<< (f , f') = g ∘ f , g' ∘ f' RawFam : RawCategory (lsuc (ℓa ⊔ ℓb)) (ℓa ⊔ ℓb) RawFam = record diff --git a/src/Cat/Categories/Rel.agda b/src/Cat/Categories/Rel.agda index 71c9044..3aa4e59 100644 --- a/src/Cat/Categories/Rel.agda +++ b/src/Cat/Categories/Rel.agda @@ -2,7 +2,6 @@ module Cat.Categories.Rel where open import Cat.Prelude hiding (Rel) -open import Function open import Cat.Category diff --git a/src/Cat/Categories/Sets.agda b/src/Cat/Categories/Sets.agda index f950339..b2ae61f 100644 --- a/src/Cat/Categories/Sets.agda +++ b/src/Cat/Categories/Sets.agda @@ -4,8 +4,6 @@ module Cat.Categories.Sets where open import Cat.Prelude as P -open import Function using (_∘_ ; _∘′_) - open import Cat.Category open import Cat.Category.Functor open import Cat.Category.Product @@ -25,14 +23,14 @@ module _ (ℓ : Level) where SetsRaw : RawCategory (lsuc ℓ) ℓ RawCategory.Object SetsRaw = hSet ℓ RawCategory.Arrow SetsRaw (T , _) (U , _) = T → U - RawCategory.identity SetsRaw = Function.id - RawCategory._<<<_ SetsRaw = Function._∘′_ + RawCategory.identity SetsRaw = idFun _ + RawCategory._<<<_ SetsRaw = _∘′_ module _ where private open RawCategory SetsRaw hiding (_<<<_) - isIdentity : IsIdentity Function.id + isIdentity : IsIdentity (idFun _) fst isIdentity = funExt λ _ → refl snd isIdentity = funExt λ _ → refl @@ -70,17 +68,17 @@ module _ (ℓ : Level) where where module xxA = AreInverses xx module yyA = AreInverses yy - ve-re : g ∘ f ≡ Function.id + ve-re : g ∘ f ≡ idFun _ ve-re = arrowsAreSets {A = hA} {B = hA} _ _ xxA.verso-recto yyA.verso-recto i - re-ve : f ∘ g ≡ Function.id + re-ve : f ∘ g ≡ idFun _ re-ve = arrowsAreSets {A = hB} {B = hB} _ _ xxA.recto-verso yyA.recto-verso i 1eq : x.inverse ≡ y.inverse 1eq = begin x.inverse ≡⟨⟩ - x.inverse ∘ Function.id ≡⟨ cong (λ φ → x.inverse ∘ φ) (sym yA.recto-verso) ⟩ + x.inverse ∘ idFun _ ≡⟨ cong (λ φ → x.inverse ∘ φ) (sym yA.recto-verso) ⟩ x.inverse ∘ (f ∘ y.inverse) ≡⟨⟩ (x.inverse ∘ f) ∘ y.inverse ≡⟨ cong (λ φ → φ ∘ y.inverse) xA.verso-recto ⟩ - Function.id ∘ y.inverse ≡⟨⟩ + idFun _ ∘ y.inverse ≡⟨⟩ y.inverse ∎ 2eq : (λ i → AreInverses f (1eq i)) [ x.areInverses ≡ y.areInverses ] 2eq = lemPropF p 1eq @@ -266,7 +264,7 @@ module _ {ℓ : Level} where module _ (hX : Object) where open Σ hX renaming (fst to X) module _ (f : X → A ) (g : X → B) where - ump : fst Function.∘′ (f &&& g) ≡ f × snd Function.∘′ (f &&& g) ≡ g + ump : fst ∘′ (f &&& g) ≡ f × snd ∘′ (f &&& g) ≡ g fst ump = refl snd ump = refl @@ -280,7 +278,7 @@ module _ {ℓ : Level} where = f &&& g , ump hX f g , λ eq → funExt (umpUniq eq) where open Σ hX renaming (fst to X) using () - module _ {y : X → A × B} (eq : fst Function.∘′ y ≡ f × snd Function.∘′ y ≡ g) (x : X) where + module _ {y : X → A × B} (eq : fst ∘′ y ≡ f × snd ∘′ y ≡ g) (x : X) where p1 : fst ((f &&& g) x) ≡ fst (y x) p1 = begin fst ((f &&& g) x) ≡⟨⟩ diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 6190052..428d357 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -35,8 +35,6 @@ open Cat.Equivalence renaming (_≅_ to _≈_) hiding (preorder≅ ; Isomorphism) -import Function - ------------------ -- * Categories -- ------------------ @@ -146,7 +144,7 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where postulate from[Contr] : Univalent[Contr] → Univalent from[Andrea] : Univalent[Andrea] → Univalent - from[Andrea] = from[Contr] Function.∘ step + from[Andrea] = from[Contr] ∘ step where module _ (f : Univalent[Andrea]) (A : Object) where aux : isContr (Σ[ B ∈ Object ] A ≡ B) @@ -510,7 +508,7 @@ module Opposite {ℓa ℓb : Level} where module ℂ = Category ℂ opRaw : RawCategory ℓa ℓb RawCategory.Object opRaw = ℂ.Object - RawCategory.Arrow opRaw = Function.flip ℂ.Arrow + RawCategory.Arrow opRaw = flip ℂ.Arrow RawCategory.identity opRaw = ℂ.identity RawCategory._<<<_ opRaw = ℂ._>>>_ @@ -529,9 +527,6 @@ module Opposite {ℓa ℓb : Level} where open Σ k renaming (fst to η ; snd to inv-η) open AreInverses inv-η - _⊙_ = Function._∘_ - infixr 9 _⊙_ - genericly : {ℓa ℓb ℓc : Level} {a : Set ℓa} {b : Set ℓb} {c : Set ℓc} → a × b × c → b × a × c genericly (a , b , c) = (b , a , c) @@ -557,22 +552,22 @@ module Opposite {ℓa ℓb : Level} where open Σ r-iso renaming (fst to r-l ; snd to r-r) ζ : A ≅ B → A ≡ B - ζ = η ⊙ shuffle + ζ = η ∘ shuffle -- inv : AreInverses (ℂ.idToIso A B) f inv-ζ : AreInverses (idToIso A B) ζ -- recto-verso : ℂ.idToIso A B <<< f ≡ idFun (A ℂ.≅ B) inv-ζ = record { verso-recto = funExt (λ x → begin - (ζ ⊙ idToIso A B) x ≡⟨⟩ - (η ⊙ shuffle ⊙ idToIso A B) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → η ⊙ shuffle ⊙ φ) (funExt lem)) ⟩ - (η ⊙ shuffle ⊙ shuffle~ ⊙ ℂ.idToIso A B) x ≡⟨⟩ - (η ⊙ ℂ.idToIso A B) x ≡⟨ (λ i → verso-recto i x) ⟩ + (ζ ∘ idToIso A B) x ≡⟨⟩ + (η ∘ shuffle ∘ idToIso A B) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → η ∘ shuffle ∘ φ) (funExt lem)) ⟩ + (η ∘ shuffle ∘ shuffle~ ∘ ℂ.idToIso A B) x ≡⟨⟩ + (η ∘ ℂ.idToIso A B) x ≡⟨ (λ i → verso-recto i x) ⟩ x ∎) ; recto-verso = funExt (λ x → begin - (idToIso A B ⊙ η ⊙ shuffle) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → φ ⊙ η ⊙ shuffle) (funExt lem)) ⟩ - (shuffle~ ⊙ ℂ.idToIso A B ⊙ η ⊙ shuffle) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → shuffle~ ⊙ φ ⊙ shuffle) recto-verso) ⟩ - (shuffle~ ⊙ shuffle) x ≡⟨⟩ + (idToIso A B ∘ η ∘ shuffle) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → φ ∘ η ∘ shuffle) (funExt lem)) ⟩ + (shuffle~ ∘ ℂ.idToIso A B ∘ η ∘ shuffle) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → shuffle~ ∘ φ ∘ shuffle) recto-verso) ⟩ + (shuffle~ ∘ shuffle) x ≡⟨⟩ x ∎) } diff --git a/src/Cat/Category/Functor.agda b/src/Cat/Category/Functor.agda index 08dcafa..b94dff2 100644 --- a/src/Cat/Category/Functor.agda +++ b/src/Cat/Category/Functor.agda @@ -2,7 +2,6 @@ module Cat.Category.Functor where open import Cat.Prelude -open import Function open import Cubical @@ -165,8 +164,8 @@ module Functors where module _ {ℓc ℓcc : Level} {ℂ : Category ℓc ℓcc} where private raw : RawFunctor ℂ ℂ - RawFunctor.omap raw = Function.id - RawFunctor.fmap raw = Function.id + RawFunctor.omap raw = idFun _ + RawFunctor.fmap raw = idFun _ isFunctor : IsFunctor ℂ ℂ raw IsFunctor.isIdentity isFunctor = refl diff --git a/src/Cat/Category/Monad/Voevodsky.agda b/src/Cat/Category/Monad/Voevodsky.agda index f4dc465..3ba9653 100644 --- a/src/Cat/Category/Monad/Voevodsky.agda +++ b/src/Cat/Category/Monad/Voevodsky.agda @@ -5,7 +5,6 @@ This module provides construction 2.3 in [voe] module Cat.Category.Monad.Voevodsky where open import Cat.Prelude -open import Function open import Cat.Category open import Cat.Category.Functor as F @@ -132,10 +131,10 @@ module voe {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where Kleisli→Monoidal : K.Monad → M.Monad Kleisli→Monoidal = E.reverse - ve-re : Kleisli→Monoidal ∘ Monoidal→Kleisli ≡ Function.id + ve-re : Kleisli→Monoidal ∘ Monoidal→Kleisli ≡ idFun _ ve-re = E.verso-recto - re-ve : Monoidal→Kleisli ∘ Kleisli→Monoidal ≡ Function.id + re-ve : Monoidal→Kleisli ∘ Kleisli→Monoidal ≡ idFun _ re-ve = E.recto-verso forth : §2-3.§1 omap pure → §2-3.§2 omap pure diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index caa993f..6ec32ba 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -3,7 +3,6 @@ module Cat.Category.Product where open import Cat.Prelude as P hiding (_×_ ; fst ; snd) open import Cat.Equivalence hiding (_≅_) --- module P = Cat.Prelude open import Cat.Category @@ -203,15 +202,13 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} : ((X , xa , xb) ≡ (Y , ya , yb)) ≈ (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)) step0 - = (λ p → cong fst p , cong-d (fst ⊙ snd) p , cong-d (snd ⊙ snd) p) + = (λ p → cong fst p , cong-d (fst ∘ snd) p , cong-d (snd ∘ snd) p) -- , (λ x → λ i → fst x i , (fst (snd x) i) , (snd (snd x) i)) , (λ{ (p , q , r) → Σ≡ p λ i → q i , r i}) , record { verso-recto = funExt (λ{ p → refl}) ; recto-verso = funExt (λ{ (p , q , r) → refl}) } - where - open import Function renaming (_∘_ to _⊙_) -- Should follow from c being univalent iso-id-inv : {p : X ≡ Y} → p ≡ ℂ.isoToId (ℂ.idToIso X Y p) diff --git a/src/Cat/Equivalence.agda b/src/Cat/Equivalence.agda index 43a25e4..4ca5a93 100644 --- a/src/Cat/Equivalence.agda +++ b/src/Cat/Equivalence.agda @@ -151,8 +151,6 @@ module _ {ℓa ℓb ℓ : Level} (A : Set ℓa) (B : Set ℓb) where (x ∘ f) ∘ y ≡⟨ cong (λ φ → φ ∘ y) inv-x.verso-recto ⟩ y ∎ - open import Cat.Prelude - propInv : ∀ g → isProp (AreInverses f g) propInv g t u i = record { verso-recto = a i ; recto-verso = b i } where diff --git a/src/Cat/Prelude.agda b/src/Cat/Prelude.agda index 0646bf5..a3d34a4 100644 --- a/src/Cat/Prelude.agda +++ b/src/Cat/Prelude.agda @@ -9,7 +9,10 @@ open import Data.Product public renaming (∃! to ∃!≈) using (_×_ ; Σ-syntax ; swap) --- TODO Import Data.Function under appropriate names. +open import Function using (_∘_ ; _∘′_ ; _$_ ; case_of_ ; flip) public + +idFun : ∀ {a} (A : Set a) → A → A +idFun A a = a open import Cubical public -- FIXME rename `gradLemma` to `fromIsomorphism` - perhaps just use wrapper From c23c2716a59cb6871ebd56c1f67a0fd22f70f54f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 11 Apr 2018 12:27:33 +0200 Subject: [PATCH 45/93] Move lemma to equivalence-module --- src/Cat/Categories/Sets.agda | 57 ++--------------------------------- src/Cat/Category.agda | 5 ++- src/Cat/Category/Product.agda | 46 +++++++++------------------- src/Cat/Equivalence.agda | 54 +++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 87 deletions(-) diff --git a/src/Cat/Categories/Sets.agda b/src/Cat/Categories/Sets.agda index b2ae61f..a0982fd 100644 --- a/src/Cat/Categories/Sets.agda +++ b/src/Cat/Categories/Sets.agda @@ -106,59 +106,6 @@ module _ (ℓ : Level) where iso : (p ≡ q) ≈ (fst p ≡ fst q) iso = f , g , inv - lem3 : ∀ {ℓc} {Q : A → Set (ℓc ⊔ ℓb)} - → ((a : A) → P a ≃ Q a) → Σ A P ≃ Σ A Q - lem3 {Q = Q} eA = res - where - f : Σ A P → Σ A Q - f (a , pA) = a , fst (eA a) pA - g : Σ A Q → Σ A P - g (a , qA) = a , g' qA - where - k : TypeIsomorphism _ - k = toIso _ _ (snd (eA a)) - open Σ k renaming (fst to g') - ve-re : (x : Σ A P) → (g ∘ f) x ≡ x - ve-re x i = fst x , eq i - where - eq : snd ((g ∘ f) x) ≡ snd x - eq = begin - snd ((g ∘ f) x) ≡⟨⟩ - snd (g (f (a , pA))) ≡⟨⟩ - g' (fst (eA a) pA) ≡⟨ lem ⟩ - pA ∎ - where - open Σ x renaming (fst to a ; snd to pA) - k : TypeIsomorphism _ - k = toIso _ _ (snd (eA a)) - open Σ k renaming (fst to g' ; snd to inv) - module A = AreInverses inv - -- anti-funExt - lem : (g' ∘ (fst (eA a))) pA ≡ pA - lem i = A.verso-recto i pA - re-ve : (x : Σ A Q) → (f ∘ g) x ≡ x - re-ve x i = fst x , eq i - where - open Σ x renaming (fst to a ; snd to qA) - eq = begin - snd ((f ∘ g) x) ≡⟨⟩ - fst (eA a) (g' qA) ≡⟨ (λ i → A.recto-verso i qA) ⟩ - qA ∎ - where - k : TypeIsomorphism _ - k = toIso _ _ (snd (eA a)) - open Σ k renaming (fst to g' ; snd to inv) - module A = AreInverses inv - inv : AreInverses f g - inv = record - { verso-recto = funExt ve-re - ; recto-verso = funExt re-ve - } - iso : Σ A P ≈ Σ A Q - iso = f , g , inv - res : Σ A P ≃ Σ A Q - res = fromIsomorphism _ _ iso - module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where lem4 : isSet A → isSet B → (f : A → B) → isEquiv A B f ≃ isIso f @@ -186,7 +133,7 @@ module _ (ℓ : Level) where -- lem3 and the equivalence from lem4 step0 : Σ (A → B) isIso ≃ Σ (A → B) (isEquiv A B) - step0 = lem3 {ℓc = lzero} (λ f → sym≃ (lem4 sA sB f)) + step0 = equivSig (λ f → sym≃ (lem4 sA sB f)) -- univalence step1 : Σ (A → B) (isEquiv A B) ≃ (A ≡ B) @@ -219,7 +166,7 @@ module _ (ℓ : Level) where open Σ hA renaming (fst to A) eq1 : (Σ[ hB ∈ Object ] hA ≅ hB) ≡ (Σ[ hB ∈ Object ] hA ≡ hB) - eq1 = ua (lem3 (\ hB → univ≃)) + eq1 = ua (equivSig (\ hB → univ≃)) univalent[Contr] : isContr (Σ[ hB ∈ Object ] hA ≅ hB) univalent[Contr] = subst {P = isContr} (sym eq1) tres diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 428d357..8f39dac 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -147,8 +147,11 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where from[Andrea] = from[Contr] ∘ step where module _ (f : Univalent[Andrea]) (A : Object) where + lem : Σ Object (A ≅_) ≃ Σ Object (A ≡_) + lem = equivSig {ℓa} {ℓb} {Object} {A ≅_} {_} {A ≡_} (f A) + aux : isContr (Σ[ B ∈ Object ] A ≡ B) - aux = {!!} + aux = {!Σ Object (A ≡_)!} step : isContr (Σ Object (A ≅_)) step = {!subst {P = isContr} {!!} aux!} diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 6ec32ba..663503f 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -172,32 +172,15 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} open IsPreCategory isPreCat univalent : Univalent - univalent {(X , xa , xb)} {(Y , ya , yb)} = univalenceFromIsomorphism res - where - open import Cat.Equivalence using (composeIso) renaming (_≅_ to _≈_) - -- open import Relation.Binary.PreorderReasoning (Cat.Equivalence.preorder≅ {!!}) using () - -- renaming - -- ( _∼⟨_⟩_ to _≈⟨_⟩_ - -- ; begin_ to begin!_ - -- ; _∎ to _∎! ) - -- lawl - -- : ((X , xa , xb) ≡ (Y , ya , yb)) - -- ≈ (Σ[ iso ∈ (X ℂ.≅ Y) ] let p = ℂ.isoToId iso in (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)) - -- lawl = {!begin! ? ≈⟨ ? ⟩ ? ∎!!} - -- Problem with the above approach: Preorders only work for heterogeneous equaluties. + univalent {(X , xa , xb)} {(Y , ya , yb)} = {!!} - -- (X , xa , xb) ≡ (Y , ya , yb) - -- ≅ - -- Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb) - -- ≅ - -- Σ (X ℂ.≅ Y) (λ iso - -- → let p = ℂ.isoToId iso - -- in - -- ( PathP (λ i → ℂ.Arrow (p i) A) xa ya) - -- × PathP (λ i → ℂ.Arrow (p i) B) xb yb - -- ) - -- ≅ - -- (X , xa , xb) ≅ (Y , ya , yb) + -- module _ {(X , xa , xb) : Object} {(Y , ya , yb) : Object} where + module _ (𝕏 𝕐 : Object) where + open Σ 𝕏 renaming (fst to X ; snd to x) + open Σ x renaming (fst to xa ; snd to xb) + open Σ 𝕐 renaming (fst to Y ; snd to y) + open Σ y renaming (fst to ya ; snd to yb) + open import Cat.Equivalence using (composeIso) renaming (_≅_ to _≈_) step0 : ((X , xa , xb) ≡ (Y , ya , yb)) ≈ (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)) @@ -287,7 +270,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} let iso : X ℂ.≅ Y iso = fst f , fst f~ , cong fst inv-f , cong fst inv-f~ - helper : PathP (λ i → ℂ.Arrow (ℂ.isoToId ? i) A) xa ya + helper : PathP (λ i → ℂ.Arrow (ℂ.isoToId {!!} i) A) xa ya helper = {!!} in iso , helper , {!!}}) , record @@ -315,12 +298,13 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} : ((X , xa , xb) ≡ (Y , ya , yb)) ≃ ((X , xa , xb) ≅ (Y , ya , yb)) equiv1 = _ , fromIso _ _ (snd iso) + equiv4reel + : ((X , xa , xb) ≅ (Y , ya , yb)) + ≃ ((X , xa , xb) ≡ (Y , ya , yb)) + equiv4reel = {!!} - res : TypeIsomorphism (idToIso (X , xa , xb) (Y , ya , yb)) - res = {!snd equiv1!} - - univalent2 : ∀ X Y → (X ≅ Y) ≃ (X ≡ Y) - univalent2 = {!!} + univalent' : Univalent + univalent' = from[Andrea] equiv4reel isCat : IsCategory raw IsCategory.isPreCategory isCat = isPreCat diff --git a/src/Cat/Equivalence.agda b/src/Cat/Equivalence.agda index 4ca5a93..dbdc2aa 100644 --- a/src/Cat/Equivalence.agda +++ b/src/Cat/Equivalence.agda @@ -445,3 +445,57 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where ; recto-verso = funExt ve-re } in fromIsomorphism _ _ iso + +module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where + equivSig : {ℓc : Level} {Q : A → Set ℓc} + → ((a : A) → P a ≃ Q a) → Σ A P ≃ Σ A Q + equivSig {Q = Q} eA = res + where + f : Σ A P → Σ A Q + f (a , pA) = a , fst (eA a) pA + g : Σ A Q → Σ A P + g (a , qA) = a , g' qA + where + k : Isomorphism _ + k = toIso _ _ (snd (eA a)) + open Σ k renaming (fst to g') + ve-re : (x : Σ A P) → (g ∘ f) x ≡ x + ve-re x i = fst x , eq i + where + eq : snd ((g ∘ f) x) ≡ snd x + eq = begin + snd ((g ∘ f) x) ≡⟨⟩ + snd (g (f (a , pA))) ≡⟨⟩ + g' (fst (eA a) pA) ≡⟨ lem ⟩ + pA ∎ + where + open Σ x renaming (fst to a ; snd to pA) + k : Isomorphism _ + k = toIso _ _ (snd (eA a)) + open Σ k renaming (fst to g' ; snd to inv) + module A = AreInverses inv + -- anti-funExt + lem : (g' ∘ (fst (eA a))) pA ≡ pA + lem i = A.verso-recto i pA + re-ve : (x : Σ A Q) → (f ∘ g) x ≡ x + re-ve x i = fst x , eq i + where + open Σ x renaming (fst to a ; snd to qA) + eq = begin + snd ((f ∘ g) x) ≡⟨⟩ + fst (eA a) (g' qA) ≡⟨ (λ i → A.recto-verso i qA) ⟩ + qA ∎ + where + k : Isomorphism _ + k = toIso _ _ (snd (eA a)) + open Σ k renaming (fst to g' ; snd to inv) + module A = AreInverses inv + inv : AreInverses f g + inv = record + { verso-recto = funExt ve-re + ; recto-verso = funExt re-ve + } + iso : Σ A P ≅ Σ A Q + iso = f , g , inv + res : Σ A P ≃ Σ A Q + res = fromIsomorphism _ _ iso From 4ff8f155abc43d7a9423a2bf01c7be350e0f1369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 11 Apr 2018 12:46:22 +0200 Subject: [PATCH 46/93] [QED] Get equivalence from 3rd formulation --- src/Cat/Category.agda | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 8f39dac..a39dd27 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -150,11 +150,11 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where lem : Σ Object (A ≅_) ≃ Σ Object (A ≡_) lem = equivSig {ℓa} {ℓb} {Object} {A ≅_} {_} {A ≡_} (f A) - aux : isContr (Σ[ B ∈ Object ] A ≡ B) - aux = {!Σ Object (A ≡_)!} + aux : isContr (Σ Object (A ≡_)) + aux = (A , refl) , (λ y → contrSingl (snd y)) step : isContr (Σ Object (A ≅_)) - step = {!subst {P = isContr} {!!} aux!} + step = equivPreservesNType {n = ⟨-2⟩} (Equivalence.symmetry lem) aux propUnivalent : isProp Univalent propUnivalent a b i = propPi (λ iso → propIsContr) a b i From 770bce52a26dd82aba3fb8367db42d2bb33c1ca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 11 Apr 2018 12:54:22 +0200 Subject: [PATCH 47/93] Use 3rd formulation of univalence --- src/Cat/Categories/Sets.agda | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/Cat/Categories/Sets.agda b/src/Cat/Categories/Sets.agda index a0982fd..be62a35 100644 --- a/src/Cat/Categories/Sets.agda +++ b/src/Cat/Categories/Sets.agda @@ -162,25 +162,8 @@ module _ (ℓ : Level) where univ≃ : (hA ≅ hB) ≃ (hA ≡ hB) univ≃ = trivial? ⊙ step0 ⊙ step1 ⊙ step2 - module _ (hA : Object) where - open Σ hA renaming (fst to A) - - eq1 : (Σ[ hB ∈ Object ] hA ≅ hB) ≡ (Σ[ hB ∈ Object ] hA ≡ hB) - eq1 = ua (equivSig (\ hB → univ≃)) - - univalent[Contr] : isContr (Σ[ hB ∈ Object ] hA ≅ hB) - univalent[Contr] = subst {P = isContr} (sym eq1) tres - where - module _ (y : Σ[ hB ∈ Object ] hA ≡ hB) where - open Σ y renaming (fst to hB ; snd to hA≡hB) - qres : (hA , refl) ≡ (hB , hA≡hB) - qres = contrSingl hA≡hB - - tres : isContr (Σ[ hB ∈ Object ] hA ≡ hB) - tres = (hA , refl) , qres - univalent : Univalent - univalent = from[Contr] univalent[Contr] + univalent = from[Andrea] (λ _ _ → univ≃) SetsIsCategory : IsCategory SetsRaw IsCategory.isPreCategory SetsIsCategory = isPreCat From e6a2e3a0f090b9bf2c03e2c1e465d53935cb46ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 11 Apr 2018 13:18:34 +0200 Subject: [PATCH 48/93] Reduce applications of symmetry --- src/Cat/Categories/Sets.agda | 24 ++++++++---------------- src/Cat/Category.agda | 8 ++++---- src/Cat/Category/Product.agda | 12 ++---------- 3 files changed, 14 insertions(+), 30 deletions(-) diff --git a/src/Cat/Categories/Sets.agda b/src/Cat/Categories/Sets.agda index be62a35..80b8080 100644 --- a/src/Cat/Categories/Sets.agda +++ b/src/Cat/Categories/Sets.agda @@ -132,20 +132,16 @@ module _ (ℓ : Level) where open Σ hB renaming (fst to B ; snd to sB) -- lem3 and the equivalence from lem4 - step0 : Σ (A → B) isIso ≃ Σ (A → B) (isEquiv A B) - step0 = equivSig (λ f → sym≃ (lem4 sA sB f)) - - -- univalence - step1 : Σ (A → B) (isEquiv A B) ≃ (A ≡ B) - step1 = sym≃ univalence + step0 : Σ (A → B) (isEquiv A B) ≃ Σ (A → B) isIso + step0 = equivSig (lem4 sA sB) -- lem2 with propIsSet - step2 : (A ≡ B) ≃ (hA ≡ hB) - step2 = sym≃ (lem2 (λ A → isSetIsProp) hA hB) + step2 : (hA ≡ hB) ≃ (A ≡ B) + step2 = lem2 (λ A → isSetIsProp) hA hB -- Go from an isomorphism on sets to an isomorphism on homotopic sets - trivial? : (hA ≅ hB) ≃ (A ≈ B) - trivial? = sym≃ (fromIsomorphism _ _ res) + trivial? : (A ≈ B) ≃ (hA ≅ hB) + trivial? = fromIsomorphism _ _ res where fwd : Σ (A → B) isIso → hA ≅ hB fwd (f , g , inv) = f , g , inv.toPair @@ -155,12 +151,8 @@ module _ (ℓ : Level) where bwd (f , g , x , y) = f , g , record { verso-recto = x ; recto-verso = y } res : Σ (A → B) isIso ≈ (hA ≅ hB) res = fwd , bwd , record { verso-recto = refl ; recto-verso = refl } - - conclusion : (hA ≅ hB) ≃ (hA ≡ hB) - conclusion = trivial? ⊙ step0 ⊙ step1 ⊙ step2 - - univ≃ : (hA ≅ hB) ≃ (hA ≡ hB) - univ≃ = trivial? ⊙ step0 ⊙ step1 ⊙ step2 + univ≃ : (hA ≡ hB) ≃ (hA ≅ hB) + univ≃ = step2 ⊙ univalence ⊙ step0 ⊙ trivial? univalent : Univalent univalent = from[Andrea] (λ _ _ → univ≃) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index a39dd27..d8febb7 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -135,7 +135,7 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where Univalent[Contr] = ∀ A → isContr (Σ[ X ∈ Object ] A ≅ X) Univalent[Andrea] : Set _ - Univalent[Andrea] = ∀ A B → (A ≅ B) ≃ (A ≡ B) + Univalent[Andrea] = ∀ A B → (A ≡ B) ≃ (A ≅ B) -- From: Thierry Coquand -- Date: Wed, Mar 21, 2018 at 3:12 PM @@ -147,14 +147,14 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where from[Andrea] = from[Contr] ∘ step where module _ (f : Univalent[Andrea]) (A : Object) where - lem : Σ Object (A ≅_) ≃ Σ Object (A ≡_) - lem = equivSig {ℓa} {ℓb} {Object} {A ≅_} {_} {A ≡_} (f A) + lem : Σ Object (A ≡_) ≃ Σ Object (A ≅_) + lem = equivSig (f A) aux : isContr (Σ Object (A ≡_)) aux = (A , refl) , (λ y → contrSingl (snd y)) step : isContr (Σ Object (A ≅_)) - step = equivPreservesNType {n = ⟨-2⟩} (Equivalence.symmetry lem) aux + step = equivPreservesNType {n = ⟨-2⟩} lem aux propUnivalent : isProp Univalent propUnivalent a b i = propPi (λ iso → propIsContr) a b i diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 663503f..0c7170d 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -171,10 +171,6 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} open IsPreCategory isPreCat - univalent : Univalent - univalent {(X , xa , xb)} {(Y , ya , yb)} = {!!} - - -- module _ {(X , xa , xb) : Object} {(Y , ya , yb) : Object} where module _ (𝕏 𝕐 : Object) where open Σ 𝕏 renaming (fst to X ; snd to x) open Σ x renaming (fst to xa ; snd to xb) @@ -298,13 +294,9 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} : ((X , xa , xb) ≡ (Y , ya , yb)) ≃ ((X , xa , xb) ≅ (Y , ya , yb)) equiv1 = _ , fromIso _ _ (snd iso) - equiv4reel - : ((X , xa , xb) ≅ (Y , ya , yb)) - ≃ ((X , xa , xb) ≡ (Y , ya , yb)) - equiv4reel = {!!} - univalent' : Univalent - univalent' = from[Andrea] equiv4reel + univalent : Univalent + univalent = from[Andrea] equiv1 isCat : IsCategory raw IsCategory.isPreCategory isCat = isPreCat From 1c963db7e66a1c7cceb5cbf6649ca79b1ecef3db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 11 Apr 2018 13:53:33 +0200 Subject: [PATCH 49/93] Make AreInveres an alias for \Sigma --- src/Cat/Categories/Sets.agda | 42 ++----- src/Cat/Category.agda | 6 +- src/Cat/Category/Monad.agda | 2 +- src/Cat/Category/Monad/Voevodsky.agda | 2 +- src/Cat/Category/Product.agda | 22 ++-- src/Cat/Equivalence.agda | 164 ++++++++++++-------------- 6 files changed, 98 insertions(+), 140 deletions(-) diff --git a/src/Cat/Categories/Sets.agda b/src/Cat/Categories/Sets.agda index 80b8080..97afcd4 100644 --- a/src/Cat/Categories/Sets.agda +++ b/src/Cat/Categories/Sets.agda @@ -54,30 +54,23 @@ module _ (ℓ : Level) where module _ (x y : isIso f) where module x = Σ x renaming (fst to inverse ; snd to areInverses) module y = Σ y renaming (fst to inverse ; snd to areInverses) - module xA = AreInverses x.areInverses - module yA = AreInverses y.areInverses -- I had a lot of difficulty using the corresponding proof where -- AreInverses is defined. This is sadly a bit anti-modular. The -- reason for my troubles is probably related to the type of objects -- being hSet's rather than sets. p : ∀ {f} g → isProp (AreInverses {A = A} {B} f g) - p {f} g xx yy i = record - { verso-recto = ve-re - ; recto-verso = re-ve - } + p {f} g xx yy i = ve-re , re-ve where - module xxA = AreInverses xx - module yyA = AreInverses yy ve-re : g ∘ f ≡ idFun _ - ve-re = arrowsAreSets {A = hA} {B = hA} _ _ xxA.verso-recto yyA.verso-recto i + ve-re = arrowsAreSets {A = hA} {B = hA} _ _ (fst xx) (fst yy) i re-ve : f ∘ g ≡ idFun _ - re-ve = arrowsAreSets {A = hB} {B = hB} _ _ xxA.recto-verso yyA.recto-verso i + re-ve = arrowsAreSets {A = hB} {B = hB} _ _ (snd xx) (snd yy) i 1eq : x.inverse ≡ y.inverse 1eq = begin x.inverse ≡⟨⟩ - x.inverse ∘ idFun _ ≡⟨ cong (λ φ → x.inverse ∘ φ) (sym yA.recto-verso) ⟩ + x.inverse ∘ idFun _ ≡⟨ cong (λ φ → x.inverse ∘ φ) (sym (snd y.areInverses)) ⟩ x.inverse ∘ (f ∘ y.inverse) ≡⟨⟩ - (x.inverse ∘ f) ∘ y.inverse ≡⟨ cong (λ φ → φ ∘ y.inverse) xA.verso-recto ⟩ + (x.inverse ∘ f) ∘ y.inverse ≡⟨ cong (λ φ → φ ∘ y.inverse) (fst x.areInverses) ⟩ idFun _ ∘ y.inverse ≡⟨⟩ y.inverse ∎ 2eq : (λ i → AreInverses f (1eq i)) [ x.areInverses ≡ y.areInverses ] @@ -99,10 +92,7 @@ module _ (ℓ : Level) where re-ve : (e : fst p ≡ fst q) → (f {p} {q} ∘ g {p} {q}) e ≡ e re-ve e = refl inv : AreInverses (f {p} {q}) (g {p} {q}) - inv = record - { verso-recto = funExt ve-re - ; recto-verso = funExt re-ve - } + inv = funExt ve-re , funExt re-ve iso : (p ≡ q) ≈ (fst p ≡ fst q) iso = f , g , inv @@ -120,11 +110,7 @@ module _ (ℓ : Level) where ve-re : (x : isIso f) → (obv ∘ inv) x ≡ x ve-re = inverse-to-from-iso A B sA sB iso : isEquiv A B f ≈ isIso f - iso = obv , inv , - record - { verso-recto = funExt re-ve - ; recto-verso = funExt ve-re - } + iso = obv , inv , funExt re-ve , funExt ve-re in fromIsomorphism _ _ iso module _ {hA hB : Object} where @@ -139,20 +125,8 @@ module _ (ℓ : Level) where step2 : (hA ≡ hB) ≃ (A ≡ B) step2 = lem2 (λ A → isSetIsProp) hA hB - -- Go from an isomorphism on sets to an isomorphism on homotopic sets - trivial? : (A ≈ B) ≃ (hA ≅ hB) - trivial? = fromIsomorphism _ _ res - where - fwd : Σ (A → B) isIso → hA ≅ hB - fwd (f , g , inv) = f , g , inv.toPair - where - module inv = AreInverses inv - bwd : hA ≅ hB → Σ (A → B) isIso - bwd (f , g , x , y) = f , g , record { verso-recto = x ; recto-verso = y } - res : Σ (A → B) isIso ≈ (hA ≅ hB) - res = fwd , bwd , record { verso-recto = refl ; recto-verso = refl } univ≃ : (hA ≡ hB) ≃ (hA ≅ hB) - univ≃ = step2 ⊙ univalence ⊙ step0 ⊙ trivial? + univ≃ = step2 ⊙ univalence ⊙ step0 univalent : Univalent univalent = from[Andrea] (λ _ _ → univ≃) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index d8febb7..7a764f9 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -528,7 +528,7 @@ module Opposite {ℓa ℓb : Level} where k : TypeIsomorphism (ℂ.idToIso A B) k = toIso _ _ ℂ.univalent open Σ k renaming (fst to η ; snd to inv-η) - open AreInverses inv-η + open AreInverses {f = ℂ.idToIso A B} {η} inv-η genericly : {ℓa ℓb ℓc : Level} {a : Set ℓa} {b : Set ℓb} {c : Set ℓc} → a × b × c → b × a × c @@ -561,13 +561,13 @@ module Opposite {ℓa ℓb : Level} where inv-ζ : AreInverses (idToIso A B) ζ -- recto-verso : ℂ.idToIso A B <<< f ≡ idFun (A ℂ.≅ B) inv-ζ = record - { verso-recto = funExt (λ x → begin + { fst = funExt (λ x → begin (ζ ∘ idToIso A B) x ≡⟨⟩ (η ∘ shuffle ∘ idToIso A B) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → η ∘ shuffle ∘ φ) (funExt lem)) ⟩ (η ∘ shuffle ∘ shuffle~ ∘ ℂ.idToIso A B) x ≡⟨⟩ (η ∘ ℂ.idToIso A B) x ≡⟨ (λ i → verso-recto i x) ⟩ x ∎) - ; recto-verso = funExt (λ x → begin + ; snd = funExt (λ x → begin (idToIso A B ∘ η ∘ shuffle) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → φ ∘ η ∘ shuffle) (funExt lem)) ⟩ (shuffle~ ∘ ℂ.idToIso A B ∘ η ∘ shuffle) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → shuffle~ ∘ φ ∘ shuffle) recto-verso) ⟩ (shuffle~ ∘ shuffle) x ≡⟨⟩ diff --git a/src/Cat/Category/Monad.agda b/src/Cat/Category/Monad.agda index 85b23e4..ac9c9bb 100644 --- a/src/Cat/Category/Monad.agda +++ b/src/Cat/Category/Monad.agda @@ -205,7 +205,7 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where open import Cat.Equivalence Monoidal≅Kleisli : M.Monad ≅ K.Monad - Monoidal≅Kleisli = forth , (back , (record { verso-recto = funExt backeq ; recto-verso = funExt fortheq })) + Monoidal≅Kleisli = forth , back , funExt backeq , funExt fortheq Monoidal≃Kleisli : M.Monad ≃ K.Monad Monoidal≃Kleisli = forth , eqv diff --git a/src/Cat/Category/Monad/Voevodsky.agda b/src/Cat/Category/Monad/Voevodsky.agda index 3ba9653..8f4c610 100644 --- a/src/Cat/Category/Monad/Voevodsky.agda +++ b/src/Cat/Category/Monad/Voevodsky.agda @@ -123,7 +123,7 @@ module voe {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where -- | to talk about voevodsky's construction. module _ (omap : Omap ℂ ℂ) (pure : {X : Object} → Arrow X (omap X)) where private - module E = AreInverses (Monoidal≅Kleisli ℂ .snd .snd) + module E = AreInverses {f = (fst (Monoidal≅Kleisli ℂ))} {fst (snd (Monoidal≅Kleisli ℂ))}(Monoidal≅Kleisli ℂ .snd .snd) Monoidal→Kleisli : M.Monad → K.Monad Monoidal→Kleisli = E.obverse diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 0c7170d..b8f39fb 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -184,10 +184,8 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} = (λ p → cong fst p , cong-d (fst ∘ snd) p , cong-d (snd ∘ snd) p) -- , (λ x → λ i → fst x i , (fst (snd x) i) , (snd (snd x) i)) , (λ{ (p , q , r) → Σ≡ p λ i → q i , r i}) - , record - { verso-recto = funExt (λ{ p → refl}) - ; recto-verso = funExt (λ{ (p , q , r) → refl}) - } + , funExt (λ{ p → refl}) + , funExt (λ{ (p , q , r) → refl}) -- Should follow from c being univalent iso-id-inv : {p : X ≡ Y} → p ≡ ℂ.isoToId (ℂ.idToIso X Y p) @@ -240,11 +238,8 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} -- I have `φ p` in scope, but surely `p` and `x` are the same - though -- perhaps not definitonally. , (λ{ (iso , x) → ℂ.isoToId iso , x}) - , record - { verso-recto = funExt (λ{ (p , q , r) → Σ≡ (sym iso-id-inv) (toPathP {A = λ i → {!!}} {!!})}) - -- { verso-recto = funExt (λ{ (p , q , r) → Σ≡ (sym iso-id-inv) {!!}}) - ; recto-verso = funExt (λ x → Σ≡ (sym id-iso-inv) {!!}) - } + , funExt (λ{ (p , q , r) → Σ≡ (sym iso-id-inv) (toPathP {A = λ i → {!!}} {!!})}) + , funExt (λ x → Σ≡ (sym id-iso-inv) {!!}) step2 : Σ (X ℂ.≅ Y) (λ iso → let p = ℂ.isoToId iso @@ -270,11 +265,11 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} helper = {!!} in iso , helper , {!!}}) , record - { verso-recto = funExt (λ x → lemSig + { fst = funExt (λ x → lemSig (λ x → propSig prop0 (λ _ → prop1)) _ _ (Σ≡ {!!} (ℂ.propIsomorphism _ _ _))) - ; recto-verso = funExt (λ{ (f , _) → lemSig propIsomorphism _ _ {!refl!}}) + ; snd = funExt (λ{ (f , _) → lemSig propIsomorphism _ _ {!refl!}}) } where prop0 : ∀ {x} → isProp (PathP (λ i → ℂ.Arrow (ℂ.isoToId x i) A) xa ya) @@ -386,10 +381,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} RawProduct.fst (e i) = p.fst RawProduct.snd (e i) = p.snd inv : AreInverses f g - inv = record - { verso-recto = funExt ve-re - ; recto-verso = funExt re-ve - } + inv = funExt ve-re , funExt re-ve propProduct : isProp (Product ℂ A B) propProduct = equivPreservesNType {n = ⟨-1⟩} lemma Propositionality.propTerminal diff --git a/src/Cat/Equivalence.agda b/src/Cat/Equivalence.agda index dbdc2aa..87a686a 100644 --- a/src/Cat/Equivalence.agda +++ b/src/Cat/Equivalence.agda @@ -31,10 +31,12 @@ module _ {ℓa ℓb : Level} where module _ {A : Set ℓa} {B : Set ℓb} where -- Quasi-inverse in [HoTT] §2.4.6 -- FIXME Maybe rename? - record AreInverses (f : A → B) (g : B → A) : Set ℓ where - field - verso-recto : g ∘ f ≡ idFun A - recto-verso : f ∘ g ≡ idFun B + AreInverses : (f : A → B) (g : B → A) → Set ℓ + AreInverses f g = g ∘ f ≡ idFun A × f ∘ g ≡ idFun B + + module AreInverses {f : A → B} {g : B → A} + (inv : AreInverses f g) where + open Σ inv renaming (fst to verso-recto ; snd to recto-verso) public obverse = f reverse = g inverse = reverse @@ -49,10 +51,7 @@ module _ {ℓa ℓb : Level} where × (f ∘ g) ≡ idFun B) where open Σ inv renaming (fst to ve-re ; snd to re-ve) toAreInverses : AreInverses f g - toAreInverses = record - { verso-recto = ve-re - ; recto-verso = re-ve - } + toAreInverses = ve-re , re-ve _≅_ : Set ℓa → Set ℓb → Set _ A ≅ B = Σ (A → B) Isomorphism @@ -61,16 +60,12 @@ module _ {ℓ : Level} {A B : Set ℓ} {f : A → B} (g : B → A) (s : {A B : Set ℓ} → isSet (A → B)) where propAreInverses : isProp (AreInverses {A = A} {B} f g) - propAreInverses x y i = record - { verso-recto = ve-re - ; recto-verso = re-ve - } + propAreInverses x y i = ve-re , re-ve where - open AreInverses ve-re : g ∘ f ≡ idFun A - ve-re = s (g ∘ f) (idFun A) (verso-recto x) (verso-recto y) i + ve-re = s (g ∘ f) (idFun A) (fst x) (fst y) i re-ve : f ∘ g ≡ idFun B - re-ve = s (f ∘ g) (idFun B) (recto-verso x) (recto-verso y) i + re-ve = s (f ∘ g) (idFun B) (snd x) (snd y) i module _ {ℓ : Level} {A B : Set ℓ} (f : A → B) (sA : isSet A) (sB : isSet B) where @@ -81,20 +76,17 @@ module _ {ℓ : Level} {A B : Set ℓ} (f : A → B) module _ (x y : Isomorphism f) where module x = Σ x renaming (fst to inverse ; snd to areInverses) module y = Σ y renaming (fst to inverse ; snd to areInverses) - module xA = AreInverses x.areInverses - module yA = AreInverses y.areInverses + module xA = AreInverses {f = f} {x.inverse} x.areInverses + module yA = AreInverses {f = f} {y.inverse} y.areInverses -- I had a lot of difficulty using the corresponding proof where -- AreInverses is defined. This is sadly a bit anti-modular. The -- reason for my troubles is probably related to the type of objects -- being hSet's rather than sets. p : ∀ {f} g → isProp (AreInverses {A = A} {B} f g) - p {f} g xx yy i = record - { verso-recto = ve-re - ; recto-verso = re-ve - } + p {f} g xx yy i = ve-re , re-ve where - module xxA = AreInverses xx - module yyA = AreInverses yy + module xxA = AreInverses {f = f} {g} xx + module yyA = AreInverses {f = f} {g} yy setPiB : ∀ {X : Set ℓ} → isSet (X → B) setPiB = setPi (λ _ → sB) setPiA : ∀ {X : Set ℓ} → isSet (X → A) @@ -141,33 +133,29 @@ module _ {ℓa ℓb ℓ : Level} (A : Set ℓa) (B : Set ℓb) where module _ (iso-x iso-y : Isomorphism f) where open Σ iso-x renaming (fst to x ; snd to inv-x) open Σ iso-y renaming (fst to y ; snd to inv-y) - module inv-x = AreInverses inv-x - module inv-y = AreInverses inv-y fx≡fy : x ≡ y fx≡fy = begin - x ≡⟨ cong (λ φ → x ∘ φ) (sym inv-y.recto-verso) ⟩ + x ≡⟨ cong (λ φ → x ∘ φ) (sym (snd inv-y)) ⟩ x ∘ (f ∘ y) ≡⟨⟩ - (x ∘ f) ∘ y ≡⟨ cong (λ φ → φ ∘ y) inv-x.verso-recto ⟩ + (x ∘ f) ∘ y ≡⟨ cong (λ φ → φ ∘ y) (fst inv-x) ⟩ y ∎ propInv : ∀ g → isProp (AreInverses f g) - propInv g t u i = record { verso-recto = a i ; recto-verso = b i } + propInv g t u i = a i , b i where - module t = AreInverses t - module u = AreInverses u - a : t.verso-recto ≡ u.verso-recto + a : (fst t) ≡ (fst u) a i = h where hh : ∀ a → (g ∘ f) a ≡ a - hh a = sA ((g ∘ f) a) a (λ i → t.verso-recto i a) (λ i → u.verso-recto i a) i + hh a = sA ((g ∘ f) a) a (λ i → (fst t) i a) (λ i → (fst u) i a) i h : g ∘ f ≡ idFun A h i a = hh a i - b : t.recto-verso ≡ u.recto-verso + b : (snd t) ≡ (snd u) b i = h where hh : ∀ b → (f ∘ g) b ≡ b - hh b = sB _ _ (λ i → t.recto-verso i b) (λ i → u.recto-verso i b) i + hh b = sB _ _ (λ i → snd t i b) (λ i → snd u i b) i h : f ∘ g ≡ idFun B h i b = hh b i @@ -201,10 +189,7 @@ module _ {ℓa ℓb : Level} (A : Set ℓa) (B : Set ℓb) where reverse = inverse areInverses : AreInverses obverse inverse - areInverses = record - { verso-recto = funExt verso-recto - ; recto-verso = funExt recto-verso - } + areInverses = funExt verso-recto , funExt recto-verso where recto-verso : ∀ b → (obverse ∘ inverse) b ≡ b recto-verso b = begin @@ -245,11 +230,10 @@ module _ {ℓa ℓb : Level} (A : Set ℓa) (B : Set ℓb) where ≃isEquiv : Equiv A B (isEquiv A B) Equiv.fromIso ≃isEquiv {f} (f~ , iso) = gradLemma f f~ rv vr where - open AreInverses iso rv : (b : B) → _ ≡ b - rv b i = recto-verso i b + rv b i = snd iso i b vr : (a : A) → _ ≡ a - vr a i = verso-recto i a + vr a i = fst iso i a Equiv.toIso ≃isEquiv = toIsomorphism Equiv.propIsEquiv ≃isEquiv = P.propIsEquiv where @@ -266,21 +250,19 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where composeIsomorphism a b = f~ ∘ g~ , inv where open Σ a renaming (fst to f~ ; snd to inv-a) - module A = AreInverses inv-a open Σ b renaming (fst to g~ ; snd to inv-b) - module B = AreInverses inv-b inv : AreInverses (g ∘ f) (f~ ∘ g~) inv = record - { verso-recto = begin + { fst = begin (f~ ∘ g~) ∘ (g ∘ f) ≡⟨⟩ - f~ ∘ (g~ ∘ g) ∘ f  ≡⟨ cong (λ φ → f~ ∘ φ ∘ f) B.verso-recto ⟩ + f~ ∘ (g~ ∘ g) ∘ f  ≡⟨ cong (λ φ → f~ ∘ φ ∘ f) (fst inv-b) ⟩ f~ ∘ idFun _ ∘ f   ≡⟨⟩ - f~ ∘ f ≡⟨ A.verso-recto ⟩ + f~ ∘ f ≡⟨ (fst inv-a) ⟩ idFun A  ∎ - ; recto-verso = begin + ; snd = begin (g ∘ f) ∘ (f~ ∘ g~) ≡⟨⟩ - g ∘ (f ∘ f~) ∘ g~  ≡⟨ cong (λ φ → g ∘ φ ∘ g~) A.recto-verso ⟩ - g ∘ g~ ≡⟨ B.recto-verso ⟩ + g ∘ (f ∘ f~) ∘ g~  ≡⟨ cong (λ φ → g ∘ φ ∘ g~) (snd inv-a) ⟩ + g ∘ g~ ≡⟨ (snd inv-b) ⟩ idFun C  ∎ } @@ -299,7 +281,7 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where iso : Isomorphism (fst e) iso = snd (toIsomorphism _ _ e) - open AreInverses (snd iso) public + open AreInverses {f = fst e} {fst iso} (snd iso) public compose : {ℓc : Level} {C : Set ℓc} → (B ≃ C) → A ≃ C compose (f , isEquiv) = f ∘ obverse , composeIsEquiv (snd e) isEquiv @@ -308,10 +290,8 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where symmetryIso = inverse , obverse - , record - { verso-recto = recto-verso - ; recto-verso = verso-recto - } + , recto-verso + , verso-recto symmetry : B ≃ A symmetry = fromIsomorphism _ _ symmetryIso @@ -325,13 +305,43 @@ preorder≅ ℓ = record → coe p , coe (sym p) -- I believe I stashed the proof of this somewhere. - , record - { verso-recto = {!refl!} - ; recto-verso = {!!} - } + , funExt (λ x → inv-coe p) + , funExt (λ x → inv-coe' p) ; trans = composeIso } } + where + module _ {ℓ : Level} {A : Set ℓ} {a : A} where + id-coe : coe refl a ≡ a + id-coe = begin + coe refl a ≡⟨⟩ + pathJ (λ y x → A) _ A refl ≡⟨ pathJprop {x = a} (λ y x → A) _ ⟩ + _ ≡⟨ pathJprop {x = a} (λ y x → A) _ ⟩ + a ∎ + + module _ {ℓ : Level} {A B : Set ℓ} {a : A} where + inv-coe : (p : A ≡ B) → coe (sym p) (coe p a) ≡ a + inv-coe p = + let + D : (y : Set ℓ) → _ ≡ y → Set _ + D _ q = coe (sym q) (coe q a) ≡ a + d : D A refl + d = begin + coe (sym refl) (coe refl a) ≡⟨⟩ + coe refl (coe refl a) ≡⟨ id-coe ⟩ + coe refl a ≡⟨ id-coe ⟩ + a ∎ + in pathJ D d B p + inv-coe' : (p : B ≡ A) → coe p (coe (sym p) a) ≡ a + inv-coe' p = + let + D : (y : Set ℓ) → _ ≡ y → Set _ + D _ q = coe (sym q) (coe q a) ≡ a + k : coe p (coe (sym p) a) ≡ a + k = pathJ D (trans id-coe id-coe) B (sym p) + in k + + module _ {ℓ : Level} {A B : Set ℓ} where univalence : (A ≡ B) ≃ (A ≃ B) univalence = Equivalence.compose u' aux @@ -341,7 +351,7 @@ module _ {ℓ : Level} {A B : Set ℓ} where u' : (A ≡ B) ≃ (A U.≃ B) u' = doEta u aux : (A U.≃ B) ≃ (A ≃ B) - aux = fromIsomorphism _ _ (doEta , deEta , record { verso-recto = funExt (λ{ (U.con _ _) → refl}) ; recto-verso = refl }) + aux = fromIsomorphism _ _ (doEta , deEta , funExt (λ{ (U.con _ _) → refl}) , refl) -- A few results that I have not generalized to work with both the eta and no-eta variable of ≃ module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where @@ -361,10 +371,7 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where re-ve : (e : fst p ≡ fst q) → (f {p} {q} ∘ g {p} {q}) e ≡ e re-ve e = refl inv : AreInverses (f {p} {q}) (g {p} {q}) - inv = record - { verso-recto = funExt ve-re - ; recto-verso = funExt re-ve - } + inv = funExt ve-re , funExt re-ve iso : (p ≡ q) ≅ (fst p ≡ fst q) iso = f , g , inv @@ -396,28 +403,22 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where k : Isomorphism _ k = toIso _ _ (snd (eA a)) open Σ k renaming (fst to g' ; snd to inv) - module A = AreInverses inv - -- anti-funExt lem : (g' ∘ (fst (eA a))) pA ≡ pA - lem i = A.verso-recto i pA + lem i = fst inv i pA re-ve : (x : Σ A Q) → (f ∘ g) x ≡ x re-ve x i = fst x , eq i where open Σ x renaming (fst to a ; snd to qA) eq = begin snd ((f ∘ g) x) ≡⟨⟩ - fst (eA a) (g' qA) ≡⟨ (λ i → A.recto-verso i qA) ⟩ - qA ∎ + fst (eA a) (g' qA) ≡⟨ (λ i → snd inv i qA) ⟩ + qA ∎ where k : Isomorphism _ k = toIso _ _ (snd (eA a)) open Σ k renaming (fst to g' ; snd to inv) - module A = AreInverses inv inv : AreInverses f g - inv = record - { verso-recto = funExt ve-re - ; recto-verso = funExt re-ve - } + inv = funExt ve-re , funExt re-ve iso : Σ A P ≅ Σ A Q iso = f , g , inv res : Σ A P ≃ Σ A Q @@ -439,11 +440,7 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where ve-re : (x : Isomorphism f) → (obv ∘ inv) x ≡ x ve-re = inverse-to-from-iso A B sA sB iso : isEquiv A B f ≅ Isomorphism f - iso = obv , inv , - record - { verso-recto = funExt re-ve - ; recto-verso = funExt ve-re - } + iso = obv , inv , funExt re-ve , funExt ve-re in fromIsomorphism _ _ iso module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where @@ -473,28 +470,23 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where k : Isomorphism _ k = toIso _ _ (snd (eA a)) open Σ k renaming (fst to g' ; snd to inv) - module A = AreInverses inv -- anti-funExt lem : (g' ∘ (fst (eA a))) pA ≡ pA - lem i = A.verso-recto i pA + lem i = fst inv i pA re-ve : (x : Σ A Q) → (f ∘ g) x ≡ x re-ve x i = fst x , eq i where open Σ x renaming (fst to a ; snd to qA) eq = begin snd ((f ∘ g) x) ≡⟨⟩ - fst (eA a) (g' qA) ≡⟨ (λ i → A.recto-verso i qA) ⟩ + fst (eA a) (g' qA) ≡⟨ (λ i → snd inv i qA) ⟩ qA ∎ where k : Isomorphism _ k = toIso _ _ (snd (eA a)) open Σ k renaming (fst to g' ; snd to inv) - module A = AreInverses inv inv : AreInverses f g - inv = record - { verso-recto = funExt ve-re - ; recto-verso = funExt re-ve - } + inv = funExt ve-re , funExt re-ve iso : Σ A P ≅ Σ A Q iso = f , g , inv res : Σ A P ≃ Σ A Q From 5c4b4db6920c4bc1e5005ea1b868ec503af2e5d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 11 Apr 2018 14:10:01 +0200 Subject: [PATCH 50/93] Simplifications --- src/Cat/Equivalence.agda | 51 ++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/src/Cat/Equivalence.agda b/src/Cat/Equivalence.agda index 87a686a..27e77e5 100644 --- a/src/Cat/Equivalence.agda +++ b/src/Cat/Equivalence.agda @@ -8,17 +8,10 @@ open import Cubical.PathPrelude hiding (inverse ; _≃_) open import Cubical.PathPrelude using (isEquiv ; isContr ; fiber) public open import Cubical.GradLemma -open import Cat.Prelude using (lemPropF ; setPi ; lemSig ; propSet ; Preorder ; equalityIsEquivalence ; _≃_) +open import Cat.Prelude using (lemPropF ; setPi ; lemSig ; propSet ; Preorder ; equalityIsEquivalence ; _≃_ ; propSig) import Cubical.Univalence as U -module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where - open Cubical.PathPrelude - deEta : A ≃ B → A U.≃ B - deEta (a , b) = U.con a b - doEta : A U.≃ B → A ≃ B - doEta (U.con eqv isEqv) = eqv , isEqv - module _ {ℓ : Level} {A B : Set ℓ} where open Cubical.PathPrelude ua : A ≃ B → A ≡ B @@ -40,19 +33,10 @@ module _ {ℓa ℓb : Level} where obverse = f reverse = g inverse = reverse - toPair : Σ _ _ - toPair = verso-recto , recto-verso Isomorphism : (f : A → B) → Set _ Isomorphism f = Σ (B → A) λ g → AreInverses f g - module _ {f : A → B} {g : B → A} - (inv : (g ∘ f) ≡ idFun A - × (f ∘ g) ≡ idFun B) where - open Σ inv renaming (fst to ve-re ; snd to re-ve) - toAreInverses : AreInverses f g - toAreInverses = ve-re , re-ve - _≅_ : Set ℓa → Set ℓb → Set _ A ≅ B = Σ (A → B) Isomorphism @@ -127,7 +111,8 @@ module _ {ℓa ℓb ℓ : Level} (A : Set ℓa) (B : Set ℓb) where fromIso (toIso x) ≡⟨ propIsEquiv _ (fromIso (toIso x)) x ⟩ x ∎ - -- `toIso` is abstract - so I probably can't close this proof. + -- | The other inverse law does not hold in general, it does hold, however, + -- | if `A` and `B` are sets. module _ (sA : isSet A) (sB : isSet B) where module _ {f : A → B} (iso : Isomorphism f) where module _ (iso-x iso-y : Isomorphism f) where @@ -275,26 +260,20 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where composeIso : {ℓc : Level} {C : Set ℓc} → (A ≅ B) → (B ≅ C) → A ≅ C composeIso {C = C} (f , iso-f) (g , iso-g) = g ∘ f , composeIsomorphism iso-f iso-g + symmetryIso : (A ≅ B) → B ≅ A + symmetryIso (inverse , obverse , verso-recto , recto-verso) + = obverse + , inverse + , recto-verso + , verso-recto + -- Gives the quasi inverse from an equivalence. module Equivalence (e : A ≃ B) where - private - iso : Isomorphism (fst e) - iso = snd (toIsomorphism _ _ e) - - open AreInverses {f = fst e} {fst iso} (snd iso) public - compose : {ℓc : Level} {C : Set ℓc} → (B ≃ C) → A ≃ C - compose (f , isEquiv) = f ∘ obverse , composeIsEquiv (snd e) isEquiv - - symmetryIso : B ≅ A - symmetryIso - = inverse - , obverse - , recto-verso - , verso-recto + compose e' = fromIsomorphism _ _ (composeIso (toIsomorphism _ _ e) (toIsomorphism _ _ e')) symmetry : B ≃ A - symmetry = fromIsomorphism _ _ symmetryIso + symmetry = fromIsomorphism _ _ (symmetryIso (toIsomorphism _ _ e)) preorder≅ : (ℓ : Level) → Preorder _ _ _ preorder≅ ℓ = record @@ -304,7 +283,6 @@ preorder≅ ℓ = record ; reflexive = λ p → coe p , coe (sym p) - -- I believe I stashed the proof of this somewhere. , funExt (λ x → inv-coe p) , funExt (λ x → inv-coe' p) ; trans = composeIso @@ -346,6 +324,11 @@ module _ {ℓ : Level} {A B : Set ℓ} where univalence : (A ≡ B) ≃ (A ≃ B) univalence = Equivalence.compose u' aux where + module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where + deEta : A ≃ B → A U.≃ B + deEta (a , b) = U.con a b + doEta : A U.≃ B → A ≃ B + doEta (U.con eqv isEqv) = eqv , isEqv u : (A ≡ B) U.≃ (A U.≃ B) u = U.univalence u' : (A ≡ B) ≃ (A U.≃ B) From 7eac677efb88fdd39f6cbf23f463fff61abd3bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 12 Apr 2018 10:05:02 +0200 Subject: [PATCH 51/93] Prove 9.1.9 --- src/Cat/Category.agda | 22 +++++++++++++++++++++- src/Cat/Equivalence.agda | 13 ++----------- src/Cat/Prelude.agda | 8 ++++++++ 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 7a764f9..e2c79dc 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -342,8 +342,28 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where pq : Arrow a b ≡ Arrow a' b' pq i = Arrow (p i) (q i) + U : ∀ b'' → b ≡ b'' → Set _ + U b'' q' = coe (λ i → Arrow a (q' i)) f ≡ fst (idToIso _ _ q') <<< f <<< (fst (snd (idToIso _ _ refl))) + u : coe (λ i → Arrow a b) f ≡ fst (idToIso _ _ refl) <<< f <<< (fst (snd (idToIso _ _ refl))) + u = begin + coe refl f ≡⟨ id-coe ⟩ + f ≡⟨ sym leftIdentity ⟩ + identity <<< f ≡⟨ sym rightIdentity ⟩ + identity <<< f <<< identity ≡⟨ cong (λ φ → identity <<< f <<< φ) lem ⟩ + identity <<< f <<< (fst (snd (idToIso _ _ refl))) ≡⟨ cong (λ φ → φ <<< f <<< (fst (snd (idToIso _ _ refl)))) lem ⟩ + fst (idToIso _ _ refl) <<< f <<< (fst (snd (idToIso _ _ refl))) ∎ + where + lem : ∀ {x} → PathP (λ _ → Arrow x x) identity (fst (idToIso x x refl)) + lem = sym (subst-neutral {P = λ x → Arrow x x}) + + D : ∀ a'' → a ≡ a'' → Set _ + D a'' p' = coe (λ i → Arrow (p' i) (q i)) f ≡ fst (idToIso b b' q) <<< f <<< (fst (snd (idToIso _ _ p'))) + + d : coe (λ i → Arrow a (q i)) f ≡ fst (idToIso b b' q) <<< f <<< (fst (snd (idToIso _ _ refl))) + d = pathJ U u b' q + 9-1-9 : coe pq f ≡ q* <<< f <<< p~ - 9-1-9 = transpP {!!} {!!} + 9-1-9 = pathJ D d a' p -- | All projections are propositions. module Propositionality where diff --git a/src/Cat/Equivalence.agda b/src/Cat/Equivalence.agda index 27e77e5..9a36a52 100644 --- a/src/Cat/Equivalence.agda +++ b/src/Cat/Equivalence.agda @@ -3,12 +3,11 @@ module Cat.Equivalence where open import Cubical.Primitives open import Cubical.FromStdLib renaming (ℓ-max to _⊔_) --- FIXME: Don't hide ≃ -open import Cubical.PathPrelude hiding (inverse ; _≃_) +open import Cubical.PathPrelude hiding (inverse) open import Cubical.PathPrelude using (isEquiv ; isContr ; fiber) public open import Cubical.GradLemma -open import Cat.Prelude using (lemPropF ; setPi ; lemSig ; propSet ; Preorder ; equalityIsEquivalence ; _≃_ ; propSig) +open import Cat.Prelude using (lemPropF ; setPi ; lemSig ; propSet ; Preorder ; equalityIsEquivalence ; propSig ; id-coe) import Cubical.Univalence as U @@ -289,14 +288,6 @@ preorder≅ ℓ = record } } where - module _ {ℓ : Level} {A : Set ℓ} {a : A} where - id-coe : coe refl a ≡ a - id-coe = begin - coe refl a ≡⟨⟩ - pathJ (λ y x → A) _ A refl ≡⟨ pathJprop {x = a} (λ y x → A) _ ⟩ - _ ≡⟨ pathJprop {x = a} (λ y x → A) _ ⟩ - a ∎ - module _ {ℓ : Level} {A B : Set ℓ} {a : A} where inv-coe : (p : A ≡ B) → coe (sym p) (coe p a) ≡ a inv-coe p = diff --git a/src/Cat/Prelude.agda b/src/Cat/Prelude.agda index a3d34a4..409549c 100644 --- a/src/Cat/Prelude.agda +++ b/src/Cat/Prelude.agda @@ -88,3 +88,11 @@ IsPreorder → (_∼_ : Rel A ℓ) -- The relation. → Set _ IsPreorder _~_ = Relation.Binary.IsPreorder _≡_ _~_ + +module _ {ℓ : Level} {A : Set ℓ} {a : A} where + id-coe : coe refl a ≡ a + id-coe = begin + coe refl a ≡⟨⟩ + pathJ (λ y x → A) _ A refl ≡⟨ pathJprop {x = a} (λ y x → A) _ ⟩ + _ ≡⟨ pathJprop {x = a} (λ y x → A) _ ⟩ + a ∎ From 7fcd8e631ae72ec48c54da77e379f94c58ae0697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 12 Apr 2018 11:21:05 +0200 Subject: [PATCH 52/93] Modified verion of 9.1.9 --- src/Cat/Category.agda | 13 +++++++++++++ src/Cat/Category/Product.agda | 9 ++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index e2c79dc..58bcc5e 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -337,6 +337,8 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where private q* : Arrow b b' q* = fst (idToIso b b' q) + p* : Arrow a a' + p* = fst (idToIso _ _ p) p~ : Arrow a' a p~ = fst (snd (idToIso _ _ p)) pq : Arrow a b ≡ Arrow a' b' @@ -365,6 +367,17 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where 9-1-9 : coe pq f ≡ q* <<< f <<< p~ 9-1-9 = pathJ D d a' p + 9-1-9' : coe pq f <<< p* ≡ q* <<< f + 9-1-9' = begin + coe pq f <<< p* ≡⟨ cong (_<<< p*) 9-1-9 ⟩ + q* <<< f <<< p~ <<< p* ≡⟨ sym isAssociative ⟩ + q* <<< f <<< (p~ <<< p*) ≡⟨ cong (λ φ → q* <<< f <<< φ) lem ⟩ + q* <<< f <<< identity ≡⟨ rightIdentity ⟩ + q* <<< f ∎ + where + lem : p~ <<< p* ≡ identity + lem = fst (snd (snd (idToIso _ _ p))) + -- | All projections are propositions. module Propositionality where -- | Terminal objects are propositional - a.k.a uniqueness of terminal diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index b8f39fb..d480ae5 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -250,11 +250,10 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} ≈ ((X , xa , xb) ≅ (Y , ya , yb)) step2 = ( λ{ ((f , f~ , inv-f) , p , q) - → ( f , (let r = fromPathP p in {!r!}) , {!!}) - , ( (f~ , {!!} , {!!}) - , lemA (fst inv-f) - , lemA (snd inv-f) - ) + → ( f , {!ℂ.9-1-9'!} , {!!}) + , ( f~ , {!!} , {!!}) + , lemA (fst inv-f) + , lemA (snd inv-f) } ) , (λ{ (f , f~ , inv-f , inv-f~) → From 5bbb40b664e136f7f72b022f27050364c2d491eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 12 Apr 2018 13:16:25 +0200 Subject: [PATCH 53/93] Make progress with univalence in product-category --- src/Cat/Category/Product.agda | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index d480ae5..8382ec2 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -250,8 +250,31 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} ≈ ((X , xa , xb) ≅ (Y , ya , yb)) step2 = ( λ{ ((f , f~ , inv-f) , p , q) - → ( f , {!ℂ.9-1-9'!} , {!!}) - , ( f~ , {!!} , {!!}) + → + let + r : X ≡ Y + r = ℂ.isoToId (f , f~ , inv-f) + r-arrow : (ℂ.Arrow X A) ≡ (ℂ.Arrow Y A) + r-arrow i = ℂ.Arrow (r i) A + t : coe r-arrow xa ≡ ℂ.identity ℂ.<<< xa ℂ.<<< f~ + t = {!? ≡ ?!} + lem : ∀ {x} → ℂ.idToIso _ _ (ℂ.isoToId x) ≡ x + lem {x} i = snd ℂ.inverse-from-to-iso' i x + h : ya ≡ xa ℂ.<<< f~ + h = begin + ya ≡⟨ {!!} ⟩ + coe r-arrow xa + ≡⟨ ℂ.9-1-9 r refl xa ⟩ + fst (ℂ.idToIso _ _ refl) ℂ.<<< xa ℂ.<<< fst (snd (ℂ.idToIso _ _ r)) + ≡⟨ cong (λ φ → φ ℂ.<<< xa ℂ.<<< fst (snd (ℂ.idToIso _ _ r))) (subst-neutral {P = λ x → ℂ.Arrow x x}) ⟩ + ℂ.identity ℂ.<<< xa ℂ.<<< fst (snd (ℂ.idToIso _ _ r)) + ≡⟨ cong (λ φ → ℂ.identity ℂ.<<< xa ℂ.<<< φ) (cong (λ x → (fst (snd x))) lem) ⟩ + ℂ.identity ℂ.<<< xa ℂ.<<< f~ + ≡⟨ cong (ℂ._<<< f~) ℂ.leftIdentity ⟩ + xa ℂ.<<< f~ ∎ + in + ( f , {!h!} , {!!}) + , ( f~ , sym h , {!!}) , lemA (fst inv-f) , lemA (snd inv-f) } From 0ced448fa66f25796cc2355084d5c58a9aaa9516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 13 Apr 2018 09:40:09 +0200 Subject: [PATCH 54/93] Progress on univalence --- src/Cat/Category.agda | 34 ++++++++++----------- src/Cat/Category/Product.agda | 57 +++++++++++++++++++++++++++++------ 2 files changed, 64 insertions(+), 27 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 58bcc5e..e1cd33d 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -344,25 +344,25 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where pq : Arrow a b ≡ Arrow a' b' pq i = Arrow (p i) (q i) - U : ∀ b'' → b ≡ b'' → Set _ - U b'' q' = coe (λ i → Arrow a (q' i)) f ≡ fst (idToIso _ _ q') <<< f <<< (fst (snd (idToIso _ _ refl))) - u : coe (λ i → Arrow a b) f ≡ fst (idToIso _ _ refl) <<< f <<< (fst (snd (idToIso _ _ refl))) - u = begin - coe refl f ≡⟨ id-coe ⟩ - f ≡⟨ sym leftIdentity ⟩ - identity <<< f ≡⟨ sym rightIdentity ⟩ - identity <<< f <<< identity ≡⟨ cong (λ φ → identity <<< f <<< φ) lem ⟩ - identity <<< f <<< (fst (snd (idToIso _ _ refl))) ≡⟨ cong (λ φ → φ <<< f <<< (fst (snd (idToIso _ _ refl)))) lem ⟩ - fst (idToIso _ _ refl) <<< f <<< (fst (snd (idToIso _ _ refl))) ∎ - where - lem : ∀ {x} → PathP (λ _ → Arrow x x) identity (fst (idToIso x x refl)) - lem = sym (subst-neutral {P = λ x → Arrow x x}) + U : ∀ b'' → b ≡ b'' → Set _ + U b'' q' = coe (λ i → Arrow a (q' i)) f ≡ fst (idToIso _ _ q') <<< f <<< (fst (snd (idToIso _ _ refl))) + u : coe (λ i → Arrow a b) f ≡ fst (idToIso _ _ refl) <<< f <<< (fst (snd (idToIso _ _ refl))) + u = begin + coe refl f ≡⟨ id-coe ⟩ + f ≡⟨ sym leftIdentity ⟩ + identity <<< f ≡⟨ sym rightIdentity ⟩ + identity <<< f <<< identity ≡⟨ cong (λ φ → identity <<< f <<< φ) lem ⟩ + identity <<< f <<< (fst (snd (idToIso _ _ refl))) ≡⟨ cong (λ φ → φ <<< f <<< (fst (snd (idToIso _ _ refl)))) lem ⟩ + fst (idToIso _ _ refl) <<< f <<< (fst (snd (idToIso _ _ refl))) ∎ + where + lem : ∀ {x} → PathP (λ _ → Arrow x x) identity (fst (idToIso x x refl)) + lem = sym subst-neutral - D : ∀ a'' → a ≡ a'' → Set _ - D a'' p' = coe (λ i → Arrow (p' i) (q i)) f ≡ fst (idToIso b b' q) <<< f <<< (fst (snd (idToIso _ _ p'))) + D : ∀ a'' → a ≡ a'' → Set _ + D a'' p' = coe (λ i → Arrow (p' i) (q i)) f ≡ fst (idToIso b b' q) <<< f <<< (fst (snd (idToIso _ _ p'))) - d : coe (λ i → Arrow a (q i)) f ≡ fst (idToIso b b' q) <<< f <<< (fst (snd (idToIso _ _ refl))) - d = pathJ U u b' q + d : coe (λ i → Arrow a (q i)) f ≡ fst (idToIso b b' q) <<< f <<< (fst (snd (idToIso _ _ refl))) + d = pathJ U u b' q 9-1-9 : coe pq f ≡ q* <<< f <<< p~ 9-1-9 = pathJ D d a' p diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 8382ec2..4a318cb 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -258,22 +258,45 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} r-arrow i = ℂ.Arrow (r i) A t : coe r-arrow xa ≡ ℂ.identity ℂ.<<< xa ℂ.<<< f~ t = {!? ≡ ?!} - lem : ∀ {x} → ℂ.idToIso _ _ (ℂ.isoToId x) ≡ x - lem {x} i = snd ℂ.inverse-from-to-iso' i x + lem : ∀ {A B} {x : A ℂ.≅ B} → ℂ.idToIso A B (ℂ.isoToId x) ≡ x + lem = λ{ {x = x} i → snd ℂ.inverse-from-to-iso' i x} + lem' : ∀ {A B} {x : A ≡ B} → ℂ.isoToId (ℂ.idToIso _ _ x) ≡ x + lem' = λ{ {x = x} i → fst ℂ.inverse-from-to-iso' i x} h : ya ≡ xa ℂ.<<< f~ h = begin - ya ≡⟨ {!!} ⟩ - coe r-arrow xa + ya ≡⟨ sym (coe-lem p) ⟩ + coe r-arrow xa ≡⟨ ℂ.9-1-9 r refl xa ⟩ fst (ℂ.idToIso _ _ refl) ℂ.<<< xa ℂ.<<< fst (snd (ℂ.idToIso _ _ r)) - ≡⟨ cong (λ φ → φ ℂ.<<< xa ℂ.<<< fst (snd (ℂ.idToIso _ _ r))) (subst-neutral {P = λ x → ℂ.Arrow x x}) ⟩ + ≡⟨ cong (λ φ → φ ℂ.<<< xa ℂ.<<< fst (snd (ℂ.idToIso _ _ r))) subst-neutral ⟩ ℂ.identity ℂ.<<< xa ℂ.<<< fst (snd (ℂ.idToIso _ _ r)) ≡⟨ cong (λ φ → ℂ.identity ℂ.<<< xa ℂ.<<< φ) (cong (λ x → (fst (snd x))) lem) ⟩ ℂ.identity ℂ.<<< xa ℂ.<<< f~ ≡⟨ cong (ℂ._<<< f~) ℂ.leftIdentity ⟩ xa ℂ.<<< f~ ∎ + complicated : Y ≡ X + complicated = (λ z → sym (ℂ.isoToId (f , f~ , inv-f)) z) in - ( f , {!h!} , {!!}) + ( f , (begin + ℂ [ ya ∘ f ] ≡⟨⟩ + ya ℂ.<<< f ≡⟨ sym ℂ.leftIdentity ⟩ + ℂ.identity ℂ.<<< (ya ℂ.<<< f) + ≡⟨ ℂ.isAssociative ⟩ + ℂ.identity ℂ.<<< ya ℂ.<<< f + ≡⟨ cong (λ φ → φ ℂ.<<< ya ℂ.<<< f) (sym subst-neutral) ⟩ + fst (ℂ.idToIso _ _ refl) ℂ.<<< ya ℂ.<<< f + ≡⟨ cong (λ φ → fst (ℂ.idToIso _ _ refl) ℂ.<<< ya ℂ.<<< φ) + (begin + f ≡⟨ {!cong (λ x → (fst (snd x))) ((lem {x = f~ , f , swap inv-f}))!} ⟩ + -- f ≡⟨ cong fst (sym (lem {f , f~ , inv-f})) ⟩ + -- fst ( ℂ.idToIso X Y ( ℂ.isoToId (f , f~ , inv-f))) ≡⟨ {!fst inv-f!} ⟩ + fst (snd (ℂ.idToIso Y X (λ z → sym (ℂ.isoToId (f , f~ , inv-f)) z))) ∎) + ⟩ + _ ℂ.<<< ya ℂ.<<< fst (snd (ℂ.idToIso _ _ _)) + ≡⟨ sym (ℂ.9-1-9 (sym r) refl ya) ⟩ + coe (sym r-arrow) ya + ≡⟨ coe-lem (λ i → p (~ i)) ⟩ + xa ∎) , {!!}) , ( f~ , sym h , {!!}) , lemA (fst inv-f) , lemA (snd inv-f) @@ -283,14 +306,28 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} let iso : X ℂ.≅ Y iso = fst f , fst f~ , cong fst inv-f , cong fst inv-f~ - helper : PathP (λ i → ℂ.Arrow (ℂ.isoToId {!!} i) A) xa ya - helper = {!!} - in iso , helper , {!!}}) + p : X ≡ Y + p = ℂ.isoToId iso + lem : xa ≡ _ + lem = begin + xa ≡⟨ sym (fst (snd f)) ⟩ + ya ℂ.<<< fst f ≡⟨ sym ℂ.leftIdentity ⟩ + ℂ.identity ℂ.<<< (ya ℂ.<<< fst f) ≡⟨ ℂ.isAssociative ⟩ + ℂ.identity ℂ.<<< ya ℂ.<<< fst f ≡⟨ {!sym (ℂ.9-1-9 ? refl ya)!} ⟩ + _ ℂ.<<< ya ℂ.<<< _ ≡⟨ sym (ℂ.9-1-9 (sym p) refl ya) ⟩ + coe (λ i → ℂ.Arrow (p (~ i)) A) ya ∎ + lem0 = begin + xa ≡⟨ {!!} ⟩ + coe _ xa ≡⟨ {!!} ⟩ + ya ℂ.<<< fst f ∎ + helper : PathP (λ i → ℂ.Arrow (p i) A) xa ya + helper = {!snd f!} + in iso , ? , {!!}}) , record { fst = funExt (λ x → lemSig (λ x → propSig prop0 (λ _ → prop1)) _ _ - (Σ≡ {!!} (ℂ.propIsomorphism _ _ _))) + (Σ≡ {!ℂ!} (ℂ.propIsomorphism _ _ _))) ; snd = funExt (λ{ (f , _) → lemSig propIsomorphism _ _ {!refl!}}) } where From e25ef31907dc7d01f7529795deb2e808e1149138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 13 Apr 2018 13:24:17 +0200 Subject: [PATCH 55/93] Construct the morphism for equivalence 2 I must still show that they are inverses. --- src/Cat/Category.agda | 57 +++++++++++++++++++++++ src/Cat/Category/Product.agda | 86 ++++++++--------------------------- 2 files changed, 77 insertions(+), 66 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index e1cd33d..9e51447 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -327,6 +327,7 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where asTypeIso : TypeIsomorphism (idToIso A B) asTypeIso = toIso _ _ univalent + -- FIXME Rename inverse-from-to-iso' : AreInverses (idToIso A B) isoToId inverse-from-to-iso' = snd iso @@ -377,6 +378,62 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where where lem : p~ <<< p* ≡ identity lem = fst (snd (snd (idToIso _ _ p))) + module _ {A B X : Object} (iso : A ≅ B) where + private + p : A ≡ B + p = isoToId iso + p-dom : Arrow A X ≡ Arrow B X + p-dom = cong (λ x → Arrow x X) p + p-cod : Arrow X A ≡ Arrow X B + p-cod = cong (λ x → Arrow X x) p + lem : ∀ {A B} {x : A ≅ B} → idToIso A B (isoToId x) ≡ x + lem {x = x} i = snd inverse-from-to-iso' i x + + open Σ iso renaming (fst to ι) using () + open Σ (snd iso) renaming (fst to ι~ ; snd to inv) + + coe-dom : {f : Arrow A X} → coe p-dom f ≡ f <<< ι~ + coe-dom {f} = begin + coe p-dom f + ≡⟨ 9-1-9 p refl f ⟩ + fst (idToIso _ _ refl) <<< f <<< fst (snd (idToIso _ _ p)) + ≡⟨ cong (λ φ → φ <<< f <<< fst (snd (idToIso _ _ p))) subst-neutral ⟩ + identity <<< f <<< fst (snd (idToIso _ _ p)) + ≡⟨ cong (λ φ → identity <<< f <<< φ) (cong (λ x → (fst (snd x))) lem) ⟩ + identity <<< f <<< ι~ + ≡⟨ cong (_<<< ι~) leftIdentity ⟩ + f <<< ι~ ∎ + + coe-cod : {f : Arrow X A} → coe p-cod f ≡ ι <<< f + coe-cod {f} = begin + coe p-cod f + ≡⟨ 9-1-9 refl p f ⟩ + fst (idToIso _ _ p) <<< f <<< fst (snd (idToIso _ _ refl)) + ≡⟨ cong (λ φ → fst (idToIso _ _ p) <<< f <<< φ) subst-neutral ⟩ + fst (idToIso _ _ p) <<< f <<< identity + ≡⟨ cong (λ φ → φ <<< f <<< identity) (cong fst lem) ⟩ + ι <<< f <<< identity + ≡⟨ sym isAssociative ⟩ + ι <<< (f <<< identity) + ≡⟨ cong (ι <<<_) rightIdentity ⟩ + ι <<< f ∎ + + module _ {f : Arrow A X} {g : Arrow B X} (q : PathP (λ i → p-dom i) f g) where + domain-twist : g ≡ f <<< ι~ + domain-twist = begin + g ≡⟨ sym (coe-lem q) ⟩ + coe p-dom f ≡⟨ coe-dom ⟩ + f <<< ι~ ∎ + + -- This can probably also just be obtained from the above my taking the + -- symmetric isomorphism. + domain-twist0 : f ≡ g <<< ι + domain-twist0 = begin + f ≡⟨ sym rightIdentity ⟩ + f <<< identity ≡⟨ cong (f <<<_) (sym (fst inv)) ⟩ + f <<< (ι~ <<< ι) ≡⟨ isAssociative ⟩ + f <<< ι~ <<< ι ≡⟨ cong (_<<< ι) (sym domain-twist) ⟩ + g <<< ι ∎ -- | All projections are propositions. module Propositionality where diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 4a318cb..8a91642 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -238,7 +238,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} -- I have `φ p` in scope, but surely `p` and `x` are the same - though -- perhaps not definitonally. , (λ{ (iso , x) → ℂ.isoToId iso , x}) - , funExt (λ{ (p , q , r) → Σ≡ (sym iso-id-inv) (toPathP {A = λ i → {!!}} {!!})}) + , funExt (λ{ (p , q , r) → Σ≡ (sym iso-id-inv) {!!}}) , funExt (λ x → Σ≡ (sym id-iso-inv) {!!}) step2 : Σ (X ℂ.≅ Y) (λ iso @@ -249,55 +249,9 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} ) ≈ ((X , xa , xb) ≅ (Y , ya , yb)) step2 - = ( λ{ ((f , f~ , inv-f) , p , q) - → - let - r : X ≡ Y - r = ℂ.isoToId (f , f~ , inv-f) - r-arrow : (ℂ.Arrow X A) ≡ (ℂ.Arrow Y A) - r-arrow i = ℂ.Arrow (r i) A - t : coe r-arrow xa ≡ ℂ.identity ℂ.<<< xa ℂ.<<< f~ - t = {!? ≡ ?!} - lem : ∀ {A B} {x : A ℂ.≅ B} → ℂ.idToIso A B (ℂ.isoToId x) ≡ x - lem = λ{ {x = x} i → snd ℂ.inverse-from-to-iso' i x} - lem' : ∀ {A B} {x : A ≡ B} → ℂ.isoToId (ℂ.idToIso _ _ x) ≡ x - lem' = λ{ {x = x} i → fst ℂ.inverse-from-to-iso' i x} - h : ya ≡ xa ℂ.<<< f~ - h = begin - ya ≡⟨ sym (coe-lem p) ⟩ - coe r-arrow xa - ≡⟨ ℂ.9-1-9 r refl xa ⟩ - fst (ℂ.idToIso _ _ refl) ℂ.<<< xa ℂ.<<< fst (snd (ℂ.idToIso _ _ r)) - ≡⟨ cong (λ φ → φ ℂ.<<< xa ℂ.<<< fst (snd (ℂ.idToIso _ _ r))) subst-neutral ⟩ - ℂ.identity ℂ.<<< xa ℂ.<<< fst (snd (ℂ.idToIso _ _ r)) - ≡⟨ cong (λ φ → ℂ.identity ℂ.<<< xa ℂ.<<< φ) (cong (λ x → (fst (snd x))) lem) ⟩ - ℂ.identity ℂ.<<< xa ℂ.<<< f~ - ≡⟨ cong (ℂ._<<< f~) ℂ.leftIdentity ⟩ - xa ℂ.<<< f~ ∎ - complicated : Y ≡ X - complicated = (λ z → sym (ℂ.isoToId (f , f~ , inv-f)) z) - in - ( f , (begin - ℂ [ ya ∘ f ] ≡⟨⟩ - ya ℂ.<<< f ≡⟨ sym ℂ.leftIdentity ⟩ - ℂ.identity ℂ.<<< (ya ℂ.<<< f) - ≡⟨ ℂ.isAssociative ⟩ - ℂ.identity ℂ.<<< ya ℂ.<<< f - ≡⟨ cong (λ φ → φ ℂ.<<< ya ℂ.<<< f) (sym subst-neutral) ⟩ - fst (ℂ.idToIso _ _ refl) ℂ.<<< ya ℂ.<<< f - ≡⟨ cong (λ φ → fst (ℂ.idToIso _ _ refl) ℂ.<<< ya ℂ.<<< φ) - (begin - f ≡⟨ {!cong (λ x → (fst (snd x))) ((lem {x = f~ , f , swap inv-f}))!} ⟩ - -- f ≡⟨ cong fst (sym (lem {f , f~ , inv-f})) ⟩ - -- fst ( ℂ.idToIso X Y ( ℂ.isoToId (f , f~ , inv-f))) ≡⟨ {!fst inv-f!} ⟩ - fst (snd (ℂ.idToIso Y X (λ z → sym (ℂ.isoToId (f , f~ , inv-f)) z))) ∎) - ⟩ - _ ℂ.<<< ya ℂ.<<< fst (snd (ℂ.idToIso _ _ _)) - ≡⟨ sym (ℂ.9-1-9 (sym r) refl ya) ⟩ - coe (sym r-arrow) ya - ≡⟨ coe-lem (λ i → p (~ i)) ⟩ - xa ∎) , {!!}) - , ( f~ , sym h , {!!}) + = ( λ{ (iso@(f , f~ , inv-f) , p , q) + → ( f , sym (ℂ.domain-twist0 iso p) , sym (ℂ.domain-twist0 iso q)) + , ( f~ , sym (ℂ.domain-twist iso p) , sym (ℂ.domain-twist iso q)) , lemA (fst inv-f) , lemA (snd inv-f) } @@ -308,26 +262,26 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} iso = fst f , fst f~ , cong fst inv-f , cong fst inv-f~ p : X ≡ Y p = ℂ.isoToId iso - lem : xa ≡ _ - lem = begin - xa ≡⟨ sym (fst (snd f)) ⟩ - ya ℂ.<<< fst f ≡⟨ sym ℂ.leftIdentity ⟩ - ℂ.identity ℂ.<<< (ya ℂ.<<< fst f) ≡⟨ ℂ.isAssociative ⟩ - ℂ.identity ℂ.<<< ya ℂ.<<< fst f ≡⟨ {!sym (ℂ.9-1-9 ? refl ya)!} ⟩ - _ ℂ.<<< ya ℂ.<<< _ ≡⟨ sym (ℂ.9-1-9 (sym p) refl ya) ⟩ - coe (λ i → ℂ.Arrow (p (~ i)) A) ya ∎ - lem0 = begin - xa ≡⟨ {!!} ⟩ - coe _ xa ≡⟨ {!!} ⟩ - ya ℂ.<<< fst f ∎ - helper : PathP (λ i → ℂ.Arrow (p i) A) xa ya - helper = {!snd f!} - in iso , ? , {!!}}) + pA : ℂ.Arrow X A ≡ ℂ.Arrow Y A + pA = cong (λ x → ℂ.Arrow x A) p + pB : ℂ.Arrow X B ≡ ℂ.Arrow Y B + pB = cong (λ x → ℂ.Arrow x B) p + k0 = begin + coe pB xb ≡⟨ ℂ.coe-dom iso ⟩ + xb ℂ.<<< fst f~ ≡⟨ snd (snd f~) ⟩ + yb ∎ + k1 = begin + coe pA xa ≡⟨ ℂ.coe-dom iso ⟩ + xa ℂ.<<< fst f~ ≡⟨ fst (snd f~) ⟩ + ya ∎ + helper : PathP (λ i → pA i) xa ya + helper = coe-lem-inv k1 + in iso , coe-lem-inv k1 , coe-lem-inv k0}) , record { fst = funExt (λ x → lemSig (λ x → propSig prop0 (λ _ → prop1)) _ _ - (Σ≡ {!ℂ!} (ℂ.propIsomorphism _ _ _))) + (Σ≡ {!!} (ℂ.propIsomorphism _ _ _))) ; snd = funExt (λ{ (f , _) → lemSig propIsomorphism _ _ {!refl!}}) } where From c1f58b1a4f2acf5145736ae2a59f603a21d65c2a Mon Sep 17 00:00:00 2001 From: Andrea Vezzosi Date: Fri, 13 Apr 2018 14:18:28 +0200 Subject: [PATCH 56/93] univalence in product-category step1 --- src/Cat/Category/Product.agda | 30 ++++-------------------------- src/Cat/Equivalence.agda | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 8a91642..dcb200a 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -214,32 +214,10 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} × PathP (λ i → ℂ.Arrow (p i) B) xb yb ) step1 - = (λ{ (p , x) - → (ℂ.idToIso _ _ p) - , let - P-l : (p : X ≡ Y) → Set _ - P-l φ = PathP (λ i → ℂ.Arrow (φ i) A) xa ya - P-r : (p : X ≡ Y) → Set _ - P-r φ = PathP (λ i → ℂ.Arrow (φ i) B) xb yb - left : P-l p - left = fst x - right : P-r p - right = snd x - in subst {P = P-l} iso-id-inv left , subst {P = P-r} iso-id-inv right - }) - -- Goal is: - -- - -- φ x - -- - -- where `x` is - -- - -- ℂ.isoToId (ℂ.idToIso _ _ p) - -- - -- I have `φ p` in scope, but surely `p` and `x` are the same - though - -- perhaps not definitonally. - , (λ{ (iso , x) → ℂ.isoToId iso , x}) - , funExt (λ{ (p , q , r) → Σ≡ (sym iso-id-inv) {!!}}) - , funExt (λ x → Σ≡ (sym id-iso-inv) {!!}) + = symIso + (isoSigFst {A = (X ℂ.≅ Y)} {B = (X ≡ Y)} {!!} {Q = \ p → (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)} ℂ.isoToId + (symIso (_ , ℂ.asTypeIso {X} {Y}) .snd)) + step2 : Σ (X ℂ.≅ Y) (λ iso → let p = ℂ.isoToId iso diff --git a/src/Cat/Equivalence.agda b/src/Cat/Equivalence.agda index 9a36a52..2972c2b 100644 --- a/src/Cat/Equivalence.agda +++ b/src/Cat/Equivalence.agda @@ -39,6 +39,23 @@ module _ {ℓa ℓb : Level} where _≅_ : Set ℓa → Set ℓb → Set _ A ≅ B = Σ (A → B) Isomorphism +symIso : ∀ {ℓa ℓb} {A : Set ℓa}{B : Set ℓb} → A ≅ B → B ≅ A +symIso (f , g , p , q)= g , f , q , p + +module _ {ℓa ℓb ℓc} {A : Set ℓa} {B : Set ℓb} (sB : isSet B) {Q : B → Set ℓc} (f : A → B) where + + Σ-fst-map : Σ A (\ a → Q (f a)) → Σ B Q + Σ-fst-map (x , q) = f x , q + + isoSigFst : Isomorphism f → Σ A (\ a → Q (f a)) ≅ (Σ B Q) + isoSigFst (g , g-f , f-g) = Σ-fst-map + , (\ { (b , q) → g b , transp (\ i → Q (f-g (~ i) b)) q }) + , funExt (\ { (a , q) → Cat.Prelude.Σ≡ (\ i → g-f i a) + let r = (transp-iso' ((λ i → Q (f-g (i) (f a)))) q) in + transp (\ i → PathP (\ j → Q (sB _ _ (λ j₁ → f-g j₁ (f a)) (λ j₁ → f (g-f j₁ a)) i j)) (transp (λ i₁ → Q (f-g (~ i₁) (f a))) q) q) r }) + , funExt (\ { (b , q) → Cat.Prelude.Σ≡ (\ i → f-g i b) (transp-iso' (λ i → Q (f-g i b)) q)}) + + module _ {ℓ : Level} {A B : Set ℓ} {f : A → B} (g : B → A) (s : {A B : Set ℓ} → isSet (A → B)) where From 6023a49da6a08d9c58312c08bca239944f928e5e Mon Sep 17 00:00:00 2001 From: Andrea Vezzosi Date: Fri, 13 Apr 2018 14:35:10 +0200 Subject: [PATCH 57/93] Category.Product: get rid of the yellow --- src/Cat/Category/Product.agda | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index dcb200a..86dd336 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -189,9 +189,9 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} -- Should follow from c being univalent iso-id-inv : {p : X ≡ Y} → p ≡ ℂ.isoToId (ℂ.idToIso X Y p) - iso-id-inv {p} = sym (λ i → AreInverses.verso-recto ℂ.inverse-from-to-iso' i p) + iso-id-inv {p} = sym (λ i → fst (ℂ.inverse-from-to-iso' {X} {Y}) i p) id-iso-inv : {iso : X ℂ.≅ Y} → iso ≡ ℂ.idToIso X Y (ℂ.isoToId iso) - id-iso-inv {iso} = sym (λ i → AreInverses.recto-verso ℂ.inverse-from-to-iso' i iso) + id-iso-inv {iso} = sym (λ i → snd (ℂ.inverse-from-to-iso' {X} {Y}) i iso) lemA : {A B : Object} {f g : Arrow A B} → fst f ≡ fst g → f ≡ g lemA {A} {B} {f = f} {g} p i = p i , h i From 5afa835787b4709748fcaeafa6a2f26b9baf821e Mon Sep 17 00:00:00 2001 From: Andrea Vezzosi Date: Fri, 13 Apr 2018 14:35:54 +0200 Subject: [PATCH 58/93] Category.Product complete step2 --- src/Cat/Category/Product.agda | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 86dd336..e738a16 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -125,10 +125,11 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} private open RawCategory raw - propEqs : ∀ {X' : Object}{Y' : Object} (let X , xa , xb = X') (let Y , ya , yb = Y') + propEqs : ∀ {X' : Object}{Y' : Object} (let X , xa , xb = X') (let Y , ya , yb = Y') → (xy : ℂ.Arrow X Y) → isProp (ℂ [ ya ∘ xy ] ≡ xa × ℂ [ yb ∘ xy ] ≡ xb) - propEqs xs = propSig (ℂ.arrowsAreSets _ _) (\ _ → ℂ.arrowsAreSets _ _) + propEqs xs = propSig (ℂ.arrowsAreSets _ _) (\ _ → ℂ.arrowsAreSets _ _) + private isAssociative : IsAssociative isAssociative {A'@(A , a0 , a1)} {B , _} {C , c0 , c1} {D'@(D , d0 , d1)} {ff@(f , f0 , f1)} {gg@(g , g0 , g1)} {hh@(h , h0 , h1)} i = s0 i , lemPropF propEqs s0 {P.snd l} {P.snd r} i @@ -259,8 +260,8 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} { fst = funExt (λ x → lemSig (λ x → propSig prop0 (λ _ → prop1)) _ _ - (Σ≡ {!!} (ℂ.propIsomorphism _ _ _))) - ; snd = funExt (λ{ (f , _) → lemSig propIsomorphism _ _ {!refl!}}) + (Σ≡ refl (ℂ.propIsomorphism _ _ _))) + ; snd = funExt (λ{ (f , _) → lemSig propIsomorphism _ _ (Σ≡ refl (propEqs _ _ _))}) } where prop0 : ∀ {x} → isProp (PathP (λ i → ℂ.Arrow (ℂ.isoToId x i) A) xa ya) From 7b45b5cdc36afdc1871a3d830c3dd156fc360e61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 13 Apr 2018 15:22:13 +0200 Subject: [PATCH 59/93] Show that objects are groupoids --- src/Cat/Category.agda | 14 ++++++++++ src/Cat/Category/Product.agda | 10 +++++-- src/Cat/Prelude.agda | 4 ++- src/Cat/Wishlist.agda | 49 ++++++++++++++++++----------------- 4 files changed, 50 insertions(+), 27 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 9e51447..aa77c28 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -496,6 +496,20 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where res : Xi ≡ Yi res = lemSig propIsInitial _ _ (isoToId iso) + groupoidObject : isGrpd Object + groupoidObject A B = res + where + open import Data.Nat using (_≤_ ; z≤n ; s≤s) + setIso : ∀ x → isSet (Isomorphism x) + setIso x = ntypeCommulative ((s≤s {n = 1} z≤n)) (propIsomorphism x) + step : isSet (A ≅ B) + step = setSig {sA = arrowsAreSets} {sB = setIso} + res : isSet (A ≡ B) + res = equivPreservesNType + {A = A ≅ B} {B = A ≡ B} {n = ⟨0⟩} + (Equivalence.symmetry (univalent≃ {A = A} {B})) + step + module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where open RawCategory ℂ open Univalence diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index e738a16..5286976 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -216,8 +216,14 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} ) step1 = symIso - (isoSigFst {A = (X ℂ.≅ Y)} {B = (X ≡ Y)} {!!} {Q = \ p → (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)} ℂ.isoToId - (symIso (_ , ℂ.asTypeIso {X} {Y}) .snd)) + (isoSigFst + {A = (X ℂ.≅ Y)} + {B = (X ≡ Y)} + (ℂ.groupoidObject _ _) + {Q = \ p → (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)} + ℂ.isoToId + (symIso (_ , ℂ.asTypeIso {X} {Y}) .snd) + ) step2 : Σ (X ℂ.≅ Y) (λ iso diff --git a/src/Cat/Prelude.agda b/src/Cat/Prelude.agda index 409549c..55f031c 100644 --- a/src/Cat/Prelude.agda +++ b/src/Cat/Prelude.agda @@ -21,7 +21,7 @@ open import Cubical.GradLemma using (gradLemma) public open import Cubical.NType - using (⟨-2⟩ ; ⟨-1⟩ ; ⟨0⟩ ; TLevel ; HasLevel) + using (⟨-2⟩ ; ⟨-1⟩ ; ⟨0⟩ ; TLevel ; HasLevel ; isGrpd) public open import Cubical.NType.Properties using @@ -96,3 +96,5 @@ module _ {ℓ : Level} {A : Set ℓ} {a : A} where pathJ (λ y x → A) _ A refl ≡⟨ pathJprop {x = a} (λ y x → A) _ ⟩ _ ≡⟨ pathJprop {x = a} (λ y x → A) _ ⟩ a ∎ + +open import Cat.Wishlist public diff --git a/src/Cat/Wishlist.agda b/src/Cat/Wishlist.agda index 8385afd..a0c8a26 100644 --- a/src/Cat/Wishlist.agda +++ b/src/Cat/Wishlist.agda @@ -9,31 +9,32 @@ open import Agda.Builtin.Sigma open import Cubical.NType.Properties -step : ∀ {ℓ} {A : Set ℓ} → isContr A → (x y : A) → isContr (x ≡ y) -step (a , contr) x y = {!p , c!} - -- where - -- p : x ≡ y - -- p = begin - -- x ≡⟨ sym (contr x) ⟩ - -- a ≡⟨ contr y ⟩ - -- y ∎ - -- c : (q : x ≡ y) → p ≡ q - -- c q i j = contr (p {!!}) {!!} +private + step : ∀ {ℓ} {A : Set ℓ} → isContr A → (x y : A) → isContr (x ≡ y) + step (a , contr) x y = {!p , c!} + -- where + -- p : x ≡ y + -- p = begin + -- x ≡⟨ sym (contr x) ⟩ + -- a ≡⟨ contr y ⟩ + -- y ∎ + -- c : (q : x ≡ y) → p ≡ q + -- c q i j = contr (p {!!}) {!!} --- Contractible types have any given homotopy level. -contrInitial : {ℓ : Level} {A : Set ℓ} → ∀ n → isContr A → HasLevel n A -contrInitial ⟨-2⟩ contr = contr --- lem' (S ⟨-2⟩) (a , contr) = {!step!} -contrInitial (S ⟨-2⟩) (a , contr) x y = begin - x ≡⟨ sym (contr x) ⟩ - a ≡⟨ contr y ⟩ - y ∎ -contrInitial (S (S n)) contr x y = {!lvl!} -- Why is this not well-founded? - where - c : isContr (x ≡ y) - c = step contr x y - lvl : HasLevel (S n) (x ≡ y) - lvl = contrInitial {A = x ≡ y} (S n) c + -- Contractible types have any given homotopy level. + contrInitial : {ℓ : Level} {A : Set ℓ} → ∀ n → isContr A → HasLevel n A + contrInitial ⟨-2⟩ contr = contr + -- lem' (S ⟨-2⟩) (a , contr) = {!step!} + contrInitial (S ⟨-2⟩) (a , contr) x y = begin + x ≡⟨ sym (contr x) ⟩ + a ≡⟨ contr y ⟩ + y ∎ + contrInitial (S (S n)) contr x y = {!lvl!} -- Why is this not well-founded? + where + c : isContr (x ≡ y) + c = step contr x y + lvl : HasLevel (S n) (x ≡ y) + lvl = contrInitial {A = x ≡ y} (S n) c module _ {ℓ : Level} {A : Set ℓ} where ntypeCommulative : ∀ {n m} → n ≤ m → HasLevel ⟨ n ⟩₋₂ A → HasLevel ⟨ m ⟩₋₂ A From 6b7d66b7fc936fe3674b2fd9fa790bd0e3fec12f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 13 Apr 2018 15:26:46 +0200 Subject: [PATCH 60/93] Formatting --- src/Cat/Category/Product.agda | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 5286976..e08d7c9 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -122,8 +122,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} } module _ where - private - open RawCategory raw + open RawCategory raw propEqs : ∀ {X' : Object}{Y' : Object} (let X , xa , xb = X') (let Y , ya , yb = Y') → (xy : ℂ.Arrow X Y) → isProp (ℂ [ ya ∘ xy ] ≡ xa × ℂ [ yb ∘ xy ] ≡ xb) @@ -262,13 +261,11 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} helper : PathP (λ i → pA i) xa ya helper = coe-lem-inv k1 in iso , coe-lem-inv k1 , coe-lem-inv k0}) - , record - { fst = funExt (λ x → lemSig + , funExt (λ x → lemSig (λ x → propSig prop0 (λ _ → prop1)) _ _ (Σ≡ refl (ℂ.propIsomorphism _ _ _))) - ; snd = funExt (λ{ (f , _) → lemSig propIsomorphism _ _ (Σ≡ refl (propEqs _ _ _))}) - } + , funExt (λ{ (f , _) → lemSig propIsomorphism _ _ (Σ≡ refl (propEqs _ _ _))}) where prop0 : ∀ {x} → isProp (PathP (λ i → ℂ.Arrow (ℂ.isoToId x i) A) xa ya) prop0 {x} = pathJ (λ y p → ∀ x → isProp (PathP (λ i → ℂ.Arrow (p i) A) xa x)) (λ x → ℂ.arrowsAreSets _ _) Y (ℂ.isoToId x) ya From b7c0fe64cf9700d3d9691c836295be03378ba8a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 13 Apr 2018 15:30:20 +0200 Subject: [PATCH 61/93] Remove work-in-progress for functors --- src/Cat/Categories/Fun.agda | 153 ++---------------------------------- 1 file changed, 7 insertions(+), 146 deletions(-) diff --git a/src/Cat/Categories/Fun.agda b/src/Cat/Categories/Fun.agda index da71f2c..07e2263 100644 --- a/src/Cat/Categories/Fun.agda +++ b/src/Cat/Categories/Fun.agda @@ -33,152 +33,13 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C open IsPreCategory isPreCategory hiding (identity) - module _ (F : Functor ℂ 𝔻) where - center : Σ[ G ∈ Object ] (F ≅ G) - center = F , idToIso F F refl - - open Σ center renaming (snd to isoF) - - module _ (cG : Σ[ G ∈ Object ] (F ≅ G)) where - open Σ cG renaming (fst to G ; snd to isoG) - module G = Functor G - open Σ isoG renaming (fst to θNT ; snd to invθNT) - open Σ invθNT renaming (fst to ηNT ; snd to areInv) - open Σ θNT renaming (fst to θ ; snd to θN) - open Σ ηNT renaming (fst to η ; snd to ηN) - open Σ areInv renaming (fst to ve-re ; snd to re-ve) - - -- f ~ Transformation G G - -- f : (X : ℂ.Object) → 𝔻 [ G.omap X , G.omap X ] - -- f X = T[ θ ∘ η ] X - -- g = T[ η ∘ θ ] {!!} - - ntF : NaturalTransformation F F - ntF = identity F - - ntG : NaturalTransformation G G - ntG = identity G - - idFunctor = Functors.identity - - -- Dunno if this is the way to go, but if I can construct a an inverse of - -- G that is also inverse of F (possibly by being propositionally equal to - -- another functor F~) - postulate - G~ : Functor 𝔻 ℂ - F~ : Functor 𝔻 ℂ - F~ = G~ - postulate - prop0 : F[ G~ ∘ G ] ≡ idFunctor - prop1 : F[ F ∘ G~ ] ≡ idFunctor - - lem : F[ F ∘ F~ ] ≡ idFunctor - lem = begin - F[ F ∘ F~ ] ≡⟨⟩ - F[ F ∘ G~ ] ≡⟨ prop1 ⟩ - idFunctor ∎ - - p0 : F ≡ G - p0 = begin - F ≡⟨ sym Functors.rightIdentity ⟩ - F[ F ∘ idFunctor ] ≡⟨ cong (λ φ → F[ F ∘ φ ]) (sym prop0) ⟩ - F[ F ∘ F[ G~ ∘ G ] ] ≡⟨ Functors.isAssociative {F = G} {G = G~} {H = F} ⟩ - F[ F[ F ∘ G~ ] ∘ G ] ≡⟨⟩ - F[ F[ F ∘ F~ ] ∘ G ] ≡⟨ cong (λ φ → F[ φ ∘ G ]) lem ⟩ - F[ idFunctor ∘ G ] ≡⟨ Functors.leftIdentity ⟩ - G ∎ - - p1 : (λ i → Σ (Arrow F (p0 i)) (Isomorphism {A = F} {B = p0 i})) [ isoF ≡ isoG ] - p1 = {!!} - - isContractible : (F , isoF) ≡ (G , isoG) - isContractible i = p0 i , p1 i - - univalent[Contr] : isContr (Σ[ G ∈ Object ] (F ≅ G)) - univalent[Contr] = center , isContractible - - module _ {A B : Functor ℂ 𝔻} where - module A = Functor A - module B = Functor B - module _ (p : A ≡ B) where - omapP : A.omap ≡ B.omap - omapP i = Functor.omap (p i) - - coerceAB : ∀ {X} → 𝔻 [ A.omap X , A.omap X ] ≡ 𝔻 [ A.omap X , B.omap X ] - coerceAB {X} = cong (λ φ → 𝔻 [ A.omap X , φ X ]) omapP - - -- The transformation will be the identity on 𝔻. Such an arrow has the - -- type `A.omap A → A.omap A`. Which we can coerce to have the type - -- `A.omap → B.omap` since `A` and `B` are equal. - coeidentity : Transformation A B - coeidentity X = coe coerceAB 𝔻.identity - - module _ {a b : ℂ.Object} (f : ℂ [ a , b ]) where - nat' : 𝔻 [ coeidentity b ∘ A.fmap f ] ≡ 𝔻 [ B.fmap f ∘ coeidentity a ] - nat' = begin - (𝔻 [ coeidentity b ∘ A.fmap f ]) ≡⟨ {!!} ⟩ - (𝔻 [ B.fmap f ∘ coeidentity a ]) ∎ - - transs : (i : I) → Transformation A (p i) - transs = {!!} - - natt : (i : I) → Natural A (p i) {!!} - natt = {!!} - - t : Natural A B coeidentity - t = coe c (identityNatural A) - where - c : Natural A A (identityTrans A) ≡ Natural A B coeidentity - c = begin - Natural A A (identityTrans A) ≡⟨ (λ x → {!natt ?!}) ⟩ - Natural A B coeidentity ∎ - -- cong (λ φ → {!Natural A A (identityTrans A)!}) {!!} - - k : Natural A A (identityTrans A) → Natural A B coeidentity - k n {a} {b} f = res - where - res : (𝔻 [ coeidentity b ∘ A.fmap f ]) ≡ (𝔻 [ B.fmap f ∘ coeidentity a ]) - res = {!!} - - nat : Natural A B coeidentity - nat = nat' - - fromEq : NaturalTransformation A B - fromEq = coeidentity , nat - - module _ {A B : Functor ℂ 𝔻} where - obverse : A ≡ B → A ≅ B - obverse p = res - where - ob : Arrow A B - ob = fromEq p - re : Arrow B A - re = fromEq (sym p) - vr : _<<<_ {A = A} {B} {A} re ob ≡ identity A - vr = {!!} - rv : _<<<_ {A = B} {A} {B} ob re ≡ identity B - rv = {!!} - isInverse : IsInverseOf {A} {B} ob re - isInverse = vr , rv - iso : Isomorphism {A} {B} ob - iso = re , isInverse - res : A ≅ B - res = ob , iso - - reverse : A ≅ B → A ≡ B - reverse iso = {!!} - - ve-re : (y : A ≅ B) → obverse (reverse y) ≡ y - ve-re = {!!} - - re-ve : (x : A ≡ B) → reverse (obverse x) ≡ x - re-ve = {!!} - - done : isEquiv (A ≡ B) (A ≅ B) (idToIso A B) - done = {!gradLemma obverse reverse ve-re re-ve!} - - univalent : Univalent - univalent = {!done!} + -- There used to be some work-in-progress on this theorem, please go back to + -- this point in time to see it: + -- + -- commit 6b7d66b7fc936fe3674b2fd9fa790bd0e3fec12f + -- Author: Frederik Hanghøj Iversen + -- Date: Fri Apr 13 15:26:46 2018 +0200 + postulate univalent : Univalent isCategory : IsCategory raw IsCategory.isPreCategory isCategory = isPreCategory From 98b90f2370abbb386c8b2bc66c3deb4beeee9561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 13 Apr 2018 15:35:56 +0200 Subject: [PATCH 62/93] Clean-up names a bit --- src/Cat/Categories/Sets.agda | 2 +- src/Cat/Category.agda | 28 +++++++++++++--------------- src/Cat/Category/Product.agda | 4 ++-- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/Cat/Categories/Sets.agda b/src/Cat/Categories/Sets.agda index 97afcd4..31d6926 100644 --- a/src/Cat/Categories/Sets.agda +++ b/src/Cat/Categories/Sets.agda @@ -129,7 +129,7 @@ module _ (ℓ : Level) where univ≃ = step2 ⊙ univalence ⊙ step0 univalent : Univalent - univalent = from[Andrea] (λ _ _ → univ≃) + univalent = univalenceFrom≃ univ≃ SetsIsCategory : IsCategory SetsRaw IsCategory.isPreCategory SetsIsCategory = isPreCat diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index aa77c28..3cc5068 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -130,25 +130,23 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where -- A perhaps more readable version of univalence: Univalent≃ = {A B : Object} → (A ≡ B) ≃ (A ≅ B) - -- | Equivalent formulation of univalence. - Univalent[Contr] : Set _ - Univalent[Contr] = ∀ A → isContr (Σ[ X ∈ Object ] A ≅ X) + private + -- | Equivalent formulation of univalence. + Univalent[Contr] : Set _ + Univalent[Contr] = ∀ A → isContr (Σ[ X ∈ Object ] A ≅ X) - Univalent[Andrea] : Set _ - Univalent[Andrea] = ∀ A B → (A ≡ B) ≃ (A ≅ B) + -- From: Thierry Coquand + -- Date: Wed, Mar 21, 2018 at 3:12 PM + -- + -- This is not so straight-forward so you can assume it + postulate from[Contr] : Univalent[Contr] → Univalent - -- From: Thierry Coquand - -- Date: Wed, Mar 21, 2018 at 3:12 PM - -- - -- This is not so straight-forward so you can assume it - postulate from[Contr] : Univalent[Contr] → Univalent - - from[Andrea] : Univalent[Andrea] → Univalent - from[Andrea] = from[Contr] ∘ step + univalenceFrom≃ : Univalent≃ → Univalent + univalenceFrom≃ = from[Contr] ∘ step where - module _ (f : Univalent[Andrea]) (A : Object) where + module _ (f : Univalent≃) (A : Object) where lem : Σ Object (A ≡_) ≃ Σ Object (A ≅_) - lem = equivSig (f A) + lem = equivSig λ _ → f aux : isContr (Σ Object (A ≡_)) aux = (A , refl) , (λ y → contrSingl (snd y)) diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index e08d7c9..0a2ed8b 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -171,7 +171,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} open IsPreCategory isPreCat - module _ (𝕏 𝕐 : Object) where + module _ {𝕏 𝕐 : Object} where open Σ 𝕏 renaming (fst to X ; snd to x) open Σ x renaming (fst to xa ; snd to xb) open Σ 𝕐 renaming (fst to Y ; snd to y) @@ -286,7 +286,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} equiv1 = _ , fromIso _ _ (snd iso) univalent : Univalent - univalent = from[Andrea] equiv1 + univalent = univalenceFrom≃ equiv1 isCat : IsCategory raw IsCategory.isPreCategory isCat = isPreCat From 92fb53098abc56db1bf056daf3a815ae1ae08adc Mon Sep 17 00:00:00 2001 From: Andrea Vezzosi Date: Sun, 15 Apr 2018 13:49:46 +0200 Subject: [PATCH 63/93] Implemented ntypeCumulative --- src/Cat/Category.agda | 4 +-- src/Cat/Category/NaturalTransformation.agda | 6 ++-- src/Cat/Wishlist.agda | 36 +++------------------ 3 files changed, 10 insertions(+), 36 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 3cc5068..a821a37 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -497,9 +497,9 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where groupoidObject : isGrpd Object groupoidObject A B = res where - open import Data.Nat using (_≤_ ; z≤n ; s≤s) + open import Data.Nat using (_≤_ ; ≤′-refl ; ≤′-step) setIso : ∀ x → isSet (Isomorphism x) - setIso x = ntypeCommulative ((s≤s {n = 1} z≤n)) (propIsomorphism x) + setIso x = ntypeCumulative {n = 1} (≤′-step ≤′-refl) (propIsomorphism x) step : isSet (A ≅ B) step = setSig {sA = arrowsAreSets} {sB = setIso} res : isSet (A ≡ B) diff --git a/src/Cat/Category/NaturalTransformation.agda b/src/Cat/Category/NaturalTransformation.agda index 01eff6d..d8b20a8 100644 --- a/src/Cat/Category/NaturalTransformation.agda +++ b/src/Cat/Category/NaturalTransformation.agda @@ -20,7 +20,7 @@ {-# OPTIONS --allow-unsolved-metas --cubical #-} open import Cat.Prelude -open import Data.Nat using (_≤_ ; z≤n ; s≤s) +open import Data.Nat using (_≤′_ ; ≤′-refl ; ≤′-step) module Nat = Data.Nat open import Cat.Category @@ -112,8 +112,8 @@ module Properties where naturalIsSet : (θ : Transformation F G) → isSet (Natural F G θ) naturalIsSet θ = - ntypeCommulative - (s≤s {n = Nat.suc Nat.zero} z≤n) + ntypeCumulative {n = 1} + (Data.Nat.≤′-step Data.Nat.≤′-refl) (naturalIsProp θ) naturalTransformationIsSet : isSet (NaturalTransformation F G) diff --git a/src/Cat/Wishlist.agda b/src/Cat/Wishlist.agda index a0c8a26..37b8c87 100644 --- a/src/Cat/Wishlist.agda +++ b/src/Cat/Wishlist.agda @@ -1,42 +1,16 @@ {-# OPTIONS --allow-unsolved-metas #-} module Cat.Wishlist where -open import Level hiding (suc) +open import Level hiding (suc; zero) open import Cubical open import Cubical.NType -open import Data.Nat using (_≤_ ; z≤n ; s≤s ; zero ; suc) +open import Data.Nat using (_≤′_ ; ≤′-refl ; ≤′-step ; zero ; suc) open import Agda.Builtin.Sigma open import Cubical.NType.Properties -private - step : ∀ {ℓ} {A : Set ℓ} → isContr A → (x y : A) → isContr (x ≡ y) - step (a , contr) x y = {!p , c!} - -- where - -- p : x ≡ y - -- p = begin - -- x ≡⟨ sym (contr x) ⟩ - -- a ≡⟨ contr y ⟩ - -- y ∎ - -- c : (q : x ≡ y) → p ≡ q - -- c q i j = contr (p {!!}) {!!} - - -- Contractible types have any given homotopy level. - contrInitial : {ℓ : Level} {A : Set ℓ} → ∀ n → isContr A → HasLevel n A - contrInitial ⟨-2⟩ contr = contr - -- lem' (S ⟨-2⟩) (a , contr) = {!step!} - contrInitial (S ⟨-2⟩) (a , contr) x y = begin - x ≡⟨ sym (contr x) ⟩ - a ≡⟨ contr y ⟩ - y ∎ - contrInitial (S (S n)) contr x y = {!lvl!} -- Why is this not well-founded? - where - c : isContr (x ≡ y) - c = step contr x y - lvl : HasLevel (S n) (x ≡ y) - lvl = contrInitial {A = x ≡ y} (S n) c module _ {ℓ : Level} {A : Set ℓ} where - ntypeCommulative : ∀ {n m} → n ≤ m → HasLevel ⟨ n ⟩₋₂ A → HasLevel ⟨ m ⟩₋₂ A - ntypeCommulative {n = zero} {m} z≤n lvl = {!contrInitial ⟨ m ⟩₋₂ lvl!} - ntypeCommulative {n = .(suc _)} {.(suc _)} (s≤s x) lvl = {!!} + ntypeCumulative : ∀ {n m} → n ≤′ m → HasLevel ⟨ n ⟩₋₂ A → HasLevel ⟨ m ⟩₋₂ A + ntypeCumulative {m} ≤′-refl lvl = lvl + ntypeCumulative {n} {suc m} (≤′-step le) lvl = HasLevel+1 ⟨ m ⟩₋₂ (ntypeCumulative le lvl) From 313c7593d194154a07b33c8b0a9e852446287a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 19 Apr 2018 12:20:44 +0200 Subject: [PATCH 64/93] Distinguish isomorphism of categories and of types --- src/Cat/Categories/Free.agda | 2 +- src/Cat/Categories/Fun.agda | 130 +++++++++++++++++++++++++- src/Cat/Categories/Sets.agda | 8 +- src/Cat/Category.agda | 105 ++++++++++++++------- src/Cat/Category/Monad.agda | 9 +- src/Cat/Category/Monad/Voevodsky.agda | 2 +- src/Cat/Category/Product.agda | 22 ++--- src/Cat/Equivalence.agda | 5 +- src/Cat/Prelude.agda | 1 + 9 files changed, 226 insertions(+), 58 deletions(-) diff --git a/src/Cat/Categories/Free.agda b/src/Cat/Categories/Free.agda index 58b777d..8fe148a 100644 --- a/src/Cat/Categories/Free.agda +++ b/src/Cat/Categories/Free.agda @@ -67,7 +67,7 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where IsPreCategory.arrowsAreSets isPreCategory = arrowsAreSets module _ {A B : ℂ.Object} where - eqv : isEquiv (A ≡ B) (A ≅ B) (Univalence.idToIso isIdentity A B) + eqv : isEquiv (A ≡ B) (A ≊ B) (Univalence.idToIso isIdentity A B) eqv = {!!} univalent : Univalent diff --git a/src/Cat/Categories/Fun.agda b/src/Cat/Categories/Fun.agda index 07e2263..eb861e7 100644 --- a/src/Cat/Categories/Fun.agda +++ b/src/Cat/Categories/Fun.agda @@ -2,6 +2,7 @@ module Cat.Categories.Fun where open import Cat.Prelude +open import Cat.Equivalence open import Cat.Category open import Cat.Category.Functor @@ -33,13 +34,140 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C open IsPreCategory isPreCategory hiding (identity) + module _ {F G : Functor ℂ 𝔻} (p : F ≡ G) where + private + module F = Functor F + module G = Functor G + p-omap : F.omap ≡ G.omap + p-omap = cong Functor.omap p + pp : {C : ℂ.Object} → 𝔻 [ Functor.omap F C , Functor.omap F C ] ≡ 𝔻 [ Functor.omap F C , Functor.omap G C ] + pp {C} = cong (λ f → 𝔻 [ Functor.omap F C , f C ]) p-omap + module _ {C : ℂ.Object} where + p* : F.omap C ≡ G.omap C + p* = cong (_$ C) p-omap + iso : F.omap C 𝔻.≊ G.omap C + iso = 𝔻.idToIso _ _ p* + open Σ iso renaming (fst to f→g) public + open Σ (snd iso) renaming (fst to g→f ; snd to inv) public + lem : coe (pp {C}) 𝔻.identity ≡ f→g + lem = trans (𝔻.9-1-9-right {b = Functor.omap F C} 𝔻.identity p*) 𝔻.rightIdentity + + idToNatTrans : NaturalTransformation F G + idToNatTrans = (λ C → coe pp 𝔻.identity) , λ f → begin + coe pp 𝔻.identity 𝔻.<<< F.fmap f ≡⟨ cong (𝔻._<<< F.fmap f) lem ⟩ + -- Just need to show that f→g is a natural transformation + -- I know that it has an inverse; g→f + f→g 𝔻.<<< F.fmap f ≡⟨ {!lem!} ⟩ + G.fmap f 𝔻.<<< f→g ≡⟨ cong (G.fmap f 𝔻.<<<_) (sym lem) ⟩ + G.fmap f 𝔻.<<< coe pp 𝔻.identity ∎ + + module _ {A B : Functor ℂ 𝔻} where + module A = Functor A + module B = Functor B + module _ (iso : A ≊ B) where + omapEq : A.omap ≡ B.omap + omapEq = funExt eq + where + module _ (C : ℂ.Object) where + f : 𝔻.Arrow (A.omap C) (B.omap C) + f = fst (fst iso) C + g : 𝔻.Arrow (B.omap C) (A.omap C) + g = fst (fst (snd iso)) C + inv : 𝔻.IsInverseOf f g + inv + = ( begin + g 𝔻.<<< f ≡⟨ cong (λ x → fst x $ C) (fst (snd (snd iso))) ⟩ + 𝔻.identity ∎ + ) + , ( begin + f 𝔻.<<< g ≡⟨ cong (λ x → fst x $ C) (snd (snd (snd iso))) ⟩ + 𝔻.identity ∎ + ) + isoC : A.omap C 𝔻.≊ B.omap C + isoC = f , g , inv + eq : A.omap C ≡ B.omap C + eq = 𝔻.isoToId isoC + + + U : (F : ℂ.Object → 𝔻.Object) → Set _ + U F = {A B : ℂ.Object} → ℂ [ A , B ] → 𝔻 [ F A , F B ] + + module _ + (omap : ℂ.Object → 𝔻.Object) + (p : A.omap ≡ omap) + where + D : Set _ + D = ( fmap : U omap) + → ( let + raw-B : RawFunctor ℂ 𝔻 + raw-B = record { omap = omap ; fmap = fmap } + ) + → (isF-B' : IsFunctor ℂ 𝔻 raw-B) + → ( let + B' : Functor ℂ 𝔻 + B' = record { raw = raw-B ; isFunctor = isF-B' } + ) + → (iso' : A ≊ B') → PathP (λ i → U (p i)) A.fmap fmap + -- D : Set _ + -- D = PathP (λ i → U (p i)) A.fmap fmap + -- eeq : (λ f → A.fmap f) ≡ fmap + -- eeq = funExtImp (λ A → funExtImp (λ B → funExt (λ f → isofmap {A} {B} f))) + -- where + -- module _ {X : ℂ.Object} {Y : ℂ.Object} (f : ℂ [ X , Y ]) where + -- isofmap : A.fmap f ≡ fmap f + -- isofmap = {!ap!} + d : D A.omap refl + d = res + where + module _ + ( fmap : U A.omap ) + ( let + raw-B : RawFunctor ℂ 𝔻 + raw-B = record { omap = A.omap ; fmap = fmap } + ) + ( isF-B' : IsFunctor ℂ 𝔻 raw-B ) + ( let + B' : Functor ℂ 𝔻 + B' = record { raw = raw-B ; isFunctor = isF-B' } + ) + ( iso' : A ≊ B' ) + where + module _ {X Y : ℂ.Object} (f : ℂ [ X , Y ]) where + step : {!!} 𝔻.≊ {!!} + step = {!!} + resres : A.fmap {X} {Y} f ≡ fmap {X} {Y} f + resres = {!!} + res : PathP (λ i → U A.omap) A.fmap fmap + res i {X} {Y} f = resres f i + + fmapEq : PathP (λ i → U (omapEq i)) A.fmap B.fmap + fmapEq = pathJ D d B.omap omapEq B.fmap B.isFunctor iso + + rawEq : A.raw ≡ B.raw + rawEq i = record { omap = omapEq i ; fmap = fmapEq i } + + private + f : (A ≡ B) → (A ≊ B) + f p = idToNatTrans p , idToNatTrans (sym p) , NaturalTransformation≡ A A (funExt (λ C → {!!})) , {!!} + g : (A ≊ B) → (A ≡ B) + g = Functor≡ ∘ rawEq + inv : AreInverses f g + inv = {!funExt λ p → ?!} , {!!} + + iso : (A ≡ B) ≅ (A ≊ B) + iso = f , g , inv + + univ : (A ≡ B) ≃ (A ≊ B) + univ = fromIsomorphism _ _ iso + -- There used to be some work-in-progress on this theorem, please go back to -- this point in time to see it: -- -- commit 6b7d66b7fc936fe3674b2fd9fa790bd0e3fec12f -- Author: Frederik Hanghøj Iversen -- Date: Fri Apr 13 15:26:46 2018 +0200 - postulate univalent : Univalent + univalent : Univalent + univalent = univalenceFrom≃ univ isCategory : IsCategory raw IsCategory.isPreCategory isCategory = isPreCategory diff --git a/src/Cat/Categories/Sets.agda b/src/Cat/Categories/Sets.agda index 31d6926..ccf3e05 100644 --- a/src/Cat/Categories/Sets.agda +++ b/src/Cat/Categories/Sets.agda @@ -8,7 +8,7 @@ open import Cat.Category open import Cat.Category.Functor open import Cat.Category.Product open import Cat.Wishlist -open import Cat.Equivalence renaming (_≅_ to _≈_) +open import Cat.Equivalence _⊙_ : {ℓa ℓb ℓc : Level} {A : Set ℓa} {B : Set ℓb} {C : Set ℓc} → (A ≃ B) → (B ≃ C) → A ≃ C eqA ⊙ eqB = Equivalence.compose eqA eqB @@ -93,7 +93,7 @@ module _ (ℓ : Level) where re-ve e = refl inv : AreInverses (f {p} {q}) (g {p} {q}) inv = funExt ve-re , funExt re-ve - iso : (p ≡ q) ≈ (fst p ≡ fst q) + iso : (p ≡ q) ≅ (fst p ≡ fst q) iso = f , g , inv module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where @@ -109,7 +109,7 @@ module _ (ℓ : Level) where re-ve = inverse-from-to-iso A B ve-re : (x : isIso f) → (obv ∘ inv) x ≡ x ve-re = inverse-to-from-iso A B sA sB - iso : isEquiv A B f ≈ isIso f + iso : isEquiv A B f ≅ isIso f iso = obv , inv , funExt re-ve , funExt ve-re in fromIsomorphism _ _ iso @@ -125,7 +125,7 @@ module _ (ℓ : Level) where step2 : (hA ≡ hB) ≃ (A ≡ B) step2 = lem2 (λ A → isSetIsProp) hA hB - univ≃ : (hA ≡ hB) ≃ (hA ≅ hB) + univ≃ : (hA ≡ hB) ≃ (hA ≊ hB) univ≃ = step2 ⊙ univalence ⊙ step0 univalent : Univalent diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 3cc5068..26a3b02 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -32,7 +32,6 @@ open import Cat.Prelude import Cat.Equivalence open Cat.Equivalence public using () renaming (Isomorphism to TypeIsomorphism) open Cat.Equivalence - renaming (_≅_ to _≈_) hiding (preorder≅ ; Isomorphism) ------------------ @@ -52,6 +51,8 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where identity : {A : Object} → Arrow A A _<<<_ : {A B C : Object} → Arrow B C → Arrow A B → Arrow A C + -- infixr 8 _<<<_ + -- infixl 8 _>>>_ infixl 10 _<<<_ _>>>_ -- | Operations on data @@ -86,8 +87,8 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where Isomorphism : ∀ {A B} → (f : Arrow A B) → Set ℓb Isomorphism {A} {B} f = Σ[ g ∈ Arrow B A ] IsInverseOf f g - _≅_ : (A B : Object) → Set ℓb - _≅_ A B = Σ[ f ∈ Arrow A B ] (Isomorphism f) + _≊_ : (A B : Object) → Set ℓb + _≊_ A B = Σ[ f ∈ Arrow A B ] (Isomorphism f) module _ {A B : Object} where Epimorphism : {X : Object } → (f : Arrow A B) → Set ℓb @@ -111,29 +112,30 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where -- | Univalence is indexed by a raw category as well as an identity proof. module Univalence (isIdentity : IsIdentity identity) where -- | The identity isomorphism - idIso : (A : Object) → A ≅ A + idIso : (A : Object) → A ≊ A idIso A = identity , identity , isIdentity -- | Extract an isomorphism from an equality -- -- [HoTT §9.1.4] - idToIso : (A B : Object) → A ≡ B → A ≅ B - idToIso A B eq = transp (\ i → A ≅ eq i) (idIso A) + idToIso : (A B : Object) → A ≡ B → A ≊ B + idToIso A B eq = transp (\ i → A ≊ eq i) (idIso A) Univalent : Set (ℓa ⊔ ℓb) - Univalent = {A B : Object} → isEquiv (A ≡ B) (A ≅ B) (idToIso A B) + Univalent = {A B : Object} → isEquiv (A ≡ B) (A ≊ B) (idToIso A B) univalenceFromIsomorphism : {A B : Object} - → TypeIsomorphism (idToIso A B) → isEquiv (A ≡ B) (A ≅ B) (idToIso A B) + → TypeIsomorphism (idToIso A B) → isEquiv (A ≡ B) (A ≊ B) (idToIso A B) univalenceFromIsomorphism = fromIso _ _ -- A perhaps more readable version of univalence: - Univalent≃ = {A B : Object} → (A ≡ B) ≃ (A ≅ B) + Univalent≃ = {A B : Object} → (A ≡ B) ≃ (A ≊ B) + Univalent≅ = {A B : Object} → (A ≡ B) ≅ (A ≊ B) private -- | Equivalent formulation of univalence. Univalent[Contr] : Set _ - Univalent[Contr] = ∀ A → isContr (Σ[ X ∈ Object ] A ≅ X) + Univalent[Contr] = ∀ A → isContr (Σ[ X ∈ Object ] A ≊ X) -- From: Thierry Coquand -- Date: Wed, Mar 21, 2018 at 3:12 PM @@ -145,15 +147,18 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where univalenceFrom≃ = from[Contr] ∘ step where module _ (f : Univalent≃) (A : Object) where - lem : Σ Object (A ≡_) ≃ Σ Object (A ≅_) + lem : Σ Object (A ≡_) ≃ Σ Object (A ≊_) lem = equivSig λ _ → f aux : isContr (Σ Object (A ≡_)) aux = (A , refl) , (λ y → contrSingl (snd y)) - step : isContr (Σ Object (A ≅_)) + step : isContr (Σ Object (A ≊_)) step = equivPreservesNType {n = ⟨-2⟩} lem aux + univalenceFrom≅ : Univalent≅ → Univalent + univalenceFrom≅ x = univalenceFrom≃ $ fromIsomorphism _ _ x + propUnivalent : isProp Univalent propUnivalent a b i = propPi (λ iso → propIsContr) a b i @@ -263,8 +268,8 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where module _ where private - trans≅ : Transitive _≅_ - trans≅ (f , f~ , f-inv) (g , g~ , g-inv) + trans≊ : Transitive _≊_ + trans≊ (f , f~ , f-inv) (g , g~ , g-inv) = g <<< f , f~ <<< g~ , ( begin @@ -283,11 +288,11 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where g <<< g~ ≡⟨ snd g-inv ⟩ identity ∎ ) - isPreorder : IsPreorder _≅_ - isPreorder = record { isEquivalence = equalityIsEquivalence ; reflexive = idToIso _ _ ; trans = trans≅ } + isPreorder : IsPreorder _≊_ + isPreorder = record { isEquivalence = equalityIsEquivalence ; reflexive = idToIso _ _ ; trans = trans≊ } - preorder≅ : Preorder _ _ _ - preorder≅ = record { Carrier = Object ; _≈_ = _≡_ ; _∼_ = _≅_ ; isPreorder = isPreorder } + preorder≊ : Preorder _ _ _ + preorder≊ = record { Carrier = Object ; _≈_ = _≡_ ; _∼_ = _≊_ ; isPreorder = isPreorder } record PreCategory : Set (lsuc (ℓa ⊔ ℓb)) where field @@ -319,7 +324,7 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where iso : TypeIsomorphism (idToIso A B) iso = toIso _ _ univalent - isoToId : (A ≅ B) → (A ≡ B) + isoToId : (A ≊ B) → (A ≡ B) isoToId = fst iso asTypeIso : TypeIsomorphism (idToIso A B) @@ -329,14 +334,47 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where inverse-from-to-iso' : AreInverses (idToIso A B) isoToId inverse-from-to-iso' = snd iso - -- lemma 9.1.9 in hott + module _ {a b : Object} (f : Arrow a b) where + module _ {a' : Object} (p : a ≡ a') where + private + p~ : Arrow a' a + p~ = fst (snd (idToIso _ _ p)) + + D : ∀ a'' → a ≡ a'' → Set _ + D a'' p' = coe (cong (λ x → Arrow x b) p') f ≡ f <<< (fst (snd (idToIso _ _ p'))) + + 9-1-9-left : coe (cong (λ x → Arrow x b) p) f ≡ f <<< p~ + 9-1-9-left = pathJ D (begin + coe refl f ≡⟨ id-coe ⟩ + f ≡⟨ sym rightIdentity ⟩ + f <<< identity ≡⟨ cong (f <<<_) (sym subst-neutral) ⟩ + f <<< _ ∎) a' p + + module _ {b' : Object} (p : b ≡ b') where + private + p* : Arrow b b' + p* = fst (idToIso _ _ p) + + D : ∀ b'' → b ≡ b'' → Set _ + D b'' p' = coe (cong (λ x → Arrow a x) p') f ≡ fst (idToIso _ _ p') <<< f + + 9-1-9-right : coe (cong (λ x → Arrow a x) p) f ≡ p* <<< f + 9-1-9-right = pathJ D (begin + coe refl f ≡⟨ id-coe ⟩ + f ≡⟨ sym leftIdentity ⟩ + identity <<< f ≡⟨ cong (_<<< f) (sym subst-neutral) ⟩ + _ <<< f ∎) b' p + + -- lemma 9.1.9 in hott module _ {a a' b b' : Object} (p : a ≡ a') (q : b ≡ b') (f : Arrow a b) where private - q* : Arrow b b' - q* = fst (idToIso b b' q) - p* : Arrow a a' + q* : Arrow b b' + q* = fst (idToIso _ _ q) + q~ : Arrow b' b + q~ = fst (snd (idToIso _ _ q)) + p* : Arrow a a' p* = fst (idToIso _ _ p) p~ : Arrow a' a p~ = fst (snd (idToIso _ _ p)) @@ -376,7 +414,8 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where where lem : p~ <<< p* ≡ identity lem = fst (snd (snd (idToIso _ _ p))) - module _ {A B X : Object} (iso : A ≅ B) where + + module _ {A B X : Object} (iso : A ≊ B) where private p : A ≡ B p = isoToId iso @@ -384,7 +423,7 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where p-dom = cong (λ x → Arrow x X) p p-cod : Arrow X A ≡ Arrow X B p-cod = cong (λ x → Arrow X x) p - lem : ∀ {A B} {x : A ≅ B} → idToIso A B (isoToId x) ≡ x + lem : ∀ {A B} {x : A ≊ B} → idToIso A B (isoToId x) ≡ x lem {x = x} i = snd inverse-from-to-iso' i x open Σ iso renaming (fst to ι) using () @@ -459,7 +498,7 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where left = Xprop _ _ right : X→Y <<< Y→X ≡ identity right = Yprop _ _ - iso : X ≅ Y + iso : X ≊ Y iso = X→Y , Y→X , left , right p0 : X ≡ Y p0 = isoToId iso @@ -489,7 +528,7 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where left = Yprop _ _ right : X→Y <<< Y→X ≡ identity right = Xprop _ _ - iso : X ≅ Y + iso : X ≊ Y iso = Y→X , X→Y , right , left res : Xi ≡ Yi res = lemSig propIsInitial _ _ (isoToId iso) @@ -500,11 +539,11 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where open import Data.Nat using (_≤_ ; z≤n ; s≤s) setIso : ∀ x → isSet (Isomorphism x) setIso x = ntypeCommulative ((s≤s {n = 1} z≤n)) (propIsomorphism x) - step : isSet (A ≅ B) + step : isSet (A ≊ B) step = setSig {sA = arrowsAreSets} {sB = setIso} res : isSet (A ≡ B) res = equivPreservesNType - {A = A ≅ B} {B = A ≡ B} {n = ⟨0⟩} + {A = A ≊ B} {B = A ≡ B} {n = ⟨0⟩} (Equivalence.symmetry (univalent≃ {A = A} {B})) step @@ -636,10 +675,10 @@ module Opposite {ℓa ℓb : Level} where → a × b × c → b × a × c genericly (a , b , c) = (b , a , c) - shuffle : A ≅ B → A ℂ.≅ B + shuffle : A ≊ B → A ℂ.≊ B shuffle (f , g , inv) = g , f , inv - shuffle~ : A ℂ.≅ B → A ≅ B + shuffle~ : A ℂ.≊ B → A ≊ B shuffle~ (f , g , inv) = g , f , inv -- Shouldn't be necessary to use `arrowsAreSets` here, but we have it, @@ -656,12 +695,12 @@ module Opposite {ℓa ℓb : Level} where open Σ r-areInv renaming (fst to r-invs ; snd to r-iso) open Σ r-iso renaming (fst to r-l ; snd to r-r) - ζ : A ≅ B → A ≡ B + ζ : A ≊ B → A ≡ B ζ = η ∘ shuffle -- inv : AreInverses (ℂ.idToIso A B) f inv-ζ : AreInverses (idToIso A B) ζ - -- recto-verso : ℂ.idToIso A B <<< f ≡ idFun (A ℂ.≅ B) + -- recto-verso : ℂ.idToIso A B <<< f ≡ idFun (A ℂ.≊ B) inv-ζ = record { fst = funExt (λ x → begin (ζ ∘ idToIso A B) x ≡⟨⟩ diff --git a/src/Cat/Category/Monad.agda b/src/Cat/Category/Monad.agda index ac9c9bb..63fbab7 100644 --- a/src/Cat/Category/Monad.agda +++ b/src/Cat/Category/Monad.agda @@ -204,11 +204,8 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where open import Cat.Equivalence - Monoidal≅Kleisli : M.Monad ≅ K.Monad - Monoidal≅Kleisli = forth , back , funExt backeq , funExt fortheq - - Monoidal≃Kleisli : M.Monad ≃ K.Monad - Monoidal≃Kleisli = forth , eqv + Monoidal≊Kleisli : M.Monad ≅ K.Monad + Monoidal≊Kleisli = forth , back , funExt backeq , funExt fortheq Monoidal≡Kleisli : M.Monad ≡ K.Monad - Monoidal≡Kleisli = ua (forth , eqv) + Monoidal≡Kleisli = isoToPath Monoidal≊Kleisli diff --git a/src/Cat/Category/Monad/Voevodsky.agda b/src/Cat/Category/Monad/Voevodsky.agda index 8f4c610..e5ff355 100644 --- a/src/Cat/Category/Monad/Voevodsky.agda +++ b/src/Cat/Category/Monad/Voevodsky.agda @@ -123,7 +123,7 @@ module voe {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where -- | to talk about voevodsky's construction. module _ (omap : Omap ℂ ℂ) (pure : {X : Object} → Arrow X (omap X)) where private - module E = AreInverses {f = (fst (Monoidal≅Kleisli ℂ))} {fst (snd (Monoidal≅Kleisli ℂ))}(Monoidal≅Kleisli ℂ .snd .snd) + module E = AreInverses {f = (fst (Monoidal≊Kleisli ℂ))} {fst (snd (Monoidal≊Kleisli ℂ))}(Monoidal≊Kleisli ℂ .snd .snd) Monoidal→Kleisli : M.Monad → K.Monad Monoidal→Kleisli = E.obverse diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 0a2ed8b..be77ec8 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -2,7 +2,7 @@ module Cat.Category.Product where open import Cat.Prelude as P hiding (_×_ ; fst ; snd) -open import Cat.Equivalence hiding (_≅_) +open import Cat.Equivalence open import Cat.Category @@ -176,10 +176,10 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} open Σ x renaming (fst to xa ; snd to xb) open Σ 𝕐 renaming (fst to Y ; snd to y) open Σ y renaming (fst to ya ; snd to yb) - open import Cat.Equivalence using (composeIso) renaming (_≅_ to _≈_) + open import Cat.Equivalence using (composeIso) renaming (_≅_ to _≅_) step0 : ((X , xa , xb) ≡ (Y , ya , yb)) - ≈ (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)) + ≅ (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)) step0 = (λ p → cong fst p , cong-d (fst ∘ snd) p , cong-d (snd ∘ snd) p) -- , (λ x → λ i → fst x i , (fst (snd x) i) , (snd (snd x) i)) @@ -190,7 +190,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} -- Should follow from c being univalent iso-id-inv : {p : X ≡ Y} → p ≡ ℂ.isoToId (ℂ.idToIso X Y p) iso-id-inv {p} = sym (λ i → fst (ℂ.inverse-from-to-iso' {X} {Y}) i p) - id-iso-inv : {iso : X ℂ.≅ Y} → iso ≡ ℂ.idToIso X Y (ℂ.isoToId iso) + id-iso-inv : {iso : X ℂ.≊ Y} → iso ≡ ℂ.idToIso X Y (ℂ.isoToId iso) id-iso-inv {iso} = sym (λ i → snd (ℂ.inverse-from-to-iso' {X} {Y}) i iso) lemA : {A B : Object} {f g : Arrow A B} → fst f ≡ fst g → f ≡ g @@ -207,7 +207,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} step1 : (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)) - ≈ Σ (X ℂ.≅ Y) (λ iso + ≅ Σ (X ℂ.≊ Y) (λ iso → let p = ℂ.isoToId iso in ( PathP (λ i → ℂ.Arrow (p i) A) xa ya) @@ -216,7 +216,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} step1 = symIso (isoSigFst - {A = (X ℂ.≅ Y)} + {A = (X ℂ.≊ Y)} {B = (X ≡ Y)} (ℂ.groupoidObject _ _) {Q = \ p → (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)} @@ -225,13 +225,13 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} ) step2 - : Σ (X ℂ.≅ Y) (λ iso + : Σ (X ℂ.≊ Y) (λ iso → let p = ℂ.isoToId iso in ( PathP (λ i → ℂ.Arrow (p i) A) xa ya) × PathP (λ i → ℂ.Arrow (p i) B) xb yb ) - ≈ ((X , xa , xb) ≅ (Y , ya , yb)) + ≅ ((X , xa , xb) ≊ (Y , ya , yb)) step2 = ( λ{ (iso@(f , f~ , inv-f) , p , q) → ( f , sym (ℂ.domain-twist0 iso p) , sym (ℂ.domain-twist0 iso q)) @@ -242,7 +242,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} ) , (λ{ (f , f~ , inv-f , inv-f~) → let - iso : X ℂ.≅ Y + iso : X ℂ.≊ Y iso = fst f , fst f~ , cong fst inv-f , cong fst inv-f~ p : X ≡ Y p = ℂ.isoToId iso @@ -275,14 +275,14 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} -- must compose to give idToIso iso : ((X , xa , xb) ≡ (Y , ya , yb)) - ≈ ((X , xa , xb) ≅ (Y , ya , yb)) + ≅ ((X , xa , xb) ≊ (Y , ya , yb)) iso = step0 ⊙ step1 ⊙ step2 where infixl 5 _⊙_ _⊙_ = composeIso equiv1 : ((X , xa , xb) ≡ (Y , ya , yb)) - ≃ ((X , xa , xb) ≅ (Y , ya , yb)) + ≃ ((X , xa , xb) ≊ (Y , ya , yb)) equiv1 = _ , fromIso _ _ (snd iso) univalent : Univalent diff --git a/src/Cat/Equivalence.agda b/src/Cat/Equivalence.agda index 2972c2b..a6a8582 100644 --- a/src/Cat/Equivalence.agda +++ b/src/Cat/Equivalence.agda @@ -5,7 +5,7 @@ open import Cubical.Primitives open import Cubical.FromStdLib renaming (ℓ-max to _⊔_) open import Cubical.PathPrelude hiding (inverse) open import Cubical.PathPrelude using (isEquiv ; isContr ; fiber) public -open import Cubical.GradLemma +open import Cubical.GradLemma hiding (isoToPath) open import Cat.Prelude using (lemPropF ; setPi ; lemSig ; propSet ; Preorder ; equalityIsEquivalence ; propSig ; id-coe) @@ -329,6 +329,9 @@ preorder≅ ℓ = record module _ {ℓ : Level} {A B : Set ℓ} where + isoToPath : (A ≅ B) → (A ≡ B) + isoToPath = ua ∘ fromIsomorphism _ _ + univalence : (A ≡ B) ≃ (A ≃ B) univalence = Equivalence.compose u' aux where diff --git a/src/Cat/Prelude.agda b/src/Cat/Prelude.agda index 55f031c..bedad50 100644 --- a/src/Cat/Prelude.agda +++ b/src/Cat/Prelude.agda @@ -90,6 +90,7 @@ IsPreorder IsPreorder _~_ = Relation.Binary.IsPreorder _≡_ _~_ module _ {ℓ : Level} {A : Set ℓ} {a : A} where + -- FIXME rename to `coe-neutral` id-coe : coe refl a ≡ a id-coe = begin coe refl a ≡⟨⟩ From aa52bc8f077a39abc117d9b1627417f6ed0c9de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Mon, 23 Apr 2018 17:04:27 +0200 Subject: [PATCH 65/93] Move lemmas about equivalences to that module --- src/Cat/Categories/Sets.agda | 85 +++-------------------------------- src/Cat/Category.agda | 27 ++++------- src/Cat/Category/Product.agda | 3 -- src/Cat/Equivalence.agda | 67 ++++++++++++++++++++++++++- src/Cat/Prelude.agda | 4 +- 5 files changed, 82 insertions(+), 104 deletions(-) diff --git a/src/Cat/Categories/Sets.agda b/src/Cat/Categories/Sets.agda index ccf3e05..af52c8b 100644 --- a/src/Cat/Categories/Sets.agda +++ b/src/Cat/Categories/Sets.agda @@ -42,91 +42,16 @@ module _ (ℓ : Level) where IsPreCategory.isIdentity isPreCat {A} {B} = isIdentity {A} {B} IsPreCategory.arrowsAreSets isPreCat {A} {B} = arrowsAreSets {A} {B} - open IsPreCategory isPreCat hiding (_<<<_) - - isIso = TypeIsomorphism - module _ {hA hB : hSet ℓ} where - open Σ hA renaming (fst to A ; snd to sA) - open Σ hB renaming (fst to B ; snd to sB) - lem1 : (f : A → B) → isSet A → isSet B → isProp (isIso f) - lem1 f sA sB = res - where - module _ (x y : isIso f) where - module x = Σ x renaming (fst to inverse ; snd to areInverses) - module y = Σ y renaming (fst to inverse ; snd to areInverses) - -- I had a lot of difficulty using the corresponding proof where - -- AreInverses is defined. This is sadly a bit anti-modular. The - -- reason for my troubles is probably related to the type of objects - -- being hSet's rather than sets. - p : ∀ {f} g → isProp (AreInverses {A = A} {B} f g) - p {f} g xx yy i = ve-re , re-ve - where - ve-re : g ∘ f ≡ idFun _ - ve-re = arrowsAreSets {A = hA} {B = hA} _ _ (fst xx) (fst yy) i - re-ve : f ∘ g ≡ idFun _ - re-ve = arrowsAreSets {A = hB} {B = hB} _ _ (snd xx) (snd yy) i - 1eq : x.inverse ≡ y.inverse - 1eq = begin - x.inverse ≡⟨⟩ - x.inverse ∘ idFun _ ≡⟨ cong (λ φ → x.inverse ∘ φ) (sym (snd y.areInverses)) ⟩ - x.inverse ∘ (f ∘ y.inverse) ≡⟨⟩ - (x.inverse ∘ f) ∘ y.inverse ≡⟨ cong (λ φ → φ ∘ y.inverse) (fst x.areInverses) ⟩ - idFun _ ∘ y.inverse ≡⟨⟩ - y.inverse ∎ - 2eq : (λ i → AreInverses f (1eq i)) [ x.areInverses ≡ y.areInverses ] - 2eq = lemPropF p 1eq - res : x ≡ y - res i = 1eq i , 2eq i - module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where - lem2 : ((x : A) → isProp (P x)) → (p q : Σ A P) - → (p ≡ q) ≃ (fst p ≡ fst q) - lem2 pA p q = fromIsomorphism _ _ iso - where - f : ∀ {p q} → p ≡ q → fst p ≡ fst q - f e i = fst (e i) - g : ∀ {p q} → fst p ≡ fst q → p ≡ q - g {p} {q} = lemSig pA p q - ve-re : (e : p ≡ q) → (g ∘ f) e ≡ e - ve-re = pathJ (\ q (e : p ≡ q) → (g ∘ f) e ≡ e) - (\ i j → p .fst , propSet (pA (p .fst)) (p .snd) (p .snd) (λ i → (g {p} {p} ∘ f) (λ i₁ → p) i .snd) (λ i → p .snd) i j ) q - re-ve : (e : fst p ≡ fst q) → (f {p} {q} ∘ g {p} {q}) e ≡ e - re-ve e = refl - inv : AreInverses (f {p} {q}) (g {p} {q}) - inv = funExt ve-re , funExt re-ve - iso : (p ≡ q) ≅ (fst p ≡ fst q) - iso = f , g , inv - - module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where - lem4 : isSet A → isSet B → (f : A → B) - → isEquiv A B f ≃ isIso f - lem4 sA sB f = - let - obv : isEquiv A B f → isIso f - obv = toIso A B - inv : isIso f → isEquiv A B f - inv = fromIso A B - re-ve : (x : isEquiv A B f) → (inv ∘ obv) x ≡ x - re-ve = inverse-from-to-iso A B - ve-re : (x : isIso f) → (obv ∘ inv) x ≡ x - ve-re = inverse-to-from-iso A B sA sB - iso : isEquiv A B f ≅ isIso f - iso = obv , inv , funExt re-ve , funExt ve-re - in fromIsomorphism _ _ iso - + open IsPreCategory isPreCat module _ {hA hB : Object} where open Σ hA renaming (fst to A ; snd to sA) open Σ hB renaming (fst to B ; snd to sB) - -- lem3 and the equivalence from lem4 - step0 : Σ (A → B) (isEquiv A B) ≃ Σ (A → B) isIso - step0 = equivSig (lem4 sA sB) - - -- lem2 with propIsSet - step2 : (hA ≡ hB) ≃ (A ≡ B) - step2 = lem2 (λ A → isSetIsProp) hA hB - univ≃ : (hA ≡ hB) ≃ (hA ≊ hB) - univ≃ = step2 ⊙ univalence ⊙ step0 + univ≃ + = equivSigProp (λ A → isSetIsProp) + ⊙ univalence + ⊙ equivSig {P = isEquiv A B} {Q = TypeIsomorphism} (equiv≃iso sA sB) univalent : Univalent univalent = univalenceFrom≃ univ≃ diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 26a3b02..9394089 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -119,7 +119,7 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where -- -- [HoTT §9.1.4] idToIso : (A B : Object) → A ≡ B → A ≊ B - idToIso A B eq = transp (\ i → A ≊ eq i) (idIso A) + idToIso A B eq = subst eq (idIso A) Univalent : Set (ℓa ⊔ ℓb) Univalent = {A B : Object} → isEquiv (A ≡ B) (A ≊ B) (idToIso A B) @@ -348,7 +348,7 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where coe refl f ≡⟨ id-coe ⟩ f ≡⟨ sym rightIdentity ⟩ f <<< identity ≡⟨ cong (f <<<_) (sym subst-neutral) ⟩ - f <<< _ ∎) a' p + f <<< _ ≡⟨ {!!} ⟩ _ ∎) a' p module _ {b' : Object} (p : b ≡ b') where private @@ -431,28 +431,17 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where coe-dom : {f : Arrow A X} → coe p-dom f ≡ f <<< ι~ coe-dom {f} = begin - coe p-dom f - ≡⟨ 9-1-9 p refl f ⟩ - fst (idToIso _ _ refl) <<< f <<< fst (snd (idToIso _ _ p)) - ≡⟨ cong (λ φ → φ <<< f <<< fst (snd (idToIso _ _ p))) subst-neutral ⟩ - identity <<< f <<< fst (snd (idToIso _ _ p)) - ≡⟨ cong (λ φ → identity <<< f <<< φ) (cong (λ x → (fst (snd x))) lem) ⟩ - identity <<< f <<< ι~ - ≡⟨ cong (_<<< ι~) leftIdentity ⟩ + coe p-dom f ≡⟨ 9-1-9-left f p ⟩ + f <<< fst (snd (idToIso _ _ (isoToId iso))) ≡⟨⟩ + f <<< fst (snd (idToIso _ _ p)) ≡⟨ cong (f <<<_) (cong (fst ∘ snd) lem) ⟩ f <<< ι~ ∎ coe-cod : {f : Arrow X A} → coe p-cod f ≡ ι <<< f coe-cod {f} = begin coe p-cod f - ≡⟨ 9-1-9 refl p f ⟩ - fst (idToIso _ _ p) <<< f <<< fst (snd (idToIso _ _ refl)) - ≡⟨ cong (λ φ → fst (idToIso _ _ p) <<< f <<< φ) subst-neutral ⟩ - fst (idToIso _ _ p) <<< f <<< identity - ≡⟨ cong (λ φ → φ <<< f <<< identity) (cong fst lem) ⟩ - ι <<< f <<< identity - ≡⟨ sym isAssociative ⟩ - ι <<< (f <<< identity) - ≡⟨ cong (ι <<<_) rightIdentity ⟩ + ≡⟨ 9-1-9-right f p ⟩ + fst (idToIso _ _ p) <<< f + ≡⟨ cong (λ φ → φ <<< f) (cong fst lem) ⟩ ι <<< f ∎ module _ {f : Arrow A X} {g : Arrow B X} (q : PathP (λ i → p-dom i) f g) where diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index be77ec8..757c5cc 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -7,7 +7,6 @@ open import Cat.Equivalence open import Cat.Category module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where - open Category ℂ module _ (A B : Object) where @@ -18,8 +17,6 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where fst : ℂ [ object , A ] snd : ℂ [ object , B ] - -- FIXME Not sure this is actually a proposition - so this name is - -- misleading. record IsProduct (raw : RawProduct) : Set (ℓa ⊔ ℓb) where open RawProduct raw public field diff --git a/src/Cat/Equivalence.agda b/src/Cat/Equivalence.agda index a6a8582..6c96f1b 100644 --- a/src/Cat/Equivalence.agda +++ b/src/Cat/Equivalence.agda @@ -7,7 +7,10 @@ open import Cubical.PathPrelude hiding (inverse) open import Cubical.PathPrelude using (isEquiv ; isContr ; fiber) public open import Cubical.GradLemma hiding (isoToPath) -open import Cat.Prelude using (lemPropF ; setPi ; lemSig ; propSet ; Preorder ; equalityIsEquivalence ; propSig ; id-coe) +open import Cat.Prelude using + ( lemPropF ; setPi ; lemSig ; propSet + ; Preorder ; equalityIsEquivalence ; propSig ; id-coe + ; Setoid ) import Cubical.Univalence as U @@ -327,6 +330,48 @@ preorder≅ ℓ = record k = pathJ D (trans id-coe id-coe) B (sym p) in k +setoid≅ : (ℓ : Level) → Setoid _ _ +setoid≅ ℓ = record + { Carrier = Set ℓ + ; _≈_ = _≅_ + ; isEquivalence = record + { refl = idFun _ , idFun _ , (funExt λ _ → refl) , (funExt λ _ → refl) + ; sym = symmetryIso + ; trans = composeIso + } + } + +setoid≃ : (ℓ : Level) → Setoid _ _ +setoid≃ ℓ = record + { Carrier = Set ℓ + ; _≈_ = _≃_ + ; isEquivalence = record + { refl = idEquiv + ; sym = Equivalence.symmetry + ; trans = λ x x₁ → Equivalence.compose x x₁ + } + } + +-- If the second component of a pair is propositional, then equality of such +-- pairs is equivalent to equality of their first components. +module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where + equivSigProp : ((x : A) → isProp (P x)) → {p q : Σ A P} + → (p ≡ q) ≃ (fst p ≡ fst q) + equivSigProp pA {p} {q} = fromIsomorphism _ _ iso + where + f : ∀ {p q} → p ≡ q → fst p ≡ fst q + f = cong fst + g : ∀ {p q} → fst p ≡ fst q → p ≡ q + g = lemSig pA _ _ + ve-re : (e : p ≡ q) → (g ∘ f) e ≡ e + ve-re = pathJ (\ q (e : p ≡ q) → (g ∘ f) e ≡ e) + (\ i j → p .fst , propSet (pA (p .fst)) (p .snd) (p .snd) (λ i → (g {p} {p} ∘ f) (λ i₁ → p) i .snd) (λ i → p .snd) i j ) q + re-ve : (e : fst p ≡ fst q) → (f {p} {q} ∘ g {p} {q}) e ≡ e + re-ve e = refl + inv : AreInverses (f {p} {q}) (g {p} {q}) + inv = funExt ve-re , funExt re-ve + iso : (p ≡ q) ≅ (fst p ≡ fst q) + iso = f , g , inv module _ {ℓ : Level} {A B : Set ℓ} where isoToPath : (A ≅ B) → (A ≡ B) @@ -347,6 +392,24 @@ module _ {ℓ : Level} {A B : Set ℓ} where aux : (A U.≃ B) ≃ (A ≃ B) aux = fromIsomorphism _ _ (doEta , deEta , funExt (λ{ (U.con _ _) → refl}) , refl) + -- Equivalence is equivalent to isomorphism when the equivalence (resp. + -- isomorphism) acts on sets. + module _ (sA : isSet A) (sB : isSet B) where + equiv≃iso : (f : A → B) → isEquiv A B f ≃ Isomorphism f + equiv≃iso f = + let + obv : isEquiv A B f → Isomorphism f + obv = toIso A B + inv : Isomorphism f → isEquiv A B f + inv = fromIso A B + re-ve : (x : isEquiv A B f) → (inv ∘ obv) x ≡ x + re-ve = inverse-from-to-iso A B + ve-re : (x : Isomorphism f) → (obv ∘ inv) x ≡ x + ve-re = inverse-to-from-iso A B sA sB + iso : isEquiv A B f ≅ Isomorphism f + iso = obv , inv , funExt re-ve , funExt ve-re + in fromIsomorphism _ _ iso + -- A few results that I have not generalized to work with both the eta and no-eta variable of ≃ module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where -- Equality on sigma's whose second component is a proposition is equivalent @@ -438,6 +501,8 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {B : Set ℓb} where in fromIsomorphism _ _ iso module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where + -- Equivalence of pairs whose first components are identitical can be obtained + -- from an equivalence of their seecond components. equivSig : {ℓc : Level} {Q : A → Set ℓc} → ((a : A) → P a ≃ Q a) → Σ A P ≃ Σ A Q equivSig {Q = Q} eA = res diff --git a/src/Cat/Prelude.agda b/src/Cat/Prelude.agda index bedad50..0c0bec0 100644 --- a/src/Cat/Prelude.agda +++ b/src/Cat/Prelude.agda @@ -76,7 +76,9 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {B : A → Set ℓb} {a b : Σ A B} snd (Σ≡ i) = snd≡ i import Relation.Binary -open Relation.Binary public using (Preorder ; Transitive ; IsEquivalence ; Rel) +open Relation.Binary public using + ( Preorder ; Transitive ; IsEquivalence ; Rel + ; Setoid ) equalityIsEquivalence : {ℓ : Level} {A : Set ℓ} → IsEquivalence {A = A} _≡_ IsEquivalence.refl equalityIsEquivalence = refl From f6cf0515191738cb9113241961ea54429b423533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Mon, 23 Apr 2018 17:06:09 +0200 Subject: [PATCH 66/93] Section about univalence and equivalences --- doc/.gitignore | 1 + doc/implementation.tex | 472 ++++++++++++++++++--------- doc/{report.tex => introduction.tex} | 10 +- doc/macros.tex | 19 +- doc/main.tex | 7 +- doc/packages.tex | 16 +- 6 files changed, 359 insertions(+), 166 deletions(-) rename doc/{report.tex => introduction.tex} (98%) diff --git a/doc/.gitignore b/doc/.gitignore index b19d31d..bc1675b 100644 --- a/doc/.gitignore +++ b/doc/.gitignore @@ -6,3 +6,4 @@ *.pdf *.bbl *.blg +*.toc diff --git a/doc/implementation.tex b/doc/implementation.tex index 79981d9..6ff388b 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -1,4 +1,3 @@ -\section{Implementation} This implementation formalizes the following concepts: % \begin{itemize} @@ -16,9 +15,9 @@ This implementation formalizes the following concepts: \subsubitem Voevodsky's construction \item Category of \ldots \subitem Homotopy sets -\subitem Categories -\subitem Relations -\subitem Functors +\subitem Categories -- only data-part +\subitem Relations -- only data-part +\subitem Functors -- only as a precategory \subitem Free category \end{itemize} % @@ -33,7 +32,7 @@ This allows me to reason about things in a more mathematical way, where one can reason about two categories by simply focusing on the data. This is acheived by creating a function embodying the ``equality principle'' for a given type. -\subsubsection{Categories} +\section{Categories} The data for a category consist of objects, morphisms (or arrows as I will refer to them henceforth), the identity arrow and composition of arrows. @@ -50,28 +49,33 @@ Raw categories satisfying these properties are called a pre-categories. As a further requirement to be a proper category we require it to be univalent. This requirement is quite similiar to univalence for types, but we let -isomorphism of objects play the role of equivalence of types. The univalence +isomorphism on objects play the role of equivalence on types. The univalence criterion is: % $$ -\isEquiv\ (A \cong B)\ (A \equiv B)\ \idToIso_{A\ B} +\isEquiv\ (A \equiv B)\ (A \approxeq B)\ \idToIso $$ % -Note that this is a stronger requirement than: +Here $\approxeq$ denotes isomorphism on objects (whereas $\cong$ denotes +isomorphism of types). + +Note that this is not the same as: % $$ -(A \cong B) \simeq (A \equiv B) +(A \equiv B) \simeq (A \approxeq B) $$ % -Which is permissable simply by ``forgetting'' that $\idToIso_{A\ B}$ plays the -role of the equivalence. +The two types are logically equivalent, however. One can construct the latter +from the formerr simply by ``forgetting'' that $\idToIso$ plays the role +of the equivalence. The other direction is more involved. With all this in place it is now possible to prove that all the laws are indeed mere propositions. Most of the proofs simply use the fact that the type of arrows are sets. This is because most of the laws are a collection of equations -between arrows in the category. And since such a proof does not have any -content, two witnesses must be the same. All the proofs are really quite -mechanical. Lets have a look at one of them: The identity law states that: +between arrows in the category. And since such a proof does not have any content +exactly because the type of arrows form a set, two witnesses must be the same. +All the proofs are really quite mechanical. Lets have a look at one of them: The +identity law states that: % $$ \prod_{A\ B \tp \Object} \prod_{f \tp A \to B} \id \comp f \equiv f \x f \comp \id \equiv f @@ -92,24 +96,29 @@ $$ $$ % I.e.; sigma-types preserve propositionality whenever it's first component is a -proposition, and it's second component is always a proposition for all points of -in the left type. +proposition, and it's second component is a proposition for all points of in the +left type. So the proof goes like this: We `eliminate' the 3 function abstractions by -applying $\propPi$ three times, then we eliminate the (non-dependent) sigma-type -by applying $\propSig$ and are thus left with the two proof-obligations: -$\isProp\ (\id \comp f \equiv f)$ and $\isProp\ (f \comp \id \equiv f)$ which -follows from the type of arrows being a set. +applying $\propPi$ three times. So our proof obligation becomes: +% +$$ +\isProp \left( \id \comp f \equiv f \x f \comp \id \equiv f \right) +$$ +% +then we eliminate the (non-dependent) sigma-type by applying $\propSig$ giving +us the two obligations: $\isProp\ (\id \comp f \equiv f)$ and $\isProp\ (f \comp +\id \equiv f)$ which follows from the type of arrows being a set. This example illustrates nicely how we can use these combinators to reason about `canonical' types like $\sum$ and $\prod$. Similiar combinators can be defined at the other homotopic levels. These combinators are however not applicable in situations where we want to reason about other types - e.g. types we've defined ourselves. For instance, after we've proven that all the projections of -pre-categories are propositions, we would like to bundle this up to show that -the type of pre-categories is also a proposition. Since pre-categories are not -formulates with a chain of sigma-types we wont have any combinators available to -help us here. In stead we'll use the path-type directly. +pre-categories are propositions, then we would like to bundle this up to show +that the type of pre-categories is also a proposition. Since pre-categories are +not formulated with a chain of sigma-types we wont have any combinators +available to help us here. In stead we'll have to use the path-type directly. What we want to prove is: % @@ -180,7 +189,7 @@ $$ and one heterogeneous: % $$ -Path\ (\Gl i \to Univalent_{p\ i})\ \isPreCategory_a\ \isPreCategory_b +Path\ (\lambda i \to Univalent_{p\ i})\ \isPreCategory_a\ \isPreCategory_b $$ % Which depends on the choice of $p_{\isPreCategory}$. The first of these we can @@ -194,7 +203,7 @@ path between some two elements in $A$; $p : a_0 \equiv a_1$ then we can built a heterogeneous path between any two $b$'s at the endpoints: % $$ -Path\ (\Gl i \to B\ (p\ i))\ b0\ b1 +Path\ (\lambda i \to B\ (p\ i))\ b0\ b1 $$ % where $b_0 \tp B a_0$ and $b_1 \tp B\ a_1$. This is quite a mouthful, but the @@ -211,7 +220,7 @@ isomorphic types'' (TODO cite awodey here). That is, we can construct the function: % $$ -\isoToId \tp (A \cong B) \to (A \equiv B) +\isoToId \tp (A \approxeq B) \to (A \equiv B) $$ % One application of this, and a perhaps somewhat surprising result, is that @@ -221,40 +230,8 @@ any two terminal objects are isomorphic. The proof is omitted here, but the curious reader can check the implementation for the details. (TODO: The proof is a bit fun, should I include it?) -In the following I will demonstrate how to instantiate a category and -subsequently why the result above is very useful to have when equating -categories (TODO: This promise is not fulfilled immediately as I digress and -talk about equivalences). So let us define the notion of the opposite category. -This is arguably one of the simplest constructions of a category one can give. -Let $\bC$ be a category, we then define a new category called the opposite of -$\bC$; $\overline{\bC}$. It has the same objects and the same identity, an arrow -from $A$ to $B$ in this category corresponds to an arrow from $B$ to $A$ in the -underlying category. Function composition will then be reverse function -composition from the underlying category. - -Showing that this forms a pre-category is rather straightforward. I'll state the -laws in terms of the underlying category $\bC$: -% -$$ -h >>> (g >>> f) \equiv h >>> g >>> f -$$ -% -Since $>>>$ is reverse function composition this is just the symmetric version -of associativity. -% -$$ -\matit{identity} >>> f \equiv f \x f >>> identity \equiv f -$$ -This is just the swapped version of identity. - -Finally, that the arrows form sets just follows by flipping the order of the -arguments. Or in other words since $\Hom_{A\ B}$ is a set for all $A\ B \tp -\Object$ then so is $\Hom_{B\ A}$. - -Now, to show that this category is univalent is not as trivial. So I will -digress at this point and talk about equivalences. We will return to this category in section ????. - -\subsection{Equivalences} +\section{Equivalences} +\label{equiv} The usual notion of a function $f : A \to B$ having an inverses is: % $$ @@ -263,20 +240,20 @@ $$ % This is defined in \cite[p. 129]{hott-2013} and is referred to as the a quasi-inverse. At the same place \cite{hott-2013} gives an ``interface'' for -what an equivalence $\isequiv : (A \to B) \to \MCU$ must supply: +what an equivalence $\isEquiv : (A \to B) \to \MCU$ must supply: % \begin{itemize} \item - $\qinv\ f \to \isequiv\ f$ + $\qinv\ f \to \isEquiv\ f$ \item - $\isequiv\ f \to \qinv\ f$ + $\isEquiv\ f \to \qinv\ f$ \item - $\isequiv\ f$ is a proposition + $\isEquiv\ f$ is a proposition \end{itemize} % -Having such an interface us to both 1) think rather abstractly about how to work -with equivalences and 2) to use ad-hoc definitions of equivalences. The specific -instantiation of $\isequiv$ as defined in \cite{cubical} is: +Having such an interface gives us both 1) a way to think rather abstractly about +how to work with equivalences and 2) to use ad-hoc definitions of equivalences. +The specific instantiation of $\isEquiv$ as defined in \cite{cubical} is: % $$ isEquiv\ f \defeq \prod_{b : B} \isContr\ (\fiber\ f\ b) @@ -296,37 +273,200 @@ $\mathit{fromIsomorphism}$, this is known as $\mathit{gradLemma}$ in implementation can be found in the sources. Likewise the proof that this equivalence is propositional can be found in my implementation. -So another way to provide a proof that a category is univalent is to give give -an inverse to $\idToIso\ A\ B$. I want to stress here that the notion of an -inverse at this point is conflated. There is the notion of an inverse in the -context of a category (where the concept of functions are generalized to arrows) -and, as here, an inverse as a regular type-theoretic function. This is -particularly confusing because the function that one must give the inverse to -has the type +We say that two types $A\;B \tp \Type$ are equivalent exactly if there exists an +equivalence between them: % $$ -(A \cong B) \to (A \equiv B) +A \simeq B \defeq \sum_{f \tp A \to B} \isEquiv\ f $$ % -where $\cong$ refers to ismorphism \emph{in the category}! +Note that the term equivalence here is overloaded referring both to the map $f +\tp A \to B$ and the type $A \simeq B$. I will use these conflated terms when it +it is clear from the context what is being referred to. -TODO: There is a lot more to say about equivalences! +Just like we could promote a quasi-inverse to an equivalence we can promote an +isomorphism to an equivalence: +% +$$ +\mathit{fromIsomorphism} \tp A \cong B \to A \simeq B +$$ +% +and vice-versa: +% +$$ +\mathit{toIsomorphism} \tp A \simeq B \to A \cong B +$$ +% +The notion of an isomorphism is similarly conflated as isomorphism can refer to +the type $A \cong B$ as well as the the map $A \to B$ that witness this. -\subsection{Categories contd.} -Back from this aside, we can now show that the opposite category is also -univalent simply by showing that $\idToIso \tp (A \equiv B) \to (A \cong B)$ is -an isomorphism (seen as a function). Dually we have that $\idToIso_{\bC} \tp (A -\equiv B) \to (A \cong_{\bC} B)$ is an isomorphism. Let us denote it's inverse -as $\eta \tp (A \cong_{\bC} B) \to (A \equiv B)$. If we squint we can see what -we need is a way to go between $\cong$ and $\cong_{\bC}$, well, an inhabitant of -$A \cong B$ is simply a pair of arrows $f$ being the isomorphism and $g$ it's -inverse. In the present category $g$ will play the role of the isomorphism and -$f$ will be the inverse. Similarly we can go in the opposite direction. These -two functions are obviously inverses. Name them $\mathit{shuffle} \tp (A \cong -B) \to (A \cong_{\bC} B)$ and $\mathit{shuffle}^{-1} : (A \cong_{\bC} B) \to (A -\cong B)$ respectively. +Both $\cong$ and $\simeq$ form equivalence relations. -As the inverse of $\idToIso$ we will pick $\zeta \defeq \eta \comp +\section{Univalence} +\label{univalence} +As noted in the introduction the univalence for types $A\; B \tp \Type$ states +that: +% +$$ +\mathit{Univalence} \defeq (A \equiv B) \simeq (A \simeq B) +$$ +% +As mentioned the univalence criterion for some category $\bC$ says that for all +\emph{objects} $A\;B$ we must have: +$$ +\isEquiv\ (A \equiv B)\ (A \approxeq B)\ \idToIso +$$ +And I mentioned that this was logically equivalent to +% +$$ +(A \equiv B) \simeq (A \approxeq B) +$$ +% +Given that we saw in the previous section that we can construct an equivalence +from an isomorphism it suffices to demonstrate: +% +$$ +(A \equiv B) \cong (A \approxeq B) +$$ +% +That is, we must demonstrate that there is an isomorphism (on types) between +equalities and isomorphisms (on arrows). It's worthwhile to dwell on this for a +few seconds. This type looks very similar to univalence for types and is +therefore perhaps a bit more intuitive to grasp the implications of. Of course +univalence for types (which is a proposition -- i.e. provable) does not imply +univalence in any category since morphisms in a category are not regular maps -- +in stead they can be thought of as a generalization hereof; i.e. arrows. The +univalence criterion therefore is simply a way of restricting arrows to behave +similarly to maps. + +I will now mention a few helpful thoerems that follow from univalence that will +become useful later. + +Obviously univalence gives us an isomorphism $A \equiv B \to A \approxeq B$. I +will name these for convenience: +% +$$ +\idToIso \tp A \equiv B \to A \approxeq B +$$ +% +$$ +\isoToId \tp A \approxeq B \to A \equiv B +$$ +% +The next few theorems are variations on theorem 9.1.9 from \cite{HoTT-book}. Let +an isomorphism $A \approxeq B$ in some category $\bC$ be given. Name the +isomorphism $\iota \tp A \to B$ and its inverse $\widetilde{\iota} \tp B \to A$. +Since $\bC$ is a category (and therefore univalent) the isomorphism induces a +path $p \tp A \equiv B$. From this equality we can get two further paths: +$p_{\mathit{dom}} \tp \mathit{Arrow}\ A\ X \equiv \mathit{Arrow}\ A'\ X$ and +$p_{\mathit{cod}} \tp \mathit{Arrow}\ X\ A \equiv \mathit{Arrow}\ X\ A'$. We +then have the following two theorems: +% +$$ +\mathit{coeDom} \tp \prod_{f \tp A \to X} \mathit{coe}\ p_{\mathit{dom}}\ f \equiv f \lll \widetilde{\iota} +$$ +% +% +$$ +\mathit{coeCod} \tp \prod_{f \tp A \to X} \mathit{coe}\ p_{\mathit{cod}}\ f \equiv \iota \lll f +$$ +% +I will give the proof of the first theorem here, the second one is analagous. +\begin{align*} +\mathit{coe}\ p_{\mathit{dom}}\ f + & \equiv f \lll \mathit{obverse}_{\mathit{idToIso}\ p} && \text{lemma} \\ + & \equiv f \lll \widetilde{\iota} + && \text{$\mathit{idToIso}$ and $\mathit{isoToId}$ are inverses}\\ +\end{align*} +% +In the second step we use the fact that $p$ is constructed from the isomorphism +$\iota$ -- $\mathit{obverse}$ denotes the map $B \to A$ induced by the +isomorphism $\mathit{idToIso}\ p \tp A \cong B$. The helper-lemma is similar to +what we're trying to prove but talks about paths rather than isomorphisms: +% +$$ +\prod_{f \tp \mathit{Arrow}\ A\ B} \prod_{p \tp A \equiv A'} \mathit{coe}\ p^*\ f \equiv f \lll \mathit{obverse}_{\mathit{idToIso}\ p} +$$ +% +Note that the asterisk in $p^*$ denotes the path $\mathit{Arrow}\ A\ B \equiv +\mathit{Arrow}\ A'\ B$ induced by $p$. To prove this statement I let $f$ and $p$ +be given and then invoke based-path-induction. The induction will be based at $A +\tp \mathit{Object}$, so let $\widetilde{A} \tp \Object$ and $\widetilde{p} \tp +A \equiv \widetilde{A}$ be given. The family that we perform induction over will +be: +% +$$ +\mathit{coe}\ {\widetilde{p}}^*\ f \equiv f \lll \mathit{obverse}_{\mathit{idToIso}\ \widetilde{p}} +$$ +The base-case therefore becomes: +\begin{align*} +\mathit{coe}\ {\widetilde{\refl}}^*\ f +& \equiv f \\ +& \equiv f \lll \mathit{identity} \\ +& \equiv f \lll \mathit{obverse}_{\mathit{idToIso}\ \widetilde{\refl}} +\end{align*} +% +The first step follows because reflixivity is a neutral element for coercions. +The second step is the identity law in the category. The last step has to do +with the fact that $\mathit{idToIso}$ is constructed by substituting according +to the supplied path and since reflexivity is also the neutral element for +substuitutions we arrive at the desired expression. To close the +based-path-induction we must supply the value at the other end and the +connecting path, but in this case this is simply $A' \tp \Object$ and $p \tp A +\equiv A'$ which we have. +% +\section{Categories} +\subsection{Opposite category} +\label{op-cat} +The first category I'll present is a pure construction on categories. Given some +category we can construct it's dual, called the opposite category. Starting with +a simple example allows us to focus on how we work with equivalences and +univalence in a very simple category where the structure of the category is +rather simple. + +Let $\bC$ be some category, we then define the opposite category +$\bC^{\matit{Op}}$. It has the same objects, but the type of arrows are flipped, +that is to say an arrow from $A$ to $B$ in the opposite category corresponds to +an arrow from $B$ to $A$ in the underlying category. The identity arrow is the +same as the one in the underlying category (they have the same type). Function +composition will be reverse function composition from the underlying category. + +Showing that this forms a pre-category is rather straightforward. I'll state the +laws in terms of the underlying category $\bC$: +% +$$ +h \rrr (g \rrr f) \equiv h \rrr g \rrr f +$$ +% +Since $\rrr$ is reverse function composition this is just the symmetric version +of associativity. +% +$$ +\matit{identity} \rrr f \equiv f \x f \rrr identity \equiv f +$$ +% +This is just the swapped version of identity. + +Finally, that the arrows form sets just follows by flipping the order of the +arguments. Or in other words since $\Hom_{A\ B}$ is a set for all $A\ B \tp +\Object$ then so is $\Hom_{B\ A}$. + +Now, to show that this category is univalent is not as straight-forward. Lucliy +section \ref{equiv} gave us some tools to work with equivalences. We saw that we +can prove this category univalent by giving an inverse to +$\idToIso_{\mathit{Op}} \tp (A \equiv B) \to (A \approxeq_{\mathit{Op}} B)$. +From the original category we have that $\idToIso \tp (A \equiv B) \to (A \cong +B)$ is an isomorphism. Let us denote it's inverse with $\eta \tp (A \approxeq B) +\to (A \equiv B)$. If we squint we can see what we need is a way to go between +$\approxeq_{\mathit{Op}}$ and $\approxeq$, well, an inhabitant of $A \approxeq +B$ is simply an arrow $f \tp \mathit{Arrow}\ A\ B$ and it's inverse $g \tp +\mathit{Arrow}\ B\ A$. In the opposite category $g$ will play the role of the +isomorphism and $f$ will be the inverse. Similarly we can go in the opposite +direction. I name these maps $\mathit{shuffle} \tp (A \approxeq B) \to (A +\approxeq_{\bC} B)$ and $\mathit{shuffle}^{-1} : (A \approxeq_{\bC} B) \to (A +\approxeq B)$ respectively. + +As the inverse of $\idToIso_{\mathit{Op}}$ I will pick $\zeta \defeq \eta \comp \mathit{shuffle}$. The proof that they are inverses go as follows: % \begin{align*} @@ -345,37 +485,113 @@ As the inverse of $\idToIso$ we will pick $\zeta \defeq \eta \comp %% ≡⟨ (λ i → verso-recto i x) ⟩ \\ & \equiv \identity -&& \text{$\eta$ is an ismorphism} \\ +&& \text{$\eta$ is an ismorphism} \end{align*} % The other direction is analogous. -The lemma used in this proof show that $\idToIso \equiv \inv{\shuffle} \comp +The lemma used in this proof states that $\idToIso \equiv \inv{\shuffle} \comp \idToIso_{\bC}$ it's a rather straight-forward proof since being-an-inverse-of is a proposition. So, in conclusion, we've shown that the opposite category is indeed a category. -We can now proceed to show that this construction is an involution, namely: + +This finished the proof that the opposite category is in fact a category. Now, +to prove that that opposite-of is an involution we must show: % $$ -\prod_{\bC : \Category} \left(\bC^T\right)^T \equiv \bC +\prod_{\bC \tp \mathit{Category}} \left(\bC^{\matit{Op}}\right)^{\matit{Op}} \equiv \bC $$ % -As we've seen the laws in $\left(\bC^T\right)^T$ get quite involved.\footnote{We - haven't even seen the full story because we've used this `interface' for - equivalences.} Luckily they being a category is a proposition, so we need not -concern ourselves with this bit when proving the above. We can use the equality -principle for categories that lets us prove an equality just by giving an -equality on the data-part. So, given a category $\bC$ what we must provide is -the following proof: +As we've seen the laws in $\left(\bC^{\mathit{Op}}\right)^{\mathit{Op}}$ get +quite involved.\footnote{We haven't even seen the full story because we've used + this `interface' for equivalences.} Luckily since being-a-category is a mere +proposition, we need not concern ourselves with this bit when proving the above. +We can use the equality principle for categories that lets us prove an equality +just by giving an equality on the data-part. So, given a category $\bC$ all we +must provide is the following proof: % $$ -\mathit{raw}\ \left(\bC^T\right)^T \equiv \mathit{raw}\ \bC +\mathit{raw}\ \left(\bC^{\mathit{Op}}\right)^{\mathit{Op}} \equiv \mathit{raw}\ \bC $$ % And these are judgmentally the same. I remind the reader that the left-hand side -is constructed by flipping the arrows, an action that is certainly an -involution. +is constructed by flipping the arrows, which judgmentally is an involution. + +\subsection{Category of sets} +The category of sets has as objects, not types, but only those types that are +homotopic sets. This is encapsulated in Agda with the following type: +% +$$\Set_\ell \defeq \sum_{A \tp \MCU_\ell} \isSet\ A$$ +% +The more straight-forward notion of a category where the objects are types is +not a valid (1-)category. Since in cubical Agda types can have higher homotopic +structure. + +Univalence does not follow immediately from univalence for types: +% +$$(A \equiv B) \simeq (A \simeq B)$$ +% +Because here $A\ B \tp \Type$ whereas the objects in this category have the type +$\Set$ so we cannot form the type $\mathit{hA} \simeq \mathit{hB}$ for objects +$\mathit{hA}\;\mathit{hB} \tp \Set$. In stead I show that this category +satisfies: +% +$$ +(\mathit{hA} \equiv \mathit{hB}) \simeq (\mathit{hA} \approxeq \mathit{hB}) +$$ +% +Which, as we saw in section \ref{univalence}, is sufficient to show that the +category is univalent. The way that I have shown this is with a three-step +process. For objects $(A, s_A)\; (B, s_B) \tp \Set$ I show that. +% +\begin{align*} + ((A, s_A) \equiv (B, s_B)) & \simeq (A \equiv B) \\ + (A \equiv B) & \simeq (\fst A \simeq \fst B) \\ + (A \simeq B) & \simeq ((A, s_A) \approxeq (B, s_B)) +\end{align*} + +And since $\simeq$ is an equivalence relation we can chain these equivalences +together. Step one will be proven with the following lemma: +% +$$ +\left(\prod_{a \tp A} \isProp (P\ a)\right) \to \prod_{x\;y \tp \sum_{a \tp A} P\ a} (x \equiv y) \simeq (\fst\ x \equiv \fst\ y) +$$ +% +The lemma states that for pairs whose second component are mere propositions +equiality is equivalent to equality of the first components. In this case the +type-family $P$ is $\isSet$ which itself is a proposition for any type $A \tp +\Type$. Step two is univalence. Step three will be proven with the following +lemma: +% +$$ +\prod_{a \tp A} \left( P\ a \simeq Q\ a \right) \to \sum_{a \tp A} P\ a \simeq \sum_{a \tp A} Q\ a +$$ +% +Which says that if two type-families are equivalent at all points, then pairs +with identitical first components and these families as second components will +also be equivalent. For our purposes $P \defeq \isEquiv\ A\ B$ and $Q \defeq +\mathit{Isomorphism}$. So we must finally prove: +% +$$ +\prod_{f \tp A \to B} \left( \isEquiv\ A\ B\ f \simeq \mathit{Isomorphism}\ f \right) +$$ + + +\subsection{Categories} +Note that this category does in fact not exist. In stead I provide the +definition of the ``raw'' category as well as some of the laws. + +Furthermore I provide some helpful lemmas about this raw category. For instance +I have shown what would be the exponential object in such a category. + +These lemmas can be used to provide the actual exponential object in a context +where we have a witness to this being a category. This is useful if this library +is later extended to talk about higher categories. + + +\section{Product} +\section{Monads} %% \subsubsection{Functors} %% Defines the notion of a functor - also split up into data and laws. @@ -446,50 +662,6 @@ involution. %% \footnote{ TODO: I would like to include in the thesis some motivation for why %% this construction is particularly interesting.} -%% \subsubsection{Homotopy sets} -%% The typical category of sets where the objects are modelled by an Agda set -%% (henceforth ``$\Type$'') at a given level is not a valid category in this cubical -%% settings, we need to restrict the types to be those that are homotopy sets. Thus -%% the objects of this category are: -%% % -%% $$\hSet_\ell \defeq \sum_{A \tp \MCU_\ell} \isSet\ A$$ -%% % -%% The definition of univalence for categories I have defined is: -%% % -%% $$\isEquiv\ (\hA \equiv \hB)\ (\hA \cong \hB)\ \idToIso$$ -%% % -%% Where $\hA and \hB$ denote objects in the category. Note that this is stronger -%% than -%% % -%% $$(\hA \equiv \hB) \simeq (\hA \cong \hB)$$ -%% % -%% Because we require that the equivalence is constructed from the witness to: -%% % -%% $$\id \comp f \equiv f \x f \comp \id \equiv f$$ -%% % -%% And indeed univalence does not follow immediately from univalence for types: -%% % -%% $$(A \equiv B) \simeq (A \simeq B)$$ -%% % -%% Because $A\ B \tp \Type$ whereas $\hA\ \hB \tp \hSet$. - -%% For this reason I have shown that this category satisfies the following -%% equivalent formulation of being univalent: -%% % -%% $$\prod_{A \tp hSet} \isContr \left( \sum_{X \tp hSet} A \cong X \right)$$ -%% % -%% But I have not shown that it is indeed equivalent to my former definition. -%% \subsubsection{Categories} -%% Note that this category does in fact not exist. In stead I provide the -%% definition of the ``raw'' category as well as some of the laws. - -%% Furthermore I provide some helpful lemmas about this raw category. For instance -%% I have shown what would be the exponential object in such a category. - -%% These lemmas can be used to provide the actual exponential object in a context -%% where we have a witness to this being a category. This is useful if this library -%% is later extended to talk about higher categories. - %% \subsubsection{Functors} %% The category of functors and natural transformations. An immediate corrolary is %% the set of presheaf categories. diff --git a/doc/report.tex b/doc/introduction.tex similarity index 98% rename from doc/report.tex rename to doc/introduction.tex index bcf85d9..3153e83 100644 --- a/doc/report.tex +++ b/doc/introduction.tex @@ -1,5 +1,3 @@ -\section{Introduction} -% Functional extensionality and univalence is not expressible in \nomen{Intensional Martin Löf Type Theory} (ITT). This poses a severe limitation on both 1) what is \emph{provable} and 2) the \emph{reusability} of proofs. @@ -10,7 +8,9 @@ Furthermore an extension has been implemented for the proof assistant Agda (\cite{agda}, \cite{cubical-agda}) that allows us to work in such a ``cubical setting''. This thesis will explore the usefulness of this extension in the context of category theory. - +% +\section{Motivating examples} +% In the following two sections I present two examples that illustrate some limitations inherent in ITT and -- by extension -- Agda. % @@ -94,7 +94,7 @@ $$\mathit{univalence} \tp (A \simeq B) \simeq (A \equiv B)$$ % In particular this allows us to construct an equality from an equivalence $\mathit{ua} \tp (A \simeq B) \to (A \equiv B)$ and vice-versa. -\subsection{Formalizing Category Theory} +\section{Formalizing Category Theory} % The above examples serve to illustrate the limitation of Agda. One case where these limitations are particularly prohibitive is in the study of Category @@ -162,3 +162,5 @@ constructor: data _≡_ {a} {A : Set a} (x : A) : A → Set a where instance refl : x ≡ x \end{verbatim} +% +I shall refer to this as the (usual) inductive equality type. diff --git a/doc/macros.tex b/doc/macros.tex index e63ff35..33f09d2 100644 --- a/doc/macros.tex +++ b/doc/macros.tex @@ -13,24 +13,23 @@ \newcommand{\mto}{\mapsto} \newcommand{\UU}{\ensuremath{\mathcal{U}}\xspace} \let\type\UU +\newcommand{\MCU}{\UU} \newcommand{\nomen}[1]{\emph{#1}} \newcommand{\todo}[1]{\textit{#1}} \newcommand{\comp}{\circ} \newcommand{\x}{\times} +\newcommand\inv[1]{#1\raisebox{1.15ex}{$\scriptscriptstyle-\!1$}} +\newcommand{\tp}{\;\mathord{:}\;} +\newcommand{\Type}{\mathcal{U}} + +\newcommand{\var}[1]{\mathit{#1}} \newcommand{\Hom}{\mathit{Hom}} \newcommand{\fmap}{\mathit{fmap}} \newcommand{\idFun}{\mathit{id}} \newcommand{\Sets}{\mathit{Sets}} \newcommand{\Set}{\mathit{Set}} \newcommand{\hSet}{\mathit{hSet}} -\newcommand{\Type}{\mathcal{U}} - -\newcommand{\MCU}{\UU} \newcommand{\id}{\mathit{id}} -\newcommand{\tp}{\,\mathord{:}\,} -\newcommand\hA{\mathit{hA}} -\newcommand\hB{\mathit{hB}} - \newcommand{\isEquiv}{\mathit{isEquiv}} \newcommand{\idToIso}{\mathit{idToIso}} \newcommand{\isSet}{\mathit{isSet}} @@ -54,5 +53,9 @@ \newcommand\qinv{\mathit{qinv}} \newcommand\fiber{\mathit{fiber}} \newcommand\shuffle{\mathit{shuffle}} -\newcommand\inv[1]{#1\raisebox{1.15ex}{$\scriptscriptstyle-\!1$}} +\newcommand\Univalent{\mathit{Univalent}} +\newcommand\refl{\mathit{refl}} \newcommand\isoToId{\mathit{isoToId}} +\newcommand\rrr{\ggg} +\newcommand\fst{\mathit{fst}} +\newcommand\snd{\mathit{snd}} diff --git a/doc/main.tex b/doc/main.tex index 98cba0d..cf00dc9 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -1,4 +1,4 @@ -\documentclass{article} +\documentclass{report} \input{packages.tex} \input{macros.tex} @@ -15,9 +15,12 @@ \begin{document} \maketitle +\tableofcontents -\input{report.tex} +\chapter{Introduction} +\input{introduction.tex} +\chapter{Implementation} \input{implementation.tex} \bibliographystyle{plainnat} diff --git a/doc/packages.tex b/doc/packages.tex index fcd169e..c55dad5 100644 --- a/doc/packages.tex +++ b/doc/packages.tex @@ -7,7 +7,7 @@ \usepackage{parskip} \usepackage{multicol} -\usepackage{amsmath,amssymb} +\usepackage{amssymb,amsmath,amsthm,stmaryrd,mathrsfs,wasysym} \usepackage[toc,page]{appendix} \usepackage{xspace} @@ -24,5 +24,17 @@ \usepackage{chalmerstitle} +\usepackage{mathpazo} +\usepackage[scaled=0.95]{helvet} +\usepackage{courier} +\linespread{1.05} % Palatino looks better with this + \usepackage{fontspec} -\setmonofont{FreeMono.otf} +\setmonofont[Mapping=tex-text]{FreeMono.otf} +%% \setmonofont{FreeMono.otf} + + +\pagestyle{fancyplain} +\setlength{\headheight}{15pt} +\renewcommand{\chaptermark}[1]{\markboth{\textsc{Chapter \thechapter. #1}}{}} +\renewcommand{\sectionmark}[1]{\markright{\textsc{\thesection\ #1}}} From 129eef115035373ec57f9cadbc6b99ac60b28447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 24 Apr 2018 14:11:22 +0200 Subject: [PATCH 67/93] Finish section on category of sets --- doc/feedback.txt | 72 +++++++++++++++++ doc/implementation.tex | 169 +++++++++++++++++++++++++++++++++------ doc/introduction.tex | 35 ++++---- doc/macros.tex | 6 ++ doc/main.tex | 4 +- src/Cat/Equivalence.agda | 50 +++++------- src/Cat/Prelude.agda | 4 +- 7 files changed, 265 insertions(+), 75 deletions(-) create mode 100644 doc/feedback.txt diff --git a/doc/feedback.txt b/doc/feedback.txt new file mode 100644 index 0000000..e45ae95 --- /dev/null +++ b/doc/feedback.txt @@ -0,0 +1,72 @@ +Andrea Vezzosi Tue, Apr 24, 2018 at 2:02 PM +To: Frederik Hanghøj Iversen +Cc: Thierry Coquand +On Tue, Apr 24, 2018 at 12:57 PM, Frederik Hanghøj Iversen + wrote: +> I've written the first few sections about my implementation. I was wondering +> if you could have a quick look at it. You don't need to read it +> word-for-word but I would like some indication from you if this is the sort +> of thing you would like to see in the final report. + +Yes! I would say this very much fits the bill of what the main part of +the report should be, then you could have a discussion section where +you might put some analysis of the pros and cons of cubical, design +choices you made, and your experience overall. + +I wonder if there should be some short introduction to Cubical Type +Theory before this chapter, so you can introduce the Path type by +itself and show some simple proof with it. e.g. how to get function +extensionality. + +You mention a few "combinators" like propPi and lemPropF, you might +want to call them just lemmas, so it's clearer that these can be +proven in --cubical. + +> +> I refer you specifically to "Chapter 2 - Implementation" on p. 6. +> +> In this chapter I plan to additionally include some text about the proof we +> did that products are mere propositions and the proof about the two +> equivalent notions of a monad. + +I've read the chapter up until 2.3 and skimmed the rest for now, but I +accumulated some editing suggestions I copy here. +Remember to look for things like these when you proof-read the rest :) + + +You should be careful to properly introduce things before you use +them, like IsPreCategory (I'd prefer if it took the raw category as +argument btw) and its fields isIdentity, isAssociative, .. come up a +bit out of the blue from the end of page 8. +Maybe the easiest is to show the definition of IsPreCategory. + +Maybe give a type for propIsIdentity and mention the other prop* are similar. + +Also the notation "isIdentity_a" to apply projections is a bit unusual +so it needs to be introduced as well. +To be fair it would be simpler to stick to function application +(though I see that it would introduce more parentheses), + +"The situation is a bit more complicated when we have a dependent +type" could be more clear by being more specific: +"The situation is a bit more complicated when the type of a field +depends on a previous field" + +Here too it might be more concrete if you also give the code for IsCategory. + +In Path ( λ i → Univalent_{p i} ) isPreCategory_a isPreCategory_b +I suggest parentheses around (p i), but also you should be consistent +on whether you want to call the proof "p" or "p_{isPreCategory}", +finally i'm guessing the two fields should be "isUnivalent" rather +than "isPreCategory". + +You can cite the book on the specific definition of isEquiv, +"contractible fibers" in section 4.4, the grad lemma is also from +somewhere but I don't remember off-hand. + +You have not defined what you mean by _\~=_ and isomorphism. + + +Cheers, +Andrea +[Quoted text hidden] diff --git a/doc/implementation.tex b/doc/implementation.tex index 6ff388b..02ca940 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -189,7 +189,7 @@ $$ and one heterogeneous: % $$ -Path\ (\lambda i \to Univalent_{p\ i})\ \isPreCategory_a\ \isPreCategory_b +\Path\ (\lambda\; i \mto Univalent_{p\ i})\ \isPreCategory_a\ \isPreCategory_b $$ % Which depends on the choice of $p_{\isPreCategory}$. The first of these we can @@ -203,7 +203,7 @@ path between some two elements in $A$; $p : a_0 \equiv a_1$ then we can built a heterogeneous path between any two $b$'s at the endpoints: % $$ -Path\ (\lambda i \to B\ (p\ i))\ b0\ b1 +\Path\ (\lambda\; i \mto B\ (p\ i))\ b0\ b1 $$ % where $b_0 \tp B a_0$ and $b_1 \tp B\ a_1$. This is quite a mouthful, but the @@ -216,7 +216,7 @@ applying using congruence of paths: $\congruence\ \mathit{isIdentity}\ p_{\isPreCategory}$ When we have a proper category we can make precise the notion of ``identifying -isomorphic types'' (TODO cite awodey here). That is, we can construct the +isomorphic types'' \TODO{cite awodey here}. That is, we can construct the function: % $$ @@ -227,11 +227,11 @@ One application of this, and a perhaps somewhat surprising result, is that terminal objects are propositional. Intuitively; they do not have any interesting structure. The proof of this follows from the usual observation that any two terminal objects are isomorphic. The proof is omitted here, but the -curious reader can check the implementation for the details. (TODO: The proof is -a bit fun, should I include it?) +curious reader can check the implementation for the details. \TODO{The proof is +a bit fun, should I include it?} \section{Equivalences} -\label{equiv} +\label{sec:equiv} The usual notion of a function $f : A \to B$ having an inverses is: % $$ @@ -253,7 +253,7 @@ what an equivalence $\isEquiv : (A \to B) \to \MCU$ must supply: % Having such an interface gives us both 1) a way to think rather abstractly about how to work with equivalences and 2) to use ad-hoc definitions of equivalences. -The specific instantiation of $\isEquiv$ as defined in \cite{cubical} is: +The specific instantiation of $\isEquiv$ as defined in \cite{cubical-agda} is: % $$ isEquiv\ f \defeq \prod_{b : B} \isContr\ (\fiber\ f\ b) @@ -269,7 +269,7 @@ once we have shown that this definition actually works as an equivalence. The first function from the list of requirements we will call $\mathit{fromIsomorphism}$, this is known as $\mathit{gradLemma}$ in -\cite{cubical} the second one we will refer to as $\mathit{toIsmorphism}$. It's +\cite{cubical-agda} the second one we will refer to as $\mathit{toIsmorphism}$. It's implementation can be found in the sources. Likewise the proof that this equivalence is propositional can be found in my implementation. @@ -353,7 +353,7 @@ $$ \isoToId \tp A \approxeq B \to A \equiv B $$ % -The next few theorems are variations on theorem 9.1.9 from \cite{HoTT-book}. Let +The next few theorems are variations on theorem 9.1.9 from \cite{hott-2013}. Let an isomorphism $A \approxeq B$ in some category $\bC$ be given. Name the isomorphism $\iota \tp A \to B$ and its inverse $\widetilde{\iota} \tp B \to A$. Since $\bC$ is a category (and therefore univalent) the isomorphism induces a @@ -425,7 +425,7 @@ univalence in a very simple category where the structure of the category is rather simple. Let $\bC$ be some category, we then define the opposite category -$\bC^{\matit{Op}}$. It has the same objects, but the type of arrows are flipped, +$\bC^{\mathit{Op}}$. It has the same objects, but the type of arrows are flipped, that is to say an arrow from $A$ to $B$ in the opposite category corresponds to an arrow from $B$ to $A$ in the underlying category. The identity arrow is the same as the one in the underlying category (they have the same type). Function @@ -442,7 +442,7 @@ Since $\rrr$ is reverse function composition this is just the symmetric version of associativity. % $$ -\matit{identity} \rrr f \equiv f \x f \rrr identity \equiv f +\mathit{identity} \rrr f \equiv f \x f \rrr identity \equiv f $$ % This is just the swapped version of identity. @@ -452,7 +452,7 @@ arguments. Or in other words since $\Hom_{A\ B}$ is a set for all $A\ B \tp \Object$ then so is $\Hom_{B\ A}$. Now, to show that this category is univalent is not as straight-forward. Lucliy -section \ref{equiv} gave us some tools to work with equivalences. We saw that we +section \ref{sec:equiv} gave us some tools to work with equivalences. We saw that we can prove this category univalent by giving an inverse to $\idToIso_{\mathit{Op}} \tp (A \equiv B) \to (A \approxeq_{\mathit{Op}} B)$. From the original category we have that $\idToIso \tp (A \equiv B) \to (A \cong @@ -500,7 +500,7 @@ This finished the proof that the opposite category is in fact a category. Now, to prove that that opposite-of is an involution we must show: % $$ -\prod_{\bC \tp \mathit{Category}} \left(\bC^{\matit{Op}}\right)^{\matit{Op}} \equiv \bC +\prod_{\bC \tp \mathit{Category}} \left(\bC^{\mathit{Op}}\right)^{\mathit{Op}} \equiv \bC $$ % As we've seen the laws in $\left(\bC^{\mathit{Op}}\right)^{\mathit{Op}}$ get @@ -543,20 +543,23 @@ $$ % Which, as we saw in section \ref{univalence}, is sufficient to show that the category is univalent. The way that I have shown this is with a three-step -process. For objects $(A, s_A)\; (B, s_B) \tp \Set$ I show that. +process. For objects $(A, s_A)\; (B, s_B) \tp \Set$ I show the following chain +of equivalences: % \begin{align*} - ((A, s_A) \equiv (B, s_B)) & \simeq (A \equiv B) \\ - (A \equiv B) & \simeq (\fst A \simeq \fst B) \\ - (A \simeq B) & \simeq ((A, s_A) \approxeq (B, s_B)) +((A, s_A) \equiv (B, s_B)) + & \simeq (A \equiv B) && \ref{eq:equivPropSig} \\ + & \simeq (A \simeq B) && \text{Univalence} \\ + & \simeq ((A, s_A) \approxeq (B, s_B)) && \text{\ref{eq:equivSig} and \ref{eq:equivIso}} \end{align*} And since $\simeq$ is an equivalence relation we can chain these equivalences together. Step one will be proven with the following lemma: % -$$ +\begin{align} + \label{eq:equivPropSig} \left(\prod_{a \tp A} \isProp (P\ a)\right) \to \prod_{x\;y \tp \sum_{a \tp A} P\ a} (x \equiv y) \simeq (\fst\ x \equiv \fst\ y) -$$ +\end{align} % The lemma states that for pairs whose second component are mere propositions equiality is equivalent to equality of the first components. In this case the @@ -564,21 +567,105 @@ type-family $P$ is $\isSet$ which itself is a proposition for any type $A \tp \Type$. Step two is univalence. Step three will be proven with the following lemma: % -$$ +\begin{align} + \label{eq:equivSig} \prod_{a \tp A} \left( P\ a \simeq Q\ a \right) \to \sum_{a \tp A} P\ a \simeq \sum_{a \tp A} Q\ a -$$ +\end{align} % Which says that if two type-families are equivalent at all points, then pairs with identitical first components and these families as second components will also be equivalent. For our purposes $P \defeq \isEquiv\ A\ B$ and $Q \defeq \mathit{Isomorphism}$. So we must finally prove: % -$$ +\begin{align} + \label{eq:equivIso} \prod_{f \tp A \to B} \left( \isEquiv\ A\ B\ f \simeq \mathit{Isomorphism}\ f \right) -$$ +\end{align} +First, lets proove \ref{eq:equivPropSig}: Let $propP \tp \prod_{a \tp A} \isProp (P\ a)$ and $x\;y \tp \sum_{a \tp A} P\ a$ be given. Because +of $\mathit{fromIsomorphism}$ it suffices to give an isomorphism between +$x \equiv y$ and $\fst\ x \equiv \fst\ y$: +% +\begin{align*} + f & \defeq \congruence\ \fst \tp x \equiv y \to \fst\ x \equiv \fst\ y \\ + g & \defeq \mathit{lemSig}\ \mathit{propP}\ x\ y \tp \fst\ x \equiv \fst\ y \to x \equiv y +\end{align*} +% +\TODO{Is it confusing that I use point-free style here?} +Here $\mathit{lemSig}$ is a lemma that says that if the second component of a +pair is a proposition, it suffices to give a path between it's first components +to construct an equality of the two pairs: +% +\begin{align*} +\mathit{lemSig} \tp \left( \prod_{x \tp A} \isProp\ (B\ x) \right) \to +\prod_{u\; v \tp \sum_{a \tp A} B\ a} + \left( \fst\ u \equiv \fst\ v \right) \to u \equiv v +\end{align*} +% +The proof that these are indeed inverses has been omitted. \TODO{Do I really + want to ommit it?}\QED -\subsection{Categories} +Now to prove \ref{eq:equivSig}: Let $e \tp \prod_{a \tp A} \left( P\ a \simeq +Q\ a \right)$ be given. To prove the equivalence, it suffices to give an +isomorphism between $\sum_{a \tp A} P\ a$ and $\sum_{a \tp A} Q\ a$, but since +they have identical first components it suffices to give an isomorphism between +$P\ a$ and $Q\ a$ for all $a \tp A$. This is exactly what we can get from +the equivalence $e$.\QED + +Lastly we prove \ref{eq:equivIso}. Let $f \tp A \to B$ be given. For the maps we +choose: +% +\begin{align*} +\mathit{toIso} + & \tp \isEquiv\ f \to \mathit{Isomorphism}\ f \\ +\mathit{fromIso} + & \tp \mathit{Isomorphism}\ f \to \isEquiv\ f +\end{align*} +% +As mentioned in section \ref{sec:equiv}. These maps are not in general inverses +of each other. In stead, we will use the fact that $A$ and $B$ are sets. The first thing we must prove is: +% +\begin{align*} + \mathit{fromIso} \comp \mathit{toIso} \equiv \identity_{\isEquiv\ f} +\end{align*} +% +For this we can use the fact that being-an-equivalence is a mere proposition. +For the other direction: +% +\begin{align*} + \mathit{toIso} \comp \mathit{fromIso} \equiv \identity_{\mathit{Isomorphism}\ f} +\end{align*} +% +We will show that $\mathit{Isomorphism}\ f$ is also a mere proposition. To this +end, let $X\;Y \tp \mathit{Isomorphism}\ f$ be given. Name the maps $x\;y \tp B +\to A$ respectively. Now, the proof that $X$ and $Y$ are the same is a pair of +paths: $p \tp x \equiv y$ and $\Path\ (\lambda\; i \mto +\mathit{AreInverses}\ f\ (p\ i))\ \mathcal{X}\ \mathcal{Y}$ where $\mathcal{X}$ +and $\mathcal{Y}$ denotes the witnesses that $x$ (respectively $y$) is an +inverse to $f$. $p$ is inhabited by: +% +\begin{align*} + x + & \equiv x \comp \identity \\ + & \equiv x \comp (f \comp y) + && \text{$y$ is an inverse to $f$} \\ + & \equiv (x \comp f) \comp y \\ + & \equiv \identity \comp y + && \text{$x$ is an inverse to $f$} \\ + & \equiv y +\end{align*} +% +For the other (dependent) path we can prove that being-an-inverse-of is a +proposition and then use $\lemPropF$. So we prove the generalization: +% +\begin{align*} +\prod_{g : B \to A} \isProp\ (\mathit{AreInverses}\ f\ g) +\end{align*} +% +But $\mathit{AreInverses}\ f\ g$ is a pair of equations on arrows, so we use +$\propSig$ and the fact that both $A$ and $B$ are sets to close this proof. + +\subsection{Category of categories} Note that this category does in fact not exist. In stead I provide the definition of the ``raw'' category as well as some of the laws. @@ -589,8 +676,40 @@ These lemmas can be used to provide the actual exponential object in a context where we have a witness to this being a category. This is useful if this library is later extended to talk about higher categories. - \section{Product} +In the following I'll demonstrate a technique for using categories to prove +properties. The goal in this section is to show that products are propositions: +% +$$ +\prod_{\bC \tp \Category} \prod_{A\;B \tp \Object} \isProp\ (\mathit{Product}\ \bC\ A\ B) +$$ +% +Where $\mathit{Product}\ \bC\ A\ B$ denotes the type of products of objects $A$ +and $B$ in the category $\bC$. I do this by constructing a category whose +terminal objects are equivalent to products in $\bC$, and since terminal objects +are propositional in a proper category and equivalences preservehomotopy level, +then we know that products also are propositions. But before we get to that, +let's recall the definition of products. + +Given a category $\bC$ and two objects $A$ and $B$ in $bC$ we define the product +of $A$ and $B$ to be an object $A \x B$ in $\bC$ and two arrows $\pi_1 \tp A \x +B \to A$ and $\pi_2 \tp A \x B \to B$ called the projections of the product. The projections must satisfy the following property: + +For all $X \tp Object$, $f \tp \Arrow\ X\ A$ and $g \tp \Arrow\ X\ B$ we have +that there exists a unique arrow $\pi \tp \Arrow\ X\ (A \x B)$ satisfying +% +\begin{align} +\label{eq:umpProduct} +%% \prod_{X \tp Object} \prod_{f \tp \Arrow\ X\ A} \prod_{g \tp \Arrow\ X\ B}\\ +%% \uexists_{f \x g \tp \Arrow\ X\ (A \x B)} +\pi_1 \lll \pi \equiv f \x \pi_2 \lll \pi \equiv g +%% ump : ∀ {X : Object} (f : ℂ [ X , A ]) (g : ℂ [ X , B ]) +%% → ∃![ f×g ] (ℂ [ fst ∘ f×g ] ≡ f P.× ℂ [ snd ∘ f×g ] ≡ g) +\end{align*} +$ +$\pi$ is called the product (arrow) of $f$ and $g$. + + \section{Monads} %% \subsubsection{Functors} diff --git a/doc/introduction.tex b/doc/introduction.tex index 3153e83..08fde09 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -73,12 +73,13 @@ the (left) identity law of the underlying category to proove $\idFun \comp g % \subsection{Equality of isomorphic types} % -Let $\top$ denote the unit type -- a type with a single constructor. In the -propositions-as-types interpretation of type theory $\top$ is the proposition -that is always true. The type $A \x \top$ and $A$ has an element for each $a : -A$. So in a sense they are the same. The second element of the pair does not add -any ``interesting information''. It can be useful to identify such types. In -fact, it is quite commonplace in mathematics. Say we look at a set $\{x \mid +Let $\top$ denote the unit type -- a type with a single constructor. In +the propositions-as-types interpretation of type theory $\top$ is the +proposition that is always true. The type $A \x \top$ and $A$ has an element for +each $a : A$. So in a sense they are the same. The second element of the pair +does not add any ``interesting information''. It can be useful to identify such +types. In fact, it is quite commonplace in mathematics. Say we look at a set +$\{x \mid \phi\ x \land \psi\ x\}$ and somehow conclude that $\psi\ x \equiv \top$ for all $x$. A mathematician would immediately conclude $\{x \mid \phi\ x \land \psi\ x\} \equiv \{x \mid \phi\ x\}$ without thinking twice. Unfortunately such @@ -92,8 +93,9 @@ types. The principle of univalence says that: % $$\mathit{univalence} \tp (A \simeq B) \simeq (A \equiv B)$$ % -In particular this allows us to construct an equality from an equivalence $\mathit{ua} \tp -(A \simeq B) \to (A \equiv B)$ and vice-versa. +In particular this allows us to construct an equality from an equivalence +($\mathit{ua} \tp (A \simeq B) \to (A \equiv B)$) and vice-versa. + \section{Formalizing Category Theory} % The above examples serve to illustrate the limitation of Agda. One case where @@ -115,20 +117,21 @@ Inspiration: \end{verbatim} The idea of formalizing Category Theory in proof assistants is not new. There are a multitude of these available online. Just as first reference see this -question on Math Overflow: \cite{mo-formalizations}. Notably these two implementations of category theory in Agda: +question on Math Overflow: \cite{mo-formalizations}. Notably these +implementations of category theory in Agda: \begin{itemize} \item -\url{https://github.com/copumpkin/categories} - setoid interpretation +\url{https://github.com/copumpkin/categories} -- setoid interpretation \item -\url{https://github.com/pcapriotti/agda-categories} - homotopic setting with postulates +\url{https://github.com/pcapriotti/agda-categories} -- homotopic setting with postulates \item -\url{https://github.com/pcapriotti/agda-categories} - homotopic setting in coq +\url{https://github.com/pcapriotti/agda-categories} -- homotopic setting in coq \item -\url{https://github.com/mortberg/cubicaltt} - homotopic setting in \texttt{cubicaltt} +\url{https://github.com/mortberg/cubicaltt} -- homotopic setting in \texttt{cubicaltt} \end{itemize} -The contribution of this -thesis is to explore how working in a cubical setting will make it possible to -prove more things and to reuse proofs. + +The contribution of this thesis is to explore how working in a cubical setting +will make it possible to prove more things and to reuse proofs. There are alternative approaches to working in a cubical setting where one can still have univalence and functional extensionality. One option is to postulate diff --git a/doc/macros.tex b/doc/macros.tex index 33f09d2..6a2a0ee 100644 --- a/doc/macros.tex +++ b/doc/macros.tex @@ -59,3 +59,9 @@ \newcommand\rrr{\ggg} \newcommand\fst{\mathit{fst}} \newcommand\snd{\mathit{snd}} +\newcommand\Path{\mathit{Path}} +\newcommand\Category{\mathit{Category}} +\newcommand\TODO[1]{TODO: \emph{#1}} +\newcommand*{\QED}{\hfill\ensuremath{\square}}% +\newcommand\uexists{\exists!} +\newcommand\Arrow{\mathit{Arrow}} diff --git a/doc/main.tex b/doc/main.tex index cf00dc9..bae31dd 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -26,8 +26,8 @@ \bibliographystyle{plainnat} \nocite{cubical-demo} \nocite{coquand-2013} -%% \bibliography{refs} -%% \begin{appendices} +\bibliography{refs} +\begin{appendices} %% \input{planning.tex} %% \input{halftime.tex} \end{appendices} diff --git a/src/Cat/Equivalence.agda b/src/Cat/Equivalence.agda index 6c96f1b..cc8870c 100644 --- a/src/Cat/Equivalence.agda +++ b/src/Cat/Equivalence.agda @@ -10,7 +10,7 @@ open import Cubical.GradLemma hiding (isoToPath) open import Cat.Prelude using ( lemPropF ; setPi ; lemSig ; propSet ; Preorder ; equalityIsEquivalence ; propSig ; id-coe - ; Setoid ) + ; Setoid ; _$_ ; propPi ) import Cubical.Univalence as U @@ -133,7 +133,7 @@ module _ {ℓa ℓb ℓ : Level} (A : Set ℓa) (B : Set ℓb) where -- | The other inverse law does not hold in general, it does hold, however, -- | if `A` and `B` are sets. module _ (sA : isSet A) (sB : isSet B) where - module _ {f : A → B} (iso : Isomorphism f) where + module _ {f : A → B} where module _ (iso-x iso-y : Isomorphism f) where open Σ iso-x renaming (fst to x ; snd to inv-x) open Σ iso-y renaming (fst to y ; snd to inv-y) @@ -146,22 +146,18 @@ module _ {ℓa ℓb ℓ : Level} (A : Set ℓa) (B : Set ℓb) where y ∎ propInv : ∀ g → isProp (AreInverses f g) - propInv g t u i = a i , b i + propInv g t u = λ i → a i , b i where a : (fst t) ≡ (fst u) - a i = h + a i = funExt hh where hh : ∀ a → (g ∘ f) a ≡ a hh a = sA ((g ∘ f) a) a (λ i → (fst t) i a) (λ i → (fst u) i a) i - h : g ∘ f ≡ idFun A - h i a = hh a i b : (snd t) ≡ (snd u) - b i = h + b i = funExt hh where hh : ∀ b → (f ∘ g) b ≡ b hh b = sB _ _ (λ i → snd t i b) (λ i → snd u i b) i - h : f ∘ g ≡ idFun B - h i b = hh b i inx≡iny : (λ i → AreInverses f (fx≡fy i)) [ inv-x ≡ inv-y ] inx≡iny = lemPropF propInv fx≡fy @@ -169,11 +165,12 @@ module _ {ℓa ℓb ℓ : Level} (A : Set ℓa) (B : Set ℓb) where propIso : iso-x ≡ iso-y propIso i = fx≡fy i , inx≡iny i - inverse-to-from-iso : (toIso {f} ∘ fromIso {f}) iso ≡ iso - inverse-to-from-iso = begin - (toIso ∘ fromIso) iso ≡⟨⟩ - toIso (fromIso iso) ≡⟨ propIso _ _ ⟩ - iso ∎ + module _ (iso : Isomorphism f) where + inverse-to-from-iso : (toIso {f} ∘ fromIso {f}) iso ≡ iso + inverse-to-from-iso = begin + (toIso ∘ fromIso) iso ≡⟨⟩ + toIso (fromIso iso) ≡⟨ propIso _ _ ⟩ + iso ∎ fromIsomorphism : A ≅ B → A ~ B fromIsomorphism (f , iso) = f , fromIso iso @@ -419,7 +416,7 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where equivPropSig pA p q = fromIsomorphism _ _ iso where f : ∀ {p q} → p ≡ q → fst p ≡ fst q - f e i = fst (e i) + f = cong fst g : ∀ {p q} → fst p ≡ fst q → p ≡ q g {p} {q} = lemSig pA p q ve-re : (e : p ≡ q) → (g ∘ f) e ≡ e @@ -507,31 +504,26 @@ module _ {ℓa ℓb : Level} {A : Set ℓa} {P : A → Set ℓb} where → ((a : A) → P a ≃ Q a) → Σ A P ≃ Σ A Q equivSig {Q = Q} eA = res where + P≅Q : ∀ {a} → P a ≅ Q a + P≅Q {a} = toIsomorphism _ _ (eA a) f : Σ A P → Σ A Q - f (a , pA) = a , fst (eA a) pA + f (a , pA) = a , fst P≅Q pA g : Σ A Q → Σ A P - g (a , qA) = a , g' qA - where - k : Isomorphism _ - k = toIso _ _ (snd (eA a)) - open Σ k renaming (fst to g') + g (a , qA) = a , fst (snd P≅Q) qA ve-re : (x : Σ A P) → (g ∘ f) x ≡ x - ve-re x i = fst x , eq i + ve-re (a , pA) i = a , eq i where - eq : snd ((g ∘ f) x) ≡ snd x + eq : snd ((g ∘ f) (a , pA)) ≡ pA eq = begin - snd ((g ∘ f) x) ≡⟨⟩ + snd ((g ∘ f) (a , pA)) ≡⟨⟩ snd (g (f (a , pA))) ≡⟨⟩ g' (fst (eA a) pA) ≡⟨ lem ⟩ pA ∎ where - open Σ x renaming (fst to a ; snd to pA) - k : Isomorphism _ - k = toIso _ _ (snd (eA a)) - open Σ k renaming (fst to g' ; snd to inv) + open Σ (snd P≅Q) renaming (fst to g' ; snd to inv) -- anti-funExt lem : (g' ∘ (fst (eA a))) pA ≡ pA - lem i = fst inv i pA + lem = cong (_$ pA) (fst (snd (snd P≅Q))) re-ve : (x : Σ A Q) → (f ∘ g) x ≡ x re-ve x i = fst x , eq i where diff --git a/src/Cat/Prelude.agda b/src/Cat/Prelude.agda index 0c0bec0..71e5cbd 100644 --- a/src/Cat/Prelude.agda +++ b/src/Cat/Prelude.agda @@ -62,10 +62,8 @@ module _ (ℓ : Level) where syntax ∃!-syntax (λ x → B) = ∃![ x ] B module _ {ℓa ℓb} {A : Set ℓa} {P : A → Set ℓb} (f g : ∃! P) where - open Σ (snd f) renaming (snd to u) - ∃-unique : fst f ≡ fst g - ∃-unique = u (fst (snd g)) + ∃-unique = (snd (snd f)) (fst (snd g)) module _ {ℓa ℓb : Level} {A : Set ℓa} {B : A → Set ℓb} {a b : Σ A B} (fst≡ : (λ _ → A) [ fst a ≡ fst b ]) From 6b6e6672e090b26fd70a9558ae0db6481de6dd70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 25 Apr 2018 08:19:36 +0200 Subject: [PATCH 68/93] Rename variable --- src/Cat/Category/Product.agda | 60 +++++++++++++++++------------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 757c5cc..4fb6237 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -87,18 +87,18 @@ module _ {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} {A B : Category.Object q = lemPropF propIsProduct p module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} - (let module ℂ = Category ℂ) {A B : ℂ.Object} where + (let module ℂ = Category ℂ) {𝓐 𝓑 : ℂ.Object} where open P module _ where raw : RawCategory _ _ raw = record - { Object = Σ[ X ∈ ℂ.Object ] ℂ.Arrow X A × ℂ.Arrow X B - ; Arrow = λ{ (X , x0 , x1) (Y , y0 , y1) - → Σ[ f ∈ ℂ.Arrow X Y ] - ℂ [ y0 ∘ f ] ≡ x0 - × ℂ [ y1 ∘ f ] ≡ x1 + { Object = Σ[ X ∈ ℂ.Object ] ℂ.Arrow X 𝓐 × ℂ.Arrow X 𝓑 + ; Arrow = λ{ (A , a0 , a1) (B , b0 , b1) + → Σ[ f ∈ ℂ.Arrow A B ] + ℂ [ b0 ∘ f ] ≡ a0 + × ℂ [ b1 ∘ f ] ≡ a1 } ; identity = λ{ {X , f , g} → ℂ.identity {X} , ℂ.rightIdentity , ℂ.rightIdentity} ; _<<<_ = λ { {_ , a0 , a1} {_ , b0 , b1} {_ , c0 , c1} (f , f0 , f1) (g , g0 , g1) @@ -176,7 +176,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} open import Cat.Equivalence using (composeIso) renaming (_≅_ to _≅_) step0 : ((X , xa , xb) ≡ (Y , ya , yb)) - ≅ (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)) + ≅ (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) 𝓐) xa ya) × (PathP (λ i → ℂ.Arrow (p i) 𝓑) xb yb)) step0 = (λ p → cong fst p , cong-d (fst ∘ snd) p , cong-d (snd ∘ snd) p) -- , (λ x → λ i → fst x i , (fst (snd x) i) , (snd (snd x) i)) @@ -203,12 +203,12 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} p step1 - : (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)) + : (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) 𝓐) xa ya) × (PathP (λ i → ℂ.Arrow (p i) 𝓑) xb yb)) ≅ Σ (X ℂ.≊ Y) (λ iso → let p = ℂ.isoToId iso in - ( PathP (λ i → ℂ.Arrow (p i) A) xa ya) - × PathP (λ i → ℂ.Arrow (p i) B) xb yb + ( PathP (λ i → ℂ.Arrow (p i) 𝓐) xa ya) + × PathP (λ i → ℂ.Arrow (p i) 𝓑) xb yb ) step1 = symIso @@ -216,7 +216,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} {A = (X ℂ.≊ Y)} {B = (X ≡ Y)} (ℂ.groupoidObject _ _) - {Q = \ p → (PathP (λ i → ℂ.Arrow (p i) A) xa ya) × (PathP (λ i → ℂ.Arrow (p i) B) xb yb)} + {Q = \ p → (PathP (λ i → ℂ.Arrow (p i) 𝓐) xa ya) × (PathP (λ i → ℂ.Arrow (p i) 𝓑) xb yb)} ℂ.isoToId (symIso (_ , ℂ.asTypeIso {X} {Y}) .snd) ) @@ -225,8 +225,8 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} : Σ (X ℂ.≊ Y) (λ iso → let p = ℂ.isoToId iso in - ( PathP (λ i → ℂ.Arrow (p i) A) xa ya) - × PathP (λ i → ℂ.Arrow (p i) B) xb yb + ( PathP (λ i → ℂ.Arrow (p i) 𝓐) xa ya) + × PathP (λ i → ℂ.Arrow (p i) 𝓑) xb yb ) ≅ ((X , xa , xb) ≊ (Y , ya , yb)) step2 @@ -243,10 +243,10 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} iso = fst f , fst f~ , cong fst inv-f , cong fst inv-f~ p : X ≡ Y p = ℂ.isoToId iso - pA : ℂ.Arrow X A ≡ ℂ.Arrow Y A - pA = cong (λ x → ℂ.Arrow x A) p - pB : ℂ.Arrow X B ≡ ℂ.Arrow Y B - pB = cong (λ x → ℂ.Arrow x B) p + pA : ℂ.Arrow X 𝓐 ≡ ℂ.Arrow Y 𝓐 + pA = cong (λ x → ℂ.Arrow x 𝓐) p + pB : ℂ.Arrow X 𝓑 ≡ ℂ.Arrow Y 𝓑 + pB = cong (λ x → ℂ.Arrow x 𝓑) p k0 = begin coe pB xb ≡⟨ ℂ.coe-dom iso ⟩ xb ℂ.<<< fst f~ ≡⟨ snd (snd f~) ⟩ @@ -264,10 +264,10 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} (Σ≡ refl (ℂ.propIsomorphism _ _ _))) , funExt (λ{ (f , _) → lemSig propIsomorphism _ _ (Σ≡ refl (propEqs _ _ _))}) where - prop0 : ∀ {x} → isProp (PathP (λ i → ℂ.Arrow (ℂ.isoToId x i) A) xa ya) - prop0 {x} = pathJ (λ y p → ∀ x → isProp (PathP (λ i → ℂ.Arrow (p i) A) xa x)) (λ x → ℂ.arrowsAreSets _ _) Y (ℂ.isoToId x) ya - prop1 : ∀ {x} → isProp (PathP (λ i → ℂ.Arrow (ℂ.isoToId x i) B) xb yb) - prop1 {x} = pathJ (λ y p → ∀ x → isProp (PathP (λ i → ℂ.Arrow (p i) B) xb x)) (λ x → ℂ.arrowsAreSets _ _) Y (ℂ.isoToId x) yb + prop0 : ∀ {x} → isProp (PathP (λ i → ℂ.Arrow (ℂ.isoToId x i) 𝓐) xa ya) + prop0 {x} = pathJ (λ y p → ∀ x → isProp (PathP (λ i → ℂ.Arrow (p i) 𝓐) xa x)) (λ x → ℂ.arrowsAreSets _ _) Y (ℂ.isoToId x) ya + prop1 : ∀ {x} → isProp (PathP (λ i → ℂ.Arrow (ℂ.isoToId x i) 𝓑) xb yb) + prop1 {x} = pathJ (λ y p → ∀ x → isProp (PathP (λ i → ℂ.Arrow (p i) 𝓑) xb x)) (λ x → ℂ.arrowsAreSets _ _) Y (ℂ.isoToId x) yb -- One thing to watch out for here is that the isomorphisms going forwards -- must compose to give idToIso iso @@ -297,34 +297,34 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} open Category cat - lemma : Terminal ≃ Product ℂ A B - lemma = fromIsomorphism Terminal (Product ℂ A B) (f , g , inv) + lemma : Terminal ≃ Product ℂ 𝓐 𝓑 + lemma = fromIsomorphism Terminal (Product ℂ 𝓐 𝓑) (f , g , inv) where - f : Terminal → Product ℂ A B + f : Terminal → Product ℂ 𝓐 𝓑 f ((X , x0 , x1) , uniq) = p where - rawP : RawProduct ℂ A B + rawP : RawProduct ℂ 𝓐 𝓑 rawP = record { object = X ; fst = x0 ; snd = x1 } -- open RawProduct rawP renaming (fst to x0 ; snd to x1) - module _ {Y : ℂ.Object} (p0 : ℂ [ Y , A ]) (p1 : ℂ [ Y , B ]) where + module _ {Y : ℂ.Object} (p0 : ℂ [ Y , 𝓐 ]) (p1 : ℂ [ Y , 𝓑 ]) where uy : isContr (Arrow (Y , p0 , p1) (X , x0 , x1)) uy = uniq {Y , p0 , p1} open Σ uy renaming (fst to Y→X ; snd to contractible) open Σ Y→X renaming (fst to p0×p1 ; snd to cond) ump : ∃![ f×g ] (ℂ [ x0 ∘ f×g ] ≡ p0 P.× ℂ [ x1 ∘ f×g ] ≡ p1) ump = p0×p1 , cond , λ {y} x → let k = contractible (y , x) in λ i → fst (k i) - isP : IsProduct ℂ A B rawP + isP : IsProduct ℂ 𝓐 𝓑 rawP isP = record { ump = ump } - p : Product ℂ A B + p : Product ℂ 𝓐 𝓑 p = record { raw = rawP ; isProduct = isP } - g : Product ℂ A B → Terminal + g : Product ℂ 𝓐 𝓑 → Terminal g p = o , t where module p = Product p @@ -375,7 +375,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} inv : AreInverses f g inv = funExt ve-re , funExt re-ve - propProduct : isProp (Product ℂ A B) + propProduct : isProp (Product ℂ 𝓐 𝓑) propProduct = equivPreservesNType {n = ⟨-1⟩} lemma Propositionality.propTerminal module _ {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} {A B : Category.Object ℂ} where From 9a8b09e15f0df351547b01a445540330bed62909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 25 Apr 2018 08:21:45 +0200 Subject: [PATCH 69/93] Change title-page, write stuff about products --- doc/chalmerstitle.sty | 86 +++++++++++++++++++++++++++++++----------- doc/implementation.tex | 49 ++++++++++++++++++++++++ doc/macros.tex | 78 +++++++++++++++++++------------------- doc/main.tex | 23 +++++++++-- doc/packages.tex | 8 +++- 5 files changed, 177 insertions(+), 67 deletions(-) diff --git a/doc/chalmerstitle.sty b/doc/chalmerstitle.sty index 76a8111..d224ac3 100644 --- a/doc/chalmerstitle.sty +++ b/doc/chalmerstitle.sty @@ -4,45 +4,85 @@ \newcommand*{\authoremail}[1]{\gdef\@authoremail{#1}} \newcommand*{\supervisor}[1]{\gdef\@supervisor{#1}} \newcommand*{\supervisoremail}[1]{\gdef\@supervisoremail{#1}} +\newcommand*{\supervisordepartment}[1]{\gdef\@supervisordepartment{#1}} \newcommand*{\cosupervisor}[1]{\gdef\@cosupervisor{#1}} \newcommand*{\cosupervisoremail}[1]{\gdef\@cosupervisoremail{#1}} +\newcommand*{\cosupervisordepartment}[1]{\gdef\@cosupervisordepartment{#1}} +\newcommand*{\examiner}[1]{\gdef\@examiner{#1}} +\newcommand*{\examineremail}[1]{\gdef\@examineremail{#1}} +\newcommand*{\examinerdepartment}[1]{\gdef\@examinerdepartment{#1}} \newcommand*{\institution}[1]{\gdef\@institution{#1}} +\newcommand*{\department}[1]{\gdef\@department{#1}} +\newcommand*{\researchgroup}[1]{\gdef\@researchgroup{#1}} \renewcommand*{\maketitle}{% \begin{titlepage} - +% TITLE PAGE +\newpage +\thispagestyle{empty} \begin{center} + \textsc{\LARGE Master's thesis \the\year}\\[4cm] % Report number is currently not in use + \textbf{\LARGE \@title} \\[1cm] + {\large \@subtitle}\\[1cm] + {\large \@author} + + \vfill + \centering + \includegraphics[width=0.2\pdfpagewidth]{logo_eng.pdf} + \vspace{5mm} + + Department of Computer Science and Engineering\\ + \emph{\@researchgroup}\\ + %Name of research group (if applicable)\\ + \textsc{\@institution} \\ + Gothenburg, Sweden \the\year \\ +\end{center} -{\scshape\LARGE Master thesis\\} +% IMPRINT PAGE (BACK OF TITLE PAGE) +\newpage +\thispagestyle{plain} +\vspace*{4.5cm} +\@title\\ +\@subtitle\\ +\textbf{Author:}\\ +\@author\\ +\href{mailto:\@authoremail>}{\texttt{<\@authoremail>}} +\setlength{\parskip}{1cm} -\vspace{0.5cm} +\copyright ~ \MakeUppercase{\@author}, \the\year. -{\LARGE\bfseries \@title\\} +\setlength{\parskip}{0.5cm} +\textbf{Supervisor:}\\ +\@supervisor\\ +\href{mailto:\@supervisoremail>}{\texttt{<\@supervisoremail>}}\\ +\@supervisordepartment -\vspace{2cm} +\textbf{Co-supervisor:}\\ +\@cosupervisor\\ +\href{mailto:\@cosupervisoremail>}{\texttt{<\@cosupervisoremail>}}\\ +\@cosupervisordepartment -{\Large \@author\\ \href{mailto:\@authoremail>}{\texttt{<\@authoremail>}} \\} +\textbf{Examiner:}\\ +\@examiner\\ +\href{mailto:\@examineremail>}{\texttt{<\@examineremail>}}\\ +\@examinerdepartment\setlength{\parskip}{1cm} -% \vspace{0.2cm} -% -% {\Large name and email adress of student 2\\} - -\vspace{1.0cm} - -{\large Supervisor: \@supervisor\\ \href{mailto:\@supervisoremail>}{\texttt{<\@supervisoremail>}}\\} - -\vspace{0.2cm} - -{\large Co-supervisor: \@cosupervisor\\ \href{mailto:\@cosupervisoremail>}{\texttt{<\@cosupervisoremail>}}\\} - -\vspace{1.5cm} +Master's Thesis \the\year\\ % Report number currently not in use +\@department\\ +%Division of Division name\\ +%Name of research group (if applicable)\\ +\@institution\\ +SE-412 96 Gothenburg\\ +Telephone +46 31 772 1000 \setlength{\parskip}{0.5cm} \vfill +% Caption for cover page figure if used, possibly with reference to further information in the report +%% Cover: Wind visualization constructed in Matlab showing a surface of constant wind speed along with streamlines of the flow. \setlength{\parskip}{0.5cm} -{\large \@institution\\\today\\} +%Printed by [Name of printing company]\\ +Gothenburg, Sweden \the\year -\end{center} -\end{titlepage} -} + +\end{titlepage}} diff --git a/doc/implementation.tex b/doc/implementation.tex index 02ca940..70af29a 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -691,6 +691,7 @@ are propositional in a proper category and equivalences preservehomotopy level, then we know that products also are propositions. But before we get to that, let's recall the definition of products. +\subsection{Products} Given a category $\bC$ and two objects $A$ and $B$ in $bC$ we define the product of $A$ and $B$ to be an object $A \x B$ in $\bC$ and two arrows $\pi_1 \tp A \x B \to A$ and $\pi_2 \tp A \x B \to B$ called the projections of the product. The projections must satisfy the following property: @@ -709,6 +710,54 @@ that there exists a unique arrow $\pi \tp \Arrow\ X\ (A \x B)$ satisfying $ $\pi$ is called the product (arrow) of $f$ and $g$. +\subsection{Pair category} + +\newcommand\pairA{\mathcal{A}} +\newcommand\pairB{\mathcal{B}} +Given a base category $\bC$ and two objects in this category $\pairA$ and +$\pairrB$ we can construct the ``pair category'': \TODO{This is a working title, + it's nice to have a name for this thing to refer back to} + +The type objects in this category will be an object in the underlying category, +$X$, and two arrows (also from the underlying category) +$\Arrow\ X\ \pairA$ and $\Arrow\ X\ \pairB$. + +\newcommand\pairf{\ensuremath{f}} +\newcommand\pairFst{\mathcal{\pi_1}} +\newcommand\pairSnd{\mathcal{\pi_2}} + +An arrow between objects $A ,\ a_0 ,\ a_1$ and $B ,\ b_0 ,\ b_1$ in this +category will consist of an arrow from the underlying category $\pairf \tp +\Arrow\ A\ B$ satisfying: +% +\begin{align} +\begin{split} +\label{eq:pairArrowLaw} +b_0 \lll f & \equiv a_0 \\ +b_1 \lll f & \equiv a_1 +\end{split} +\end{align} + +The identity morphism is the identity morphism from the underlying category. +This choice satisfies \ref{eq:pairArrowLaw} because of the right-identity law +from the underlying category. + +For composition of arrows $f \tp \Arrow\ A\ B$ and $g \tp \Arrow\ B\ C$ we +choose $g \lll f$ and we must now verify that it satisfies +\ref{eq:pairArrowLaw}: +% +\begin{align*} + c_0 \lll (f \lll g) + & \equiv + (c_0 \lll f) \lll g + && \text{Associativity} \\ + & \equiv + b_0 \lll g + && \text{$f$ satisfies \ref{eq:pairArrowLaw}} \\ + & \equiv + a_0 + && \text{$g$ satisfies \ref{eq:pairArrowLaw}} \\ +\end{align*} \section{Monads} diff --git a/doc/macros.tex b/doc/macros.tex index 6a2a0ee..d43b2c4 100644 --- a/doc/macros.tex +++ b/doc/macros.tex @@ -22,46 +22,46 @@ \newcommand{\tp}{\;\mathord{:}\;} \newcommand{\Type}{\mathcal{U}} -\newcommand{\var}[1]{\mathit{#1}} -\newcommand{\Hom}{\mathit{Hom}} -\newcommand{\fmap}{\mathit{fmap}} -\newcommand{\idFun}{\mathit{id}} -\newcommand{\Sets}{\mathit{Sets}} -\newcommand{\Set}{\mathit{Set}} -\newcommand{\hSet}{\mathit{hSet}} -\newcommand{\id}{\mathit{id}} -\newcommand{\isEquiv}{\mathit{isEquiv}} -\newcommand{\idToIso}{\mathit{idToIso}} -\newcommand{\isSet}{\mathit{isSet}} -\newcommand{\isContr}{\mathit{isContr}} -\newcommand\Object{\mathit{Object}} -\newcommand\Functor{\mathit{Functor}} -\newcommand\isProp{\mathit{isProp}} -\newcommand\propPi{\mathit{propPi}} -\newcommand\propSig{\mathit{propSig}} -\newcommand\PreCategory{\mathit{PreCategory}} -\newcommand\IsPreCategory{\mathit{IsPreCategory}} -\newcommand\isIdentity{\mathit{isIdentity}} -\newcommand\propIsIdentity{\mathit{propIsIdentity}} -\newcommand\IsCategory{\mathit{IsCategory}} -\newcommand\Gl{\mathit{\lambda}} -\newcommand\lemPropF{\mathit{lemPropF}} -\newcommand\isPreCategory{\mathit{isPreCategory}} -\newcommand\congruence{\mathit{cong}} -\newcommand\identity{\mathit{identity}} -\newcommand\isequiv{\mathit{isequiv}} -\newcommand\qinv{\mathit{qinv}} -\newcommand\fiber{\mathit{fiber}} -\newcommand\shuffle{\mathit{shuffle}} -\newcommand\Univalent{\mathit{Univalent}} -\newcommand\refl{\mathit{refl}} -\newcommand\isoToId{\mathit{isoToId}} +\newcommand{\var}[1]{\ensuremath{\mathit{#1}}} +\newcommand{\Hom}{\var{Hom}} +\newcommand{\fmap}{\var{fmap}} +\newcommand{\idFun}{\var{id}} +\newcommand{\Sets}{\var{Sets}} +\newcommand{\Set}{\var{Set}} +\newcommand{\hSet}{\var{hSet}} +\newcommand{\id}{\var{id}} +\newcommand{\isEquiv}{\var{isEquiv}} +\newcommand{\idToIso}{\var{idToIso}} +\newcommand{\isSet}{\var{isSet}} +\newcommand{\isContr}{\var{isContr}} +\newcommand\Object{\var{Object}} +\newcommand\Functor{\var{Functor}} +\newcommand\isProp{\var{isProp}} +\newcommand\propPi{\var{propPi}} +\newcommand\propSig{\var{propSig}} +\newcommand\PreCategory{\var{PreCategory}} +\newcommand\IsPreCategory{\var{IsPreCategory}} +\newcommand\isIdentity{\var{isIdentity}} +\newcommand\propIsIdentity{\var{propIsIdentity}} +\newcommand\IsCategory{\var{IsCategory}} +\newcommand\Gl{\var{\lambda}} +\newcommand\lemPropF{\var{lemPropF}} +\newcommand\isPreCategory{\var{isPreCategory}} +\newcommand\congruence{\var{cong}} +\newcommand\identity{\var{identity}} +\newcommand\isequiv{\var{isequiv}} +\newcommand\qinv{\var{qinv}} +\newcommand\fiber{\var{fiber}} +\newcommand\shuffle{\var{shuffle}} +\newcommand\Univalent{\var{Univalent}} +\newcommand\refl{\var{refl}} +\newcommand\isoToId{\var{isoToId}} \newcommand\rrr{\ggg} -\newcommand\fst{\mathit{fst}} -\newcommand\snd{\mathit{snd}} -\newcommand\Path{\mathit{Path}} -\newcommand\Category{\mathit{Category}} +\newcommand\fst{\var{fst}} +\newcommand\snd{\var{snd}} +\newcommand\Path{\var{Path}} +\newcommand\Category{\var{Category}} \newcommand\TODO[1]{TODO: \emph{#1}} \newcommand*{\QED}{\hfill\ensuremath{\square}}% \newcommand\uexists{\exists!} -\newcommand\Arrow{\mathit{Arrow}} +\newcommand\Arrow{\var{Arrow}} diff --git a/doc/main.tex b/doc/main.tex index bae31dd..f133be7 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -1,22 +1,34 @@ -\documentclass{report} +\documentclass[a4paper]{report} +%% \documentclass[compact,a4paper]{article} \input{packages.tex} \input{macros.tex} -\title{Univalent categories} +\title{Univalent categories in cubical Agda} +\subtitle{} \author{Frederik Hanghøj Iversen} \authoremail{hanghj@student.chalmers.se} +\newcommand{\chalmers}{Chalmers University of Technology} \supervisor{Thierry Coquand} \supervisoremail{coquand@chalmers.se} +\supervisordepartment{\chalmers} \cosupervisor{Andrea Vezzosi} \cosupervisoremail{vezzosi@chalmers.se} -\institution{Chalmers University of Technology} +\cosupervisordepartment{\chalmers} +\examiner{Andreas Abel} +\examineremail{abela@chalmers.se} +\examinerdepartment{\chalmers} +\institution{\chalmers} +\department{Department of Computer Science and Engineering} +\researchgroup{Programming Logic Group} \begin{document} +\pagenumbering{roman} \maketitle \tableofcontents - +% +\pagenumbering{arabic} \chapter{Introduction} \input{introduction.tex} @@ -27,7 +39,10 @@ \nocite{cubical-demo} \nocite{coquand-2013} \bibliography{refs} + \begin{appendices} +\setcounter{page}{1} +\pagenumbering{roman} %% \input{planning.tex} %% \input{halftime.tex} \end{appendices} diff --git a/doc/packages.tex b/doc/packages.tex index c55dad5..b786de2 100644 --- a/doc/packages.tex +++ b/doc/packages.tex @@ -1,7 +1,12 @@ \usepackage[utf8]{inputenc} \usepackage{natbib} -\usepackage[hidelinks]{hyperref} +\usepackage[ + hidelinks, + pdfusetitle, + pdfsubject={category theory}, + pdfkeywords={type theory, homotopy theory, category theory, agda}] + {hyperref} \usepackage{graphicx} @@ -10,6 +15,7 @@ \usepackage{amssymb,amsmath,amsthm,stmaryrd,mathrsfs,wasysym} \usepackage[toc,page]{appendix} \usepackage{xspace} +%% \usepackage{geometry} % \setlength{\parskip}{10pt} From 45eafe683fa92a7b5059a930934761c49b40a959 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 26 Apr 2018 10:20:57 +0200 Subject: [PATCH 70/93] Simplify --- src/Cat/Category.agda | 4 +-- src/Cat/Category/Product.agda | 60 ++++++----------------------------- src/Cat/Equivalence.agda | 2 +- 3 files changed, 13 insertions(+), 53 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 9394089..d9c109c 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -453,8 +453,8 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where -- This can probably also just be obtained from the above my taking the -- symmetric isomorphism. - domain-twist0 : f ≡ g <<< ι - domain-twist0 = begin + domain-twist-sym : f ≡ g <<< ι + domain-twist-sym = begin f ≡⟨ sym rightIdentity ⟩ f <<< identity ≡⟨ cong (f <<<_) (sym (fst inv)) ⟩ f <<< (ι~ <<< ι) ≡⟨ isAssociative ⟩ diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 4fb6237..7f7ddbe 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -125,41 +125,19 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} → (xy : ℂ.Arrow X Y) → isProp (ℂ [ ya ∘ xy ] ≡ xa × ℂ [ yb ∘ xy ] ≡ xb) propEqs xs = propSig (ℂ.arrowsAreSets _ _) (\ _ → ℂ.arrowsAreSets _ _) + arrowEq : {X Y : Object} {f g : Arrow X Y} → fst f ≡ fst g → f ≡ g + arrowEq {X} {Y} {f} {g} p = λ i → p i , lemPropF propEqs p {snd f} {snd g} i + private isAssociative : IsAssociative - isAssociative {A'@(A , a0 , a1)} {B , _} {C , c0 , c1} {D'@(D , d0 , d1)} {ff@(f , f0 , f1)} {gg@(g , g0 , g1)} {hh@(h , h0 , h1)} i - = s0 i , lemPropF propEqs s0 {P.snd l} {P.snd r} i - where - l = hh <<< (gg <<< ff) - r = hh <<< gg <<< ff - -- s0 : h ℂ.<<< (g ℂ.<<< f) ≡ h ℂ.<<< g ℂ.<<< f - s0 : fst l ≡ fst r - s0 = ℂ.isAssociative {f = f} {g} {h} - + isAssociative {f = f , f0 , f1} {g , g0 , g1} {h , h0 , h1} = arrowEq ℂ.isAssociative isIdentity : IsIdentity identity - isIdentity {AA@(A , a0 , a1)} {BB@(B , b0 , b1)} {f , f0 , f1} = leftIdentity , rightIdentity - where - leftIdentity : identity <<< (f , f0 , f1) ≡ (f , f0 , f1) - leftIdentity i = l i , lemPropF propEqs l {snd L} {snd R} i - where - L = identity <<< (f , f0 , f1) - R : Arrow AA BB - R = f , f0 , f1 - l : fst L ≡ fst R - l = ℂ.leftIdentity - rightIdentity : (f , f0 , f1) <<< identity ≡ (f , f0 , f1) - rightIdentity i = l i , lemPropF propEqs l {snd L} {snd R} i - where - L = (f , f0 , f1) <<< identity - R : Arrow AA BB - R = (f , f0 , f1) - l : ℂ [ f ∘ ℂ.identity ] ≡ f - l = ℂ.rightIdentity + isIdentity {AA@(A , a0 , a1)} {BB@(B , b0 , b1)} {f , f0 , f1} = arrowEq ℂ.leftIdentity , arrowEq ℂ.rightIdentity arrowsAreSets : ArrowsAreSets arrowsAreSets {X , x0 , x1} {Y , y0 , y1} - = sigPresNType {n = ⟨0⟩} ℂ.arrowsAreSets λ a → propSet (propEqs _) + = sigPresSet ℂ.arrowsAreSets λ a → propSet (propEqs _) isPreCat : IsPreCategory raw IsPreCategory.isAssociative isPreCat = isAssociative @@ -184,24 +162,6 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} , funExt (λ{ p → refl}) , funExt (λ{ (p , q , r) → refl}) - -- Should follow from c being univalent - iso-id-inv : {p : X ≡ Y} → p ≡ ℂ.isoToId (ℂ.idToIso X Y p) - iso-id-inv {p} = sym (λ i → fst (ℂ.inverse-from-to-iso' {X} {Y}) i p) - id-iso-inv : {iso : X ℂ.≊ Y} → iso ≡ ℂ.idToIso X Y (ℂ.isoToId iso) - id-iso-inv {iso} = sym (λ i → snd (ℂ.inverse-from-to-iso' {X} {Y}) i iso) - - lemA : {A B : Object} {f g : Arrow A B} → fst f ≡ fst g → f ≡ g - lemA {A} {B} {f = f} {g} p i = p i , h i - where - h : PathP (λ i → - (ℂ [ fst (snd B) ∘ p i ]) ≡ fst (snd A) × - (ℂ [ snd (snd B) ∘ p i ]) ≡ snd (snd A) - ) (snd f) (snd g) - h = lemPropF (λ a → propSig - (ℂ.arrowsAreSets (ℂ [ fst (snd B) ∘ a ]) (fst (snd A))) - λ _ → ℂ.arrowsAreSets (ℂ [ snd (snd B) ∘ a ]) (snd (snd A))) - p - step1 : (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) 𝓐) xa ya) × (PathP (λ i → ℂ.Arrow (p i) 𝓑) xb yb)) ≅ Σ (X ℂ.≊ Y) (λ iso @@ -231,10 +191,10 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} ≅ ((X , xa , xb) ≊ (Y , ya , yb)) step2 = ( λ{ (iso@(f , f~ , inv-f) , p , q) - → ( f , sym (ℂ.domain-twist0 iso p) , sym (ℂ.domain-twist0 iso q)) - , ( f~ , sym (ℂ.domain-twist iso p) , sym (ℂ.domain-twist iso q)) - , lemA (fst inv-f) - , lemA (snd inv-f) + → ( f , sym (ℂ.domain-twist-sym iso p) , sym (ℂ.domain-twist-sym iso q)) + , ( f~ , sym (ℂ.domain-twist iso p) , sym (ℂ.domain-twist iso q)) + , arrowEq (fst inv-f) + , arrowEq (snd inv-f) } ) , (λ{ (f , f~ , inv-f , inv-f~) → diff --git a/src/Cat/Equivalence.agda b/src/Cat/Equivalence.agda index cc8870c..1103b9f 100644 --- a/src/Cat/Equivalence.agda +++ b/src/Cat/Equivalence.agda @@ -50,7 +50,7 @@ module _ {ℓa ℓb ℓc} {A : Set ℓa} {B : Set ℓb} (sB : isSet B) {Q : B Σ-fst-map : Σ A (\ a → Q (f a)) → Σ B Q Σ-fst-map (x , q) = f x , q - isoSigFst : Isomorphism f → Σ A (\ a → Q (f a)) ≅ (Σ B Q) + isoSigFst : Isomorphism f → Σ A (Q ∘ f) ≅ Σ B Q isoSigFst (g , g-f , f-g) = Σ-fst-map , (\ { (b , q) → g b , transp (\ i → Q (f-g (~ i) b)) q }) , funExt (\ { (a , q) → Cat.Prelude.Σ≡ (\ i → g-f i a) From d726159fa0dfa03573daf751efdd2b4835bf6000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 26 Apr 2018 10:22:15 +0200 Subject: [PATCH 71/93] Stuff about product-category --- doc/chalmerstitle.sty | 43 +++++++--- doc/implementation.tex | 183 +++++++++++++++++++++++++++++++++++++---- doc/introduction.tex | 4 +- doc/macros.tex | 4 +- doc/main.tex | 24 +++++- doc/packages.tex | 14 +++- 6 files changed, 238 insertions(+), 34 deletions(-) diff --git a/doc/chalmerstitle.sty b/doc/chalmerstitle.sty index d224ac3..ac849be 100644 --- a/doc/chalmerstitle.sty +++ b/doc/chalmerstitle.sty @@ -1,6 +1,29 @@ % Requires: hypperref \ProvidesPackage{chalmerstitle} +%% \RequirePackage{kvoptions} + +%% \SetupKeyvalOptions{ +%% family=ct, +%% prefix=ct@ +%% } + +%% \DeclareStringOption{authoremail} +%% \DeclareStringOption{supervisor} +%% \DeclareStringOption{supervisoremail} +%% \DeclareStringOption{supervisordepartment} +%% \DeclareStringOption{cosupervisor} +%% \DeclareStringOption{cosupervisoremail} +%% \DeclareStringOption{cosupervisordepartment} +%% \DeclareStringOption{examiner} +%% \DeclareStringOption{examineremail} +%% \DeclareStringOption{examinerdepartment} +%% \DeclareStringOption{institution} +%% \DeclareStringOption{department} +%% \DeclareStringOption{researchgroup} +%% \DeclareStringOption{subtitle} +%% \ProcessKeyvalOptions* + \newcommand*{\authoremail}[1]{\gdef\@authoremail{#1}} \newcommand*{\supervisor}[1]{\gdef\@supervisor{#1}} \newcommand*{\supervisoremail}[1]{\gdef\@supervisoremail{#1}} @@ -14,6 +37,7 @@ \newcommand*{\institution}[1]{\gdef\@institution{#1}} \newcommand*{\department}[1]{\gdef\@department{#1}} \newcommand*{\researchgroup}[1]{\gdef\@researchgroup{#1}} +\newcommand*{\subtitle}[1]{\gdef\@subtitle{#1}} \renewcommand*{\maketitle}{% \begin{titlepage} @@ -43,17 +67,16 @@ % IMPRINT PAGE (BACK OF TITLE PAGE) \newpage \thispagestyle{plain} -\vspace*{4.5cm} -\@title\\ +\textit{\@title}\\ \@subtitle\\ +\copyright\ \the\year ~ \MakeUppercase{\@author} +\vspace{4.5cm} + +\setlength{\parskip}{0.5cm} \textbf{Author:}\\ \@author\\ \href{mailto:\@authoremail>}{\texttt{<\@authoremail>}} -\setlength{\parskip}{1cm} -\copyright ~ \MakeUppercase{\@author}, \the\year. - -\setlength{\parskip}{0.5cm} \textbf{Supervisor:}\\ \@supervisor\\ \href{mailto:\@supervisoremail>}{\texttt{<\@supervisoremail>}}\\ @@ -67,20 +90,18 @@ \textbf{Examiner:}\\ \@examiner\\ \href{mailto:\@examineremail>}{\texttt{<\@examineremail>}}\\ -\@examinerdepartment\setlength{\parskip}{1cm} +\@examinerdepartment +\vfill Master's Thesis \the\year\\ % Report number currently not in use \@department\\ %Division of Division name\\ %Name of research group (if applicable)\\ \@institution\\ SE-412 96 Gothenburg\\ -Telephone +46 31 772 1000 \setlength{\parskip}{0.5cm} - -\vfill +Telephone +46 31 772 1000 \setlength{\parskip}{0.5cm}\\ % Caption for cover page figure if used, possibly with reference to further information in the report %% Cover: Wind visualization constructed in Matlab showing a surface of constant wind speed along with streamlines of the flow. \setlength{\parskip}{0.5cm} - %Printed by [Name of printing company]\\ Gothenburg, Sweden \the\year diff --git a/doc/implementation.tex b/doc/implementation.tex index 70af29a..56caa98 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -66,7 +66,7 @@ $$ $$ % The two types are logically equivalent, however. One can construct the latter -from the formerr simply by ``forgetting'' that $\idToIso$ plays the role +from the former simply by ``forgetting'' that $\idToIso$ plays the role of the equivalence. The other direction is more involved. With all this in place it is now possible to prove that all the laws are indeed @@ -367,9 +367,10 @@ $$ $$ % % -$$ +\begin{align} +\label{eq:coeCod} \mathit{coeCod} \tp \prod_{f \tp A \to X} \mathit{coe}\ p_{\mathit{cod}}\ f \equiv \iota \lll f -$$ +\end{align} % I will give the proof of the first theorem here, the second one is analagous. \begin{align*} @@ -452,7 +453,8 @@ arguments. Or in other words since $\Hom_{A\ B}$ is a set for all $A\ B \tp \Object$ then so is $\Hom_{B\ A}$. Now, to show that this category is univalent is not as straight-forward. Lucliy -section \ref{sec:equiv} gave us some tools to work with equivalences. We saw that we +section \ref{sec:equiv} gave us some tools to work with equivalences. +We saw that we can prove this category univalent by giving an inverse to $\idToIso_{\mathit{Op}} \tp (A \equiv B) \to (A \approxeq_{\mathit{Op}} B)$. From the original category we have that $\idToIso \tp (A \equiv B) \to (A \cong @@ -692,9 +694,10 @@ then we know that products also are propositions. But before we get to that, let's recall the definition of products. \subsection{Products} -Given a category $\bC$ and two objects $A$ and $B$ in $bC$ we define the product -of $A$ and $B$ to be an object $A \x B$ in $\bC$ and two arrows $\pi_1 \tp A \x -B \to A$ and $\pi_2 \tp A \x B \to B$ called the projections of the product. The projections must satisfy the following property: +Given a category $\bC$ and two objects $A$ and $B$ in $\bC$ we define the +product of $A$ and $B$ to be an object $A \x B$ in $\bC$ and two arrows $\pi_1 +\tp A \x B \to A$ and $\pi_2 \tp A \x B \to B$ called the projections of the +product. The projections must satisfy the following property: For all $X \tp Object$, $f \tp \Arrow\ X\ A$ and $g \tp \Arrow\ X\ B$ we have that there exists a unique arrow $\pi \tp \Arrow\ X\ (A \x B)$ satisfying @@ -706,8 +709,8 @@ that there exists a unique arrow $\pi \tp \Arrow\ X\ (A \x B)$ satisfying \pi_1 \lll \pi \equiv f \x \pi_2 \lll \pi \equiv g %% ump : ∀ {X : Object} (f : ℂ [ X , A ]) (g : ℂ [ X , B ]) %% → ∃![ f×g ] (ℂ [ fst ∘ f×g ] ≡ f P.× ℂ [ snd ∘ f×g ] ≡ g) -\end{align*} -$ +\end{align} +% $\pi$ is called the product (arrow) of $f$ and $g$. \subsection{Pair category} @@ -715,7 +718,7 @@ $\pi$ is called the product (arrow) of $f$ and $g$. \newcommand\pairA{\mathcal{A}} \newcommand\pairB{\mathcal{B}} Given a base category $\bC$ and two objects in this category $\pairA$ and -$\pairrB$ we can construct the ``pair category'': \TODO{This is a working title, +$\pairB$ we can construct the ``pair category'': \TODO{This is a working title, it's nice to have a name for this thing to refer back to} The type objects in this category will be an object in the underlying category, @@ -731,11 +734,9 @@ category will consist of an arrow from the underlying category $\pairf \tp \Arrow\ A\ B$ satisfying: % \begin{align} -\begin{split} \label{eq:pairArrowLaw} -b_0 \lll f & \equiv a_0 \\ -b_1 \lll f & \equiv a_1 -\end{split} +b_0 \lll f \equiv a_0 \x +b_1 \lll f \equiv a_1 \end{align} The identity morphism is the identity morphism from the underlying category. @@ -758,6 +759,160 @@ choose $g \lll f$ and we must now verify that it satisfies a_0 && \text{$g$ satisfies \ref{eq:pairArrowLaw}} \\ \end{align*} +% +Now we must verify the category-laws. For all the laws we will follow the +pattern of using the law from the underlying category, and that the type of +arrows form a set. For instance, to prove associativity we must prove that +% +\begin{align} +\label{eq:productAssoc} +\overline{h} \lll (\overline{g} \lll \overline{f}) +\equiv +(\overline{h} \lll \overline{g}) \lll \overline{f} +\end{align} +% +Herer $\lll$ refers to the `embellished' composition abd $\overline{f}$, +$\overline{g}$ and $\overline{h}$ are triples consisting of arrows from the +underlying category ($f$, $g$ and $h$) and a pair of witnesses to +\ref{eq:pairArrowLaw}. +%% Luckily those winesses are paths in the hom-set of the +%% underlying category which is a set, so these are mere propositions. +The proof +obligations is: +% +\begin{align} +\label{eq:productAssocUnderlying} +h \lll (g \lll f) +\equiv +(h \lll g) \lll f +\end{align} +% +Which is provable by and that the witness to \ref{eq:pairArrowLaw} for the +left-hand-side and the right-hand-side are the same. The type of this goal is +quite involved, and I will not write it out in full, but it suffices to show the +type of the path-space. Note that the arrows in \ref{eq:productAssoc} are arrows +from $\mathcal{A} = (A , a_\pairA , a_\pairB)$ to $\mathcal{D} = (D , d_\pairA , +d_\pairB)$ where $a_\pairA$, $a_\pairB$, $d_\pairA$ and $d_\pairB$ are arrows in +the underlying category. Given that $p$ is the proof of +\ref{eq:productAssocUnderlying} we then have that the witness to +\ref{eq:pairArrowLaw} vary over the type: +% +\begin{align} +\label{eq:productPath} +λ\ i → d_\pairA \lll p\ i ≡ a_\pairA × d_\pairB \lll p\ i ≡ a_\pairB +\end{align} +% +And these paths are in the type of the hom-set of the underlying category, so +they are mere propositions. We cannot apply the fact that arrows in $\bC$ are +sets directly, however, since $\isSet$ only talks about non-dependent paths, in +stead we generalize \ref{eq:productPath} to: +% +\begin{align} +\label{eq:productEqPrinc} +\prod_{f \tp \Arrow\ X\ Y} \isProp\ \left( y_\pairA \lll f ≡ x_\pairA × y_\pairB \lll f ≡ x_\pairB \right) +\end{align} +% +For all objects $X , x_\pairA , x_\pairB$ and $Y , y_\pairA , y_\pairB$, but +this follows from pairs preserving homotopical structure and arrows in the +underlying category being sets. This gives us an equality principle for arrows +in this category that says that to prove two arrows $f, f_0, f_1$ and $g, g_0, +$g_1$ equal it suffices to give a proof that $f$ and $g$ are equal. +%% % +%% $$ +%% \prod_{(f, f_0, f_1)\; (g,g_0,g_1) \tp \Arrow\ X\ Y} f \equiv g \to (f, f_0, f_1) \equiv (g,g_0,g_1) +%% $$ +%% % +And thus we have proven \ref{eq:productAssoc} simply with +\ref{eq:productAssocUnderlying}. + +Now we must prove that arrows form a set: +% +$$ +\isSet\ (\Arrow\ \mathcal{X}\ \mathcal{Y}) +$$ +% +Since pairs preserve homotopical structure this reduces to: +% +$$ +\isSet\ (\Arrow_\bC\ X\ Y) +$$ +% +Which holds. And +% +$$ +\prod_{f \tp \Arrow\ X\ Y} \isSet\ \left( y_\pairA \lll f ≡ x_\pairA × y_\pairB \lll f ≡ x_\pairB \right) +$$ +% +This we get from \ref{eq:productEqPrinc} and the fact that homotopical structure +is cumulative. + +This finishes the proof that this is a valid pre-category. + +\subsubsection{Univalence} +To prove that this is a proper category it must be shown that it is univalent. +That is, for any two objects $\mathcal{X} = (X, x_\mathcal{A} , x_\mathca{B})$ +and $\mathcal{Y} = Y, y_\mathcal{A}, y_\mathcal{B}$ I will show: +% +\begin{align} +(\mathcal{X} \equiv \mathcal{Y}) \cong (\mathcal{X} \approxeq \mathcal{Y}) +\end{align} + +I do this by showing that the following sequence of types are isomorphic. + +The first type is: +% +\begin{align} +\label{eq:univ-0} +(X , x_\mathcal{A} , x_\mathcal{B}) ≡ (Y , y_\mathcal{A} , y_\mathcal{B}) +\end{align} +% +The next types will be the triple: +% +\begin{align} +\label{eq:univ-1} +\begin{split} +p \tp & X \equiv Y \\ +& \Path\ (λ i → \Arrow\ (p\ i)\ \mathcal{A})\ x_\mathcal{A}\ y_\mathcal{A} \\ +& \Path\ (λ i → \Arrow\ (p\ i)\ \mathcal{B})\ x_\mathcal{B}\ y_\mathcal{B} +\end{split} +%% \end{split} +\end{align} + +The next type is very similar, but in stead of a path we will have an +isomorphism, and create a path from this: +% +\begin{align} +\label{eq:univ-2} +\begin{split} +\var{iso} \tp & X \cong Y \\ +& \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{A})\ x_\mathcal{A}\ y_\mathcal{A} \\ +& \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{B})\ x_\mathcal{B}\ y_\mathcal{B} +\end{split} +\end{align} +% +Where $\widetilde{p} \defeq \var{isoToId}\ \var{iso} \tp X \equiv Y$. + +Finally we have the type: +% +\begin{align} +\label{eq:univ-3} +(X , x_\mathcal{A} , x_\mathcal{B}) ≊ (Y , y_\mathcal{A} , y_\mathcal{B}) +\end{align} + +\emph{Proposition} \ref{eq:univ-0} is isomorphic to \ref{eq:univ-1}: This is +just an application of the fact that a path between two pairs $a_0, a_1$ and +$b_0, b_1$ corresponds to a pair of paths between $a_0,b_0$ and $a_1,b_1$ (check +the implementation for the details). + +\emph{Proposition} \ref{eq:univ-1} is isomorphic to \ref{eq:univ-2}: +\TODO{Super complicated} + +\emph{Proposition} \ref{eq:univ-2} is isomorphic to \ref{eq:univ-3}: +For this I will two corrolaries of \ref{eq:coeCod}: +% +\begin{align} +\label{domain-twist} +\end{align} \section{Monads} diff --git a/doc/introduction.tex b/doc/introduction.tex index 08fde09..e5348b2 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -30,7 +30,7 @@ which is: % \newcommand{\suc}[1]{\mathit{suc}\ #1} \begin{align*} - + & : \bN \to \bN \\ + + & : \bN \to \bN \to \bN \\ n + 0 & \defeq n \\ n + (\suc{m}) & \defeq \suc{(n + m)} \end{align*} @@ -69,7 +69,7 @@ The proof obligation that this satisfies the identity law of functors % One needs functional extensionality to ``go under'' the function arrow and apply the (left) identity law of the underlying category to proove $\idFun \comp g -\equiv g$ and thus closing the. +\equiv g$ and thus closing the goal. % \subsection{Equality of isomorphic types} % diff --git a/doc/macros.tex b/doc/macros.tex index d43b2c4..885ae4c 100644 --- a/doc/macros.tex +++ b/doc/macros.tex @@ -3,9 +3,9 @@ \newcommand{\coloneqq}{\mathrel{\vcenter{\baselineskip0.5ex \lineskiplimit0pt \hbox{\scriptsize.}\hbox{\scriptsize.}}}% - =} + =} -\newcommand{\defeq}{\coloneqq} +\newcommand{\defeq}{\triangleq} \newcommand{\bN}{\mathbb{N}} \newcommand{\bC}{\mathbb{C}} \newcommand{\bX}{\mathbb{X}} diff --git a/doc/main.tex b/doc/main.tex index f133be7..6443e10 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -4,9 +4,29 @@ \input{packages.tex} \input{macros.tex} -\title{Univalent categories in cubical Agda} -\subtitle{} +\title{Univalent Categories in Cubical Agda} \author{Frederik Hanghøj Iversen} + +%% \usepackage[ +%% subtitle=foo, +%% author=Frederik Hanghøj Iversen, +%% authoremail=hanghj@student.chalmers.se, +%% newcommand=chalmers,=Chalmers University of Technology, +%% supervisor=Thierry Coquand, +%% supervisoremail=coquand@chalmers.se, +%% supervisordepartment=chalmers, +%% cosupervisor=Andrea Vezzosi, +%% cosupervisoremail=vezzosi@chalmers.se, +%% cosupervisordepartment=chalmers, +%% examiner=Andreas Abel, +%% examineremail=abela@chalmers.se, +%% examinerdepartment=chalmers, +%% institution=chalmers, +%% department=Department of Computer Science and Engineering, +%% researchgroup=Programming Logic Group +%% ]{chalmerstitle} +\usepackage{chalmerstitle} +\subtitle{} \authoremail{hanghj@student.chalmers.se} \newcommand{\chalmers}{Chalmers University of Technology} \supervisor{Thierry Coquand} diff --git a/doc/packages.tex b/doc/packages.tex index b786de2..bcbe5a2 100644 --- a/doc/packages.tex +++ b/doc/packages.tex @@ -28,15 +28,17 @@ \usepackage{listings} \usepackage{fancyvrb} -\usepackage{chalmerstitle} - \usepackage{mathpazo} \usepackage[scaled=0.95]{helvet} \usepackage{courier} \linespread{1.05} % Palatino looks better with this +\usepackage{lmodern} + \usepackage{fontspec} -\setmonofont[Mapping=tex-text]{FreeMono.otf} +\usepackage{sourcecodepro} +%% \setmonofont{Latin Modern Mono} +%% \setmonofont[Mapping=tex-text]{FreeMono.otf} %% \setmonofont{FreeMono.otf} @@ -44,3 +46,9 @@ \setlength{\headheight}{15pt} \renewcommand{\chaptermark}[1]{\markboth{\textsc{Chapter \thechapter. #1}}{}} \renewcommand{\sectionmark}[1]{\markright{\textsc{\thesection\ #1}}} + +% Allows for the use of unicode-letters: +\usepackage{unicode-math} + + +%% \RequirePackage{kvoptions} From e3eca8d90acf7330b6f91cabb93bd0c45ad6bc0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 1 May 2018 11:33:12 +0200 Subject: [PATCH 72/93] Prove other identity-law for monads --- src/Cat/Category/Monad/Kleisli.agda | 15 ++++++++++++++- src/Cat/Category/Product.agda | 2 -- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Cat/Category/Monad/Kleisli.agda b/src/Cat/Category/Monad/Kleisli.agda index 55e9cf5..bdb4966 100644 --- a/src/Cat/Category/Monad/Kleisli.agda +++ b/src/Cat/Category/Monad/Kleisli.agda @@ -50,13 +50,19 @@ record RawMonad : Set ℓ where -- There may be better names than what I've chosen here. + -- `pure` is the neutral element for `bind` IsIdentity = {X : Object} → bind pure ≡ identity {omap X} + -- pure is the left-identity for the kleisli arrow. IsNatural = {X Y : Object} (f : ℂ [ X , omap Y ]) - → pure >>> (bind f) ≡ f + → pure >=> f ≡ f + -- Composition interacts with bind in the following way. IsDistributive = {X Y Z : Object} (g : ℂ [ Y , omap Z ]) (f : ℂ [ X , omap Y ]) → (bind f) >>> (bind g) ≡ bind (f >=> g) + RightIdentity = {A B : Object} {m : ℂ [ A , omap B ]} + → m >=> pure ≡ m + -- | Functor map fusion. -- -- This is really a functor law. Should we have a kleisli-representation of @@ -215,6 +221,13 @@ record IsMonad (raw : RawMonad) : Set ℓ where bind pure ≡⟨ isIdentity ⟩ identity ∎ + rightIdentity : RightIdentity + rightIdentity {m = m} = begin + m >=> pure ≡⟨⟩ + m >>> bind pure ≡⟨ cong (m >>>_) isIdentity ⟩ + m >>> identity ≡⟨ ℂ.leftIdentity ⟩ + m ∎ + record Monad : Set ℓ where field raw : RawMonad diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 7f7ddbe..8dcc9a4 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -215,8 +215,6 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} coe pA xa ≡⟨ ℂ.coe-dom iso ⟩ xa ℂ.<<< fst f~ ≡⟨ fst (snd f~) ⟩ ya ∎ - helper : PathP (λ i → pA i) xa ya - helper = coe-lem-inv k1 in iso , coe-lem-inv k1 , coe-lem-inv k0}) , funExt (λ x → lemSig (λ x → propSig prop0 (λ _ → prop1)) From 4d27bbb401501a9704ec1476ed11ab870808af4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 1 May 2018 11:41:45 +0200 Subject: [PATCH 73/93] Use non-bold mathcal --- src/Cat/Category/Product.agda | 54 ++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 8dcc9a4..0d36004 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -87,14 +87,14 @@ module _ {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} {A B : Category.Object q = lemPropF propIsProduct p module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} - (let module ℂ = Category ℂ) {𝓐 𝓑 : ℂ.Object} where + (let module ℂ = Category ℂ) {𝒜 ℬ : ℂ.Object} where open P module _ where raw : RawCategory _ _ raw = record - { Object = Σ[ X ∈ ℂ.Object ] ℂ.Arrow X 𝓐 × ℂ.Arrow X 𝓑 + { Object = Σ[ X ∈ ℂ.Object ] ℂ.Arrow X 𝒜 × ℂ.Arrow X ℬ ; Arrow = λ{ (A , a0 , a1) (B , b0 , b1) → Σ[ f ∈ ℂ.Arrow A B ] ℂ [ b0 ∘ f ] ≡ a0 @@ -154,7 +154,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} open import Cat.Equivalence using (composeIso) renaming (_≅_ to _≅_) step0 : ((X , xa , xb) ≡ (Y , ya , yb)) - ≅ (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) 𝓐) xa ya) × (PathP (λ i → ℂ.Arrow (p i) 𝓑) xb yb)) + ≅ (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) × (PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb)) step0 = (λ p → cong fst p , cong-d (fst ∘ snd) p , cong-d (snd ∘ snd) p) -- , (λ x → λ i → fst x i , (fst (snd x) i) , (snd (snd x) i)) @@ -163,12 +163,12 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} , funExt (λ{ (p , q , r) → refl}) step1 - : (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) 𝓐) xa ya) × (PathP (λ i → ℂ.Arrow (p i) 𝓑) xb yb)) + : (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) × (PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb)) ≅ Σ (X ℂ.≊ Y) (λ iso → let p = ℂ.isoToId iso in - ( PathP (λ i → ℂ.Arrow (p i) 𝓐) xa ya) - × PathP (λ i → ℂ.Arrow (p i) 𝓑) xb yb + ( PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) + × PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb ) step1 = symIso @@ -176,7 +176,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} {A = (X ℂ.≊ Y)} {B = (X ≡ Y)} (ℂ.groupoidObject _ _) - {Q = \ p → (PathP (λ i → ℂ.Arrow (p i) 𝓐) xa ya) × (PathP (λ i → ℂ.Arrow (p i) 𝓑) xb yb)} + {Q = \ p → (PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) × (PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb)} ℂ.isoToId (symIso (_ , ℂ.asTypeIso {X} {Y}) .snd) ) @@ -185,8 +185,8 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} : Σ (X ℂ.≊ Y) (λ iso → let p = ℂ.isoToId iso in - ( PathP (λ i → ℂ.Arrow (p i) 𝓐) xa ya) - × PathP (λ i → ℂ.Arrow (p i) 𝓑) xb yb + ( PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) + × PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb ) ≅ ((X , xa , xb) ≊ (Y , ya , yb)) step2 @@ -203,10 +203,10 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} iso = fst f , fst f~ , cong fst inv-f , cong fst inv-f~ p : X ≡ Y p = ℂ.isoToId iso - pA : ℂ.Arrow X 𝓐 ≡ ℂ.Arrow Y 𝓐 - pA = cong (λ x → ℂ.Arrow x 𝓐) p - pB : ℂ.Arrow X 𝓑 ≡ ℂ.Arrow Y 𝓑 - pB = cong (λ x → ℂ.Arrow x 𝓑) p + pA : ℂ.Arrow X 𝒜 ≡ ℂ.Arrow Y 𝒜 + pA = cong (λ x → ℂ.Arrow x 𝒜) p + pB : ℂ.Arrow X ℬ ≡ ℂ.Arrow Y ℬ + pB = cong (λ x → ℂ.Arrow x ℬ) p k0 = begin coe pB xb ≡⟨ ℂ.coe-dom iso ⟩ xb ℂ.<<< fst f~ ≡⟨ snd (snd f~) ⟩ @@ -222,10 +222,10 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} (Σ≡ refl (ℂ.propIsomorphism _ _ _))) , funExt (λ{ (f , _) → lemSig propIsomorphism _ _ (Σ≡ refl (propEqs _ _ _))}) where - prop0 : ∀ {x} → isProp (PathP (λ i → ℂ.Arrow (ℂ.isoToId x i) 𝓐) xa ya) - prop0 {x} = pathJ (λ y p → ∀ x → isProp (PathP (λ i → ℂ.Arrow (p i) 𝓐) xa x)) (λ x → ℂ.arrowsAreSets _ _) Y (ℂ.isoToId x) ya - prop1 : ∀ {x} → isProp (PathP (λ i → ℂ.Arrow (ℂ.isoToId x i) 𝓑) xb yb) - prop1 {x} = pathJ (λ y p → ∀ x → isProp (PathP (λ i → ℂ.Arrow (p i) 𝓑) xb x)) (λ x → ℂ.arrowsAreSets _ _) Y (ℂ.isoToId x) yb + prop0 : ∀ {x} → isProp (PathP (λ i → ℂ.Arrow (ℂ.isoToId x i) 𝒜) xa ya) + prop0 {x} = pathJ (λ y p → ∀ x → isProp (PathP (λ i → ℂ.Arrow (p i) 𝒜) xa x)) (λ x → ℂ.arrowsAreSets _ _) Y (ℂ.isoToId x) ya + prop1 : ∀ {x} → isProp (PathP (λ i → ℂ.Arrow (ℂ.isoToId x i) ℬ) xb yb) + prop1 {x} = pathJ (λ y p → ∀ x → isProp (PathP (λ i → ℂ.Arrow (p i) ℬ) xb x)) (λ x → ℂ.arrowsAreSets _ _) Y (ℂ.isoToId x) yb -- One thing to watch out for here is that the isomorphisms going forwards -- must compose to give idToIso iso @@ -255,34 +255,36 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} open Category cat - lemma : Terminal ≃ Product ℂ 𝓐 𝓑 - lemma = fromIsomorphism Terminal (Product ℂ 𝓐 𝓑) (f , g , inv) + lemma : Terminal ≃ Product ℂ 𝒜 ℬ + lemma = fromIsomorphism Terminal (Product ℂ 𝒜 ℬ) (f , g , inv) + -- C-x 8 RET MATHEMATICAL BOLD SCRIPT CAPITAL A + -- 𝒜 where - f : Terminal → Product ℂ 𝓐 𝓑 + f : Terminal → Product ℂ 𝒜 ℬ f ((X , x0 , x1) , uniq) = p where - rawP : RawProduct ℂ 𝓐 𝓑 + rawP : RawProduct ℂ 𝒜 ℬ rawP = record { object = X ; fst = x0 ; snd = x1 } -- open RawProduct rawP renaming (fst to x0 ; snd to x1) - module _ {Y : ℂ.Object} (p0 : ℂ [ Y , 𝓐 ]) (p1 : ℂ [ Y , 𝓑 ]) where + module _ {Y : ℂ.Object} (p0 : ℂ [ Y , 𝒜 ]) (p1 : ℂ [ Y , ℬ ]) where uy : isContr (Arrow (Y , p0 , p1) (X , x0 , x1)) uy = uniq {Y , p0 , p1} open Σ uy renaming (fst to Y→X ; snd to contractible) open Σ Y→X renaming (fst to p0×p1 ; snd to cond) ump : ∃![ f×g ] (ℂ [ x0 ∘ f×g ] ≡ p0 P.× ℂ [ x1 ∘ f×g ] ≡ p1) ump = p0×p1 , cond , λ {y} x → let k = contractible (y , x) in λ i → fst (k i) - isP : IsProduct ℂ 𝓐 𝓑 rawP + isP : IsProduct ℂ 𝒜 ℬ rawP isP = record { ump = ump } - p : Product ℂ 𝓐 𝓑 + p : Product ℂ 𝒜 ℬ p = record { raw = rawP ; isProduct = isP } - g : Product ℂ 𝓐 𝓑 → Terminal + g : Product ℂ 𝒜 ℬ → Terminal g p = o , t where module p = Product p @@ -333,7 +335,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} inv : AreInverses f g inv = funExt ve-re , funExt re-ve - propProduct : isProp (Product ℂ 𝓐 𝓑) + propProduct : isProp (Product ℂ 𝒜 ℬ) propProduct = equivPreservesNType {n = ⟨-1⟩} lemma Propositionality.propTerminal module _ {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} {A B : Category.Object ℂ} where From 7cbaf996f1973f61a171a73991e77a752bf578b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 1 May 2018 18:54:08 +0200 Subject: [PATCH 74/93] Use implicit arguments for fun and profit --- src/Cat/Categories/Cat.agda | 4 +- src/Cat/Category/Monad.agda | 38 +++++++++--------- src/Cat/Category/Monad/Kleisli.agda | 3 +- src/Cat/Category/Monad/Monoidal.agda | 30 +++++++++----- src/Cat/Category/Product.agda | 59 ++++++++++++++-------------- 5 files changed, 74 insertions(+), 60 deletions(-) diff --git a/src/Cat/Categories/Cat.agda b/src/Cat/Categories/Cat.agda index a24abc8..de9b2ff 100644 --- a/src/Cat/Categories/Cat.agda +++ b/src/Cat/Categories/Cat.agda @@ -315,8 +315,8 @@ module _ (ℓ : Level) (unprovable : IsCategory (RawCat ℓ ℓ)) where exponent : Exponential Catℓ ℂ 𝔻 exponent = record { obj = CatExp.object - ; eval = eval - ; isExponential = isExponential + ; eval = {!eval!} + ; isExponential = {!isExponential!} } hasExponentials : HasExponentials Catℓ diff --git a/src/Cat/Category/Monad.agda b/src/Cat/Category/Monad.agda index 63fbab7..e071d92 100644 --- a/src/Cat/Category/Monad.agda +++ b/src/Cat/Category/Monad.agda @@ -69,20 +69,22 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where M.RawMonad.joinNT backRaw = joinNT private - open M.RawMonad backRaw + open M.RawMonad backRaw renaming + ( join to join* + ; pure to pure* + ; bind to bind* + ; fmap to fmap* + ) module R = Functor (M.RawMonad.R backRaw) backIsMonad : M.IsMonad backRaw - M.IsMonad.isAssociative backIsMonad {X} = begin - joinT X <<< R.fmap (joinT X) ≡⟨⟩ - join <<< fmap (joinT X) ≡⟨⟩ - join <<< fmap join ≡⟨ isNaturalForeign ⟩ - join <<< join ≡⟨⟩ - joinT X <<< joinT (R.omap X) ∎ + M.IsMonad.isAssociative backIsMonad = begin + join* <<< R.fmap join* ≡⟨⟩ + join <<< fmap join ≡⟨ isNaturalForeign ⟩ + join <<< join ∎ M.IsMonad.isInverse backIsMonad {X} = inv-l , inv-r where inv-l = begin - joinT X <<< pureT (R.omap X) ≡⟨⟩ join <<< pure ≡⟨ fst isInverse ⟩ identity ∎ inv-r = begin @@ -140,7 +142,7 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where bindEq : ∀ {X Y} {f : Arrow X (Romap Y)} → KM.bind f ≡ bind f bindEq {X} {Y} {f} = begin KM.bind f ≡⟨⟩ - joinT Y <<< Rfmap f ≡⟨⟩ + joinT Y <<< fmap f ≡⟨⟩ bind f ∎ joinEq : ∀ {X} → KM.join ≡ joinT X @@ -148,21 +150,21 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where KM.join ≡⟨⟩ KM.bind identity ≡⟨⟩ bind identity ≡⟨⟩ - joinT X <<< Rfmap identity ≡⟨ cong (λ φ → _ <<< φ) R.isIdentity ⟩ + joinT X <<< fmap identity ≡⟨ cong (λ φ → _ <<< φ) R.isIdentity ⟩ joinT X <<< identity ≡⟨ ℂ.rightIdentity ⟩ joinT X ∎ - fmapEq : ∀ {A B} → KM.fmap {A} {B} ≡ Rfmap + fmapEq : ∀ {A B} → KM.fmap {A} {B} ≡ fmap fmapEq {A} {B} = funExt (λ f → begin KM.fmap f ≡⟨⟩ KM.bind (f >>> KM.pure) ≡⟨⟩ bind (f >>> pureT _) ≡⟨⟩ - Rfmap (f >>> pureT B) >>> joinT B ≡⟨⟩ - Rfmap (f >>> pureT B) >>> joinT B ≡⟨ cong (λ φ → φ >>> joinT B) R.isDistributive ⟩ - Rfmap f >>> Rfmap (pureT B) >>> joinT B ≡⟨ ℂ.isAssociative ⟩ - joinT B <<< Rfmap (pureT B) <<< Rfmap f ≡⟨ cong (λ φ → φ <<< Rfmap f) (snd isInverse) ⟩ - identity <<< Rfmap f ≡⟨ ℂ.leftIdentity ⟩ - Rfmap f ∎ + fmap (f >>> pureT B) >>> joinT B ≡⟨⟩ + fmap (f >>> pureT B) >>> joinT B ≡⟨ cong (λ φ → φ >>> joinT B) R.isDistributive ⟩ + fmap f >>> fmap (pureT B) >>> joinT B ≡⟨ ℂ.isAssociative ⟩ + joinT B <<< fmap (pureT B) <<< fmap f ≡⟨ cong (λ φ → φ <<< fmap f) (snd isInverse) ⟩ + identity <<< fmap f ≡⟨ ℂ.leftIdentity ⟩ + fmap f ∎ ) rawEq : Functor.raw KM.R ≡ Functor.raw R @@ -183,7 +185,7 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where joinTEq = funExt (λ X → begin M.RawMonad.joinT (backRaw (forth m)) X ≡⟨⟩ KM.join ≡⟨⟩ - joinT X <<< Rfmap identity ≡⟨ cong (λ φ → joinT X <<< φ) R.isIdentity ⟩ + joinT X <<< fmap identity ≡⟨ cong (λ φ → joinT X <<< φ) R.isIdentity ⟩ joinT X <<< identity ≡⟨ ℂ.rightIdentity ⟩ joinT X ∎) diff --git a/src/Cat/Category/Monad/Kleisli.agda b/src/Cat/Category/Monad/Kleisli.agda index bdb4966..75e5a22 100644 --- a/src/Cat/Category/Monad/Kleisli.agda +++ b/src/Cat/Category/Monad/Kleisli.agda @@ -57,7 +57,8 @@ record RawMonad : Set ℓ where IsNatural = {X Y : Object} (f : ℂ [ X , omap Y ]) → pure >=> f ≡ f -- Composition interacts with bind in the following way. - IsDistributive = {X Y Z : Object} (g : ℂ [ Y , omap Z ]) (f : ℂ [ X , omap Y ]) + IsDistributive = {X Y Z : Object} + (g : ℂ [ Y , omap Z ]) (f : ℂ [ X , omap Y ]) → (bind f) >>> (bind g) ≡ bind (f >=> g) RightIdentity = {A B : Object} {m : ℂ [ A , omap B ]} diff --git a/src/Cat/Category/Monad/Monoidal.agda b/src/Cat/Category/Monad/Monoidal.agda index fdd739e..86111b6 100644 --- a/src/Cat/Category/Monad/Monoidal.agda +++ b/src/Cat/Category/Monad/Monoidal.agda @@ -26,35 +26,45 @@ record RawMonad : Set ℓ where pureNT : NaturalTransformation Functors.identity R joinNT : NaturalTransformation F[ R ∘ R ] R + Romap = Functor.omap R + fmap = Functor.fmap R + -- Note that `pureT` and `joinT` differs from their definition in the -- kleisli formulation only by having an explicit parameter. pureT : Transformation Functors.identity R pureT = fst pureNT + + pure : {X : Object} → ℂ [ X , Romap X ] + pure = pureT _ + pureN : Natural Functors.identity R pureT pureN = snd pureNT joinT : Transformation F[ R ∘ R ] R joinT = fst joinNT + join : {X : Object} → ℂ [ Romap (Romap X) , Romap X ] + join = joinT _ joinN : Natural F[ R ∘ R ] R joinT joinN = snd joinNT - Romap = Functor.omap R - Rfmap = Functor.fmap R - bind : {X Y : Object} → ℂ [ X , Romap Y ] → ℂ [ Romap X , Romap Y ] - bind {X} {Y} f = joinT Y <<< Rfmap f + bind {X} {Y} f = join <<< fmap f IsAssociative : Set _ IsAssociative = {X : Object} - → joinT X <<< Rfmap (joinT X) ≡ joinT X <<< joinT (Romap X) + -- R and join commute + → joinT X <<< fmap join ≡ join <<< join IsInverse : Set _ IsInverse = {X : Object} - → joinT X <<< pureT (Romap X) ≡ identity - × joinT X <<< Rfmap (pureT X) ≡ identity - IsNatural = ∀ {X Y} f → joinT Y <<< Rfmap f <<< pureT X ≡ f + -- Talks about R's action on objects + → join <<< pure ≡ identity {Romap X} + -- Talks about R's action on arrows + × join <<< fmap pure ≡ identity {Romap X} + IsNatural = ∀ {X Y} (f : Arrow X (Romap Y)) + → join <<< fmap f <<< pure ≡ f IsDistributive = ∀ {X Y Z} (g : Arrow Y (Romap Z)) (f : Arrow X (Romap Y)) - → joinT Z <<< Rfmap g <<< (joinT Y <<< Rfmap f) - ≡ joinT Z <<< Rfmap (joinT Z <<< Rfmap g <<< f) + → join <<< fmap g <<< (join <<< fmap f) + ≡ join <<< fmap (join <<< fmap g <<< f) record IsMonad (raw : RawMonad) : Set ℓ where open RawMonad raw public diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 0d36004..c0c68c3 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -276,7 +276,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} open Σ uy renaming (fst to Y→X ; snd to contractible) open Σ Y→X renaming (fst to p0×p1 ; snd to cond) ump : ∃![ f×g ] (ℂ [ x0 ∘ f×g ] ≡ p0 P.× ℂ [ x1 ∘ f×g ] ≡ p1) - ump = p0×p1 , cond , λ {y} x → let k = contractible (y , x) in λ i → fst (k i) + ump = p0×p1 , cond , λ {f} cond-f → cong fst (contractible (f , cond-f)) isP : IsProduct ℂ 𝒜 ℬ rawP isP = record { ump = ump } p : Product ℂ 𝒜 ℬ @@ -285,42 +285,43 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} ; isProduct = isP } g : Product ℂ 𝒜 ℬ → Terminal - g p = o , t + g p = 𝒳 , t where + open Product p renaming (object to X ; fst to x₀ ; snd to x₁) using () module p = Product p module isp = IsProduct p.isProduct - o : Object - o = p.object , p.fst , p.snd - module _ {Xx : Object} where - open Σ Xx renaming (fst to X ; snd to x) - ℂXo : ℂ [ X , isp.object ] - ℂXo = isp._P[_×_] (fst x) (snd x) - ump = p.ump (fst x) (snd x) - Xoo = fst (snd ump) - Xo : Arrow Xx o - Xo = ℂXo , Xoo - contractible : ∀ y → Xo ≡ y - contractible (y , yy) = res + 𝒳 : Object + 𝒳 = X , x₀ , x₁ + module _ {𝒴 : Object} where + open Σ 𝒴 renaming (fst to Y) + open Σ (snd 𝒴) renaming (fst to y₀ ; snd to y₁) + ump = p.ump y₀ y₁ + open Σ ump renaming (fst to f') + open Σ (snd ump) renaming (fst to f'-cond) + 𝒻 : Arrow 𝒴 𝒳 + 𝒻 = f' , {!f'-cond!} + contractible : (f : Arrow 𝒴 𝒳) → 𝒻 ≡ f + contractible ff@(f , f-cond) = res where - k : ℂXo ≡ y - k = snd (snd ump) (yy) - prp : ∀ a → isProp - ( (ℂ [ p.fst ∘ a ] ≡ fst x) - × (ℂ [ p.snd ∘ a ] ≡ snd x) + k : f' ≡ f + k = snd (snd ump) f-cond + prp : (a : ℂ.Arrow Y X) → isProp + ( (ℂ [ x₀ ∘ a ] ≡ y₀) + × (ℂ [ x₁ ∘ a ] ≡ y₁) ) - prp ab ac ad i - = ℂ.arrowsAreSets _ _ (fst ac) (fst ad) i - , ℂ.arrowsAreSets _ _ (snd ac) (snd ad) i + prp f f0 f1 = Σ≡ + (ℂ.arrowsAreSets _ _ (fst f0) (fst f1)) + (ℂ.arrowsAreSets _ _ (snd f0) (snd f1)) h : ( λ i - → ℂ [ p.fst ∘ k i ] ≡ fst x - × ℂ [ p.snd ∘ k i ] ≡ snd x - ) [ Xoo ≡ yy ] + → ℂ [ x₀ ∘ k i ] ≡ y₀ + × ℂ [ x₁ ∘ k i ] ≡ y₁ + ) [ f'-cond ≡ f-cond ] h = lemPropF prp k - res : (ℂXo , Xoo) ≡ (y , yy) - res i = k i , h i - t : IsTerminal o - t {Xx} = Xo , contractible + res : (f' , f'-cond) ≡ (f , f-cond) + res = Σ≡ k h + t : IsTerminal 𝒳 + t {𝒴} = 𝒻 , contractible ve-re : ∀ x → g (f x) ≡ x ve-re x = Propositionality.propTerminal _ _ re-ve : ∀ p → f (g p) ≡ p From ef90abb7e30d2cf824234563d55b1fa0fe967972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 1 May 2018 18:55:28 +0200 Subject: [PATCH 75/93] Finish section on propositionality of products and start on monads --- doc/halftime.tex | 46 ++-- doc/implementation.tex | 493 +++++++++++++++++++++++++++-------------- doc/introduction.tex | 1 + doc/macros.tex | 18 ++ doc/main.tex | 7 +- doc/packages.tex | 2 +- doc/planning.tex | 2 +- 7 files changed, 378 insertions(+), 191 deletions(-) diff --git a/doc/halftime.tex b/doc/halftime.tex index 2f3d2fa..8381f2b 100644 --- a/doc/halftime.tex +++ b/doc/halftime.tex @@ -1,4 +1,4 @@ -\section{Halftime report} +\chapter{Halftime report} I've written this as an appendix because 1) the aim of the thesis changed drastically from the planning report/proposal 2) partly I'm not sure how to structure my thesis. @@ -8,7 +8,7 @@ unclear to me at this point what I should have in the final report. Here I will describe what I have managed to formalize so far and what outstanding challenges I'm facing. -\subsection{Implementation overview} +\section{Implementation overview} The overall structure of my project is as follows: \begin{itemize} @@ -50,7 +50,7 @@ creating a function embodying the ``equality principle'' for a given record. In the case of monads, to prove two categories propositionally equal it enough to provide a proof that their data is equal. -\subsubsection{Categories} +\subsection{Categories} Defines the basic notion of a category. This definition closely follows that of [HoTT]: That is, the standard definition of a category (data; objects, arrows, composition and identity, laws; preservation of identity and composition) plus @@ -69,30 +69,30 @@ shown that univalence holds for such a construction) I also show that taking the opposite is an involution. -\subsubsection{Functors} +\subsection{Functors} Defines the notion of a functor - also split up into data and laws. Propositionality for being a functor. Composition of functors and the identity functor. -\subsubsection{Products} +\subsection{Products} Definition of what it means for an object to be a product in a given category. Definition of what it means for a category to have all products. \WIP{} Prove propositionality for being a product and having products. -\subsubsection{Exponentials} +\subsection{Exponentials} Definition of what it means to be an exponential object. Definition of what it means for a category to have all exponential objects. -\subsubsection{Cartesian closed categories} +\subsection{Cartesian closed categories} Definition of what it means for a category to be cartesian closed; namely that it has all products and all exponentials. -\subsubsection{Natural transformations} +\subsection{Natural transformations} Definition of transformations\footnote{Maybe this is a name I made up for a family of morphisms} and the naturality condition for these. @@ -101,18 +101,18 @@ principle. Proof that natural transformations are homotopic sets. The identity natural transformation. -\subsubsection{Yoneda embedding} +\subsection{Yoneda embedding} The yoneda embedding is typically presented in terms of the category of categories (cf. Awodey) \emph however this is not stricly needed - all we need is what would be the exponential object in that category - this happens to be functors and so this is how we define the yoneda embedding. -\subsubsection{Monads} +\subsection{Monads} Defines an equivalence between these two formulations of a monad: -\subsubsubsection{Monoidal monads} +\subsubsection{Monoidal monads} Defines the standard monoidal representation of a monad: @@ -121,7 +121,7 @@ and some laws about these natural transformations. Propositionality proofs and equality principle is provided. -\subsubsubsection{Kleisli monads} +\subsubsection{Kleisli monads} A presentation of monads perhaps more familiar to a functional programer: @@ -130,7 +130,7 @@ some laws about these maps. Propositionality proofs and equality principle is provided. -\subsubsubsection{Voevodsky's construction} +\subsubsection{Voevodsky's construction} Provides construction 2.3 as presented in an unpublished paper by Vladimir Voevodsky. This construction is similiar to the equivalence provided for the two @@ -138,7 +138,7 @@ preceding formulations \footnote{ TODO: I would like to include in the thesis some motivation for why this construction is particularly interesting.} -\subsubsection{Homotopy sets} +\subsection{Homotopy sets} The typical category of sets where the objects are modelled by an Agda set (henceforth ``$\Type$'') at a given level is not a valid category in this cubical settings, we need to restrict the types to be those that are homotopy sets. Thus @@ -171,7 +171,7 @@ equivalent formulation of being univalent: $$\prod_{A \tp hSet} \isContr \left( \sum_{X \tp hSet} A \cong X \right)$$ % But I have not shown that it is indeed equivalent to my former definition. -\subsubsection{Categories} +\subsection{Categories} Note that this category does in fact not exist. In stead I provide the definition of the ``raw'' category as well as some of the laws. @@ -182,21 +182,21 @@ These lemmas can be used to provide the actual exponential object in a context where we have a witness to this being a category. This is useful if this library is later extended to talk about higher categories. -\subsubsection{Functors} +\subsection{Functors} The category of functors and natural transformations. An immediate corrolary is the set of presheaf categories. \WIP{} I have not shown that the category of functors is univalent. -\subsubsection{Relations} +\subsection{Relations} The category of relations. \WIP{} I have not shown that this category is univalent. Not sure I intend to do so either. -\subsubsection{Free category} +\subsection{Free category} The free category of a category. \WIP{} I have not shown that this category is univalent. -\subsection{Current Challenges} +\section{Current Challenges} Besides the items marked \WIP{} above I still feel a bit unsure about what to include in my report. Most of my work so far has been specifically about developing this library. Some ideas: @@ -211,12 +211,12 @@ developing this library. Some ideas: structure (propositions) and those that do (sets and everything above) \end{itemize} % -\subsection{Ideas for future developments} -\subsubsection{Higher categories} +\section{Ideas for future developments} +\subsection{Higher categories} I only have a notion of (1-)categories. Perhaps it would be nice to also formalize higher categories. -\subsubsection{Hierarchy of concepts related to monads} +\subsection{Hierarchy of concepts related to monads} In Haskell the type-class Monad sits in a hierarchy atop the notion of a functor and applicative functors. There's probably a similiar notion in the category-theoretic approach to developing this. @@ -226,7 +226,7 @@ interesting to take this idea even further and actually show how monads are related to applicative functors and functors. I'm not entirely sure how this would look in Agda though. -\subsubsection{Use formulation on the standard library} +\subsection{Use formulation on the standard library} I also thought it would be interesting to use this library to show certain properties about functors, applicative functors and monads used in the Agda Standard library. So I went ahead and tried to show that agda's standard diff --git a/doc/implementation.tex b/doc/implementation.tex index 56caa98..caf5c94 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -1,4 +1,5 @@ -This implementation formalizes the following concepts: +\chapter{Implementation} +This implementation formalizes the following concepts $>\!\!>\!\!=$: % \begin{itemize} \item Core categorical concepts @@ -224,11 +225,18 @@ $$ $$ % One application of this, and a perhaps somewhat surprising result, is that -terminal objects are propositional. Intuitively; they do not have any -interesting structure. The proof of this follows from the usual observation that -any two terminal objects are isomorphic. The proof is omitted here, but the -curious reader can check the implementation for the details. \TODO{The proof is -a bit fun, should I include it?} +terminal objects are propositional. Intuitively; they do not +have any interesting structure: +% +\begin{align} +\label{eq:termProp} +\isProp\ \var{Terminal} +\end{align} +% +The proof of this follows from the usual +observation that any two terminal objects are isomorphic. The proof is omitted +here, but the curious reader can check the implementation for the details. +\TODO{The proof is a bit fun, should I include it?} \section{Equivalences} \label{sec:equiv} @@ -660,9 +668,10 @@ inverse to $f$. $p$ is inhabited by: For the other (dependent) path we can prove that being-an-inverse-of is a proposition and then use $\lemPropF$. So we prove the generalization: % -\begin{align*} +\begin{align} +\label{eq:propAreInversesGen} \prod_{g : B \to A} \isProp\ (\mathit{AreInverses}\ f\ g) -\end{align*} +\end{align} % But $\mathit{AreInverses}\ f\ g$ is a pair of equations on arrows, so we use $\propSig$ and the fact that both $A$ and $B$ are sets to close this proof. @@ -689,7 +698,7 @@ $$ Where $\mathit{Product}\ \bC\ A\ B$ denotes the type of products of objects $A$ and $B$ in the category $\bC$. I do this by constructing a category whose terminal objects are equivalent to products in $\bC$, and since terminal objects -are propositional in a proper category and equivalences preservehomotopy level, +are propositional in a proper category and equivalences preserve homotopy level, then we know that products also are propositions. But before we get to that, let's recall the definition of products. @@ -721,8 +730,8 @@ Given a base category $\bC$ and two objects in this category $\pairA$ and $\pairB$ we can construct the ``pair category'': \TODO{This is a working title, it's nice to have a name for this thing to refer back to} -The type objects in this category will be an object in the underlying category, -$X$, and two arrows (also from the underlying category) +The type of objects in this category will be an object in the underlying +category, $X$, and two arrows (also from the underlying category) $\Arrow\ X\ \pairA$ and $\Arrow\ X\ \pairB$. \newcommand\pairf{\ensuremath{f}} @@ -771,7 +780,7 @@ arrows form a set. For instance, to prove associativity we must prove that (\overline{h} \lll \overline{g}) \lll \overline{f} \end{align} % -Herer $\lll$ refers to the `embellished' composition abd $\overline{f}$, +Herer $\lll$ refers to the `embellished' composition and $\overline{f}$, $\overline{g}$ and $\overline{h}$ are triples consisting of arrows from the underlying category ($f$, $g$ and $h$) and a pair of witnesses to \ref{eq:pairArrowLaw}. @@ -787,15 +796,15 @@ h \lll (g \lll f) (h \lll g) \lll f \end{align} % -Which is provable by and that the witness to \ref{eq:pairArrowLaw} for the -left-hand-side and the right-hand-side are the same. The type of this goal is -quite involved, and I will not write it out in full, but it suffices to show the -type of the path-space. Note that the arrows in \ref{eq:productAssoc} are arrows -from $\mathcal{A} = (A , a_\pairA , a_\pairB)$ to $\mathcal{D} = (D , d_\pairA , -d_\pairB)$ where $a_\pairA$, $a_\pairB$, $d_\pairA$ and $d_\pairB$ are arrows in -the underlying category. Given that $p$ is the proof of -\ref{eq:productAssocUnderlying} we then have that the witness to -\ref{eq:pairArrowLaw} vary over the type: +Which is provable by \TODO{What?} and that the witness to \ref{eq:pairArrowLaw} +for the left-hand-side and the right-hand-side are the same. The type of this +goal is quite involved, and I will not write it out in full, but at present it +suffices to show the type of the path-space. Note that the arrows in +\ref{eq:productAssoc} are arrows from $\mathcal{A} = (A , a_\pairA , a_\pairB)$ +to $\mathcal{D} = (D , d_\pairA , d_\pairB)$ where $a_\pairA$, $a_\pairB$, +$d_\pairA$ and $d_\pairB$ are arrows in the underlying category. Given that $p$ +is the chosen proof of \ref{eq:productAssocUnderlying} we then have that the +witness to \ref{eq:pairArrowLaw} vary over the type: % \begin{align} \label{eq:productPath} @@ -907,156 +916,318 @@ the implementation for the details). \emph{Proposition} \ref{eq:univ-1} is isomorphic to \ref{eq:univ-2}: \TODO{Super complicated} -\emph{Proposition} \ref{eq:univ-2} is isomorphic to \ref{eq:univ-3}: -For this I will two corrolaries of \ref{eq:coeCod}: +\emph{Proposition} \ref{eq:univ-2} is isomorphic to \ref{eq:univ-3}: For this I +will swho two corrolaries of \ref{eq:coeCod}: For an isomorphism $(\iota, +\inv{\iota}, \var{inv}) \tp A \cong B$, arrows $f \tp \Arrow\ A\ X$, $g \tp +\Arrow\ B\ X$ and a heterogeneous path between them, $q \tp \Path\ (\lambda i +\to p_\var{dom}\ i)\ f\ g$, where $p_\var{dom} \tp \Arrow\ A\ X \equiv +\Arrow\ B\ X$ is a path induced by $\var{iso}$, we have the following two +results % \begin{align} -\label{domain-twist} +\label{eq:domain-twist-0} +f & \equiv g \lll \iota \\ +\label{eq:domain-twist-1} +g & \equiv f \lll \inv{\iota} \end{align} +% +Proof: \TODO{\ldots} +Now we can prove the equiavalence in the following way: Given $(f, \inv{f}, +\var{inv}_f) \tp X \cong Y$ and two heterogeneous paths +% +\begin{align*} +p_\mathcal{A} & \tp \Path\ (\lambda i \to p_\var{dom}\ i)\ x_\mathcal{A}\ y_\mathcal{A}\\ +% +q_\mathcal{B} & \tp \Path\ (\lambda i \to p_\var{dom}\ i)\ x_\mathcal{B}\ y_\mathcal{B} +\end{align*} +% +all as in \ref{eq:univ-2}. I use $p_\var{dom}$ here again to mean the path +induced by the isomorphism $f, \inv{f}$. I must now construct an isomorphism +$(X, x_\mathcal{A}, x_\mathcal{B}) \approxeq (Y, y_\mathcal{A}, y_\mathcal{B}$ +as in \ref{eq:univ-3}. That is, an isomorphism in the present category. I remind +the reader that such a gadget is a triple. The first component shall be: +% +\begin{align} +f \tp \Arrow\ X\ Y +\end{align} +% +To show that this choice fits the bill I must now verify that it satisfies +\ref{eq:pairArrowLaw}, which in this case becomes: +% +\begin{align} +y_\mathcal{A} \lll f ≡ x_\mathcal{A} × y_\mathcal{B} \lll f ≡ x_\mathcal{B} +\end{align} +% +Which, since $f$ is an isomorphism and $p_\mathcal{A}$ (resp. $p_\mathcal{B}$) +is a path varying according to a path constructed from this isomorphism, this is +exactly what \ref{eq:domain-twist-0} gives us. +% +The other direction is quite analagous. We choose $\inv{f}$ as the morphism and +prove that it satisfies \ref{eq:pairArrowLaw} with \ref{eq:domain-twist-1}. + +We must now show that this choice of arrows indeed form an isomorphism. Our +equality principle for arrows in this category (\ref{eq:productEqPrinc}) gives +us that it suffices to show that $f$ and $\inv{f}$, this is exactly +$\var{inv}_f$. + +This concludes the first direction of the isomorphism that we're constructing. +For the other direction we're given just given the isomorphism +% +$$ +(f, \inv{f}, \var{inv}_f) +\tp +(X, x_\mathcal{A}, x_\mathcal{B}) \approxeq (Y, y_\mathcal{A}, y_\mathcal{B}) +$$ +% +Projecting out the first component gives us the isomorphism +% +$$ +(\fst\ f, \fst\ \inv{f}, \congruence\ \fst\ \var{inv}_f, \congruence\ \fst\ \var{inv}_{\inv{f}}) +\tp X \approxeq Y +$$ +% +This gives rise to the following paths: +% +\begin{align} +\begin{split} +\widetilde{p} & \tp X \equiv Y \\ +\widetilde{p}_\mathcal{A} & \tp \Arrow\ X\ \mathcal{A} \equiv \Arrow\ Y\ \mathcal{A} \\ +\widetilde{p}_\mathcal{B} & \tp \Arrow\ X\ \mathcal{B} \equiv \Arrow\ Y\ \mathcal{B} +\end{split} +\end{align} +% +It then remains to construct the two paths: +% +\begin{align} +\begin{split} +\label{eq:product-paths} +& \Path\ (λ i → \widetilde{p}_\mathcal{A}\ i)\ x_\mathcal{A}\ y_\mathcal{A}\\ +& \Path\ (λ i → \widetilde{p}_\mathcal{B}\ i)\ x_\mathcal{B}\ y_\mathcal{B} +\end{split} +\end{align} +% +This is achieved with the following lemma: +% +\begin{align} +\prod_{a \tp A} \prod_{b \tp B} \prod_{q \tp A \equiv B} \var{coe}\ q\ a ≡ b → +\Path\ (λ i → q\ i)\ a\ b +\end{align} +% +Which is used without proof. See the implementation for the details. + +\ref{eq:product-paths} is the proven with the propositions: +% +\begin{align} +\begin{split} +\label{eq:product-paths} +\var{coe}\ \widetilde{p}_\mathcal{A}\ x_\mathcal{A} ≡ y_\mathcal{A}\\ +\var{coe}\ \widetilde{p}_\mathcal{B}\ x_\mathcal{B} ≡ y_\mathcal{B} +\end{split} +\end{align} +% +The proof of the first one is: +% +\begin{align*} + \var{coe}\ \widetilde{p}_\mathcal{A}\ x_\mathcal{A} + & ≡ x_\mathcal{A} \lll \fst\ \inv{f} && \text{$\mathit{coeDom}$ and the isomorphism $f, \inv{f}$} \\ + & ≡ y_\mathcal{A} && \text{\ref{eq:pairArrowLaw} for $\inv{f}$} +\end{align*} +% +We have now constructed the maps between \ref{eq:univ-0} and \ref{eq:univ-1}. It +remains to show that they are inverses of each other. To cut a long story short, +the proof uses the fact that isomorphism-of is propositional and that arrows (in +both categories) are sets. The reader is refered to the implementation for the +gory details. +% +\subsection{Propositionality of products} +% +Now that we've constructed the ``pair category'' I'll demonstrate how to use +this to prove that products are propositional. I will do this by showing that +terminal objects in this category are equivalent to products: +% +\begin{align} +\var{Terminal} ≃ \var{Product}\ ℂ\ \mathcal{A}\ \mathcal{B} +\end{align} +% +And as always we do this by constructing an isomorphism: +% +In the direction $\var{Terminal} → \var{Product}\ ℂ\ \mathcal{A}\ \mathcal{B}$ +we're given a terminal object $X, x_𝒜, x_ℬ$. $X$ Will be the product-object and +$x_𝒜, x_ℬ$ will be the product arrows, so it just remains to verify that this is +indeed a product. That is, for an object $Y$ and two arrows $y_𝒜 \tp +\Arrow\ Y\ 𝒜$, $y_ℬ\ \Arrow\ Y\ ℬ$ we must find a unique arrow $f \tp +\Arrow\ Y\ X$ satisfying: +% +\begin{align} +\label{eq:pairCondRev} +\begin{split} + x_𝒜 \lll f & ≡ y_𝒜 \\ + x_ℬ \lll f & ≡ y_ℬ +\end{split} +\end{align} +% +Since $X, x_𝒜, x_ℬ$ is a terminal object there is a \emph{unique} arrow from +this object to any other object, so also $Y, y_𝒜, y_ℬ$ in particular (which is +also an object in the pair category). The arrow we will play the role of $f$ and +it immediately satisfies \ref{eq:pairCondRev}. Any other arrow satisfying these +conditions will be equal since $f$ is unique. + +For the other direction we are now given a product $X, x_𝒜, x_ℬ$. Again this +will be the terminal object. So now it remains that for any other object there +is aunique arrow from that object into $X, x_𝒜, x_ℬ$. Let $Y, y_𝒜, y_ℬ$ be +another object. As the arrow $\Arrow\ Y\ X$ we choose the product-arrow $y_𝒜 \x +y_ℬ$. Since this is a product-arrow it satisfies \ref{eq:pairCondRev}. Let us +name the witness to this $\phi_{y_𝒜 \x y_ℬ}$. So we have picked as our center of +contraction $y_𝒜 \x y_ℬ , \phi_{y_𝒜 \x y_ℬ}$ we must now show that it is +contractible. So let $f \tp \Arrow\ X\ Y$ and $\phi_f$ be given (here $\phi_f$ +is the proof that $f$ satisfies \ref{eq:pairCondRev}). The proof will be a pair +of proofs: +% +\begin{alignat}{3} + p \tp & \Path\ (\lambda i \to \Arrow\ X\ Y)\quad + && f\quad && y_𝒜 \x y_ℬ \\ + & \Path\ (\lambda i \to \Phi\ (p\ i))\quad + && \phi_f\quad && \phi_{y_𝒜 \x y_ℬ} +\end{alignat} +% +Here $\Phi$ is given as: +$$ +\prod_{f \tp \Arrow\ Y\ X} + x_𝒜 \lll f ≡ y_𝒜 +× x_ℬ \lll f ≡ y_ℬ +$$ +% +$p$ follows from the universal property of $y_𝒜 \x y_ℬ$. For the latter we will +again use the same trick we did in \ref{eq:propAreInversesGen} and prove this +more general result: +% +$$ +\prod_{f \tp \Arrow\ Y\ X} \isProp\ ( + x_𝒜 \lll f ≡ y_𝒜 +× x_ℬ \lll f ≡ y_ℬ +) +$$ +% +Which follows from arrows being sets and pairs preserving such. Thus we can +close the final proof with an application of $\lemPropF$. + +This concludes the proof $\var{Terminal} ≃ +\var{Product}\ ℂ\ \mathcal{A}\ \mathcal{B}$ and since we have that equivalences +preserve homotopic levels along with \ref{eq:termProp} we get our final result. +That in any category: +% +\begin{align} +\prod_{A\ B \tp \Object} \isProp\ (\var{Product}\ \bC\ A\ B) +\end{align} +% \section{Monads} +In this section I show two formulations of monads and then show that they are +the same. The two representations are referred to as the monoidal- and kleisli- +representation respectively. -%% \subsubsection{Functors} -%% Defines the notion of a functor - also split up into data and laws. +We shall let a category $\bC$ be given. In the remainder all objects and arrows +will implicitly refer to objects and arrows in this category. +% +\subsection{Monoidal formulation} +The monoidal formulation of monads consists of the following data: +% +\begin{align} +\label{eq:monad-monoidal-data} +\begin{split} + \EndoR & \tp \Endo ℂ \\ + \var{pure} & \tp \NT{\EndoR^0}{\EndoR} \\ + \var{join} & \tp \NT{\EndoR^2}{\EndoR} +\end{split} +\end{align} +% +Here $\NTsym$ denotes natural transformations, the super-script in $\EndoR^2$ +Denotes the composition of $\EndoR$ with itself. By the same token $\EndoR^0$ is +a curious way of denoting the identity functor. This notation has been chosen +for didactic purposes. -%% Propositionality for being a functor. +Denote the arrow-map of $\EndoR$ as $\fmap$, then this data must satisfy the +following laws: +% +\begin{align} +\label{eq:monad-monoidal-laws} +\begin{split} + \var{join} \lll \fmap\ \var{join} + & ≡ \var{join} \lll \var{join}\ \fmap \\ + \var{join} \lll \var{pure}\ \fmap & ≡ \identity \\ + \var{join} \lll \fmap\ \var{pure} & ≡ \identity +\end{split} +\end{align} +% +The implicit arguments to the arrows above have been left out and the objects +they range over are universally quantified. -%% Composition of functors and the identity functor. +\subsection{Kleisli formulation} +% +The kleisli-formulation consists of the following data: +% +\begin{align} +\label{eq:monad-kleisli-data} +\begin{split} + \EndoR & \tp \Object → \Object \\ + \pure & \tp % \prod_{X \tp Object} + \Arrow\ X\ (\EndoR\ X) \\ + \bind & \tp % \prod_{X\;Y \tp Object} → \Arrow\ X\ (\EndoR\ Y) + \Arrow\ (\EndoR\ X)\ (\EndoR\ Y) +\end{split} +\end{align} +% +The objects $X$ and $Y$ are implicitly universally quantified. -%% \subsubsection{Products} -%% Definition of what it means for an object to be a product in a given category. +It's interesting to note here that this formulation does not talk about natural +transformations or other such constructs from category theory. All we have here +is a regular maps on objects and a pair of arrows. +% +This data must satisfy: +% +\begin{align} +\label{eq:monad-monoidal-laws} +\begin{split} + \bind\ \pure & ≡ \identity_{\EndoR\ X} + \\ + % \prod_{f \tp \Arrow\ X\ (\EndoR\ Y)} + \pure \fish f & ≡ f + \\ + % \prod_{\substack{g \tp \Arrow\ Y\ (\EndoR\ Z)\\f \tp \Arrow\ X\ (\EndoR\ Y)}} + (\bind\ f) \rrr (\bind\ g) & ≡ \bind\ (f \fish g) +\end{split} +\end{align} +% +Here likewise the arrows $f \tp \Arrow\ X\ (\EndoR\ Y)$ and $g \tp +\Arrow\ Y\ (\EndoR\ Z)$ are universally quantified (as well as the objects they +range over). $\fish$ is the kleisli-arrow which is defined as $f \fish g \defeq +f \rrr (\bind\ g)$ . (\TODO{Better way to typeset $\fish$?}) -%% Definition of what it means for a category to have all products. +\subsection{Equivalence of formulations} +% +In my implementation I proceede to show how the one formulation gives rise to +the other and vice-versa. For the present purpose I will briefly sketch some +parts of this construction: -%% \WIP{} Prove propositionality for being a product and having products. +The notation I have chosen here in the report +overloads e.g. $\pure$ to both refer to a natural transformation and an arrow. +This is of course not a coincidence as the arrow in the kleisli formulation +shall correspond exactly to the map on arrows from the natural transformation +called $\pure$. -%% \subsubsection{Exponentials} -%% Definition of what it means to be an exponential object. +In the monoidal formulation we can define $\bind$: +% +\begin{align} +\bind \defeq \join \lll \fmap\ f +\end{align} +% +And likewise in the kleisli formulation we can define $\join$: +% +\begin{align} +\join \defeq \bind\ \identity +\end{align} +% +Which shall play the role of $\join$. -%% Definition of what it means for a category to have all exponential objects. - -%% \subsubsection{Cartesian closed categories} -%% Definition of what it means for a category to be cartesian closed; namely that -%% it has all products and all exponentials. - -%% \subsubsection{Natural transformations} -%% Definition of transformations\footnote{Maybe this is a name I made up for a -%% family of morphisms} and the naturality condition for these. - -%% Proof that naturality is a mere proposition and the accompanying equality -%% principle. Proof that natural transformations are homotopic sets. - -%% The identity natural transformation. - -%% \subsubsection{Yoneda embedding} - -%% The yoneda embedding is typically presented in terms of the category of -%% categories (cf. Awodey) \emph however this is not stricly needed - all we need -%% is what would be the exponential object in that category - this happens to be -%% functors and so this is how we define the yoneda embedding. - -%% \subsubsection{Monads} - -%% Defines an equivalence between these two formulations of a monad: - -%% \subsubsubsection{Monoidal monads} - -%% Defines the standard monoidal representation of a monad: - -%% An endofunctor with two natural transformations (called ``pure'' and ``join'') -%% and some laws about these natural transformations. - -%% Propositionality proofs and equality principle is provided. - -%% \subsubsubsection{Kleisli monads} - -%% A presentation of monads perhaps more familiar to a functional programer: - -%% A map on objects and two maps on morphisms (called ``pure'' and ``bind'') and -%% some laws about these maps. - -%% Propositionality proofs and equality principle is provided. - -%% \subsubsubsection{Voevodsky's construction} - -%% Provides construction 2.3 as presented in an unpublished paper by Vladimir -%% Voevodsky. This construction is similiar to the equivalence provided for the two -%% preceding formulations -%% \footnote{ TODO: I would like to include in the thesis some motivation for why -%% this construction is particularly interesting.} - -%% \subsubsection{Functors} -%% The category of functors and natural transformations. An immediate corrolary is -%% the set of presheaf categories. - -%% \WIP{} I have not shown that the category of functors is univalent. - -%% \subsubsection{Relations} -%% The category of relations. \WIP{} I have not shown that this category is -%% univalent. Not sure I intend to do so either. - -%% \subsubsection{Free category} -%% The free category of a category. \WIP{} I have not shown that this category is -%% univalent. - -%% \subsection{Current Challenges} -%% Besides the items marked \WIP{} above I still feel a bit unsure about what to -%% include in my report. Most of my work so far has been specifically about -%% developing this library. Some ideas: -%% % -%% \begin{itemize} -%% \item -%% Modularity properties -%% \item -%% Compare with setoid-approach to solve similiar problems. -%% \item -%% How to structure an implementation to best deal with types that have no -%% structure (propositions) and those that do (sets and everything above) -%% \end{itemize} -%% % -%% \subsection{Ideas for future developments} -%% \subsubsection{Higher categories} -%% I only have a notion of (1-)categories. Perhaps it would be nice to also -%% formalize higher categories. - -%% \subsubsection{Hierarchy of concepts related to monads} -%% In Haskell the type-class Monad sits in a hierarchy atop the notion of a functor -%% and applicative functors. There's probably a similiar notion in the -%% category-theoretic approach to developing this. - -%% As I have already defined monads from these two perspectives, it would be -%% interesting to take this idea even further and actually show how monads are -%% related to applicative functors and functors. I'm not entirely sure how this -%% would look in Agda though. - -%% \subsubsection{Use formulation on the standard library} -%% I also thought it would be interesting to use this library to show certain -%% properties about functors, applicative functors and monads used in the Agda -%% Standard library. So I went ahead and tried to show that agda's standard -%% library's notion of a functor (along with suitable laws) is equivalent to my -%% formulation (in the category of homotopic sets). I ran into two problems here, -%% however; the first one is that the standard library's notion of a functor is -%% indexed by the object map: -%% % -%% $$ -%% \Functor \tp (\Type \to \Type) \to \Type -%% $$ -%% % -%% Where $\Functor\ F$ has the member: -%% % -%% $$ -%% \fmap \tp (A \to B) \to F A \to F B -%% $$ -%% % -%% Whereas the object map in my definition is existentially quantified: -%% % -%% $$ -%% \Functor \tp \Type -%% $$ -%% % -%% And $\Functor$ has these members: -%% \begin{align*} -%% F & \tp \Type \to \Type \\ -%% \fmap & \tp (A \to B) \to F A \to F B\} -%% \end{align*} -%% % +It now remains to show that we can prove the various laws given this choice. I +refer the reader to my implementation for the details. diff --git a/doc/introduction.tex b/doc/introduction.tex index e5348b2..97306de 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -1,3 +1,4 @@ +\chapter{Introduction} Functional extensionality and univalence is not expressible in \nomen{Intensional Martin Löf Type Theory} (ITT). This poses a severe limitation on both 1) what is \emph{provable} and 2) the \emph{reusability} of proofs. diff --git a/doc/macros.tex b/doc/macros.tex index 885ae4c..0f719db 100644 --- a/doc/macros.tex +++ b/doc/macros.tex @@ -6,6 +6,8 @@ =} \newcommand{\defeq}{\triangleq} +%% Alternatively: +%% \newcommand{\defeq}{≔} \newcommand{\bN}{\mathbb{N}} \newcommand{\bC}{\mathbb{C}} \newcommand{\bX}{\mathbb{X}} @@ -22,9 +24,20 @@ \newcommand{\tp}{\;\mathord{:}\;} \newcommand{\Type}{\mathcal{U}} +\usepackage{graphicx} +\makeatletter +\newcommand{\shorteq}{% + \settowidth{\@tempdima}{-}% Width of hyphen + \resizebox{\@tempdima}{\height}{=}% +} +\makeatother \newcommand{\var}[1]{\ensuremath{\mathit{#1}}} \newcommand{\Hom}{\var{Hom}} \newcommand{\fmap}{\var{fmap}} +\newcommand{\bind}{\var{bind}} +\newcommand{\join}{\var{join}} +\newcommand{\omap}{\var{omap}} +\newcommand{\pure}{\var{pure}} \newcommand{\idFun}{\var{id}} \newcommand{\Sets}{\var{Sets}} \newcommand{\Set}{\var{Set}} @@ -57,6 +70,7 @@ \newcommand\refl{\var{refl}} \newcommand\isoToId{\var{isoToId}} \newcommand\rrr{\ggg} +\newcommand\fish{\mathrel{\wideoverbar{\rrr}}} \newcommand\fst{\var{fst}} \newcommand\snd{\var{snd}} \newcommand\Path{\var{Path}} @@ -65,3 +79,7 @@ \newcommand*{\QED}{\hfill\ensuremath{\square}}% \newcommand\uexists{\exists!} \newcommand\Arrow{\var{Arrow}} +\newcommand\NTsym{\var{NT}} +\newcommand\NT[2]{\NTsym\ #1\ #2} +\newcommand\Endo[1]{\var{Endo}\ #1} +\newcommand\EndoR{\mathcal{R}} diff --git a/doc/main.tex b/doc/main.tex index 6443e10..7e8813f 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -41,6 +41,7 @@ \institution{\chalmers} \department{Department of Computer Science and Engineering} \researchgroup{Programming Logic Group} +\bibliographystyle{plain} \begin{document} @@ -49,17 +50,13 @@ \tableofcontents % \pagenumbering{arabic} -\chapter{Introduction} \input{introduction.tex} - -\chapter{Implementation} \input{implementation.tex} -\bibliographystyle{plainnat} \nocite{cubical-demo} \nocite{coquand-2013} -\bibliography{refs} +\bibliography{refs} \begin{appendices} \setcounter{page}{1} \pagenumbering{roman} diff --git a/doc/packages.tex b/doc/packages.tex index bcbe5a2..c6ff2ae 100644 --- a/doc/packages.tex +++ b/doc/packages.tex @@ -24,6 +24,7 @@ % \usepackage{chngcntr} % \counterwithout{figure}{section} +\numberwithin{equation}{section} \usepackage{listings} \usepackage{fancyvrb} @@ -50,5 +51,4 @@ % Allows for the use of unicode-letters: \usepackage{unicode-math} - %% \RequirePackage{kvoptions} diff --git a/doc/planning.tex b/doc/planning.tex index 91d7cc6..05d7a69 100644 --- a/doc/planning.tex +++ b/doc/planning.tex @@ -1,4 +1,4 @@ -\section{Planning report} +\chapter{Planning report} % I have already implemented multiple essential building blocks for a formalization of core-category theory. These concepts include: From e89021bc15d86dc804b7809fc13881ba3a68cccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 1 May 2018 21:26:20 +0200 Subject: [PATCH 76/93] Add frontmatter --- doc/chalmerstitle.sty | 49 ++++++++++++++++++++++++++++++++++++++---- doc/implementation.tex | 22 +++++++++---------- doc/macros.tex | 4 ++-- doc/main.tex | 4 ++-- doc/packages.tex | 2 +- 5 files changed, 60 insertions(+), 21 deletions(-) diff --git a/doc/chalmerstitle.sty b/doc/chalmerstitle.sty index ac849be..5ec687e 100644 --- a/doc/chalmerstitle.sty +++ b/doc/chalmerstitle.sty @@ -39,6 +39,47 @@ \newcommand*{\researchgroup}[1]{\gdef\@researchgroup{#1}} \newcommand*{\subtitle}[1]{\gdef\@subtitle{#1}} +%% \begin{titlepage} +\newgeometry{top=3cm, bottom=3cm, + left=2.25 cm, right=2.25cm} % Temporarily change margins +% Cover page background +%% \AddToShipoutPicture*{\backgroundpic{-4}{56.7}{figure/auxiliary/frontpage_gu_eng.pdf}} +%% \AddToShipoutPicture*{\backgroundpic{-4}{56.7}{logo_eng.pdf}} +%% \includegraphics[width=0.2\pdfpagewidth]{logo_eng.pdf} +%% \begin{center} +%% \includegraphics[width=0.5\paperwidth,height=\paperheight,keepaspectratio]{logo_eng.pdf}% +%% \end{center} +%% \addtolength{\voffset}{2cm} + +% Cover picture (replace with your own or delete) +{\Huge\@title}\\[.5cm] +{\Large A formalization of category theory in Cubical Agda}\\[2.5cm] +\begin{center} +\includegraphics[\linewidth,height=0.35\paperheight,keepaspectratio]{isomorphism.png} +\end{center} + +% Cover text +\vfill +%% \renewcommand{\familydefault}{\sfdefault} \normalfont % Set cover page font +Master's thesis in Computer Science \\[1cm] +{\Large\@author} \\[2cm] +\textsc{Department of Computer Science and Engineering}\\ +\textsc{Chalmers University of Technology}\\ +\textsc{University of Gothenburg}\\ +\textsc{Gothenburg, Sweden \the\year} + +%% \renewcommand{\familydefault}{\rmdefault} \normalfont % Reset standard font +%% \end{titlepage} + + +% BACK OF COVER PAGE (BLANK PAGE) +\newpage +\newgeometry{a4paper} % Temporarily change margins +\restoregeometry +\thispagestyle{empty} +\null + + \renewcommand*{\maketitle}{% \begin{titlepage} @@ -56,11 +97,11 @@ \includegraphics[width=0.2\pdfpagewidth]{logo_eng.pdf} \vspace{5mm} - Department of Computer Science and Engineering\\ - \emph{\@researchgroup}\\ + \textsc{Department of Computer Science and Engineering}\\ + \textsc{{\@researchgroup}}\\ %Name of research group (if applicable)\\ \textsc{\@institution} \\ - Gothenburg, Sweden \the\year \\ + \textsc{Gothenburg, Sweden \the\year}\\ \end{center} @@ -105,5 +146,5 @@ Telephone +46 31 772 1000 \setlength{\parskip}{0.5cm}\\ %Printed by [Name of printing company]\\ Gothenburg, Sweden \the\year - +\restoregeometry \end{titlepage}} diff --git a/doc/implementation.tex b/doc/implementation.tex index caf5c94..9194bae 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -149,7 +149,7 @@ $$ So to give the continuous function $I \to \IsPreCategory$ that is our goal we introduce $i \tp I$ and proceed by constructing an element of $\IsPreCategory$ by using that all the projections are propositions to generate paths between all -projections. Once we have such a path e.g. $p : \isIdentity_a \equiv +projections. Once we have such a path e.g. $p \tp \isIdentity_a \equiv \isIdentity_b$ we can elimiate it with $i$ and thus obtaining $p\ i \tp \isIdentity_{p\ i}$ and this element satisfies exactly that it corresponds to the corresponding projections at either endpoint. Thus the element we construct @@ -198,9 +198,9 @@ provide since, as we have shown, $\IsPreCategory$ is a proposition. However, even though $\Univalent$ is also a proposition, we cannot use this directly to show the latter. This is becasue $\isProp$ talks about non-dependent paths. To `promote' this to a dependent path we can use another useful combinator; -$\lemPropF$. Given a type $A \tp \MCU$ and a type family on $A$; $B : A \to +$\lemPropF$. Given a type $A \tp \MCU$ and a type family on $A$; $B \tp A \to \MCU$. Let $P$ be a proposition indexed by an element of $A$ and say we have a -path between some two elements in $A$; $p : a_0 \equiv a_1$ then we can built a +path between some two elements in $A$; $p \tp a_0 \equiv a_1$ then we can built a heterogeneous path between any two $b$'s at the endpoints: % $$ @@ -240,15 +240,15 @@ here, but the curious reader can check the implementation for the details. \section{Equivalences} \label{sec:equiv} -The usual notion of a function $f : A \to B$ having an inverses is: +The usual notion of a function $f \tp A \to B$ having an inverses is: % $$ -\sum_{g : B \to A} f \comp g \equiv \identity_{B} \x g \comp f \equiv \identity_{A} +\sum_{g \tp B \to A} f \comp g \equiv \identity_{B} \x g \comp f \equiv \identity_{A} $$ % This is defined in \cite[p. 129]{hott-2013} and is referred to as the a quasi-inverse. At the same place \cite{hott-2013} gives an ``interface'' for -what an equivalence $\isEquiv : (A \to B) \to \MCU$ must supply: +what an equivalence $\isEquiv \tp (A \to B) \to \MCU$ must supply: % \begin{itemize} \item @@ -264,11 +264,11 @@ how to work with equivalences and 2) to use ad-hoc definitions of equivalences. The specific instantiation of $\isEquiv$ as defined in \cite{cubical-agda} is: % $$ -isEquiv\ f \defeq \prod_{b : B} \isContr\ (\fiber\ f\ b) +isEquiv\ f \defeq \prod_{b \tp B} \isContr\ (\fiber\ f\ b) $$ where $$ -\fiber\ f\ b \defeq \sum_{a \tp A} b \equiv f\ a +\fiber\ f\ b \defeq \sum_{a \tp A} \left( b \equiv f\ a \right) $$ % I give it's definition here mainly for completeness, because as I stated we can @@ -473,7 +473,7 @@ B$ is simply an arrow $f \tp \mathit{Arrow}\ A\ B$ and it's inverse $g \tp \mathit{Arrow}\ B\ A$. In the opposite category $g$ will play the role of the isomorphism and $f$ will be the inverse. Similarly we can go in the opposite direction. I name these maps $\mathit{shuffle} \tp (A \approxeq B) \to (A -\approxeq_{\bC} B)$ and $\mathit{shuffle}^{-1} : (A \approxeq_{\bC} B) \to (A +\approxeq_{\bC} B)$ and $\mathit{shuffle}^{-1} \tp (A \approxeq_{\bC} B) \to (A \approxeq B)$ respectively. As the inverse of $\idToIso_{\mathit{Op}}$ I will pick $\zeta \defeq \eta \comp @@ -670,7 +670,7 @@ proposition and then use $\lemPropF$. So we prove the generalization: % \begin{align} \label{eq:propAreInversesGen} -\prod_{g : B \to A} \isProp\ (\mathit{AreInverses}\ f\ g) +\prod_{g \tp B \to A} \isProp\ (\mathit{AreInverses}\ f\ g) \end{align} % But $\mathit{AreInverses}\ f\ g$ is a pair of equations on arrows, so we use @@ -716,8 +716,6 @@ that there exists a unique arrow $\pi \tp \Arrow\ X\ (A \x B)$ satisfying %% \prod_{X \tp Object} \prod_{f \tp \Arrow\ X\ A} \prod_{g \tp \Arrow\ X\ B}\\ %% \uexists_{f \x g \tp \Arrow\ X\ (A \x B)} \pi_1 \lll \pi \equiv f \x \pi_2 \lll \pi \equiv g -%% ump : ∀ {X : Object} (f : ℂ [ X , A ]) (g : ℂ [ X , B ]) -%% → ∃![ f×g ] (ℂ [ fst ∘ f×g ] ≡ f P.× ℂ [ snd ∘ f×g ] ≡ g) \end{align} % $\pi$ is called the product (arrow) of $f$ and $g$. diff --git a/doc/macros.tex b/doc/macros.tex index 0f719db..23ce2c3 100644 --- a/doc/macros.tex +++ b/doc/macros.tex @@ -5,7 +5,7 @@ \hbox{\scriptsize.}\hbox{\scriptsize.}}}% =} -\newcommand{\defeq}{\triangleq} +\newcommand{\defeq}{\mathrel{\triangleq}} %% Alternatively: %% \newcommand{\defeq}{≔} \newcommand{\bN}{\mathbb{N}} @@ -21,7 +21,7 @@ \newcommand{\comp}{\circ} \newcommand{\x}{\times} \newcommand\inv[1]{#1\raisebox{1.15ex}{$\scriptscriptstyle-\!1$}} -\newcommand{\tp}{\;\mathord{:}\;} +\newcommand{\tp}{\mathrel{:}} \newcommand{\Type}{\mathcal{U}} \usepackage{graphicx} diff --git a/doc/main.tex b/doc/main.tex index 7e8813f..b0946e1 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -4,7 +4,7 @@ \input{packages.tex} \input{macros.tex} -\title{Univalent Categories in Cubical Agda} +\title{Univalent Categories} \author{Frederik Hanghøj Iversen} %% \usepackage[ @@ -26,7 +26,7 @@ %% researchgroup=Programming Logic Group %% ]{chalmerstitle} \usepackage{chalmerstitle} -\subtitle{} +\subtitle{A formalization of category theory in Cubical Agda} \authoremail{hanghj@student.chalmers.se} \newcommand{\chalmers}{Chalmers University of Technology} \supervisor{Thierry Coquand} diff --git a/doc/packages.tex b/doc/packages.tex index c6ff2ae..5d789a2 100644 --- a/doc/packages.tex +++ b/doc/packages.tex @@ -15,7 +15,7 @@ \usepackage{amssymb,amsmath,amsthm,stmaryrd,mathrsfs,wasysym} \usepackage[toc,page]{appendix} \usepackage{xspace} -%% \usepackage{geometry} +\usepackage{geometry} % \setlength{\parskip}{10pt} From ee41ae3740f6c08d90c574a32c306534db75d345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 2 May 2018 12:16:58 +0200 Subject: [PATCH 77/93] Include picture --- doc/chalmerstitle.sty | 25 ++++++------------------- doc/isomorphism.png | Bin 0 -> 352372 bytes 2 files changed, 6 insertions(+), 19 deletions(-) create mode 100644 doc/isomorphism.png diff --git a/doc/chalmerstitle.sty b/doc/chalmerstitle.sty index 5ec687e..5c63627 100644 --- a/doc/chalmerstitle.sty +++ b/doc/chalmerstitle.sty @@ -38,31 +38,18 @@ \newcommand*{\department}[1]{\gdef\@department{#1}} \newcommand*{\researchgroup}[1]{\gdef\@researchgroup{#1}} \newcommand*{\subtitle}[1]{\gdef\@subtitle{#1}} - -%% \begin{titlepage} -\newgeometry{top=3cm, bottom=3cm, - left=2.25 cm, right=2.25cm} % Temporarily change margins -% Cover page background -%% \AddToShipoutPicture*{\backgroundpic{-4}{56.7}{figure/auxiliary/frontpage_gu_eng.pdf}} -%% \AddToShipoutPicture*{\backgroundpic{-4}{56.7}{logo_eng.pdf}} -%% \includegraphics[width=0.2\pdfpagewidth]{logo_eng.pdf} -%% \begin{center} -%% \includegraphics[width=0.5\paperwidth,height=\paperheight,keepaspectratio]{logo_eng.pdf}% -%% \end{center} -%% \addtolength{\voffset}{2cm} - -% Cover picture (replace with your own or delete) +\sffamily +\newgeometry{top=3cm, bottom=3cm,left=2.25 cm, right=2.25cm} {\Huge\@title}\\[.5cm] -{\Large A formalization of category theory in Cubical Agda}\\[2.5cm] +{\Large A formalization of category theory in Cubical Agda}\\[.5cm] +Master's thesis in Computer Science \\[.5cm] +{\Large\@author}\\[2cm] \begin{center} -\includegraphics[\linewidth,height=0.35\paperheight,keepaspectratio]{isomorphism.png} +\includegraphics[width=\linewidth,keepaspectratio]{isomorphism.png} \end{center} - % Cover text \vfill %% \renewcommand{\familydefault}{\sfdefault} \normalfont % Set cover page font -Master's thesis in Computer Science \\[1cm] -{\Large\@author} \\[2cm] \textsc{Department of Computer Science and Engineering}\\ \textsc{Chalmers University of Technology}\\ \textsc{University of Gothenburg}\\ diff --git a/doc/isomorphism.png b/doc/isomorphism.png new file mode 100644 index 0000000000000000000000000000000000000000..03c5a8b4f538e6ff09504e5aec35aa4804232b91 GIT binary patch literal 352372 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%0AAP5Qhc6UWfT*##{7^lbfrrp%6F5BRX_SVuZ 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
ft0`{8{LMO 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 literal 0 HcmV?d00001 From e8b7a7f17cd6765d2605726ac7661fdbfc5e2ea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 2 May 2018 13:13:09 +0200 Subject: [PATCH 78/93] Use light variant of source code pro --- doc/packages.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/packages.tex b/doc/packages.tex index 5d789a2..f786c61 100644 --- a/doc/packages.tex +++ b/doc/packages.tex @@ -37,7 +37,7 @@ \usepackage{lmodern} \usepackage{fontspec} -\usepackage{sourcecodepro} +\usepackage[light]{sourcecodepro} %% \setmonofont{Latin Modern Mono} %% \setmonofont[Mapping=tex-text]{FreeMono.otf} %% \setmonofont{FreeMono.otf} From 852eb0757fe8c4e0a7b115739f09728d780f769d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 2 May 2018 13:24:01 +0200 Subject: [PATCH 79/93] Use noto on title-page --- doc/chalmerstitle.sty | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/chalmerstitle.sty b/doc/chalmerstitle.sty index 5c63627..9c55586 100644 --- a/doc/chalmerstitle.sty +++ b/doc/chalmerstitle.sty @@ -38,8 +38,10 @@ \newcommand*{\department}[1]{\gdef\@department{#1}} \newcommand*{\researchgroup}[1]{\gdef\@researchgroup{#1}} \newcommand*{\subtitle}[1]{\gdef\@subtitle{#1}} -\sffamily \newgeometry{top=3cm, bottom=3cm,left=2.25 cm, right=2.25cm} +\begingroup +\usepackage{noto} +%% \fontfamily{noto}\selectfont {\Huge\@title}\\[.5cm] {\Large A formalization of category theory in Cubical Agda}\\[.5cm] Master's thesis in Computer Science \\[.5cm] @@ -47,14 +49,13 @@ Master's thesis in Computer Science \\[.5cm] \begin{center} \includegraphics[width=\linewidth,keepaspectratio]{isomorphism.png} \end{center} +\endgroup % Cover text \vfill %% \renewcommand{\familydefault}{\sfdefault} \normalfont % Set cover page font \textsc{Department of Computer Science and Engineering}\\ \textsc{Chalmers University of Technology}\\ -\textsc{University of Gothenburg}\\ \textsc{Gothenburg, Sweden \the\year} - %% \renewcommand{\familydefault}{\rmdefault} \normalfont % Reset standard font %% \end{titlepage} From 2b4ee12ef2c2e49ae63fc1dbccb8154c4f79fcd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 2 May 2018 17:02:46 +0200 Subject: [PATCH 80/93] Add chapter on cubical --- doc/chalmerstitle.sty | 1 + doc/cubical.tex | 275 +++++++++++++++++++++++++++++++++++++++++ doc/implementation.tex | 28 ++--- doc/introduction.tex | 13 -- doc/macros.tex | 2 + doc/main.tex | 2 + 6 files changed, 294 insertions(+), 27 deletions(-) create mode 100644 doc/cubical.tex diff --git a/doc/chalmerstitle.sty b/doc/chalmerstitle.sty index 9c55586..64ddad3 100644 --- a/doc/chalmerstitle.sty +++ b/doc/chalmerstitle.sty @@ -41,6 +41,7 @@ \newgeometry{top=3cm, bottom=3cm,left=2.25 cm, right=2.25cm} \begingroup \usepackage{noto} +\fontseries{sb} %% \fontfamily{noto}\selectfont {\Huge\@title}\\[.5cm] {\Large A formalization of category theory in Cubical Agda}\\[.5cm] diff --git a/doc/cubical.tex b/doc/cubical.tex new file mode 100644 index 0000000..0fc8cbb --- /dev/null +++ b/doc/cubical.tex @@ -0,0 +1,275 @@ +\chapter{Cubical Agda} +\section{Propositional equality} +In Agda judgmental equality is a feature of the type-system. It's a property of +types that can be checked by computational means. In the example from the +introduction $n + 0$ can be judged to be equal to $n$ simply by expanding the +definition of $+$. + +Propositional equality on the other hand is defined within the language itself. +Cubical Agda extends the underlying type system (\TODO{Cite someone smarter than +me with a good resource on this}) but introduces a data-type within the +languages. + +\subsection{The equality type} +The usual notion of judgmental equality says that given a type $A \tp \MCU$ and +two points of $A$; $a_0, a_1 \tp A$ we can form the type: +% +\begin{align} + a_0 \equiv a_1 \tp \MCU +\end{align} +% +In Agda this is defined as an inductive data-type with the single constructor: +% +\begin{align} + \refl \tp a \equiv a +\end{align} +% +For any $a \tp A$. + +There also exist a related notion of \emph{heterogeneous} equality where allows +for equating points of different types. In this case given two types $A, B \tp +\MCU$ and two points $a \tp A$, $b \tp B$ we can construct the type: +% +\begin{align} + a \cong b \tp \MCU +\end{align} +% +This is likewise defined as an inductive data-type with a single constructors: +% +\begin{align} + \refl \tp a \cong a +\end{align} +% +In Cubical Agda these two notions are paralleled with homogeneous- and +heterogeneous paths respectively. +% +\subsection{The path type} +In Cubical Agda judgmental equality is encapsulated with the type: +% +$$ +\Path \tp (P : I → \MCU) → P\ 0 → P\ 1 → \MCU +$$ +% +$I$ is a special data-type (\TODO{that also has special computational properties + AFAIK}) called the index set. $I$ can be thought of simply as the interval on +the real numbers from $0$ to $1$. $P$ is a family of types over the index set +$I$. I will sometimes refer to $P$ as the ``path-space'' of some path $p \tp +\Path\ P\ a\ b$. By this token $P\ 0$ then corresponds to the type at the +left-endpoint and $P\ 1$ as the type at the right-endpoint. The type is called +$\Path$ because it is connected with paths in homotopy thoery. The intuition +behind this is that $\Path$ describes paths in $\MCU$ -- i.e. between types. For +a path $p$ for the point $p\ i$ the index $i$ describes how far along the path +one has moved. An inhabitant of $\Path\ P\ a_0\ a_1$ is a (dependent-) +function, $p$, from the index-space to the path-space: +% +$$ +p \tp I \to P\ i +$$ +% +Which must satisfy being judgmentally equal to $a_0$ (respectively $a_1$) at the +endpoints. I.e.: +% +\begin{align*} + p\ 0 & = a_0 \\ + p\ 1 & = a_1 +\end{align} +% +The notion of ``homogeneous equalities'' can be recovered by not letting the +path-space $P$ depend on it's argument: +% +$$ +a_0 \equiv a_1 \defeq \Path\ (\lambda i \to A)\ a_0\ a_1 +$$ +% +For $A \tp \MCU$, $a_0, a_1 \tp A$. I will generally prefer to use the notation +$a_0 \equiv a_1$ when talking about non-dependent paths and use the notation +$\Path\ (\lambda i \to A)\ a_0\ a_1$ when the path-space is of particular +interest. + +With this definition we can also recover reflexivity. That is, for any $A \tp +\MCU$ and $a \tp A$: +% +\begin{align} +\refl & \tp \Path (\lambda i \to A)\ a\ a \\ +\refl & \defeq \lambda i \to a +\end{align} +% +Or, in other terms; reflexivity is the path in $A$ that is $a$ at the left +endpoint as well as at the right endpoint. It is inhabited by the path which +stays constantly at $a$ at any index $i$. + +Paths have some other important properties, but they are not the focus of this +thesis. \TODO{Refer the reader somewhere for more info.} +% +\section{Homotopy levels} +In ITT all equality proofs are identical (in a closed context). This means that, +in some sense, any two inhabitants of $a \equiv b$ are ``equally good'' -- they +don't have any interesting structure. This is referred to as uniqueness of +identity proofs. Unfortunately this is orthogonal to univalence that only makes +sense in the absence of UIP. + +In homotopy type theory we have a hierarchy of types based on their ``internal +structure''. At the bottom of this hierarchy we have the set of contractible +types: +% +\begin{equation} +\begin{alignat}{2} +& \isContr && \tp \MCU \to \MCU \\ +& \isContr\ A && \defeq \sum_{c \tp A} \prod_{a \tp A} a \equiv c +\end{alignedat} +\end{equation} +% +The first component of $\isContr\ A$ is called ``the center of contraction''. +Under the propositions-as-types interpretation of type-theory $\isContr\ A$ can +be thought of as ``the true proposition $A$''. It is a theorem that if a type is +contractible, then it is isomorphic to the unit-type $\top$. + +The next step in the hierarchy is the set of mere propositions: +% +\begin{equation} +\begin{alignat}{2} +& \isProp && \tp \MCU \to \MCU \\ +& \isProp\ A && \defeq \prod_{a_0, a_1 \tp A} a_0 \equiv a_1 +\end{alignedat} +\end{equation} +% +$\isProp\ A$ can be thought of as the set of true and false propositions. It is +a result that if a mere proposition $A$ is inhabited, then so is it +contractible. If it is not inhabited it is equivalent to the empty-type (or +false proposition).\TODO{Cite!!} + +I will refer to a type $A \tp \MCU$ as a \emph{mere} proposition if I want to +stress that we have $\isProp\ A$. + +Then comes the set of homotopical sets: +% +\begin{equation} +\begin{alignat}{2} +& \isSet && \tp \MCU \to \MCU \\ +& \isSet\ A && \defeq \prod_{a_0, a_1 \tp A} \isProp\ (a_0 \equiv a_1) +\end{alignedat} +\end{equation} +% +At this point it should be noted that the term ``set'' is somewhat conflated; +there is the notion of sets from set-theory, in Agda types are denoted +\texttt{Set}. I will use it consistently to refer to a type $A$ as a set exactly +if $\isSet\ A$ is inhabited. + +The next step in the hierarchy is, as you might've guessed, the type: +% +\begin{equation} +\begin{alignat}{2} +& \isGroupoid && \tp \MCU \to \MCU \\ +& \isGroupoid\ A && \defeq \prod_{a_0, a_1 \tp A} \isSet\ (a_0 \equiv a_1) +\end{alignedat} +\end{equation} +% +And so it continues. In fact we can generalize this family of types by indexing +them with a natural number. For historical reasons, though, the bottom of the +hierarchy, the contractible tyes, is said to be a \nomen{-2-type}, propositions +are \nomen{-1-types}, (homotopical) sets are \nomen{0-types} and so on\ldots + +Just as with paths, homotopical sets are not at the center of focus for this +thesis. But I mention here some properties that will be relevant for this +exposition: + +Proposition: Homotopy levels are cumulative. That is, if $A \tp \MCU$ has +homotopy level $n$ then so does it have $n + 1$. + +Let $\left\Vert A \right\Vert = n$ denote that the level of $A$ is $n$. +Proposition: For any homotopic level $n$ this is a mere proposition. +% +\section{A few lemmas} +Rather than getting into the nitty-gritty details of Agda I venture to take a +more ``combinators-based'' approach. That is, I will use theorems about paths +already that have already been formalized. Specifically the results come from +the Agda library \texttt{cubical} (\TODO{Cite}). I have used a handful of +results from this library as well as contributed a few lemmas myself.\footnote{The module \texttt{Cat.Prelude} lists the upstream dependencies. As well my contribution to \texttt{cubical} can be found in the git logs \TODO{Cite}.} + +These theorems are all purely related to homotopy theory and cubical agda and as +such not specific to the formalization of Category Theory. I will present a few +of these theorems here, as they will be used later in chapter +\ref{ch:implementation} throughout. + +\subsection{Path induction} +The induction principle for paths intuitively gives us a way to reason about a +type-family indexed by a path by only considering if said path is $\refl$ (the +``base-case''). For \emph{based path induction}, that equaility is \emph{based} +at some element $a \tp A$. + +Let a type $A \tp \MCU$ and an element of the type $a \tp A$ be given. $a$ is said to be the base of the induction. Given a family of types: +% +$$ +P \tp \prod_{a' \tp A} \prod_{p \tp a ≡ a'} \MCU +$$ +% +And an inhabitant of $P$ at $\refl$: +% +$$ +p \tp P\ a\ \refl +$$ +% +We have the function: +% +$$ +\pathJ\ P\ p \tp \prod_{a' \tp A} \prod_{p \tp a ≡ a'} P\ a\ p +$$ +% +\subsection{Paths over propositions} +Another very useful combinator is $\lemPropF$: + +To `promote' this to a dependent path we can use another useful combinator; +$\lemPropF$. Given a type $A \tp \MCU$ and a type family on $A$; $P \tp A \to +\MCU$. Let $\var{propP} \tp \prod_{x \tp A} \isProp\ (P\ x)$ be the proof that +$P$ is a mere proposition for all elements of $A$. Furthermore say we have a +path between some two elements in $A$; $p \tp a_0 \equiv a_1$ then we can built +a heterogeneous path between any two elements of $p_0 \tp P\ a_0$ and $p_1 \tp +P\ a_1$: +% +$$ +\lemPropF\ \var{propP}\ p \defeq \Path\ (\lambda\; i \mto P\ (p\ i))\ p_0\ p_1 +$$ +% +This is quite a mouthful. So let me try to show how this is a very general and +useful result. + +Often when proving equalities between elements of some dependent types +$\lemPropF$ can be used to boil this complexity down to showing that the +dependent parts of the type are mere propositions. For instance, saw we have a type: +% +$$ +T \defeq \sum_{a : A} P\ a +$$ +% +For some proposition $P \tp A \to \MCU$. If we want to prove $t_0 \equiv t_1$ +for two elements $t_0, t_1 \tp T$ then this will be a pair of paths: +% +% +\begin{align*} + p \tp & \fst\ t_0 \equiv \fst\ t_1 \\ + & \Path\ (\lambda i \to P\ (p\ i))\ \snd\ t_0 \equiv \snd\ t_1 +\end{align*} +% +Here $\lemPropF$ directly allow us to prove the latter of these: +% +$$ +\lemPropF\ \var{propP}\ p + \tp \Path\ (\lambda i \to P\ (p\ i))\ \snd\ t_0 \equiv \snd\ t_1 +$$ +% +\subsection{Functions over propositions} +$\prod$-types preserve propositionality when the co-domain is always a +proposition. +% +$$ +\mathit{propPi} \tp \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\prod_{a \tp A} P\ a\right) +$$ +\subsection{Pairs over propositions} +% +$\sum$-types preserve propositionality whenever it's first component is a +proposition, and it's second component is a proposition for all points of in the +left type. +% +$$ +\mathit{propSig} \tp \isProp\ A \to \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\sum_{a \tp A} P\ a\right) +$$ diff --git a/doc/implementation.tex b/doc/implementation.tex index 9194bae..f1ad008 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -1,5 +1,6 @@ -\chapter{Implementation} -This implementation formalizes the following concepts $>\!\!>\!\!=$: +\chapter{Category Theory} +\label{ch:implementation} +This implementation formalizes the following concepts: % \begin{itemize} \item Core categorical concepts @@ -224,19 +225,18 @@ $$ \isoToId \tp (A \approxeq B) \to (A \equiv B) $$ % -One application of this, and a perhaps somewhat surprising result, is that -terminal objects are propositional. Intuitively; they do not -have any interesting structure: +A perhaps somewhat surprising application of this is that we can show that +terminal objects are propositional: % \begin{align} \label{eq:termProp} \isProp\ \var{Terminal} \end{align} % -The proof of this follows from the usual -observation that any two terminal objects are isomorphic. The proof is omitted -here, but the curious reader can check the implementation for the details. -\TODO{The proof is a bit fun, should I include it?} +It follows from the usual observation that any two terminal objects are +isomorphic - and since categories are univalent, so are they equal. The proof is +omitted here, but the curious reader can check the implementation for the +details. \TODO{The proof is a bit fun, should I include it?} \section{Equivalences} \label{sec:equiv} @@ -477,21 +477,21 @@ direction. I name these maps $\mathit{shuffle} \tp (A \approxeq B) \to (A \approxeq B)$ respectively. As the inverse of $\idToIso_{\mathit{Op}}$ I will pick $\zeta \defeq \eta \comp -\mathit{shuffle}$. The proof that they are inverses go as follows: +\var{shuffle}$. The proof that they are inverses go as follows: % \begin{align*} \zeta \comp \idToIso & \equiv -\eta \comp \shuffle \comp \idToIso +\eta \comp \var{shuffle} \comp \idToIso && \text{by definition} \\ %% ≡⟨ cong (λ φ → φ x) (cong (λ φ → η ⊙ shuffle ⊙ φ) (funExt lem)) ⟩ \\ % & \equiv -\eta \comp \shuffle \comp \inv{\shuffle} \comp \idToIso +\eta \comp \var{shuffle} \comp \inv{\var{shuffle}} \comp \idToIso && \text{lemma} \\ %% ≡⟨⟩ \\ & \equiv \eta \comp \idToIso_{\bC} -&& \text{$\shuffle$ is an isomorphism} \\ +&& \text{$\var{shuffle}$ is an isomorphism} \\ %% ≡⟨ (λ i → verso-recto i x) ⟩ \\ & \equiv \identity @@ -500,7 +500,7 @@ As the inverse of $\idToIso_{\mathit{Op}}$ I will pick $\zeta \defeq \eta \comp % The other direction is analogous. -The lemma used in this proof states that $\idToIso \equiv \inv{\shuffle} \comp +The lemma used in this proof states that $\idToIso \equiv \inv{\var{shuffle}} \comp \idToIso_{\bC}$ it's a rather straight-forward proof since being-an-inverse-of is a proposition. diff --git a/doc/introduction.tex b/doc/introduction.tex index 97306de..24442e9 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -155,16 +155,3 @@ all judgemental equalites of type theory, is cumbersome to work with in practice (\cite[p. 4]{huber-2016}) and makes equational proofs less reusable since equational proofs $a \sim_{X} b$ are inherently `local' to the extensional set $(X , \sim)$. -% -\section{The equality type} -The usual definition of equality in Agda is an inductive data-type with a single -constructor: -% -%% \VerbatimInput{../libs/main.tex} -% \def\verbatim@font{xits} -\begin{verbatim} -data _≡_ {a} {A : Set a} (x : A) : A → Set a where - instance refl : x ≡ x -\end{verbatim} -% -I shall refer to this as the (usual) inductive equality type. diff --git a/doc/macros.tex b/doc/macros.tex index 23ce2c3..0ce9273 100644 --- a/doc/macros.tex +++ b/doc/macros.tex @@ -47,6 +47,8 @@ \newcommand{\idToIso}{\var{idToIso}} \newcommand{\isSet}{\var{isSet}} \newcommand{\isContr}{\var{isContr}} +\newcommand{\isGroupoid}{\var{isGroupoid}} +\newcommand{\pathJ}{\var{pathJ}} \newcommand\Object{\var{Object}} \newcommand\Functor{\var{Functor}} \newcommand\isProp{\var{isProp}} diff --git a/doc/main.tex b/doc/main.tex index b0946e1..76ea1b8 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -43,6 +43,7 @@ \researchgroup{Programming Logic Group} \bibliographystyle{plain} + \begin{document} \pagenumbering{roman} @@ -51,6 +52,7 @@ % \pagenumbering{arabic} \input{introduction.tex} +\input{cubical.tex} \input{implementation.tex} \nocite{cubical-demo} From 545fb0ade6c0f7a630c23d2826d58d62a28142f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 3 May 2018 14:18:51 +0200 Subject: [PATCH 81/93] Corrections --- doc/BACKLOG.md | 15 ----- doc/cubical.tex | 4 ++ doc/implementation.tex | 147 +++++++++++++++++++---------------------- doc/introduction.tex | 60 ++++++++--------- doc/main.tex | 5 +- 5 files changed, 105 insertions(+), 126 deletions(-) diff --git a/doc/BACKLOG.md b/doc/BACKLOG.md index b889c92..8bf5f45 100644 --- a/doc/BACKLOG.md +++ b/doc/BACKLOG.md @@ -1,22 +1,7 @@ -Remove stuff about models of type theory - -Add references to specific (noteable) implementaitons of category theory: -* Unimath -* cubicaltt -* https://github.com/pcapriotti/agda-categories -* https://github.com/copumpkin/categories -* ... - Talk about structure of library: === -Propositional- and non-propositional stuff split up -Providing "equiality principles" -Provide overview of what has been proven. - What can I say about reusability? Misc ==== - -Propositional content diff --git a/doc/cubical.tex b/doc/cubical.tex index 0fc8cbb..b7dc0e9 100644 --- a/doc/cubical.tex +++ b/doc/cubical.tex @@ -192,6 +192,7 @@ of these theorems here, as they will be used later in chapter \ref{ch:implementation} throughout. \subsection{Path induction} +\label{sec:pathJ} The induction principle for paths intuitively gives us a way to reason about a type-family indexed by a path by only considering if said path is $\refl$ (the ``base-case''). For \emph{based path induction}, that equaility is \emph{based} @@ -216,6 +217,7 @@ $$ $$ % \subsection{Paths over propositions} +\label{sec:lemPropF} Another very useful combinator is $\lemPropF$: To `promote' this to a dependent path we can use another useful combinator; @@ -258,6 +260,7 @@ $$ $$ % \subsection{Functions over propositions} +\label{sec:propPi} $\prod$-types preserve propositionality when the co-domain is always a proposition. % @@ -265,6 +268,7 @@ $$ \mathit{propPi} \tp \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\prod_{a \tp A} P\ a\right) $$ \subsection{Pairs over propositions} +\label{sec:propSig} % $\sum$-types preserve propositionality whenever it's first component is a proposition, and it's second component is a proposition for all points of in the diff --git a/doc/implementation.tex b/doc/implementation.tex index f1ad008..9c9597c 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -42,10 +42,11 @@ Another record encapsulates some laws about this data: associativity of composition, identity law for the identity morphism. These are standard requirements for being a category as can be found in standard mathematical expositions on the topic. We, however, impose one further requirement on what it -means to be a category, namely that the type of arrows form a set. We could -relax this requirement, this would give us the notion of higher categorier -(\cite[p. 307]{hott-2013}). For the purpose of this project, however, this -report will restrict itself to 1-categories. +means to be a category, namely that the type of arrows form a set. Such +categories are called \nomen{1-categories}. We could relax this requirement, +this would give us the notion of higher categorier (\cite[p. 307]{hott-2013}). +For the purpose of this project, however, this report will restrict itself to +1-categories. Raw categories satisfying these properties are called a pre-categories. @@ -68,8 +69,9 @@ $$ $$ % The two types are logically equivalent, however. One can construct the latter -from the former simply by ``forgetting'' that $\idToIso$ plays the role -of the equivalence. The other direction is more involved. +from the former simply by ``forgetting'' that $\idToIso$ plays the role of the +equivalence. The other direction is more involved and will be discussed in +section \ref{sec:univalence}. With all this in place it is now possible to prove that all the laws are indeed mere propositions. Most of the proofs simply use the fact that the type of @@ -79,28 +81,21 @@ exactly because the type of arrows form a set, two witnesses must be the same. All the proofs are really quite mechanical. Lets have a look at one of them: The identity law states that: % -$$ -\prod_{A\ B \tp \Object} \prod_{f \tp A \to B} \id \comp f \equiv f \x f \comp \id \equiv f -$$ +\begin{equation} + \var{IsIdentity} \defeq + \prod_{A\ B \tp \Object} \prod_{f \tp A \to B} \id \comp f \equiv f \x f \comp \id \equiv f +\end{equation} % There are multiple ways to prove this. Perhaps one of the more intuitive proofs -is by way of the following `combinators': +is by way of the `combinators' $\propPi$ and $\propSig$ presented in sections +\ref{sec:propPi} and \ref{sec:propSig}: % -$$ -\mathit{propPi} \tp \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\prod_{a \tp A} P\ a\right) -$$ +\begin{align*} +\mathit{propPi} & \tp \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\prod_{a \tp A} P\ a\right) + \\ +\mathit{propSig} & \tp \isProp\ A \to \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\sum_{a \tp A} P\ a\right) +\end{align*} % -I.e.; pi-types preserve propositionality when the co-domain is always a -proposition. -% -$$ -\mathit{propSig} \tp \isProp\ A \to \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\sum_{a \tp A} P\ a\right) -$$ -% -I.e.; sigma-types preserve propositionality whenever it's first component is a -proposition, and it's second component is a proposition for all points of in the -left type. - So the proof goes like this: We `eliminate' the 3 function abstractions by applying $\propPi$ three times. So our proof obligation becomes: % @@ -135,13 +130,12 @@ $$ $$ % So let $a\ b \tp \IsPreCategory$ be given. To prove the equality $a \equiv b$ is -to give a continuous path from the index-type into path-space - in this case -$\IsPreCategory$. This path must satisfy being being judgmentally the same as -$a$ at the left endpoint and $b$ at the right endpoint. I.e. a function $I \to -\IsPreCategory$. We know we can form a continuous path between all projections -of $a$ and $b$, this follows from the type of all the projections being mere -propositions. For instance, the path between $\isIdentity_a$ and $\isIdentity_b$ -is simply formed by: +to give a continuous path from the index-type into the path-space. I.e. a +function $I \to \IsPreCategory$. This path must satisfy being being judgmentally +the same as $a$ at the left endpoint and $b$ at the right endpoint. We know we +can form a continuous path between all projections of $a$ and $b$, this follows +from the type of all the projections being mere propositions. For instance, the +path between $\isIdentity_a$ and $\isIdentity_b$ is simply formed by: % $$ \propIsIdentity\ \isIdentity_a\ \isIdentity_b \tp \isIdentity_a \equiv \isIdentity_b @@ -154,17 +148,18 @@ projections. Once we have such a path e.g. $p \tp \isIdentity_a \equiv \isIdentity_b$ we can elimiate it with $i$ and thus obtaining $p\ i \tp \isIdentity_{p\ i}$ and this element satisfies exactly that it corresponds to the corresponding projections at either endpoint. Thus the element we construct -at $i$ becomes: +at $i$ becomes the triple: % -\begin{align*} - & \{\ \mathit{propIsAssociative}\ \mathit{isAssociative}_x\ - \mathit{isAssociative}_y\ i \\ - & ,\ \mathit{propIsIdentity}\ \mathit{isIdentity}_x\ - \mathit{isIdentity}_y\ i \\ - & ,\ \mathit{propArrowsAreSets}\ \mathit{arrowsAreSets}_x\ - \mathit{arrowsAreSets}_y\ i \\ - & \} -\end{align*} +\begin{equation} +\begin{alignat}{4} + & \mathit{propIsAssociative} && x.\mathit{isAssociative}\ + && y.\mathit{isAssociative} && i \\ + & \mathit{propIsIdentity} && x.\mathit{isIdentity}\ + && y.\mathit{isIdentity} && i \\ + & \mathit{propArrowsAreSets} && x.\mathit{arrowsAreSets}\ + && y.\mathit{arrowsAreSets} && i +\end{alignat} +\end{equation} % I've found that this to be a general pattern when proving things in homotopy type theory, namely that you have to wrap and unwrap equalities at different @@ -181,11 +176,11 @@ The situation is a bit more complicated when we have a dependent type. For instance, when we want to show that $\IsCategory$ is a mere proposition. $\IsCategory$ is a record with two fields, a witness to being a pre-category and the univalence condition. Recall that the univalence condition is indexed by the -identity-proof. So if we follow the same recipe as above, let $a\ b \tp -\IsCategory$, to show them equal, we now need to give two paths. One homogenous: +identity-proof. So to follow the same recipe as above, let $a\ b \tp +\IsCategory$ be given, to show them equal, we now need to give two paths. One homogenous: % $$ -p_{\isPreCategory} \tp \isPreCategory_a \equiv \isPreCategory_b +p \tp \isPreCategory_a \equiv \isPreCategory_b $$ % and one heterogeneous: @@ -194,29 +189,23 @@ $$ \Path\ (\lambda\; i \mto Univalent_{p\ i})\ \isPreCategory_a\ \isPreCategory_b $$ % -Which depends on the choice of $p_{\isPreCategory}$. The first of these we can -provide since, as we have shown, $\IsPreCategory$ is a proposition. However, -even though $\Univalent$ is also a proposition, we cannot use this directly to -show the latter. This is becasue $\isProp$ talks about non-dependent paths. To -`promote' this to a dependent path we can use another useful combinator; -$\lemPropF$. Given a type $A \tp \MCU$ and a type family on $A$; $B \tp A \to -\MCU$. Let $P$ be a proposition indexed by an element of $A$ and say we have a -path between some two elements in $A$; $p \tp a_0 \equiv a_1$ then we can built a -heterogeneous path between any two $b$'s at the endpoints: -% -$$ -\Path\ (\lambda\; i \mto B\ (p\ i))\ b0\ b1 -$$ -% -where $b_0 \tp B a_0$ and $b_1 \tp B\ a_1$. This is quite a mouthful, but the -example at present should serve as an illustration. In this case $A = -\mathit{IsIdentity}\ \mathit{identity}$ and $B = \mathit{Univalent}$ we've shown -that being a category is a proposition, a result that holds for any choice of -identity proof. Finally we must provide a proof that the identity proofs at $a$ -and $b$ are indeed the same, this we can extract from $p_{\isPreCategory}$ by -applying using congruence of paths: $\congruence\ \mathit{isIdentity}\ -p_{\isPreCategory}$ +Which depends on the choice of $p$. The first of these we can provide since, as +we have shown, $\IsPreCategory$ is constantly a proposition. However, even +though $\Univalent$ is also a proposition, we cannot use this directly to show +the latter. This is becasue $\isProp$ talks about non-dependent paths. To +`promote' this to a dependent path we can use the combinator; $\lemPropF$ +introduced in \ref{sec:lemPropF}. +In this case $A = \mathit{IsIdentity}\ \mathit{identity}$ and $B = +\mathit{Univalent}$ we've shown that being a category is a proposition, a result +that holds for any choice of identity proof. Finally we must provide a proof +that the identity proofs at $a$ and $b$ are indeed the same, this we can extract +from $p$ by applying using congruence of paths: +% +$$ +\congruence\ \mathit{isIdentity}\ p +$$ +% When we have a proper category we can make precise the notion of ``identifying isomorphic types'' \TODO{cite awodey here}. That is, we can construct the function: @@ -311,7 +300,7 @@ the type $A \cong B$ as well as the the map $A \to B$ that witness this. Both $\cong$ and $\simeq$ form equivalence relations. \section{Univalence} -\label{univalence} +\label{sec:univalence} As noted in the introduction the univalence for types $A\; B \tp \Type$ states that: % @@ -342,16 +331,16 @@ equalities and isomorphisms (on arrows). It's worthwhile to dwell on this for a few seconds. This type looks very similar to univalence for types and is therefore perhaps a bit more intuitive to grasp the implications of. Of course univalence for types (which is a proposition -- i.e. provable) does not imply -univalence in any category since morphisms in a category are not regular maps -- -in stead they can be thought of as a generalization hereof; i.e. arrows. The -univalence criterion therefore is simply a way of restricting arrows to behave -similarly to maps. +univalence of all pre-category since morphisms in a category are not regular +maps -- in stead they can be thought of as a generalization hereof; i.e. arrows. +The univalence criterion therefore is simply a way of restricting arrows to +behave similarly to maps. I will now mention a few helpful thoerems that follow from univalence that will become useful later. -Obviously univalence gives us an isomorphism $A \equiv B \to A \approxeq B$. I -will name these for convenience: +Obviously univalence gives us an isomorphism between $A \equiv B$ and $A +\approxeq B$. I will name these for convenience: % $$ \idToIso \tp A \equiv B \to A \approxeq B @@ -366,8 +355,8 @@ an isomorphism $A \approxeq B$ in some category $\bC$ be given. Name the isomorphism $\iota \tp A \to B$ and its inverse $\widetilde{\iota} \tp B \to A$. Since $\bC$ is a category (and therefore univalent) the isomorphism induces a path $p \tp A \equiv B$. From this equality we can get two further paths: -$p_{\mathit{dom}} \tp \mathit{Arrow}\ A\ X \equiv \mathit{Arrow}\ A'\ X$ and -$p_{\mathit{cod}} \tp \mathit{Arrow}\ X\ A \equiv \mathit{Arrow}\ X\ A'$. We +$p_{\mathit{dom}} \tp \mathit{Arrow}\ A\ X \equiv \mathit{Arrow}\ B\ X$ and +$p_{\mathit{cod}} \tp \mathit{Arrow}\ X\ A \equiv \mathit{Arrow}\ X\ B$. We then have the following two theorems: % $$ @@ -394,11 +383,11 @@ isomorphism $\mathit{idToIso}\ p \tp A \cong B$. The helper-lemma is similar to what we're trying to prove but talks about paths rather than isomorphisms: % $$ -\prod_{f \tp \mathit{Arrow}\ A\ B} \prod_{p \tp A \equiv A'} \mathit{coe}\ p^*\ f \equiv f \lll \mathit{obverse}_{\mathit{idToIso}\ p} +\prod_{f \tp \mathit{Arrow}\ A\ B} \prod_{p \tp A \equiv B} \mathit{coe}\ p_\var{dom}\ f \equiv f \lll \mathit{obverse}_{\mathit{idToIso}\ p} $$ % -Note that the asterisk in $p^*$ denotes the path $\mathit{Arrow}\ A\ B \equiv -\mathit{Arrow}\ A'\ B$ induced by $p$. To prove this statement I let $f$ and $p$ +Again $p_\var{dom}$ denotes the path $\mathit{Arrow}\ A\ X \equiv +\mathit{Arrow}\ B\ X$ induced by $p$. To prove this statement I let $f$ and $p$ be given and then invoke based-path-induction. The induction will be based at $A \tp \mathit{Object}$, so let $\widetilde{A} \tp \Object$ and $\widetilde{p} \tp A \equiv \widetilde{A}$ be given. The family that we perform induction over will @@ -551,7 +540,7 @@ $$ (\mathit{hA} \equiv \mathit{hB}) \simeq (\mathit{hA} \approxeq \mathit{hB}) $$ % -Which, as we saw in section \ref{univalence}, is sufficient to show that the +Which, as we saw in section \ref{sec:univalence}, is sufficient to show that the category is univalent. The way that I have shown this is with a three-step process. For objects $(A, s_A)\; (B, s_B) \tp \Set$ I show the following chain of equivalences: diff --git a/doc/introduction.tex b/doc/introduction.tex index 24442e9..6d4d98a 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -70,27 +70,27 @@ The proof obligation that this satisfies the identity law of functors % One needs functional extensionality to ``go under'' the function arrow and apply the (left) identity law of the underlying category to proove $\idFun \comp g -\equiv g$ and thus closing the goal. +\equiv g$ and thus close the goal. % \subsection{Equality of isomorphic types} % -Let $\top$ denote the unit type -- a type with a single constructor. In -the propositions-as-types interpretation of type theory $\top$ is the -proposition that is always true. The type $A \x \top$ and $A$ has an element for -each $a : A$. So in a sense they are the same. The second element of the pair -does not add any ``interesting information''. It can be useful to identify such -types. In fact, it is quite commonplace in mathematics. Say we look at a set -$\{x \mid -\phi\ x \land \psi\ x\}$ and somehow conclude that $\psi\ x \equiv \top$ for all -$x$. A mathematician would immediately conclude $\{x \mid \phi\ x \land -\psi\ x\} \equiv \{x \mid \phi\ x\}$ without thinking twice. Unfortunately such -an identification can not be performed in ITT. +Let $\top$ denote the unit type -- a type with a single constructor. In the +propositions-as-types interpretation of type theory $\top$ is the proposition +that is always true. The type $A \x \top$ and $A$ has an element for each $a : +A$. So in a sense they have the same shape (greek; \nomen{isomorphic}). The +second element of the pair does not add any ``interesting information''. It can +be useful to identify such types. In fact, it is quite commonplace in +mathematics. Say we look at a set $\{x \mid \phi\ x \land \psi\ x\}$ and somehow +conclude that $\psi\ x \equiv \top$ for all $x$. A mathematician would +immediately conclude $\{x \mid \phi\ x \land \psi\ x\} \equiv \{x \mid +\phi\ x\}$ without thinking twice. Unfortunately such an identification can not +be performed in ITT. More specifically; what we are interested in is a way of identifying -\nomen{equivalent} types. I will return to the definition of equivalence later, -but for now, it is sufficient to think of an equivalence as a one-to-one -correspondence. We write $A \simeq B$ to assert that $A$ and $B$ are equivalent -types. The principle of univalence says that: +\nomen{equivalent} types. I will return to the definition of equivalence later +in section \ref{sec:equiv}, but for now it is sufficient to think of an +equivalence as a one-to-one correspondence. We write $A \simeq B$ to assert that +$A$ and $B$ are equivalent types. The principle of univalence says that: % $$\mathit{univalence} \tp (A \simeq B) \simeq (A \equiv B)$$ % @@ -99,14 +99,14 @@ In particular this allows us to construct an equality from an equivalence \section{Formalizing Category Theory} % -The above examples serve to illustrate the limitation of Agda. One case where -these limitations are particularly prohibitive is in the study of Category -Theory. At a glance category theory can be described as ``the mathematical study -of (abstract) algebras of functions'' (\cite{awodey-2006}). So by that token +The above examples serve to illustrate a limitation of ITT. One case where these +limitations are particularly prohibitive is in the study of Category Theory. At +a glance category theory can be described as ``the mathematical study of +(abstract) algebras of functions'' (\cite{awodey-2006}). So by that token functional extensionality is particularly useful for formulating Category Theory. In Category theory it is also common to identify isomorphic structures -and this is exactly what we get from univalence. In fact we can formulate this -requirement within our formulation of categories by requiring the +and univalence gives us a way to make this notion precise. In fact we can +formulate this requirement within our formulation of categories by requiring the \emph{categories} themselves to be univalent as we shall see. \section{Context} @@ -117,7 +117,7 @@ Inspiration: * HoTT - sketch of homotopy proofs \end{verbatim} The idea of formalizing Category Theory in proof assistants is not new. There -are a multitude of these available online. Just as first reference see this +are a multitude of these available online. Just as a first reference see this question on Math Overflow: \cite{mo-formalizations}. Notably these implementations of category theory in Agda: \begin{itemize} @@ -137,17 +137,17 @@ will make it possible to prove more things and to reuse proofs. There are alternative approaches to working in a cubical setting where one can still have univalence and functional extensionality. One option is to postulate these as axioms. This approach, however, has other shortcomings, e.g.; you lose -\nomen{canonicity} (\cite{huber-2016}). Canonicity means that any well-typed -term evaluates to a \emph{canonical} form. For example for a closed term $e : -\bN$ it will be the case that $e$ reduces to $n$ applications of $\mathit{suc}$ -to $0$ for some $n$; $e = \mathit{suc}^n\ 0$. Without canonicity terms in the -language can get ``stuck'' -- meaning that they do not reduce to a canonical -form. +\nomen{canonicity} (\TODO{Pageno!} \cite{huber-2016}). Canonicity means that any +well-typed term evaluates to a \emph{canonical} form. For example for a closed +term $e : \bN$ it will be the case that $e$ reduces to $n$ applications of +$\mathit{suc}$ to $0$ for some $n$; $e = \mathit{suc}^n\ 0$. Without canonicity +terms in the language can get ``stuck'' -- meaning that they do not reduce to a +canonical form. Another approach is to use the \emph{setoid interpretation} of type theory (\cite{hofmann-1995,huber-2016}). With this approach one works with \nomen{extensionals sets} $(X, \sim)$, that is a type $X \tp \MCU$ and an -equivalence relation $\sim$. +equivalence relation $\sim \tp X \to X \to \MCU$. Types should additionally `carry around' an equivalence relation that serve as propositional equality. This approach has other drawbacks; it does not satisfy diff --git a/doc/main.tex b/doc/main.tex index 76ea1b8..9686f98 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -43,14 +43,15 @@ \researchgroup{Programming Logic Group} \bibliographystyle{plain} - +\addtocontents{toc}{\protect\thispagestyle{empty}} \begin{document} \pagenumbering{roman} \maketitle + \tableofcontents -% \pagenumbering{arabic} +% \input{introduction.tex} \input{cubical.tex} \input{implementation.tex} From 29c4c4a3b9156b66a8bbe428d80abcbf40469cf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Mon, 7 May 2018 10:12:11 +0200 Subject: [PATCH 82/93] Equality principle for isomorphisms --- src/Cat/Category.agda | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index fab184b..95db7ee 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -222,9 +222,9 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where propIsInverseOf : ∀ {A B f g} → isProp (IsInverseOf {A} {B} f g) propIsInverseOf = propSig (arrowsAreSets _ _) (λ _ → arrowsAreSets _ _) - module _ {A B : Object} (f : Arrow A B) where - propIsomorphism : isProp (Isomorphism f) - propIsomorphism a@(g , η , ε) a'@(g' , η' , ε') = + module _ {A B : Object} where + propIsomorphism : (f : Arrow A B) → isProp (Isomorphism f) + propIsomorphism f a@(g , η , ε) a'@(g' , η' , ε') = lemSig (λ g → propIsInverseOf) a a' geq where geq : g ≡ g' @@ -236,6 +236,9 @@ module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where identity <<< g' ≡⟨ leftIdentity ⟩ g' ∎ + isoEq : {a b : A ≊ B} → fst a ≡ fst b → a ≡ b + isoEq = lemSig propIsomorphism _ _ + propIsInitial : ∀ I → isProp (IsInitial I) propIsInitial I x y i {X} = res X i where @@ -673,16 +676,7 @@ module Opposite {ℓa ℓb : Level} where -- Shouldn't be necessary to use `arrowsAreSets` here, but we have it, -- so why not? lem : (p : A ≡ B) → idToIso A B p ≡ shuffle~ (ℂ.idToIso A B p) - lem p = Σ≡ refl (Σ≡ refl (Σ≡ (ℂ.arrowsAreSets _ _ l-l r-l) (ℂ.arrowsAreSets _ _ l-r r-r))) - where - l = idToIso A B p - r = shuffle~ (ℂ.idToIso A B p) - open Σ l renaming (fst to l-obv ; snd to l-areInv) - open Σ l-areInv renaming (fst to l-invs ; snd to l-iso) - open Σ l-iso renaming (fst to l-l ; snd to l-r) - open Σ r renaming (fst to r-obv ; snd to r-areInv) - open Σ r-areInv renaming (fst to r-invs ; snd to r-iso) - open Σ r-iso renaming (fst to r-l ; snd to r-r) + lem p = isoEq refl ζ : A ≊ B → A ≡ B ζ = η ∘ shuffle From 4070e702d72343a8fc02c27a59744083ad61aeca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Mon, 7 May 2018 10:13:13 +0200 Subject: [PATCH 83/93] Various changes --- doc/chalmerstitle.sty | 13 +- doc/implementation.tex | 533 +++++++++++++++++++++++------------------ doc/introduction.tex | 95 ++++++-- doc/macros.tex | 1 + doc/main.tex | 4 + doc/refs.bib | 4 +- 6 files changed, 381 insertions(+), 269 deletions(-) diff --git a/doc/chalmerstitle.sty b/doc/chalmerstitle.sty index 64ddad3..70681d9 100644 --- a/doc/chalmerstitle.sty +++ b/doc/chalmerstitle.sty @@ -44,19 +44,16 @@ \fontseries{sb} %% \fontfamily{noto}\selectfont {\Huge\@title}\\[.5cm] -{\Large A formalization of category theory in Cubical Agda}\\[.5cm] -Master's thesis in Computer Science \\[.5cm] -{\Large\@author}\\[2cm] +{\Large A formalization of category theory in Cubical Agda}\\[2.5cm] \begin{center} \includegraphics[width=\linewidth,keepaspectratio]{isomorphism.png} \end{center} -\endgroup % Cover text \vfill %% \renewcommand{\familydefault}{\sfdefault} \normalfont % Set cover page font -\textsc{Department of Computer Science and Engineering}\\ -\textsc{Chalmers University of Technology}\\ -\textsc{Gothenburg, Sweden \the\year} +{\Large\@author}\\[.5cm] +Master's thesis in Computer Science +\endgroup %% \renewcommand{\familydefault}{\rmdefault} \normalfont % Reset standard font %% \end{titlepage} @@ -99,7 +96,7 @@ Master's thesis in Computer Science \\[.5cm] \thispagestyle{plain} \textit{\@title}\\ \@subtitle\\ -\copyright\ \the\year ~ \MakeUppercase{\@author} +\copyright\ \the\year ~ \textsc{\@author} \vspace{4.5cm} \setlength{\parskip}{0.5cm} diff --git a/doc/implementation.tex b/doc/implementation.tex index 9c9597c..7e18083 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -30,60 +30,111 @@ that we can provide a proof that the laws are mere propositions. As an example a category is defined to have two members: `raw` which is a collection of the data and `isCategory` which asserts some laws about that data. -This allows me to reason about things in a more mathematical way, where one can -reason about two categories by simply focusing on the data. This is acheived by -creating a function embodying the ``equality principle'' for a given type. +This allows me to reason about things in a more ``standard mathematical way'', +where one can reason about two categories by simply focusing on the data. This +is acheived by creating a function embodying the ``equality principle'' for a +given type. \section{Categories} -The data for a category consist of objects, morphisms (or arrows as I will refer -to them henceforth), the identity arrow and composition of arrows. - +The data for a category consist of a type for the sort of objects; a type for +the sort of arrows; an identity arrow and a composition operation for arrows. Another record encapsulates some laws about this data: associativity of composition, identity law for the identity morphism. These are standard -requirements for being a category as can be found in standard mathematical -expositions on the topic. We, however, impose one further requirement on what it -means to be a category, namely that the type of arrows form a set. Such -categories are called \nomen{1-categories}. We could relax this requirement, -this would give us the notion of higher categorier (\cite[p. 307]{hott-2013}). -For the purpose of this project, however, this report will restrict itself to -1-categories. +constituents of a category and can be found in typical mathematical expositions +on the topic. We, however, impose one further requirement on what it means to be +a category, namely that the type of arrows form a set. -Raw categories satisfying these properties are called a pre-categories. +Such categories are called \nomen{1-categories}. It's possible to relax this +requirement. This would lead to the notion of higher categorier (\cite[p. + 307]{hott-2013}). For the purpose of this project, however, this report will +restrict itself to 1-categories. Making based on higher categories would be a +very natural possible extension of this work. -As a further requirement to be a proper category we require it to be univalent. -This requirement is quite similiar to univalence for types, but we let -isomorphism on objects play the role of equivalence on types. The univalence -criterion is: +Raw categories satisfying all of the above requirements are called a +\nomen{pre}-categories. As a further requirement to be a proper category we +require it to be univalent. Before we can define this, I must introduce two more +definitions: If we let $p$ be a witness to the identity law, which formally is: % -$$ +\begin{equation} + \label{eq:identity} + \var{IsIdentity} \defeq + \prod_{A\ B \tp \Object} \prod_{f \tp A \to B} + \id \comp f \equiv f \x f \comp \id \equiv f +\end{equation} +% +Then we can construct the identity isomorphism $\var{idIso} \tp \identity, +\identity, p \tp A \approxeq A$ for any obejct $A$. Here $\approxeq$ denotes +isomorphism on objects (whereas $\cong$ denotes isomorphism of types). This will +be elaborated further on in sections \ref{sec:equiv} and \ref{sec:univalence}. +Moreover, due to substitution for paths we can construct an isomorphism from +\emph{any} path: +% +\begin{equation} +\var{idToIso} : A ≡ B → A ≊ B +\end{equation} +% +The univalence criterion for categories states that this map must be an +equivalence. The requirement is similar to univalence for types, but where +isomorphism on objects play the role of equivalence on types. Formally: +% +\begin{align} +\label{eq:cat-univ} \isEquiv\ (A \equiv B)\ (A \approxeq B)\ \idToIso -$$ +\end{align} % -Here $\approxeq$ denotes isomorphism on objects (whereas $\cong$ denotes -isomorphism of types). - -Note that this is not the same as: +Note that \ref{eq:cat-univ} is \emph{not} the same as: % -$$ +\begin{equation} +\label{eq:cat-univalence} +\tag{Univalence, category} (A \equiv B) \simeq (A \approxeq B) -$$ +\end{equation} % -The two types are logically equivalent, however. One can construct the latter -from the former simply by ``forgetting'' that $\idToIso$ plays the role of the +However the two are logically equivalent: One can construct the latter from the +former simply by ``forgetting'' that $\idToIso$ plays the role of the equivalence. The other direction is more involved and will be discussed in section \ref{sec:univalence}. +In summary, the definition of a category is the following collection of data: +% +\begin{align} + \Object & \tp \Type \\ + \Arrow & \tp \Object \to \Object \to \Type \\ + \identity & \tp \Arrow\ A\ A \\ + \lll & \tp \Arrow\ B\ C \to \Arrow\ A\ B \to \Arrow\ A\ C +\end{align} +% +And laws: +% +\begin{align} +\tag{associativity} +h \lll (g \lll f) ≡ (h \lll g) \lll f \\ +\tag{identity} +\identity \lll f ≡ f \x +f \lll \identity ≡ f +\\ +\label{eq:arrows-are-sets} +\tag{arrows are sets} +\isSet\ (\Arrow\ A\ B)\\ +\tag{\ref{eq:cat-univ}} +\isEquiv\ (A \equiv B)\ (A \approxeq B)\ \idToIso +\end{align} +% +$\lll$ denotes arrow composition (right-to-left), and reverse function +composition (left-to-right, diagramatic order) is denoted $\rrr$. The objects +($A$, $B$ and $C$) and arrow ($f$, $g$, $h$) are implicitly universally +quantified. + With all this in place it is now possible to prove that all the laws are indeed mere propositions. Most of the proofs simply use the fact that the type of arrows are sets. This is because most of the laws are a collection of equations between arrows in the category. And since such a proof does not have any content exactly because the type of arrows form a set, two witnesses must be the same. -All the proofs are really quite mechanical. Lets have a look at one of them: The -identity law states that: +All the proofs are really quite mechanical. Lets have a look at one of them. +Proving that \ref{eq:identity} is a mere proposition: % \begin{equation} - \var{IsIdentity} \defeq - \prod_{A\ B \tp \Object} \prod_{f \tp A \to B} \id \comp f \equiv f \x f \comp \id \equiv f + \isProp\ \var{IsIdentity} \end{equation} % There are multiple ways to prove this. Perhaps one of the more intuitive proofs @@ -91,9 +142,9 @@ is by way of the `combinators' $\propPi$ and $\propSig$ presented in sections \ref{sec:propPi} and \ref{sec:propSig}: % \begin{align*} -\mathit{propPi} & \tp \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\prod_{a \tp A} P\ a\right) +\var{propPi} & \tp \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\prod_{a \tp A} P\ a\right) \\ -\mathit{propSig} & \tp \isProp\ A \to \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\sum_{a \tp A} P\ a\right) +\var{propSig} & \tp \isProp\ A \to \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\sum_{a \tp A} P\ a\right) \end{align*} % So the proof goes like this: We `eliminate' the 3 function abstractions by @@ -103,9 +154,10 @@ $$ \isProp \left( \id \comp f \equiv f \x f \comp \id \equiv f \right) $$ % -then we eliminate the (non-dependent) sigma-type by applying $\propSig$ giving +Then we eliminate the (non-dependent) sigma-type by applying $\propSig$ giving us the two obligations: $\isProp\ (\id \comp f \equiv f)$ and $\isProp\ (f \comp -\id \equiv f)$ which follows from the type of arrows being a set. +\id \equiv f)$ which follows from the type of arrows being a +set. This example illustrates nicely how we can use these combinators to reason about `canonical' types like $\sum$ and $\prod$. Similiar combinators can be defined @@ -119,11 +171,14 @@ available to help us here. In stead we'll have to use the path-type directly. What we want to prove is: % -$$ +\begin{equation} +\label{eq:propIsPreCategory} \isProp\ \IsPreCategory -$$ +\end{equation} % -Which is judgmentally the same as +%% \begin{proof} +% +This is judgmentally the same as % $$ \prod_{a\ b \tp \IsPreCategory} a \equiv b @@ -135,42 +190,44 @@ function $I \to \IsPreCategory$. This path must satisfy being being judgmentally the same as $a$ at the left endpoint and $b$ at the right endpoint. We know we can form a continuous path between all projections of $a$ and $b$, this follows from the type of all the projections being mere propositions. For instance, the -path between $\isIdentity_a$ and $\isIdentity_b$ is simply formed by: +path between $a.\isIdentity$ and $b.\isIdentity$ is simply formed by: % $$ -\propIsIdentity\ \isIdentity_a\ \isIdentity_b \tp \isIdentity_a \equiv \isIdentity_b +\propIsIdentity\ a.\isIdentity\ b.\isIdentity +\tp +a.\isIdentity \equiv b.\isIdentity $$ % -So to give the continuous function $I \to \IsPreCategory$ that is our goal we +So to give the continuous function $I \to \IsPreCategory$, which is our goal, we introduce $i \tp I$ and proceed by constructing an element of $\IsPreCategory$ -by using that all the projections are propositions to generate paths between all -projections. Once we have such a path e.g. $p \tp \isIdentity_a \equiv -\isIdentity_b$ we can elimiate it with $i$ and thus obtaining $p\ i \tp -\isIdentity_{p\ i}$ and this element satisfies exactly that it corresponds to -the corresponding projections at either endpoint. Thus the element we construct -at $i$ becomes the triple: +by using the fact that all the projections are propositions to generate paths +between all projections. Once we have such a path e.g. $p \tp a.\isIdentity +\equiv b.\isIdentity$ we can elimiate it with $i$ and thus obtain $p\ i \tp +(p\ i).\isIdentity$. This element satisfies exactly that it corresponds to the +corresponding projections at either endpoint. Thus the element we construct at +$i$ becomes the triple: % \begin{equation} \begin{alignat}{4} - & \mathit{propIsAssociative} && x.\mathit{isAssociative}\ - && y.\mathit{isAssociative} && i \\ - & \mathit{propIsIdentity} && x.\mathit{isIdentity}\ - && y.\mathit{isIdentity} && i \\ - & \mathit{propArrowsAreSets} && x.\mathit{arrowsAreSets}\ - && y.\mathit{arrowsAreSets} && i + & \var{propIsAssociative} && a.\var{isAssociative}\ + && b.\var{isAssociative} && i \\ + & \var{propIsIdentity} && a.\var{isIdentity}\ + && b.\var{isIdentity} && i \\ + & \var{propArrowsAreSets} && a.\var{arrowsAreSets}\ + && b.\var{arrowsAreSets} && i \end{alignat} \end{equation} % -I've found that this to be a general pattern when proving things in homotopy -type theory, namely that you have to wrap and unwrap equalities at different -levels. It is worth noting that proving this theorem with the regular inductive -equality type would already not be possible, since we at least need -extensionality (the projections are all $\prod$-types). Assuming we had -functional extensionality available to us as an axiom, we would use functional -extensionality (in reverse?) to retreive the equalities in $a$ and $b$, -pattern-match on them to see that they are both $\mathit{refl}$ and then close -the proof with $\mathit{refl}$. Of course this theorem is not so interesting in -the setting of ITT since we know a priori that equality proofs are unique. +I've found this to be a general pattern when proving things in homotopy type +theory, namely that you have to wrap and unwrap equalities at different levels. +It is worth noting that proving this theorem with the regular inductive equality +type would already not be possible, since we at least need extensionality (the +projections are all $\prod$-types). Assuming we had functional extensionality +available to us as an axiom, we would use functional extensionality (in +reverse?) to retreive the equalities in $a$ and $b$, pattern-match on them to +see that they are both $\var{refl}$ and then close the proof with $\var{refl}$. +Of course this theorem is not so interesting in the setting of ITT since we know +a priori that equality proofs are unique. The situation is a bit more complicated when we have a dependent type. For instance, when we want to show that $\IsCategory$ is a mere proposition. @@ -180,32 +237,35 @@ identity-proof. So to follow the same recipe as above, let $a\ b \tp \IsCategory$ be given, to show them equal, we now need to give two paths. One homogenous: % $$ -p \tp \isPreCategory_a \equiv \isPreCategory_b +p \tp a.\isPreCategory \equiv b.\isPreCategory $$ % and one heterogeneous: % $$ -\Path\ (\lambda\; i \mto Univalent_{p\ i})\ \isPreCategory_a\ \isPreCategory_b +\Path\ (\lambda\; i \to (p\ i).Univalent)\ a.\isPreCategory\ b.\isPreCategory $$ % Which depends on the choice of $p$. The first of these we can provide since, as -we have shown, $\IsPreCategory$ is constantly a proposition. However, even -though $\Univalent$ is also a proposition, we cannot use this directly to show -the latter. This is becasue $\isProp$ talks about non-dependent paths. To -`promote' this to a dependent path we can use the combinator; $\lemPropF$ -introduced in \ref{sec:lemPropF}. +we have shown, $\IsPreCategory$ is a proposition. However, even though +$\Univalent$ is also a proposition, we cannot use this directly to show the +latter. This is becasue $\isProp$ talks about non-dependent paths. So we need to +'promote' the result that univalence is a proposition to a heterogeneous path. +To this end we can use $\lemPropF$, which wasintroduced in \ref{sec:lemPropF}. -In this case $A = \mathit{IsIdentity}\ \mathit{identity}$ and $B = -\mathit{Univalent}$ we've shown that being a category is a proposition, a result -that holds for any choice of identity proof. Finally we must provide a proof -that the identity proofs at $a$ and $b$ are indeed the same, this we can extract -from $p$ by applying using congruence of paths: +In this case $A = \var{IsIdentity}\ \identity$ and $B = \var{Univalent}$. We've +shown that being a category is a proposition, a result that holds for any choice +of identity proof. Finally we must provide a proof that the identity proofs at +$a$ and $b$ are indeed the same, this we can extract from $p$ by applying +congruence of paths: % $$ -\congruence\ \mathit{isIdentity}\ p +\congruence\ \var{isIdentity}\ p $$ % +And this finishes the proof that being-a-category is a mere proposition +(\ref{eq:propIsPreCategory}). + When we have a proper category we can make precise the notion of ``identifying isomorphic types'' \TODO{cite awodey here}. That is, we can construct the function: @@ -231,25 +291,38 @@ details. \TODO{The proof is a bit fun, should I include it?} \label{sec:equiv} The usual notion of a function $f \tp A \to B$ having an inverses is: % -$$ +\begin{equation} +\label{eq:isomorphism} \sum_{g \tp B \to A} f \comp g \equiv \identity_{B} \x g \comp f \equiv \identity_{A} -$$ +\end{equation} % -This is defined in \cite[p. 129]{hott-2013} and is referred to as the a -quasi-inverse. At the same place \cite{hott-2013} gives an ``interface'' for -what an equivalence $\isEquiv \tp (A \to B) \to \MCU$ must supply: +This is defined in \cite[p. 129]{hott-2013} where it is referred to as the a +``quasi-inverse''. We shall refer to the type \ref{eq:isomorphism} as +$\Isomorphism\ f$. This also gives rise to the following type: % -\begin{itemize} -\item - $\qinv\ f \to \isEquiv\ f$ -\item - $\isEquiv\ f \to \qinv\ f$ -\item - $\isEquiv\ f$ is a proposition -\end{itemize} +\begin{equation} +A \cong B \defeq \sum_{f \tp A \to B} \Isomorphism\ f +\end{equation} % -Having such an interface gives us both 1) a way to think rather abstractly about -how to work with equivalences and 2) to use ad-hoc definitions of equivalences. +At the same place \cite{hott-2013} gives an ``interface'' for what the judgment +$\isEquiv \tp (A \to B) \to \MCU$ must provide: +% +\begin{align} +\var{fromIso} & \tp \Isomorphism\ f \to \isEquiv\ f \\ +\var{toIso} & \tp \isEquiv\ f \to \Isomorphism\ f \\ +\label{eq:propIsEquiv} + &\mathrel{\ } \isEquiv\ f +\end{align} +% +The maps $\var{fromIso}$ and $\var{toIso}$ naturally extend to these maps: +% +\begin{align} +\var{fromIsomorphism} & \tp A \cong B \to A \simeq B \\ +\var{toIsomorphism} & \tp A \simeq B \to A \cong B +\end{align} +% +Having this interface gives us both: a way to think rather abstractly about how +to work with equivalences and a way to use ad-hoc definitions of equivalences. The specific instantiation of $\isEquiv$ as defined in \cite{cubical-agda} is: % $$ @@ -264,40 +337,26 @@ I give it's definition here mainly for completeness, because as I stated we can move away from this specific instantiation and think about it more abstractly once we have shown that this definition actually works as an equivalence. -The first function from the list of requirements we will call -$\mathit{fromIsomorphism}$, this is known as $\mathit{gradLemma}$ in -\cite{cubical-agda} the second one we will refer to as $\mathit{toIsmorphism}$. It's -implementation can be found in the sources. Likewise the proof that this -equivalence is propositional can be found in my implementation. +$\var{fromIso}$ can be found in \cite{cubical-agda} where it is known as +$\var{gradLemma}$. The implementation of $\var{fromIso}$ as well as the proof +that this equivalence is a proposition (\ref{eq:propIsEquiv}) can be found in my +implementation. We say that two types $A\;B \tp \Type$ are equivalent exactly if there exists an equivalence between them: % -$$ +\begin{equation} +\label{eq:equivalence} A \simeq B \defeq \sum_{f \tp A \to B} \isEquiv\ f -$$ +\end{equation} % Note that the term equivalence here is overloaded referring both to the map $f -\tp A \to B$ and the type $A \simeq B$. I will use these conflated terms when it +\tp A \to B$ and the type $A \simeq B$. The notion of an isomorphism is +similarly conflated as isomorphism can refer to the type $A \cong B$ as well as +the the map $A \to B$ that witness this. I will use these conflated terms when it is clear from the context what is being referred to. -Just like we could promote a quasi-inverse to an equivalence we can promote an -isomorphism to an equivalence: -% -$$ -\mathit{fromIsomorphism} \tp A \cong B \to A \simeq B -$$ -% -and vice-versa: -% -$$ -\mathit{toIsomorphism} \tp A \simeq B \to A \cong B -$$ -% -The notion of an isomorphism is similarly conflated as isomorphism can refer to -the type $A \cong B$ as well as the the map $A \to B$ that witness this. - -Both $\cong$ and $\simeq$ form equivalence relations. +Both $\cong$ and $\simeq$ form equivalence relations (no pun intended). \section{Univalence} \label{sec:univalence} @@ -305,7 +364,7 @@ As noted in the introduction the univalence for types $A\; B \tp \Type$ states that: % $$ -\mathit{Univalence} \defeq (A \equiv B) \simeq (A \simeq B) +\var{Univalence} \defeq (A \equiv B) \simeq (A \simeq B) $$ % As mentioned the univalence criterion for some category $\bC$ says that for all @@ -332,9 +391,8 @@ few seconds. This type looks very similar to univalence for types and is therefore perhaps a bit more intuitive to grasp the implications of. Of course univalence for types (which is a proposition -- i.e. provable) does not imply univalence of all pre-category since morphisms in a category are not regular -maps -- in stead they can be thought of as a generalization hereof; i.e. arrows. -The univalence criterion therefore is simply a way of restricting arrows to -behave similarly to maps. +functions -- in stead they can be thought of as a generalization hereof. The univalence criterion therefore is simply a way of restricting arrows +to behave similarly to maps. I will now mention a few helpful thoerems that follow from univalence that will become useful later. @@ -352,66 +410,72 @@ $$ % The next few theorems are variations on theorem 9.1.9 from \cite{hott-2013}. Let an isomorphism $A \approxeq B$ in some category $\bC$ be given. Name the -isomorphism $\iota \tp A \to B$ and its inverse $\widetilde{\iota} \tp B \to A$. +isomorphism $\iota \tp A \to B$ and its inverse $\inv{\iota} \tp B \to A$. Since $\bC$ is a category (and therefore univalent) the isomorphism induces a path $p \tp A \equiv B$. From this equality we can get two further paths: -$p_{\mathit{dom}} \tp \mathit{Arrow}\ A\ X \equiv \mathit{Arrow}\ B\ X$ and -$p_{\mathit{cod}} \tp \mathit{Arrow}\ X\ A \equiv \mathit{Arrow}\ X\ B$. We +$p_{\var{dom}} \tp \var{Arrow}\ A\ X \equiv \var{Arrow}\ B\ X$ and +$p_{\var{cod}} \tp \var{Arrow}\ X\ A \equiv \var{Arrow}\ X\ B$. We then have the following two theorems: % -$$ -\mathit{coeDom} \tp \prod_{f \tp A \to X} \mathit{coe}\ p_{\mathit{dom}}\ f \equiv f \lll \widetilde{\iota} -$$ -% -% \begin{align} +\label{eq:coeDom} +\var{coeDom} & \tp \prod_{f \tp A \to X} +\var{coe}\ p_{\var{dom}}\ f \equiv f \lll \inv{\iota} +\\ \label{eq:coeCod} -\mathit{coeCod} \tp \prod_{f \tp A \to X} \mathit{coe}\ p_{\mathit{cod}}\ f \equiv \iota \lll f +\var{coeCod} & \tp \prod_{f \tp A \to X} +\var{coe}\ p_{\var{cod}}\ f \equiv \iota \lll f \end{align} % I will give the proof of the first theorem here, the second one is analagous. +% \begin{align*} -\mathit{coe}\ p_{\mathit{dom}}\ f - & \equiv f \lll \mathit{obverse}_{\mathit{idToIso}\ p} && \text{lemma} \\ - & \equiv f \lll \widetilde{\iota} - && \text{$\mathit{idToIso}$ and $\mathit{isoToId}$ are inverses}\\ +\var{coe}\ p_{\var{dom}}\ f + & \equiv f \lll \inv{(\var{idToIso}\ p)} && \text{lemma} \\ + & \equiv f \lll \inv{\iota} + && \text{$\var{idToIso}$ and $\var{isoToId}$ are inverses}\\ \end{align*} % In the second step we use the fact that $p$ is constructed from the isomorphism -$\iota$ -- $\mathit{obverse}$ denotes the map $B \to A$ induced by the -isomorphism $\mathit{idToIso}\ p \tp A \cong B$. The helper-lemma is similar to +$\iota$ -- $\inv{(\var{idToIso}\ p)}$ denotes the map $B \to A$ induced by the +isomorphism $\var{idToIso}\ p \tp A \cong B$. The helper-lemma is similar to what we're trying to prove but talks about paths rather than isomorphisms: % -$$ -\prod_{f \tp \mathit{Arrow}\ A\ B} \prod_{p \tp A \equiv B} \mathit{coe}\ p_\var{dom}\ f \equiv f \lll \mathit{obverse}_{\mathit{idToIso}\ p} -$$ +\begin{equation} +\label{eq:coeDomIso} +\prod_{f \tp \var{Arrow}\ A\ B} \prod_{p \tp A \equiv B} +\var{coe}\ p_\var{dom}\ f \equiv f \lll \inv{(\var{idToIso}\ p)}} +\end{equation} % -Again $p_\var{dom}$ denotes the path $\mathit{Arrow}\ A\ X \equiv -\mathit{Arrow}\ B\ X$ induced by $p$. To prove this statement I let $f$ and $p$ +Again $p_\var{dom}$ denotes the path $\var{Arrow}\ A\ X \equiv +\var{Arrow}\ B\ X$ induced by $p$. To prove this statement I let $f$ and $p$ be given and then invoke based-path-induction. The induction will be based at $A -\tp \mathit{Object}$, so let $\widetilde{A} \tp \Object$ and $\widetilde{p} \tp -A \equiv \widetilde{A}$ be given. The family that we perform induction over will +\tp \var{Object}$, so let $\widetilde{B} \tp \Object$ and $\widetilde{p} \tp +A \equiv \widetilde{B}$ be given. The family that we perform induction over will be: % $$ -\mathit{coe}\ {\widetilde{p}}^*\ f \equiv f \lll \mathit{obverse}_{\mathit{idToIso}\ \widetilde{p}} +\var{coe}\ {\widetilde{p}}^*\ f +\equiv +f \lll \inv{(\var{idToIso}\ \widetilde{p})} $$ The base-case therefore becomes: \begin{align*} -\mathit{coe}\ {\widetilde{\refl}}^*\ f +\var{coe}\ {\widetilde{\refl}}^*\ f & \equiv f \\ -& \equiv f \lll \mathit{identity} \\ -& \equiv f \lll \mathit{obverse}_{\mathit{idToIso}\ \widetilde{\refl}} +& \equiv f \lll \var{identity} \\ +& \equiv f \lll \inv{(\var{idToIso}\ \widetilde{\refl})} \end{align*} % The first step follows because reflixivity is a neutral element for coercions. The second step is the identity law in the category. The last step has to do -with the fact that $\mathit{idToIso}$ is constructed by substituting according -to the supplied path and since reflexivity is also the neutral element for +with the fact that $\var{idToIso}$ is constructed by substituting according to +the supplied path and since reflexivity is also the neutral element for substuitutions we arrive at the desired expression. To close the -based-path-induction we must supply the value at the other end and the -connecting path, but in this case this is simply $A' \tp \Object$ and $p \tp A -\equiv A'$ which we have. +based-path-induction we must supply the value ``at the other''. In this case +this is simply $B \tp \Object$ and $p \tp A \equiv B$ which we have. + +And this finishes the proof of \ref{eq:coeDomIso} and thus \ref{eq:coeDom}. % \section{Categories} \subsection{Opposite category} @@ -423,14 +487,18 @@ univalence in a very simple category where the structure of the category is rather simple. Let $\bC$ be some category, we then define the opposite category -$\bC^{\mathit{Op}}$. It has the same objects, but the type of arrows are flipped, +$\bC^{\var{Op}}$. It has the same objects, but the type of arrows are flipped, that is to say an arrow from $A$ to $B$ in the opposite category corresponds to an arrow from $B$ to $A$ in the underlying category. The identity arrow is the same as the one in the underlying category (they have the same type). Function composition will be reverse function composition from the underlying category. -Showing that this forms a pre-category is rather straightforward. I'll state the -laws in terms of the underlying category $\bC$: +I'll refer to things in terms of the underlying category, unless they have an +over-bar. So e.g. $\idToIso$ is a function in the underlying category and the +corresponding thing is denoted $\wideoverbar{\idToIso}$ in the opposite +category. + +Showing that this forms a pre-category is rather straightforward. % $$ h \rrr (g \rrr f) \equiv h \rrr g \rrr f @@ -440,78 +508,77 @@ Since $\rrr$ is reverse function composition this is just the symmetric version of associativity. % $$ -\mathit{identity} \rrr f \equiv f \x f \rrr identity \equiv f +\var{identity} \rrr f \equiv f \x f \rrr identity \equiv f $$ % This is just the swapped version of identity. Finally, that the arrows form sets just follows by flipping the order of the -arguments. Or in other words since $\Hom_{A\ B}$ is a set for all $A\ B \tp -\Object$ then so is $\Hom_{B\ A}$. +arguments. Or in other words; since $\Arrow\ A\ B$ is a set for all $A\;B \tp +\Object$ then so is $Arrow\ B\ A$. -Now, to show that this category is univalent is not as straight-forward. Lucliy -section \ref{sec:equiv} gave us some tools to work with equivalences. -We saw that we -can prove this category univalent by giving an inverse to -$\idToIso_{\mathit{Op}} \tp (A \equiv B) \to (A \approxeq_{\mathit{Op}} B)$. +Now, to show that this category is univalent is not as straight-forward. Luckily +section \ref{sec:equiv} gave us some tools to work with equivalences. We saw +that we can prove this category univalent by giving an inverse to +$\wideoverbar{\idToIso} \tp (A \equiv B) \to (A \wideoverbar{\approxeq} B)$. From the original category we have that $\idToIso \tp (A \equiv B) \to (A \cong -B)$ is an isomorphism. Let us denote it's inverse with $\eta \tp (A \approxeq B) -\to (A \equiv B)$. If we squint we can see what we need is a way to go between -$\approxeq_{\mathit{Op}}$ and $\approxeq$, well, an inhabitant of $A \approxeq -B$ is simply an arrow $f \tp \mathit{Arrow}\ A\ B$ and it's inverse $g \tp -\mathit{Arrow}\ B\ A$. In the opposite category $g$ will play the role of the -isomorphism and $f$ will be the inverse. Similarly we can go in the opposite -direction. I name these maps $\mathit{shuffle} \tp (A \approxeq B) \to (A -\approxeq_{\bC} B)$ and $\mathit{shuffle}^{-1} \tp (A \approxeq_{\bC} B) \to (A -\approxeq B)$ respectively. +B)$ is an isomorphism. Let us denote it's inverse with $\isoToId \tp (A +\approxeq B) \to (A \equiv B)$. If we squint we can see what we need is a way to +go between $\wideoverbar{\approxeq}$ and $\approxeq$. -As the inverse of $\idToIso_{\mathit{Op}}$ I will pick $\zeta \defeq \eta \comp -\var{shuffle}$. The proof that they are inverses go as follows: +An inhabitant of $A \approxeq B$ is simply an arrow $f \tp \var{Arrow}\ A\ B$ +and it's inverse $g \tp \var{Arrow}\ B\ A$. In the opposite category $g$ will +play the role of the isomorphism and $f$ will be the inverse. Similarly we can +go in the opposite direction. I name these maps $\var{shuffle} \tp (A \approxeq +B) \to (A \wideoverbar{\approxeq} B)$ and $\var{shuffle}^{-1} \tp (A +\wideoverbar{\approxeq} B) \to (A \approxeq B)$ respectively. + +As the inverse of $\wideoverbar{\idToIso}$ I will pick $\wideoverbar{\isoToId} +\defeq \isoToId \comp \var{shuffle}$. The proof that they are inverses go as +follows: % \begin{align*} -\zeta \comp \idToIso & \equiv -\eta \comp \var{shuffle} \comp \idToIso -&& \text{by definition} \\ +\wideoverbar{\isoToId} \comp \wideoverbar{\idToIso} & = +\isoToId \comp \var{shuffle} \comp \wideoverbar{\idToIso} +\\ %% ≡⟨ cong (λ φ → φ x) (cong (λ φ → η ⊙ shuffle ⊙ φ) (funExt lem)) ⟩ \\ % & \equiv -\eta \comp \var{shuffle} \comp \inv{\var{shuffle}} \comp \idToIso +\isoToId \comp \var{shuffle} \comp \inv{\var{shuffle}} \comp \idToIso && \text{lemma} \\ %% ≡⟨⟩ \\ & \equiv -\eta \comp \idToIso_{\bC} +\isoToId \comp \idToIso && \text{$\var{shuffle}$ is an isomorphism} \\ -%% ≡⟨ (λ i → verso-recto i x) ⟩ \\ & \equiv \identity -&& \text{$\eta$ is an ismorphism} +&& \text{$\isoToId$ is an ismorphism} \end{align*} % The other direction is analogous. -The lemma used in this proof states that $\idToIso \equiv \inv{\var{shuffle}} \comp -\idToIso_{\bC}$ it's a rather straight-forward proof since being-an-inverse-of -is a proposition. - -So, in conclusion, we've shown that the opposite category is indeed a category. +The lemma used in step 2 of this proof states that $\wideoverbar{idToIso} \equiv +\inv{\var{shuffle}} \comp \idToIso$. This is a rather straight-forward proof +since being-an-inverse-of is a proposition, so it suffices to show that their +first components are equal, but this holds judgmentally. This finished the proof that the opposite category is in fact a category. Now, to prove that that opposite-of is an involution we must show: % $$ -\prod_{\bC \tp \mathit{Category}} \left(\bC^{\mathit{Op}}\right)^{\mathit{Op}} \equiv \bC +\prod_{\bC \tp \var{Category}} \left(\bC^{\var{Op}}\right)^{\var{Op}} \equiv \bC $$ % -As we've seen the laws in $\left(\bC^{\mathit{Op}}\right)^{\mathit{Op}}$ get -quite involved.\footnote{We haven't even seen the full story because we've used - this `interface' for equivalences.} Luckily since being-a-category is a mere +As we've seen the laws in $\left(\bC^{\var{Op}}\right)^{\var{Op}}$ get quite +involved.\footnote{We haven't even seen the full story because we've used this + `interface' for equivalences.} Luckily since being-a-category is a mere proposition, we need not concern ourselves with this bit when proving the above. -We can use the equality principle for categories that lets us prove an equality +We can use the equality principle for categories that let us prove an equality just by giving an equality on the data-part. So, given a category $\bC$ all we must provide is the following proof: % $$ -\mathit{raw}\ \left(\bC^{\mathit{Op}}\right)^{\mathit{Op}} \equiv \mathit{raw}\ \bC +\var{raw}\ \left(\bC^{\var{Op}}\right)^{\var{Op}} \equiv \var{raw}\ \bC $$ % And these are judgmentally the same. I remind the reader that the left-hand side @@ -521,23 +588,23 @@ is constructed by flipping the arrows, which judgmentally is an involution. The category of sets has as objects, not types, but only those types that are homotopic sets. This is encapsulated in Agda with the following type: % -$$\Set_\ell \defeq \sum_{A \tp \MCU_\ell} \isSet\ A$$ +$$\Set \defeq \sum_{A \tp \MCU} \isSet\ A$$ % The more straight-forward notion of a category where the objects are types is -not a valid (1-)category. Since in cubical Agda types can have higher homotopic -structure. +not a valid \mbox{(1-)category}. This stems from the fact that types in cubical +Agda types can have higher homotopic structure. Univalence does not follow immediately from univalence for types: % $$(A \equiv B) \simeq (A \simeq B)$$ % Because here $A\ B \tp \Type$ whereas the objects in this category have the type -$\Set$ so we cannot form the type $\mathit{hA} \simeq \mathit{hB}$ for objects -$\mathit{hA}\;\mathit{hB} \tp \Set$. In stead I show that this category +$\Set$ so we cannot form the type $\var{hA} \simeq \var{hB}$ for objects +$\var{hA}\;\var{hB} \tp \Set$. In stead I show that this category satisfies: % $$ -(\mathit{hA} \equiv \mathit{hB}) \simeq (\mathit{hA} \approxeq \mathit{hB}) +(\var{hA} \equiv \var{hB}) \simeq (\var{hA} \approxeq \var{hB}) $$ % Which, as we saw in section \ref{sec:univalence}, is sufficient to show that the @@ -561,7 +628,7 @@ together. Step one will be proven with the following lemma: \end{align} % The lemma states that for pairs whose second component are mere propositions -equiality is equivalent to equality of the first components. In this case the +equality is equivalent to equality of the first components. In this case the type-family $P$ is $\isSet$ which itself is a proposition for any type $A \tp \Type$. Step two is univalence. Step three will be proven with the following lemma: @@ -574,29 +641,31 @@ lemma: Which says that if two type-families are equivalent at all points, then pairs with identitical first components and these families as second components will also be equivalent. For our purposes $P \defeq \isEquiv\ A\ B$ and $Q \defeq -\mathit{Isomorphism}$. So we must finally prove: +\var{Isomorphism}$. So we must finally prove: % \begin{align} \label{eq:equivIso} -\prod_{f \tp A \to B} \left( \isEquiv\ A\ B\ f \simeq \mathit{Isomorphism}\ f \right) +\prod_{f \tp A \to B} \left( \isEquiv\ A\ B\ f \simeq \var{Isomorphism}\ f \right) \end{align} First, lets proove \ref{eq:equivPropSig}: Let $propP \tp \prod_{a \tp A} \isProp (P\ a)$ and $x\;y \tp \sum_{a \tp A} P\ a$ be given. Because -of $\mathit{fromIsomorphism}$ it suffices to give an isomorphism between +of $\var{fromIsomorphism}$ it suffices to give an isomorphism between $x \equiv y$ and $\fst\ x \equiv \fst\ y$: % -\begin{align*} - f & \defeq \congruence\ \fst \tp x \equiv y \to \fst\ x \equiv \fst\ y \\ - g & \defeq \mathit{lemSig}\ \mathit{propP}\ x\ y \tp \fst\ x \equiv \fst\ y \to x \equiv y -\end{align*} +\begin{alignat*}{5} + f & \defeq \congruence\ \fst + && \tp x && \equiv y && \to \fst\ x && \equiv \fst\ y \\ + g & \defeq \var{lemSig}\ \var{propP}\ x\ y + && \tp \fst\ x && \equiv \fst\ y && \to x && \equiv y +\end{alignat*} % -\TODO{Is it confusing that I use point-free style here?} -Here $\mathit{lemSig}$ is a lemma that says that if the second component of a -pair is a proposition, it suffices to give a path between it's first components -to construct an equality of the two pairs: +\TODO{Is it confusing that I use point-free style here?} Here $\var{lemSig}$ is +a lemma that says that if the second component of a pair is a proposition, it +suffices to give a path between its first components to construct an equality of +the two pairs: % \begin{align*} -\mathit{lemSig} \tp \left( \prod_{x \tp A} \isProp\ (B\ x) \right) \to +\var{lemSig} \tp \left( \prod_{x \tp A} \isProp\ (B\ x) \right) \to \prod_{u\; v \tp \sum_{a \tp A} B\ a} \left( \fst\ u \equiv \fst\ v \right) \to u \equiv v \end{align*} @@ -615,31 +684,31 @@ Lastly we prove \ref{eq:equivIso}. Let $f \tp A \to B$ be given. For the maps we choose: % \begin{align*} -\mathit{toIso} - & \tp \isEquiv\ f \to \mathit{Isomorphism}\ f \\ -\mathit{fromIso} - & \tp \mathit{Isomorphism}\ f \to \isEquiv\ f +\var{toIso} + & \tp \isEquiv\ f \to \var{Isomorphism}\ f \\ +\var{fromIso} + & \tp \var{Isomorphism}\ f \to \isEquiv\ f \end{align*} % As mentioned in section \ref{sec:equiv}. These maps are not in general inverses of each other. In stead, we will use the fact that $A$ and $B$ are sets. The first thing we must prove is: % \begin{align*} - \mathit{fromIso} \comp \mathit{toIso} \equiv \identity_{\isEquiv\ f} + \var{fromIso} \comp \var{toIso} \equiv \identity_{\isEquiv\ f} \end{align*} % For this we can use the fact that being-an-equivalence is a mere proposition. For the other direction: % \begin{align*} - \mathit{toIso} \comp \mathit{fromIso} \equiv \identity_{\mathit{Isomorphism}\ f} + \var{toIso} \comp \var{fromIso} \equiv \identity_{\var{Isomorphism}\ f} \end{align*} % -We will show that $\mathit{Isomorphism}\ f$ is also a mere proposition. To this -end, let $X\;Y \tp \mathit{Isomorphism}\ f$ be given. Name the maps $x\;y \tp B +We will show that $\var{Isomorphism}\ f$ is also a mere proposition. To this +end, let $X\;Y \tp \var{Isomorphism}\ f$ be given. Name the maps $x\;y \tp B \to A$ respectively. Now, the proof that $X$ and $Y$ are the same is a pair of -paths: $p \tp x \equiv y$ and $\Path\ (\lambda\; i \mto -\mathit{AreInverses}\ f\ (p\ i))\ \mathcal{X}\ \mathcal{Y}$ where $\mathcal{X}$ +paths: $p \tp x \equiv y$ and $\Path\ (\lambda\; i \to +\var{AreInverses}\ f\ (p\ i))\ \mathcal{X}\ \mathcal{Y}$ where $\mathcal{X}$ and $\mathcal{Y}$ denotes the witnesses that $x$ (respectively $y$) is an inverse to $f$. $p$ is inhabited by: % @@ -659,10 +728,10 @@ proposition and then use $\lemPropF$. So we prove the generalization: % \begin{align} \label{eq:propAreInversesGen} -\prod_{g \tp B \to A} \isProp\ (\mathit{AreInverses}\ f\ g) +\prod_{g \tp B \to A} \isProp\ (\var{AreInverses}\ f\ g) \end{align} % -But $\mathit{AreInverses}\ f\ g$ is a pair of equations on arrows, so we use +But $\var{AreInverses}\ f\ g$ is a pair of equations on arrows, so we use $\propSig$ and the fact that both $A$ and $B$ are sets to close this proof. \subsection{Category of categories} @@ -676,26 +745,26 @@ These lemmas can be used to provide the actual exponential object in a context where we have a witness to this being a category. This is useful if this library is later extended to talk about higher categories. -\section{Product} +\section{Products} In the following I'll demonstrate a technique for using categories to prove properties. The goal in this section is to show that products are propositions: % $$ -\prod_{\bC \tp \Category} \prod_{A\;B \tp \Object} \isProp\ (\mathit{Product}\ \bC\ A\ B) +\prod_{\bC \tp \Category} \prod_{A\;B \tp \Object} \isProp\ (\var{Product}\ \bC\ A\ B) $$ % -Where $\mathit{Product}\ \bC\ A\ B$ denotes the type of products of objects $A$ +Where $\var{Product}\ \bC\ A\ B$ denotes the type of products of objects $A$ and $B$ in the category $\bC$. I do this by constructing a category whose terminal objects are equivalent to products in $\bC$, and since terminal objects are propositional in a proper category and equivalences preserve homotopy level, then we know that products also are propositions. But before we get to that, let's recall the definition of products. -\subsection{Products} +\subsection{Definition of products} Given a category $\bC$ and two objects $A$ and $B$ in $\bC$ we define the -product of $A$ and $B$ to be an object $A \x B$ in $\bC$ and two arrows $\pi_1 -\tp A \x B \to A$ and $\pi_2 \tp A \x B \to B$ called the projections of the -product. The projections must satisfy the following property: +product (object) of $A$ and $B$ to be an object $A \x B$ in $\bC$ and two arrows +$\pi_1 \tp A \x B \to A$ and $\pi_2 \tp A \x B \to B$ called the projections of +the product. The projections must satisfy the following property: For all $X \tp Object$, $f \tp \Arrow\ X\ A$ and $g \tp \Arrow\ X\ B$ we have that there exists a unique arrow $\pi \tp \Arrow\ X\ (A \x B)$ satisfying @@ -1017,7 +1086,7 @@ The proof of the first one is: % \begin{align*} \var{coe}\ \widetilde{p}_\mathcal{A}\ x_\mathcal{A} - & ≡ x_\mathcal{A} \lll \fst\ \inv{f} && \text{$\mathit{coeDom}$ and the isomorphism $f, \inv{f}$} \\ + & ≡ x_\mathcal{A} \lll \fst\ \inv{f} && \text{$\var{coeDom}$ and the isomorphism $f, \inv{f}$} \\ & ≡ y_\mathcal{A} && \text{\ref{eq:pairArrowLaw} for $\inv{f}$} \end{align*} % @@ -1214,7 +1283,5 @@ And likewise in the kleisli formulation we can define $\join$: \join \defeq \bind\ \identity \end{align} % -Which shall play the role of $\join$. - It now remains to show that we can prove the various laws given this choice. I refer the reader to my implementation for the details. diff --git a/doc/introduction.tex b/doc/introduction.tex index 6d4d98a..2695db8 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -24,7 +24,7 @@ $f \defeq (n : \bN) \mapsto (0 + n : \bN)$ $g \defeq (n : \bN) \mapsto (n + 0 : \bN)$ \end{multicols} % -$n + 0$ is \nomen{definitionally} equal to $n$ which we write as $n + 0 = n$. +$n + 0$ is \nomen{definitionally} equal to $n$, which we write as $n + 0 = n$. This is also called \nomen{judgmental} equality. We call it definitional equality because the \emph{equality} arises from the \emph{definition} of $+$ which is: @@ -39,7 +39,7 @@ which is: Note that $0 + n$ is \emph{not} definitionally equal to $n$. $0 + n$ is in normal form. I.e.; there is no rule for $+$ whose left-hand-side matches this expression. We \emph{do}, however, have that they are \nomen{propositionally} -equal which we write as $n + 0 \equiv n$. Propositional equality means that +equal, which we write as $n + 0 \equiv n$. Propositional equality means that there is a proof that exhibits this relation. Since equality is a transitive relation we have that $n + 0 \equiv 0 + n$. @@ -62,7 +62,7 @@ for a category $\bC$ and a fixed object in $A \in \bC$ is defined to be: \end{align*} % The proof obligation that this satisfies the identity law of functors -($\fmap\ \idFun \equiv \idFun$) becomes: +($\fmap\ \idFun \equiv \idFun$) thus becomes: % \begin{align*} \Hom(A, \idFun_{\bX}) = (g \mapsto \idFun \comp g) \equiv \idFun_{\Sets} @@ -86,7 +86,7 @@ immediately conclude $\{x \mid \phi\ x \land \psi\ x\} \equiv \{x \mid \phi\ x\}$ without thinking twice. Unfortunately such an identification can not be performed in ITT. -More specifically; what we are interested in is a way of identifying +More specifically what we are interested in is a way of identifying \nomen{equivalent} types. I will return to the definition of equivalence later in section \ref{sec:equiv}, but for now it is sufficient to think of an equivalence as a one-to-one correspondence. We write $A \simeq B$ to assert that @@ -102,7 +102,7 @@ In particular this allows us to construct an equality from an equivalence The above examples serve to illustrate a limitation of ITT. One case where these limitations are particularly prohibitive is in the study of Category Theory. At a glance category theory can be described as ``the mathematical study of -(abstract) algebras of functions'' (\cite{awodey-2006}). So by that token +(abstract) algebras of functions'' (\cite{awodey-2006}). By that token functional extensionality is particularly useful for formulating Category Theory. In Category theory it is also common to identify isomorphic structures and univalence gives us a way to make this notion precise. In fact we can @@ -111,28 +111,38 @@ formulate this requirement within our formulation of categories by requiring the \section{Context} % -\begin{verbatim} -Inspiration: -* Awodey - formulation of categories -* HoTT - sketch of homotopy proofs -\end{verbatim} The idea of formalizing Category Theory in proof assistants is not new. There are a multitude of these available online. Just as a first reference see this question on Math Overflow: \cite{mo-formalizations}. Notably these implementations of category theory in Agda: +% \begin{itemize} \item -\url{https://github.com/copumpkin/categories} -- setoid interpretation -\item -\url{https://github.com/pcapriotti/agda-categories} -- homotopic setting with postulates -\item -\url{https://github.com/pcapriotti/agda-categories} -- homotopic setting in coq -\item -\url{https://github.com/mortberg/cubicaltt} -- homotopic setting in \texttt{cubicaltt} -\end{itemize} + \url{https://github.com/copumpkin/categories} + A formalization in Agda using the setoid approach +\item + \url{https://github.com/pcapriotti/agda-categories} + + A formalization in Agda with univalence and functional extensionality as + postulates. +\item + \url{https://github.com/pcapriotti/agda-categories} + + A formalization in Coq in the homotopic setting +\item + \url{https://github.com/mortberg/cubicaltt} + + A formalization in CubicalTT - a language designed for cubical-type-theory. + Formalizes many different things, but only a few concepts from category + theory. + +\end{itemize} +% The contribution of this thesis is to explore how working in a cubical setting -will make it possible to prove more things and to reuse proofs. +will make it possible to prove more things and to reuse proofs and to try and +compare some aspects of this formalization with the existing ones.\TODO{How can + I live up to this?} There are alternative approaches to working in a cubical setting where one can still have univalence and functional extensionality. One option is to postulate @@ -147,11 +157,44 @@ canonical form. Another approach is to use the \emph{setoid interpretation} of type theory (\cite{hofmann-1995,huber-2016}). With this approach one works with \nomen{extensionals sets} $(X, \sim)$, that is a type $X \tp \MCU$ and an -equivalence relation $\sim \tp X \to X \to \MCU$. - -Types should additionally `carry around' an equivalence relation that serve as +equivalence relation $\sim \tp X \to X \to \MCU$ on that type. Under the setoid +interpretation the equivalence relation serve as a sort of ``local'' propositional equality. This approach has other drawbacks; it does not satisfy -all judgemental equalites of type theory, is cumbersome to work with in practice -(\cite[p. 4]{huber-2016}) and makes equational proofs less reusable since -equational proofs $a \sim_{X} b$ are inherently `local' to the extensional set -$(X , \sim)$. +all propositional equalites of type theory (\TODO{Citation needed}, is +cumbersome to work with in practice (\cite[p. 4]{huber-2016}) and makes +equational proofs less reusable since equational proofs $a \sim_{X} b$ are +inherently `local' to the extensional set $(X , \sim)$. + +\section{Conventions} +\TODO{Talk a bit about terminology. Find a good place to stuff this little + section.} + +In the remainder of this paper I will use the term \nomen{Type} to describe -- +well, types. Thereby diverging from the notation in Agda where the keyword +\texttt{Set} refers to types. \nomen{Set} on the other hand shall refer to the +homotopical notion of a set. I will also leave all universe levels implicit. + +And I use the term \nomen{arrow} to refer to morphisms in a category, whereas +the terms morphism, map or function shall be reserved for talking about +type-theoretic functions; i.e. functions in Agda. + +$\defeq$ will be used for introducing definitions. $=$ will be used to for +judgmental equality and $\equiv$ will be used for propositional equality. + +All this is summarized in the following table: + +\begin{center} +\begin{tabular}{ c c c } +Name & Agda & Notation \\ +\hline +\nomen{Type} & \texttt{Set} & $\Type$ \\ +\nomen{Set} & \texttt{Σ Set IsSet} & $\Set$ \\ +Function, morphism, map & \texttt{A → B} & $A → B$ \\ +Dependent- ditto & \texttt{(a : A) → B} & $∏_{a \tp A} → B$ \\ +\nomen{Arrow} & \texttt{Arrow A B} & $\Arrow\ A\ B$ \\ +\nomen{Object} & \texttt{C.Object} & $̱ℂ.Object$ +Definition & \texttt{=} & $̱\defeq$ +Judgmental equality & \null & $̱=$ +Propositional equality & \null & $̱\equiv$ +\end{tabular} +\end{center} diff --git a/doc/macros.tex b/doc/macros.tex index 0ce9273..a5e03db 100644 --- a/doc/macros.tex +++ b/doc/macros.tex @@ -71,6 +71,7 @@ \newcommand\Univalent{\var{Univalent}} \newcommand\refl{\var{refl}} \newcommand\isoToId{\var{isoToId}} +\newcommand\Isomorphism{\var{Isomorphism}} \newcommand\rrr{\ggg} \newcommand\fish{\mathrel{\wideoverbar{\rrr}}} \newcommand\fst{\var{fst}} diff --git a/doc/main.tex b/doc/main.tex index 9686f98..a894748 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -44,6 +44,10 @@ \bibliographystyle{plain} \addtocontents{toc}{\protect\thispagestyle{empty}} +%% \newtheorem{prop}{Proposition} +\makeatletter +\newcommand*{\rom}[1]{\expandafter\@slowroman\romannumeral #1@} +\makeatother \begin{document} \pagenumbering{roman} diff --git a/doc/refs.bib b/doc/refs.bib index 2e376a0..4f335ac 100644 --- a/doc/refs.bib +++ b/doc/refs.bib @@ -106,11 +106,11 @@ @MISC{mo-formalizations, TITLE = {Formalizations of category theory in proof assistants}, AUTHOR = {Jason Gross}, - HOWPUBLISHED = {MathOverflow}, NOTE = {Version: 2014-01-19}, year={2014}, EPRINT = {\url{https://mathoverflow.net/q/152497}}, - URL = {https://mathoverflow.net/q/152497} + url = {https://mathoverflow.net/q/152497}, + howpublished = {MathOverflow: \url{https://mathoverflow.net/q/152497}} } @Misc{UniMath, author = {Voevodsky, Vladimir and Ahrens, Benedikt and Grayson, Daniel and others}, From d5a4550ca9d28b491db45b9613da502ab5eb8a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Mon, 7 May 2018 10:53:22 +0200 Subject: [PATCH 84/93] Always use brackets in subscript --- doc/cubical.tex | 2 +- doc/implementation.tex | 92 ++++++++++++++++++++++-------------------- doc/introduction.tex | 20 +++++---- 3 files changed, 62 insertions(+), 52 deletions(-) diff --git a/doc/cubical.tex b/doc/cubical.tex index b7dc0e9..9442b65 100644 --- a/doc/cubical.tex +++ b/doc/cubical.tex @@ -72,7 +72,7 @@ endpoints. I.e.: \begin{align*} p\ 0 & = a_0 \\ p\ 1 & = a_1 -\end{align} +\end{align*} % The notion of ``homogeneous equalities'' can be recovered by not letting the path-space $P$ depend on it's argument: diff --git a/doc/implementation.tex b/doc/implementation.tex index 7e18083..a73beb7 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -208,14 +208,14 @@ corresponding projections at either endpoint. Thus the element we construct at $i$ becomes the triple: % \begin{equation} -\begin{alignat}{4} +\begin{aligned} & \var{propIsAssociative} && a.\var{isAssociative}\ && b.\var{isAssociative} && i \\ & \var{propIsIdentity} && a.\var{isIdentity}\ && b.\var{isIdentity} && i \\ & \var{propArrowsAreSets} && a.\var{arrowsAreSets}\ && b.\var{arrowsAreSets} && i -\end{alignat} +\end{aligned} \end{equation} % I've found this to be a general pattern when proving things in homotopy type @@ -444,10 +444,10 @@ what we're trying to prove but talks about paths rather than isomorphisms: \begin{equation} \label{eq:coeDomIso} \prod_{f \tp \var{Arrow}\ A\ B} \prod_{p \tp A \equiv B} -\var{coe}\ p_\var{dom}\ f \equiv f \lll \inv{(\var{idToIso}\ p)}} +\var{coe}\ p_{\var{dom}}\ f \equiv f \lll \inv{(\var{idToIso}\ p)} \end{equation} % -Again $p_\var{dom}$ denotes the path $\var{Arrow}\ A\ X \equiv +Again $p_{\var{dom}}$ denotes the path $\var{Arrow}\ A\ X \equiv \var{Arrow}\ B\ X$ induced by $p$. To prove this statement I let $f$ and $p$ be given and then invoke based-path-induction. The induction will be based at $A \tp \var{Object}$, so let $\widetilde{B} \tp \Object$ and $\widetilde{p} \tp @@ -652,12 +652,15 @@ First, lets proove \ref{eq:equivPropSig}: Let $propP \tp \prod_{a \tp A} \isProp of $\var{fromIsomorphism}$ it suffices to give an isomorphism between $x \equiv y$ and $\fst\ x \equiv \fst\ y$: % -\begin{alignat*}{5} +%% FIXME: Too much alignement? +\begin{equation*} +\begin{aligned} f & \defeq \congruence\ \fst - && \tp x && \equiv y && \to \fst\ x && \equiv \fst\ y \\ + && \tp x \equiv y && \to \fst\ x \equiv \fst\ y \\ g & \defeq \var{lemSig}\ \var{propP}\ x\ y - && \tp \fst\ x && \equiv \fst\ y && \to x && \equiv y -\end{alignat*} + && \tp \fst\ x \equiv \fst\ y && \to x \equiv y +\end{aligned} +\end{equation*} % \TODO{Is it confusing that I use point-free style here?} Here $\var{lemSig}$ is a lemma that says that if the second component of a pair is a proposition, it @@ -856,15 +859,15 @@ Which is provable by \TODO{What?} and that the witness to \ref{eq:pairArrowLaw} for the left-hand-side and the right-hand-side are the same. The type of this goal is quite involved, and I will not write it out in full, but at present it suffices to show the type of the path-space. Note that the arrows in -\ref{eq:productAssoc} are arrows from $\mathcal{A} = (A , a_\pairA , a_\pairB)$ -to $\mathcal{D} = (D , d_\pairA , d_\pairB)$ where $a_\pairA$, $a_\pairB$, -$d_\pairA$ and $d_\pairB$ are arrows in the underlying category. Given that $p$ +\ref{eq:productAssoc} are arrows from $\mathcal{A} = (A , a_{\pairA} , a_{\pairB})$ +to $\mathcal{D} = (D , d_{\pairA} , d_{\pairB})$ where $a_{\pairA}$, $a_{\pairB}$, +$d_{\pairA}$ and $d_{\pairB}$ are arrows in the underlying category. Given that $p$ is the chosen proof of \ref{eq:productAssocUnderlying} we then have that the witness to \ref{eq:pairArrowLaw} vary over the type: % \begin{align} \label{eq:productPath} -λ\ i → d_\pairA \lll p\ i ≡ a_\pairA × d_\pairB \lll p\ i ≡ a_\pairB +λ\ i → d_{\pairA} \lll p\ i ≡ 2 a_{\pairA} × d_{\pairB} \lll p\ i ≡ a_{\pairB} \end{align} % And these paths are in the type of the hom-set of the underlying category, so @@ -874,14 +877,14 @@ stead we generalize \ref{eq:productPath} to: % \begin{align} \label{eq:productEqPrinc} -\prod_{f \tp \Arrow\ X\ Y} \isProp\ \left( y_\pairA \lll f ≡ x_\pairA × y_\pairB \lll f ≡ x_\pairB \right) +\prod_{f \tp \Arrow\ X\ Y} \isProp\ \left( y_{\pairA} \lll f ≡ x_{\pairA} × y_{\pairB} \lll f ≡ x_{\pairB} \right) \end{align} % -For all objects $X , x_\pairA , x_\pairB$ and $Y , y_\pairA , y_\pairB$, but -this follows from pairs preserving homotopical structure and arrows in the +For all objects $X , x_{\pairA} , x_{\pairB}$ and $Y , y_{\pairA} , y_{\pairB}$, +but this follows from pairs preserving homotopical structure and arrows in the underlying category being sets. This gives us an equality principle for arrows in this category that says that to prove two arrows $f, f_0, f_1$ and $g, g_0, -$g_1$ equal it suffices to give a proof that $f$ and $g$ are equal. +g_1$ equal it suffices to give a proof that $f$ and $g$ are equal. %% % %% $$ %% \prod_{(f, f_0, f_1)\; (g,g_0,g_1) \tp \Arrow\ X\ Y} f \equiv g \to (f, f_0, f_1) \equiv (g,g_0,g_1) @@ -899,13 +902,16 @@ $$ Since pairs preserve homotopical structure this reduces to: % $$ -\isSet\ (\Arrow_\bC\ X\ Y) +\isSet\ (\Arrow_{\bC}\ X\ Y) $$ % Which holds. And % $$ -\prod_{f \tp \Arrow\ X\ Y} \isSet\ \left( y_\pairA \lll f ≡ x_\pairA × y_\pairB \lll f ≡ x_\pairB \right) +\prod_{f \tp \Arrow\ X\ Y} +\isSet\ \left( y_{\pairA} \lll f ≡ x_{\pairA} + × y_{\pairB} \lll f ≡ x_{\pairB} + \right) $$ % This we get from \ref{eq:productEqPrinc} and the fact that homotopical structure @@ -915,8 +921,8 @@ This finishes the proof that this is a valid pre-category. \subsubsection{Univalence} To prove that this is a proper category it must be shown that it is univalent. -That is, for any two objects $\mathcal{X} = (X, x_\mathcal{A} , x_\mathca{B})$ -and $\mathcal{Y} = Y, y_\mathcal{A}, y_\mathcal{B}$ I will show: +That is, for any two objects $\mathcal{X} = (X, x_{\mathcal{A}} , x_{\mathcal{B}})$ +and $\mathcal{Y} = Y, y_{\mathcal{A}}, y_{\mathcal{B}}$ I will show: % \begin{align} (\mathcal{X} \equiv \mathcal{Y}) \cong (\mathcal{X} \approxeq \mathcal{Y}) @@ -928,7 +934,7 @@ The first type is: % \begin{align} \label{eq:univ-0} -(X , x_\mathcal{A} , x_\mathcal{B}) ≡ (Y , y_\mathcal{A} , y_\mathcal{B}) +(X , x_{\mathcal{A}} , x_{\mathcal{B}}) ≡ (Y , y_{\mathcal{A}} , y_{\mathcal{B}}) \end{align} % The next types will be the triple: @@ -937,8 +943,8 @@ The next types will be the triple: \label{eq:univ-1} \begin{split} p \tp & X \equiv Y \\ -& \Path\ (λ i → \Arrow\ (p\ i)\ \mathcal{A})\ x_\mathcal{A}\ y_\mathcal{A} \\ -& \Path\ (λ i → \Arrow\ (p\ i)\ \mathcal{B})\ x_\mathcal{B}\ y_\mathcal{B} +& \Path\ (λ i → \Arrow\ (p\ i)\ \mathcal{A})\ x_{\mathcal{A}}\ y_{\mathcal{A}} \\ +& \Path\ (λ i → \Arrow\ (p\ i)\ \mathcal{B})\ x_{\mathcal{B}}\ y_{\mathcal{B}} \end{split} %% \end{split} \end{align} @@ -950,8 +956,8 @@ isomorphism, and create a path from this: \label{eq:univ-2} \begin{split} \var{iso} \tp & X \cong Y \\ -& \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{A})\ x_\mathcal{A}\ y_\mathcal{A} \\ -& \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{B})\ x_\mathcal{B}\ y_\mathcal{B} +& \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{A})\ x_{\mathcal{A}}\ y_{\mathcal{A}} \\ +& \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{B})\ x_{\mathcal{B}}\ y_{\mathcal{B}} \end{split} \end{align} % @@ -961,7 +967,7 @@ Finally we have the type: % \begin{align} \label{eq:univ-3} -(X , x_\mathcal{A} , x_\mathcal{B}) ≊ (Y , y_\mathcal{A} , y_\mathcal{B}) +(X , x_{\mathcal{A}} , x_{\mathcal{B}}) ≊ (Y , y_{\mathcal{A}} , y_{\mathcal{B}}) \end{align} \emph{Proposition} \ref{eq:univ-0} is isomorphic to \ref{eq:univ-1}: This is @@ -976,7 +982,7 @@ the implementation for the details). will swho two corrolaries of \ref{eq:coeCod}: For an isomorphism $(\iota, \inv{\iota}, \var{inv}) \tp A \cong B$, arrows $f \tp \Arrow\ A\ X$, $g \tp \Arrow\ B\ X$ and a heterogeneous path between them, $q \tp \Path\ (\lambda i -\to p_\var{dom}\ i)\ f\ g$, where $p_\var{dom} \tp \Arrow\ A\ X \equiv +\to p_{\var{dom}}\ i)\ f\ g$, where $p_{\var{dom}} \tp \Arrow\ A\ X \equiv \Arrow\ B\ X$ is a path induced by $\var{iso}$, we have the following two results % @@ -993,14 +999,14 @@ Now we can prove the equiavalence in the following way: Given $(f, \inv{f}, \var{inv}_f) \tp X \cong Y$ and two heterogeneous paths % \begin{align*} -p_\mathcal{A} & \tp \Path\ (\lambda i \to p_\var{dom}\ i)\ x_\mathcal{A}\ y_\mathcal{A}\\ +p_{\mathcal{A}} & \tp \Path\ (\lambda i \to p_{\var{dom}}\ i)\ x_{\mathcal{A}}\ y_{\mathcal{A}}\\ % -q_\mathcal{B} & \tp \Path\ (\lambda i \to p_\var{dom}\ i)\ x_\mathcal{B}\ y_\mathcal{B} +q_{\mathcal{B}} & \tp \Path\ (\lambda i \to p_{\var{dom}}\ i)\ x_{\mathcal{B}}\ y_{\mathcal{B}} \end{align*} % -all as in \ref{eq:univ-2}. I use $p_\var{dom}$ here again to mean the path +all as in \ref{eq:univ-2}. I use $p_{\var{dom}}$ here again to mean the path induced by the isomorphism $f, \inv{f}$. I must now construct an isomorphism -$(X, x_\mathcal{A}, x_\mathcal{B}) \approxeq (Y, y_\mathcal{A}, y_\mathcal{B}$ +$(X, x_{\mathcal{A}}, x_{\mathcal{B}}) \approxeq (Y, y_{\mathcal{A}}, y_{\mathcal{B}})$ as in \ref{eq:univ-3}. That is, an isomorphism in the present category. I remind the reader that such a gadget is a triple. The first component shall be: % @@ -1012,10 +1018,10 @@ To show that this choice fits the bill I must now verify that it satisfies \ref{eq:pairArrowLaw}, which in this case becomes: % \begin{align} -y_\mathcal{A} \lll f ≡ x_\mathcal{A} × y_\mathcal{B} \lll f ≡ x_\mathcal{B} +y_{\mathcal{A}} \lll f ≡ x_{\mathcal{A}} × y_{\mathcal{B}} \lll f ≡ x_{\mathcal{B}} \end{align} % -Which, since $f$ is an isomorphism and $p_\mathcal{A}$ (resp. $p_\mathcal{B}$) +Which, since $f$ is an isomorphism and $p_{\mathcal{A}}$ (resp. $p_{\mathcal{B}}$) is a path varying according to a path constructed from this isomorphism, this is exactly what \ref{eq:domain-twist-0} gives us. % @@ -1033,7 +1039,7 @@ For the other direction we're given just given the isomorphism $$ (f, \inv{f}, \var{inv}_f) \tp -(X, x_\mathcal{A}, x_\mathcal{B}) \approxeq (Y, y_\mathcal{A}, y_\mathcal{B}) +(X, x_{\mathcal{A}}, x_{\mathcal{B}}) \approxeq (Y, y_{\mathcal{A}}, y_{\mathcal{B}}) $$ % Projecting out the first component gives us the isomorphism @@ -1048,8 +1054,8 @@ This gives rise to the following paths: \begin{align} \begin{split} \widetilde{p} & \tp X \equiv Y \\ -\widetilde{p}_\mathcal{A} & \tp \Arrow\ X\ \mathcal{A} \equiv \Arrow\ Y\ \mathcal{A} \\ -\widetilde{p}_\mathcal{B} & \tp \Arrow\ X\ \mathcal{B} \equiv \Arrow\ Y\ \mathcal{B} +\widetilde{p}_{\mathcal{A}} & \tp \Arrow\ X\ \mathcal{A} \equiv \Arrow\ Y\ \mathcal{A} \\ +\widetilde{p}_{\mathcal{B}} & \tp \Arrow\ X\ \mathcal{B} \equiv \Arrow\ Y\ \mathcal{B} \end{split} \end{align} % @@ -1058,8 +1064,8 @@ It then remains to construct the two paths: \begin{align} \begin{split} \label{eq:product-paths} -& \Path\ (λ i → \widetilde{p}_\mathcal{A}\ i)\ x_\mathcal{A}\ y_\mathcal{A}\\ -& \Path\ (λ i → \widetilde{p}_\mathcal{B}\ i)\ x_\mathcal{B}\ y_\mathcal{B} +& \Path\ (λ i → \widetilde{p}_{\mathcal{A}}\ i)\ x_{\mathcal{A}}\ y_{\mathcal{A}}\\ +& \Path\ (λ i → \widetilde{p}_{\mathcal{B}}\ i)\ x_{\mathcal{B}}\ y_{\mathcal{B}} \end{split} \end{align} % @@ -1077,17 +1083,17 @@ Which is used without proof. See the implementation for the details. \begin{align} \begin{split} \label{eq:product-paths} -\var{coe}\ \widetilde{p}_\mathcal{A}\ x_\mathcal{A} ≡ y_\mathcal{A}\\ -\var{coe}\ \widetilde{p}_\mathcal{B}\ x_\mathcal{B} ≡ y_\mathcal{B} +\var{coe}\ \widetilde{p}_{\mathcal{A}}\ x_{\mathcal{A}} ≡ y_{\mathcal{A}}\\ +\var{coe}\ \widetilde{p}_{\mathcal{B}}\ x_{\mathcal{B}} ≡ y_{\mathcal{B}} \end{split} \end{align} % The proof of the first one is: % \begin{align*} - \var{coe}\ \widetilde{p}_\mathcal{A}\ x_\mathcal{A} - & ≡ x_\mathcal{A} \lll \fst\ \inv{f} && \text{$\var{coeDom}$ and the isomorphism $f, \inv{f}$} \\ - & ≡ y_\mathcal{A} && \text{\ref{eq:pairArrowLaw} for $\inv{f}$} + \var{coe}\ \widetilde{p}_{\mathcal{A}}\ x_{\mathcal{A}} + & ≡ x_{\mathcal{A}} \lll \fst\ \inv{f} && \text{$\var{coeDom}$ and the isomorphism $f, \inv{f}$} \\ + & ≡ y_{\mathcal{A}} && \text{\ref{eq:pairArrowLaw} for $\inv{f}$} \end{align*} % We have now constructed the maps between \ref{eq:univ-0} and \ref{eq:univ-1}. It diff --git a/doc/introduction.tex b/doc/introduction.tex index 2695db8..99761fb 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -1,7 +1,7 @@ \chapter{Introduction} Functional extensionality and univalence is not expressible in \nomen{Intensional Martin Löf Type Theory} (ITT). This poses a severe limitation -on both 1) what is \emph{provable} and 2) the \emph{reusability} of proofs. +on both i. what is \emph{provable} and ii. the \emph{reusability} of proofs. Recent developments have, however, resulted in \nomen{Cubical Type Theory} (CTT) which permits a constructive proof of these two important notions. @@ -19,9 +19,13 @@ limitations inherent in ITT and -- by extension -- Agda. Consider the functions: % \begin{multicols}{2} -$f \defeq (n : \bN) \mapsto (0 + n : \bN)$ - -$g \defeq (n : \bN) \mapsto (n + 0 : \bN)$ + \noindent + \begin{equation*} + f \defeq (n : \bN) \mapsto (0 + n : \bN) + \end{equation*} + \begin{equation*} + g \defeq (n : \bN) \mapsto (n + 0 : \bN) + \end{equation*} \end{multicols} % $n + 0$ is \nomen{definitionally} equal to $n$, which we write as $n + 0 = n$. @@ -160,7 +164,7 @@ Another approach is to use the \emph{setoid interpretation} of type theory equivalence relation $\sim \tp X \to X \to \MCU$ on that type. Under the setoid interpretation the equivalence relation serve as a sort of ``local'' propositional equality. This approach has other drawbacks; it does not satisfy -all propositional equalites of type theory (\TODO{Citation needed}, is +all propositional equalites of type theory (\TODO{Citation needed}), is cumbersome to work with in practice (\cite[p. 4]{huber-2016}) and makes equational proofs less reusable since equational proofs $a \sim_{X} b$ are inherently `local' to the extensional set $(X , \sim)$. @@ -192,9 +196,9 @@ Name & Agda & Notation \\ Function, morphism, map & \texttt{A → B} & $A → B$ \\ Dependent- ditto & \texttt{(a : A) → B} & $∏_{a \tp A} → B$ \\ \nomen{Arrow} & \texttt{Arrow A B} & $\Arrow\ A\ B$ \\ -\nomen{Object} & \texttt{C.Object} & $̱ℂ.Object$ -Definition & \texttt{=} & $̱\defeq$ -Judgmental equality & \null & $̱=$ +\nomen{Object} & \texttt{C.Object} & $̱ℂ.Object$ \\ +Definition & \texttt{=} & $̱\defeq$ \\ +Judgmental equality & \null & $̱=$ \\ Propositional equality & \null & $̱\equiv$ \end{tabular} \end{center} From 0db4e9751194893d76356413a0180044f6cb9665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Mon, 7 May 2018 14:39:50 +0200 Subject: [PATCH 85/93] Do not use wishlist --- src/Cat/Categories/Sets.agda | 1 - src/Cat/Category/NaturalTransformation.agda | 1 - src/Cat/Prelude.agda | 8 +++++++- src/Cat/Wishlist.agda | 16 ---------------- 4 files changed, 7 insertions(+), 19 deletions(-) delete mode 100644 src/Cat/Wishlist.agda diff --git a/src/Cat/Categories/Sets.agda b/src/Cat/Categories/Sets.agda index af52c8b..3fa14ce 100644 --- a/src/Cat/Categories/Sets.agda +++ b/src/Cat/Categories/Sets.agda @@ -7,7 +7,6 @@ open import Cat.Prelude as P open import Cat.Category open import Cat.Category.Functor open import Cat.Category.Product -open import Cat.Wishlist open import Cat.Equivalence _⊙_ : {ℓa ℓb ℓc : Level} {A : Set ℓa} {B : Set ℓb} {C : Set ℓc} → (A ≃ B) → (B ≃ C) → A ≃ C diff --git a/src/Cat/Category/NaturalTransformation.agda b/src/Cat/Category/NaturalTransformation.agda index d8b20a8..1a7223d 100644 --- a/src/Cat/Category/NaturalTransformation.agda +++ b/src/Cat/Category/NaturalTransformation.agda @@ -25,7 +25,6 @@ module Nat = Data.Nat open import Cat.Category open import Cat.Category.Functor -open import Cat.Wishlist module Cat.Category.NaturalTransformation {ℓc ℓc' ℓd ℓd' : Level} diff --git a/src/Cat/Prelude.agda b/src/Cat/Prelude.agda index 71e5cbd..6835262 100644 --- a/src/Cat/Prelude.agda +++ b/src/Cat/Prelude.agda @@ -98,4 +98,10 @@ module _ {ℓ : Level} {A : Set ℓ} {a : A} where _ ≡⟨ pathJprop {x = a} (λ y x → A) _ ⟩ a ∎ -open import Cat.Wishlist public +module _ {ℓ : Level} {A : Set ℓ} where + open import Cubical.NType + open import Data.Nat using (_≤′_ ; ≤′-refl ; ≤′-step ; zero ; suc) + open import Cubical.NType.Properties + ntypeCumulative : ∀ {n m} → n ≤′ m → HasLevel ⟨ n ⟩₋₂ A → HasLevel ⟨ m ⟩₋₂ A + ntypeCumulative {m} ≤′-refl lvl = lvl + ntypeCumulative {n} {suc m} (≤′-step le) lvl = HasLevel+1 ⟨ m ⟩₋₂ (ntypeCumulative le lvl) diff --git a/src/Cat/Wishlist.agda b/src/Cat/Wishlist.agda deleted file mode 100644 index 37b8c87..0000000 --- a/src/Cat/Wishlist.agda +++ /dev/null @@ -1,16 +0,0 @@ -{-# OPTIONS --allow-unsolved-metas #-} -module Cat.Wishlist where - -open import Level hiding (suc; zero) -open import Cubical -open import Cubical.NType -open import Data.Nat using (_≤′_ ; ≤′-refl ; ≤′-step ; zero ; suc) -open import Agda.Builtin.Sigma - -open import Cubical.NType.Properties - - -module _ {ℓ : Level} {A : Set ℓ} where - ntypeCumulative : ∀ {n m} → n ≤′ m → HasLevel ⟨ n ⟩₋₂ A → HasLevel ⟨ m ⟩₋₂ A - ntypeCumulative {m} ≤′-refl lvl = lvl - ntypeCumulative {n} {suc m} (≤′-step le) lvl = HasLevel+1 ⟨ m ⟩₋₂ (ntypeCumulative le lvl) From 7faf0961c56f353c7d3bbab730e4e38c1a4e797d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 8 May 2018 00:25:34 +0200 Subject: [PATCH 86/93] Fix spelling mistakes --- doc/appendix.tex | 37 ++++++++ doc/chalmerstitle.sty | 1 + doc/conclusion.tex | 3 + doc/cubical.tex | 12 +-- doc/discussion.tex | 74 ++++++++++++++++ doc/implementation.tex | 187 +++++++++++++++++++++++------------------ doc/introduction.tex | 15 ++-- doc/main.tex | 5 +- doc/packages.tex | 4 + 9 files changed, 243 insertions(+), 95 deletions(-) create mode 100644 doc/appendix.tex create mode 100644 doc/conclusion.tex create mode 100644 doc/discussion.tex diff --git a/doc/appendix.tex b/doc/appendix.tex new file mode 100644 index 0000000..0c3affb --- /dev/null +++ b/doc/appendix.tex @@ -0,0 +1,37 @@ +\lstset{basicstyle=\footnotesize\ttfamily,breaklines=true,breakpages=true} +\def\fileps + { ../src/Cat.agda + , ../src/Cat/Categories/Cat.agda + , ../src/Cat/Categories/Cube.agda + , ../src/Cat/Categories/CwF.agda + , ../src/Cat/Categories/Fam.agda + , ../src/Cat/Categories/Free.agda + , ../src/Cat/Categories/Fun.agda + , ../src/Cat/Categories/Rel.agda + , ../src/Cat/Categories/Sets.agda + , ../src/Cat/Category.agda + , ../src/Cat/Category/CartesianClosed.agda + , ../src/Cat/Category/Exponential.agda + , ../src/Cat/Category/Functor.agda + , ../src/Cat/Category/Monad.agda + , ../src/Cat/Category/Monad/Kleisli.agda + , ../src/Cat/Category/Monad/Monoidal.agda + , ../src/Cat/Category/Monad/Voevodsky.agda + , ../src/Cat/Category/Monoid.agda + , ../src/Cat/Category/NaturalTransformation.agda + , ../src/Cat/Category/Product.agda + , ../src/Cat/Category/Yoneda.agda + , ../src/Cat/Equivalence.agda + , ../src/Cat/Prelude.agda + } + +\foreach \filep in \fileps { +\chapter{\filep} + %% \begin{figure}[htpb] + \lstinputlisting{\filep} + %% \caption{Source code for \texttt{\filep}} + %% \label{fig:\filep} + %% \end{figure} +} +%% \lstset{framextopmargin=50pt} +%% \lstinputlisting{../../src/Cat.agda} diff --git a/doc/chalmerstitle.sty b/doc/chalmerstitle.sty index 70681d9..631eaa8 100644 --- a/doc/chalmerstitle.sty +++ b/doc/chalmerstitle.sty @@ -40,6 +40,7 @@ \newcommand*{\subtitle}[1]{\gdef\@subtitle{#1}} \newgeometry{top=3cm, bottom=3cm,left=2.25 cm, right=2.25cm} \begingroup +\thispagestyle{empty} \usepackage{noto} \fontseries{sb} %% \fontfamily{noto}\selectfont diff --git a/doc/conclusion.tex b/doc/conclusion.tex new file mode 100644 index 0000000..834e579 --- /dev/null +++ b/doc/conclusion.tex @@ -0,0 +1,3 @@ +\chapter{Conclusion} + +\TODO{\ldots} diff --git a/doc/cubical.tex b/doc/cubical.tex index 9442b65..db3ffbb 100644 --- a/doc/cubical.tex +++ b/doc/cubical.tex @@ -56,7 +56,7 @@ the real numbers from $0$ to $1$. $P$ is a family of types over the index set $I$. I will sometimes refer to $P$ as the ``path-space'' of some path $p \tp \Path\ P\ a\ b$. By this token $P\ 0$ then corresponds to the type at the left-endpoint and $P\ 1$ as the type at the right-endpoint. The type is called -$\Path$ because it is connected with paths in homotopy thoery. The intuition +$\Path$ because it is connected with paths in homotopy theory. The intuition behind this is that $\Path$ describes paths in $\MCU$ -- i.e. between types. For a path $p$ for the point $p\ i$ the index $i$ describes how far along the path one has moved. An inhabitant of $\Path\ P\ a_0\ a_1$ is a (dependent-) @@ -155,7 +155,7 @@ there is the notion of sets from set-theory, in Agda types are denoted \texttt{Set}. I will use it consistently to refer to a type $A$ as a set exactly if $\isSet\ A$ is inhabited. -The next step in the hierarchy is, as you might've guessed, the type: +The next step in the hierarchy is, as the reader might've guessed, the type: % \begin{equation} \begin{alignat}{2} @@ -166,7 +166,7 @@ The next step in the hierarchy is, as you might've guessed, the type: % And so it continues. In fact we can generalize this family of types by indexing them with a natural number. For historical reasons, though, the bottom of the -hierarchy, the contractible tyes, is said to be a \nomen{-2-type}, propositions +hierarchy, the contractible types, is said to be a \nomen{-2-type}, propositions are \nomen{-1-types}, (homotopical) sets are \nomen{0-types} and so on\ldots Just as with paths, homotopical sets are not at the center of focus for this @@ -181,12 +181,12 @@ Proposition: For any homotopic level $n$ this is a mere proposition. % \section{A few lemmas} Rather than getting into the nitty-gritty details of Agda I venture to take a -more ``combinators-based'' approach. That is, I will use theorems about paths +more ``combinator-based'' approach. That is, I will use theorems about paths already that have already been formalized. Specifically the results come from the Agda library \texttt{cubical} (\TODO{Cite}). I have used a handful of results from this library as well as contributed a few lemmas myself.\footnote{The module \texttt{Cat.Prelude} lists the upstream dependencies. As well my contribution to \texttt{cubical} can be found in the git logs \TODO{Cite}.} -These theorems are all purely related to homotopy theory and cubical agda and as +These theorems are all purely related to homotopy theory and cubical Agda and as such not specific to the formalization of Category Theory. I will present a few of these theorems here, as they will be used later in chapter \ref{ch:implementation} throughout. @@ -195,7 +195,7 @@ of these theorems here, as they will be used later in chapter \label{sec:pathJ} The induction principle for paths intuitively gives us a way to reason about a type-family indexed by a path by only considering if said path is $\refl$ (the -``base-case''). For \emph{based path induction}, that equaility is \emph{based} +``base-case''). For \emph{based path induction}, that equality is \emph{based} at some element $a \tp A$. Let a type $A \tp \MCU$ and an element of the type $a \tp A$ be given. $a$ is said to be the base of the induction. Given a family of types: diff --git a/doc/discussion.tex b/doc/discussion.tex new file mode 100644 index 0000000..62564e6 --- /dev/null +++ b/doc/discussion.tex @@ -0,0 +1,74 @@ +\chapter{Perspectives} +\section{Discussion} +In the previous chapter the practical aspects of proving things in Cubical Agda +were highlighted. I also demonstrated the usefulness of separating ``laws'' from +``data''. One of the reasons for this is that dependencies within types can lead +to very complicated goals. One technique for alleviating this was to prove that +certain types are mere propositions. + +\subsection{Computational properties} +Another aspect (\TODO{That I actually didn't highlight very well in the previous + chapter}) is the computational nature of paths. Say we have formalized this +common result about monads: + +\TODO{Some equation\ldots} + +By transporting this to the Kleisli formulation we get a result that we can use +to compute with. This is particularly useful because the Kleisli formulation +will be more familiar to programmers e.g. those coming from a background in +Haskell. Whereas the theory usually talks about monoidal monads. + +\TODO{Mention that with postulates we cannot do this} + +\subsection{Reusability of proofs} +The previous example also illustrate how univalence unifies two otherwise +disparate areas: The category-theoretic study of monads; and monads as in +functional programming. Univalence thus allows one to reuse proofs. You could +say that univalence gives the developer two proofs for the price of one. + +The introduction (section \ref{sec:context}) mentioned an often +employed-technique for enabling extensional equalities is to use the +setoid-interpretation. Nowhere in this formalization has this been necessary, +$\Path$ has been used globally in the project as propositional equality. One +interesting place where this becomes apparent is in interfacing with the Agda +standard library. Multiple definitions in the Agda standard library have been +designed with the setoid-interpretation in mind. E.g. the notion of ``unique +existential'' is indexed by a relation that should play the role of +propositional equality. Likewise for equivalence relations, they are indexed, +not only by the actual equivalence relation, but also by another relation that +serve as propositional equality. +%% Unfortunately we cannot use the definition of equivalences found in the +%% standard library to do equational reasoning directly. The reason for this is +%% that the equivalence relation defined there must be a homogenous relation, +%% but paths are heterogeneous relations. + +In the formalization at present a significant amount of energy has been put +towards proving things that would not have been needed in classical Agda. The +proofs that some given type is a proposition were provided as a strategy to +simplify some otherwise very complicated proofs (e.g. +\ref{eq:proof-prop-IsPreCategory} and \label{eq:productPath}). Often these +proofs would not be this complicated. If the J-rule holds definitionally the +proof-assistant can help simplify these goals considerably. The lack of the +J-rule has a significant impact on the complexity of these kinds of proofs. + +\TODO{Universe levels.} + +\section{Future work} +\subsection{Agda \texttt{Prop}} +Jesper Cockx' work extending the universe-level-laws for Agda and the +\texttt{Prop}-type. + +\subsection{Compiling Cubical Agda} +\label{sec:compiling-cubical-agda} +Compilation of program written in Cubical Agda is currently not supported. One +issue here is that the backends does not provide an implementation for the +cubical primitives (such as the path-type). This means that even though the +path-type gives us a computational interpretation of functional extensionality, +univalence, transport, etc., we do not have a way of actually using this to +compile our programs that use these primitives. It would be interesting to see +practical applications of this. The path between monads that this library +exposes could provide one particularly interesting case-study. + +\subsection{Higher inductive types} +This library has not explored the usefulness of higher inductive types in the +context of Category Theory. diff --git a/doc/implementation.tex b/doc/implementation.tex index a73beb7..a5ae42b 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -2,37 +2,52 @@ \label{ch:implementation} This implementation formalizes the following concepts: % -\begin{itemize} -\item Core categorical concepts -\subitem Categories -\subitem Functors -\subitem Products -\subitem Exponentials -\subitem Cartesian closed categories -\subitem Natural transformations -\subitem Yoneda embedding -\subitem Monads -\subsubitem Monoidal monads -\subsubitem Kleisli monads -\subsubitem Voevodsky's construction -\item Category of \ldots -\subitem Homotopy sets -\subitem Categories -- only data-part -\subitem Relations -- only data-part -\subitem Functors -- only as a precategory -\subitem Free category -\end{itemize} +\begin{enumerate}[i.] +\item Categories +\item Functors +\item Products +\item Exponentials +\item Cartesian closed categories +\item Natural transformations +\item Yoneda embedding +\item Monads +\item Categories + \begin{enumerate}[i.] + \item Opposite category + \item Category of sets + \item ``Pair category'' + \end{enumerate} +\end{enumerate} % -Since it is useful to distinguish between types with more or less (homotopical) -structure I have followed the following design-principle: I have split concepts -up into things that represent ``data'' and ``laws'' about this data. The idea is -that we can provide a proof that the laws are mere propositions. As an example a -category is defined to have two members: `raw` which is a collection of the data -and `isCategory` which asserts some laws about that data. +Furthermore the following items have been partly formalized: +% +\begin{enumerate}[i.] +\item The (higher) category of categories. +\item Category of relations +\item Category of functors and natural transformations -- only as a precategory +\item Free category +\item Monoidal objects +\item Monoidal categories +\end{enumerate} +% +As well as a range of various results about these. E.g. I have shown that the +category of sets has products. In the following I aim to demonstrate some of the +techniques employed in this formalization and in the interest of brevity I will +not detail all the things I have formalized. In stead, I have selected a parts +of this formalization that highlight some interesting proof techniques relevant +to doing proofs in Cubical Agda. + +One such technique that is pervasive to this formalization is the idea of +distinguishing types with more or less homotopical structure. To do this I have +followed the following design-principle: I have split concepts up into things +that represent ``data'' and ``laws'' about this data. The idea is that we can +provide a proof that the laws are mere propositions. As an example a category is +defined to have two members: `raw` which is a collection of the data and +`isCategory` which asserts some laws about that data. This allows me to reason about things in a more ``standard mathematical way'', where one can reason about two categories by simply focusing on the data. This -is acheived by creating a function embodying the ``equality principle'' for a +is achieved by creating a function embodying the ``equality principle'' for a given type. \section{Categories} @@ -45,7 +60,7 @@ on the topic. We, however, impose one further requirement on what it means to be a category, namely that the type of arrows form a set. Such categories are called \nomen{1-categories}. It's possible to relax this -requirement. This would lead to the notion of higher categorier (\cite[p. +requirement. This would lead to the notion of higher categories (\cite[p. 307]{hott-2013}). For the purpose of this project, however, this report will restrict itself to 1-categories. Making based on higher categories would be a very natural possible extension of this work. @@ -63,7 +78,7 @@ definitions: If we let $p$ be a witness to the identity law, which formally is: \end{equation} % Then we can construct the identity isomorphism $\var{idIso} \tp \identity, -\identity, p \tp A \approxeq A$ for any obejct $A$. Here $\approxeq$ denotes +\identity, p \tp A \approxeq A$ for any object $A$. Here $\approxeq$ denotes isomorphism on objects (whereas $\cong$ denotes isomorphism of types). This will be elaborated further on in sections \ref{sec:equiv} and \ref{sec:univalence}. Moreover, due to substitution for paths we can construct an isomorphism from @@ -121,7 +136,7 @@ f \lll \identity ≡ f \end{align} % $\lll$ denotes arrow composition (right-to-left), and reverse function -composition (left-to-right, diagramatic order) is denoted $\rrr$. The objects +composition (left-to-right, diagrammatic order) is denoted $\rrr$. The objects ($A$, $B$ and $C$) and arrow ($f$, $g$, $h$) are implicitly universally quantified. @@ -160,25 +175,32 @@ us the two obligations: $\isProp\ (\id \comp f \equiv f)$ and $\isProp\ (f \comp set. This example illustrates nicely how we can use these combinators to reason about -`canonical' types like $\sum$ and $\prod$. Similiar combinators can be defined +`canonical' types like $\sum$ and $\prod$. Similar combinators can be defined at the other homotopic levels. These combinators are however not applicable in situations where we want to reason about other types - e.g. types we've defined ourselves. For instance, after we've proven that all the projections of pre-categories are propositions, then we would like to bundle this up to show -that the type of pre-categories is also a proposition. Since pre-categories are -not formulated with a chain of sigma-types we wont have any combinators -available to help us here. In stead we'll have to use the path-type directly. - -What we want to prove is: +that the type of pre-categories is also a proposition. Formally: % \begin{equation} \label{eq:propIsPreCategory} \isProp\ \IsPreCategory \end{equation} % -%% \begin{proof} +Where The definition of $\IsPreCategory$ is the triple: % -This is judgmentally the same as +\begin{align*} +\var{isAssociative} & \tp \var{IsAssociative}\\ +\var{isIdentity} & \tp \var{IsIdentity}\\ +\var{arrowsAreSets} & \tp \var{ArrowsAreSets} +\end{align*} +% +Each corresponding to the first three laws for categories. Note that since +$\IsPreCategory$ is not formulated with a chain of sigma-types we wont have any +combinators available to help us here. In stead we'll have to use the path-type +directly. + +\ref{eq:propIsPreCategory} is judgmentally the same as % $$ \prod_{a\ b \tp \IsPreCategory} a \equiv b @@ -202,12 +224,13 @@ So to give the continuous function $I \to \IsPreCategory$, which is our goal, we introduce $i \tp I$ and proceed by constructing an element of $\IsPreCategory$ by using the fact that all the projections are propositions to generate paths between all projections. Once we have such a path e.g. $p \tp a.\isIdentity -\equiv b.\isIdentity$ we can elimiate it with $i$ and thus obtain $p\ i \tp +\equiv b.\isIdentity$ we can eliminate it with $i$ and thus obtain $p\ i \tp (p\ i).\isIdentity$. This element satisfies exactly that it corresponds to the corresponding projections at either endpoint. Thus the element we construct at $i$ becomes the triple: % \begin{equation} +\label{eq:proof-prop-IsPreCategory} \begin{aligned} & \var{propIsAssociative} && a.\var{isAssociative}\ && b.\var{isAssociative} && i \\ @@ -224,7 +247,7 @@ It is worth noting that proving this theorem with the regular inductive equality type would already not be possible, since we at least need extensionality (the projections are all $\prod$-types). Assuming we had functional extensionality available to us as an axiom, we would use functional extensionality (in -reverse?) to retreive the equalities in $a$ and $b$, pattern-match on them to +reverse?) to retrieve the equalities in $a$ and $b$, pattern-match on them to see that they are both $\var{refl}$ and then close the proof with $\var{refl}$. Of course this theorem is not so interesting in the setting of ITT since we know a priori that equality proofs are unique. @@ -234,7 +257,7 @@ instance, when we want to show that $\IsCategory$ is a mere proposition. $\IsCategory$ is a record with two fields, a witness to being a pre-category and the univalence condition. Recall that the univalence condition is indexed by the identity-proof. So to follow the same recipe as above, let $a\ b \tp -\IsCategory$ be given, to show them equal, we now need to give two paths. One homogenous: +\IsCategory$ be given, to show them equal, we now need to give two paths. One homogeneous: % $$ p \tp a.\isPreCategory \equiv b.\isPreCategory @@ -249,9 +272,9 @@ $$ Which depends on the choice of $p$. The first of these we can provide since, as we have shown, $\IsPreCategory$ is a proposition. However, even though $\Univalent$ is also a proposition, we cannot use this directly to show the -latter. This is becasue $\isProp$ talks about non-dependent paths. So we need to +latter. This is because $\isProp$ talks about non-dependent paths. So we need to 'promote' the result that univalence is a proposition to a heterogeneous path. -To this end we can use $\lemPropF$, which wasintroduced in \ref{sec:lemPropF}. +To this end we can use $\lemPropF$, which was introduced in \ref{sec:lemPropF}. In this case $A = \var{IsIdentity}\ \identity$ and $B = \var{Univalent}$. We've shown that being a category is a proposition, a result that holds for any choice @@ -267,7 +290,7 @@ And this finishes the proof that being-a-category is a mere proposition (\ref{eq:propIsPreCategory}). When we have a proper category we can make precise the notion of ``identifying -isomorphic types'' \TODO{cite awodey here}. That is, we can construct the +isomorphic types'' \TODO{cite Awodey here}. That is, we can construct the function: % $$ @@ -322,7 +345,7 @@ The maps $\var{fromIso}$ and $\var{toIso}$ naturally extend to these maps: \end{align} % Having this interface gives us both: a way to think rather abstractly about how -to work with equivalences and a way to use ad-hoc definitions of equivalences. +to work with equivalences and a way to use ad hoc definitions of equivalences. The specific instantiation of $\isEquiv$ as defined in \cite{cubical-agda} is: % $$ @@ -394,7 +417,7 @@ univalence of all pre-category since morphisms in a category are not regular functions -- in stead they can be thought of as a generalization hereof. The univalence criterion therefore is simply a way of restricting arrows to behave similarly to maps. -I will now mention a few helpful thoerems that follow from univalence that will +I will now mention a few helpful theorems that follow from univalence that will become useful later. Obviously univalence gives us an isomorphism between $A \equiv B$ and $A @@ -427,7 +450,7 @@ then have the following two theorems: \var{coe}\ p_{\var{cod}}\ f \equiv \iota \lll f \end{align} % -I will give the proof of the first theorem here, the second one is analagous. +I will give the proof of the first theorem here, the second one is analogous. % \begin{align*} \var{coe}\ p_{\var{dom}}\ f @@ -467,11 +490,11 @@ The base-case therefore becomes: & \equiv f \lll \inv{(\var{idToIso}\ \widetilde{\refl})} \end{align*} % -The first step follows because reflixivity is a neutral element for coercions. +The first step follows because reflexivity is a neutral element for coercion. The second step is the identity law in the category. The last step has to do with the fact that $\var{idToIso}$ is constructed by substituting according to the supplied path and since reflexivity is also the neutral element for -substuitutions we arrive at the desired expression. To close the +substitutions we arrive at the desired expression. To close the based-path-induction we must supply the value ``at the other''. In this case this is simply $B \tp \Object$ and $p \tp A \equiv B$ which we have. @@ -552,7 +575,7 @@ follows: && \text{$\var{shuffle}$ is an isomorphism} \\ & \equiv \identity -&& \text{$\isoToId$ is an ismorphism} +&& \text{$\isoToId$ is an isomorphism} \end{align*} % The other direction is analogous. @@ -639,7 +662,7 @@ lemma: \end{align} % Which says that if two type-families are equivalent at all points, then pairs -with identitical first components and these families as second components will +with identical first components and these families as second components will also be equivalent. For our purposes $P \defeq \isEquiv\ A\ B$ and $Q \defeq \var{Isomorphism}$. So we must finally prove: % @@ -648,7 +671,7 @@ also be equivalent. For our purposes $P \defeq \isEquiv\ A\ B$ and $Q \defeq \prod_{f \tp A \to B} \left( \isEquiv\ A\ B\ f \simeq \var{Isomorphism}\ f \right) \end{align} -First, lets proove \ref{eq:equivPropSig}: Let $propP \tp \prod_{a \tp A} \isProp (P\ a)$ and $x\;y \tp \sum_{a \tp A} P\ a$ be given. Because +First, lets prove \ref{eq:equivPropSig}: Let $propP \tp \prod_{a \tp A} \isProp (P\ a)$ and $x\;y \tp \sum_{a \tp A} P\ a$ be given. Because of $\var{fromIsomorphism}$ it suffices to give an isomorphism between $x \equiv y$ and $\fst\ x \equiv \fst\ y$: % @@ -674,7 +697,7 @@ the two pairs: \end{align*} % The proof that these are indeed inverses has been omitted. \TODO{Do I really - want to ommit it?}\QED + want to omit it?}\QED Now to prove \ref{eq:equivSig}: Let $e \tp \prod_{a \tp A} \left( P\ a \simeq Q\ a \right)$ be given. To prove the equivalence, it suffices to give an @@ -839,14 +862,13 @@ arrows form a set. For instance, to prove associativity we must prove that (\overline{h} \lll \overline{g}) \lll \overline{f} \end{align} % -Herer $\lll$ refers to the `embellished' composition and $\overline{f}$, +Here $\lll$ refers to the `embellished' composition and $\overline{f}$, $\overline{g}$ and $\overline{h}$ are triples consisting of arrows from the underlying category ($f$, $g$ and $h$) and a pair of witnesses to \ref{eq:pairArrowLaw}. %% Luckily those winesses are paths in the hom-set of the %% underlying category which is a set, so these are mere propositions. -The proof -obligations is: +The proof obligations is consists of two things. The first one is: % \begin{align} \label{eq:productAssocUnderlying} @@ -855,15 +877,18 @@ h \lll (g \lll f) (h \lll g) \lll f \end{align} % -Which is provable by \TODO{What?} and that the witness to \ref{eq:pairArrowLaw} -for the left-hand-side and the right-hand-side are the same. The type of this -goal is quite involved, and I will not write it out in full, but at present it -suffices to show the type of the path-space. Note that the arrows in -\ref{eq:productAssoc} are arrows from $\mathcal{A} = (A , a_{\pairA} , a_{\pairB})$ -to $\mathcal{D} = (D , d_{\pairA} , d_{\pairB})$ where $a_{\pairA}$, $a_{\pairB}$, -$d_{\pairA}$ and $d_{\pairB}$ are arrows in the underlying category. Given that $p$ -is the chosen proof of \ref{eq:productAssocUnderlying} we then have that the -witness to \ref{eq:pairArrowLaw} vary over the type: +And the other proof obligation is that the witness to \ref{eq:pairArrowLaw} for +the left-hand-side and the right-hand-side are the same. + +The proof of the first goal comes directly from the underlying category. The +type of the second goal is very complicated. I will not write it out in full +here, but it suffices to show the type of the path-space. Note that the arrows +in \ref{eq:productAssoc} are arrows from $\mathcal{A} = (A , a_{\pairA} , +a_{\pairB})$ to $\mathcal{D} = (D , d_{\pairA} , d_{\pairB})$ where +$a_{\pairA}$, $a_{\pairB}$, $d_{\pairA}$ and $d_{\pairB}$ are arrows in the +underlying category. Given that $p$ is the chosen proof of +\ref{eq:productAssocUnderlying} we then have that the witness to +\ref{eq:pairArrowLaw} vary over the type: % \begin{align} \label{eq:productPath} @@ -979,7 +1004,7 @@ the implementation for the details). \TODO{Super complicated} \emph{Proposition} \ref{eq:univ-2} is isomorphic to \ref{eq:univ-3}: For this I -will swho two corrolaries of \ref{eq:coeCod}: For an isomorphism $(\iota, +will show two corollaries of \ref{eq:coeCod}: For an isomorphism $(\iota, \inv{\iota}, \var{inv}) \tp A \cong B$, arrows $f \tp \Arrow\ A\ X$, $g \tp \Arrow\ B\ X$ and a heterogeneous path between them, $q \tp \Path\ (\lambda i \to p_{\var{dom}}\ i)\ f\ g$, where $p_{\var{dom}} \tp \Arrow\ A\ X \equiv @@ -995,7 +1020,7 @@ g & \equiv f \lll \inv{\iota} % Proof: \TODO{\ldots} -Now we can prove the equiavalence in the following way: Given $(f, \inv{f}, +Now we can prove the equivalence in the following way: Given $(f, \inv{f}, \var{inv}_f) \tp X \cong Y$ and two heterogeneous paths % \begin{align*} @@ -1025,7 +1050,7 @@ Which, since $f$ is an isomorphism and $p_{\mathcal{A}}$ (resp. $p_{\mathcal{B}} is a path varying according to a path constructed from this isomorphism, this is exactly what \ref{eq:domain-twist-0} gives us. % -The other direction is quite analagous. We choose $\inv{f}$ as the morphism and +The other direction is quite analogous. We choose $\inv{f}$ as the morphism and prove that it satisfies \ref{eq:pairArrowLaw} with \ref{eq:domain-twist-1}. We must now show that this choice of arrows indeed form an isomorphism. Our @@ -1099,7 +1124,7 @@ The proof of the first one is: We have now constructed the maps between \ref{eq:univ-0} and \ref{eq:univ-1}. It remains to show that they are inverses of each other. To cut a long story short, the proof uses the fact that isomorphism-of is propositional and that arrows (in -both categories) are sets. The reader is refered to the implementation for the +both categories) are sets. The reader is referred to the implementation for the gory details. % \subsection{Propositionality of products} @@ -1137,7 +1162,7 @@ conditions will be equal since $f$ is unique. For the other direction we are now given a product $X, x_𝒜, x_ℬ$. Again this will be the terminal object. So now it remains that for any other object there -is aunique arrow from that object into $X, x_𝒜, x_ℬ$. Let $Y, y_𝒜, y_ℬ$ be +is a unique arrow from that object into $X, x_𝒜, x_ℬ$. Let $Y, y_𝒜, y_ℬ$ be another object. As the arrow $\Arrow\ Y\ X$ we choose the product-arrow $y_𝒜 \x y_ℬ$. Since this is a product-arrow it satisfies \ref{eq:pairCondRev}. Let us name the witness to this $\phi_{y_𝒜 \x y_ℬ}$. So we have picked as our center of @@ -1184,12 +1209,14 @@ That in any category: \end{align} % \section{Monads} -In this section I show two formulations of monads and then show that they are -the same. The two representations are referred to as the monoidal- and kleisli- -representation respectively. +In this section I present two formulations of monads. The two representations +are referred to as the monoidal- and Kleisli- representation respectively or +simply monoidal monads and Kleisli monads for short. We then show that the two +formulations are equivalent, which due to univalence gives us a path between the +two types. -We shall let a category $\bC$ be given. In the remainder all objects and arrows -will implicitly refer to objects and arrows in this category. +Let a category $\bC$ be given. In the remainder of this sections all objects and +arrows will implicitly refer to objects and arrows in this category. % \subsection{Monoidal formulation} The monoidal formulation of monads consists of the following data: @@ -1226,7 +1253,7 @@ they range over are universally quantified. \subsection{Kleisli formulation} % -The kleisli-formulation consists of the following data: +The Kleisli-formulation consists of the following data: % \begin{align} \label{eq:monad-kleisli-data} @@ -1262,18 +1289,18 @@ This data must satisfy: % Here likewise the arrows $f \tp \Arrow\ X\ (\EndoR\ Y)$ and $g \tp \Arrow\ Y\ (\EndoR\ Z)$ are universally quantified (as well as the objects they -range over). $\fish$ is the kleisli-arrow which is defined as $f \fish g \defeq +range over). $\fish$ is the Kleisli-arrow which is defined as $f \fish g \defeq f \rrr (\bind\ g)$ . (\TODO{Better way to typeset $\fish$?}) \subsection{Equivalence of formulations} % -In my implementation I proceede to show how the one formulation gives rise to +In my implementation I proceed to show how the one formulation gives rise to the other and vice-versa. For the present purpose I will briefly sketch some parts of this construction: The notation I have chosen here in the report overloads e.g. $\pure$ to both refer to a natural transformation and an arrow. -This is of course not a coincidence as the arrow in the kleisli formulation +This is of course not a coincidence as the arrow in the Kleisli formulation shall correspond exactly to the map on arrows from the natural transformation called $\pure$. @@ -1283,7 +1310,7 @@ In the monoidal formulation we can define $\bind$: \bind \defeq \join \lll \fmap\ f \end{align} % -And likewise in the kleisli formulation we can define $\join$: +And likewise in the Kleisli formulation we can define $\join$: % \begin{align} \join \defeq \bind\ \identity diff --git a/doc/introduction.tex b/doc/introduction.tex index 99761fb..7a5d1a0 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -1,7 +1,7 @@ \chapter{Introduction} Functional extensionality and univalence is not expressible in \nomen{Intensional Martin Löf Type Theory} (ITT). This poses a severe limitation -on both i. what is \emph{provable} and ii. the \emph{reusability} of proofs. +on both i. what is \emph{provable} and ii. the \emph{re-usability} of proofs. Recent developments have, however, resulted in \nomen{Cubical Type Theory} (CTT) which permits a constructive proof of these two important notions. @@ -54,7 +54,7 @@ not true.} There is no way to construct a proof asserting the obvious equivalence of $f$ and $g$ -- even though we can prove them equal for all points. This is exactly the notion of equality of functions that we are interested in; that they are equal for all inputs. We call this -\nomen{pointwise equality}, where the \emph{points} of a function refers +\nomen{point-wise equality}, where the \emph{points} of a function refers to it's arguments. In the context of category theory functional extensionality is e.g. needed to @@ -73,7 +73,7 @@ The proof obligation that this satisfies the identity law of functors \end{align*} % One needs functional extensionality to ``go under'' the function arrow and apply -the (left) identity law of the underlying category to proove $\idFun \comp g +the (left) identity law of the underlying category to prove $\idFun \comp g \equiv g$ and thus close the goal. % \subsection{Equality of isomorphic types} @@ -81,7 +81,7 @@ the (left) identity law of the underlying category to proove $\idFun \comp g Let $\top$ denote the unit type -- a type with a single constructor. In the propositions-as-types interpretation of type theory $\top$ is the proposition that is always true. The type $A \x \top$ and $A$ has an element for each $a : -A$. So in a sense they have the same shape (greek; \nomen{isomorphic}). The +A$. So in a sense they have the same shape (Greek; \nomen{isomorphic}). The second element of the pair does not add any ``interesting information''. It can be useful to identify such types. In fact, it is quite commonplace in mathematics. Say we look at a set $\{x \mid \phi\ x \land \psi\ x\}$ and somehow @@ -114,6 +114,7 @@ formulate this requirement within our formulation of categories by requiring the \emph{categories} themselves to be univalent as we shall see. \section{Context} +\label{sec:context} % The idea of formalizing Category Theory in proof assistants is not new. There are a multitude of these available online. Just as a first reference see this @@ -131,7 +132,7 @@ implementations of category theory in Agda: A formalization in Agda with univalence and functional extensionality as postulates. \item - \url{https://github.com/pcapriotti/agda-categories} + \url{https://github.com/HoTT/HoTT/tree/master/theories/Categories} A formalization in Coq in the homotopic setting \item @@ -160,11 +161,11 @@ canonical form. Another approach is to use the \emph{setoid interpretation} of type theory (\cite{hofmann-1995,huber-2016}). With this approach one works with -\nomen{extensionals sets} $(X, \sim)$, that is a type $X \tp \MCU$ and an +\nomen{extensional sets} $(X, \sim)$, that is a type $X \tp \MCU$ and an equivalence relation $\sim \tp X \to X \to \MCU$ on that type. Under the setoid interpretation the equivalence relation serve as a sort of ``local'' propositional equality. This approach has other drawbacks; it does not satisfy -all propositional equalites of type theory (\TODO{Citation needed}), is +all propositional equalities of type theory (\TODO{Citation needed}), is cumbersome to work with in practice (\cite[p. 4]{huber-2016}) and makes equational proofs less reusable since equational proofs $a \sim_{X} b$ are inherently `local' to the extensional set $(X , \sim)$. diff --git a/doc/main.tex b/doc/main.tex index a894748..bdf4b49 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -43,7 +43,6 @@ \researchgroup{Programming Logic Group} \bibliographystyle{plain} -\addtocontents{toc}{\protect\thispagestyle{empty}} %% \newtheorem{prop}{Proposition} \makeatletter \newcommand*{\rom}[1]{\expandafter\@slowroman\romannumeral #1@} @@ -52,13 +51,15 @@ \pagenumbering{roman} \maketitle - +\addtocontents{toc}{\protect\thispagestyle{empty}} \tableofcontents \pagenumbering{arabic} % \input{introduction.tex} \input{cubical.tex} \input{implementation.tex} +\input{discussion.tex} +\input{conclusion.tex} \nocite{cubical-demo} \nocite{coquand-2013} diff --git a/doc/packages.tex b/doc/packages.tex index f786c61..120699d 100644 --- a/doc/packages.tex +++ b/doc/packages.tex @@ -36,6 +36,8 @@ \usepackage{lmodern} +\usepackage{enumerate} + \usepackage{fontspec} \usepackage[light]{sourcecodepro} %% \setmonofont{Latin Modern Mono} @@ -52,3 +54,5 @@ \usepackage{unicode-math} %% \RequirePackage{kvoptions} + +\usepackage{pgffor} From e18730e0e5645fc1b52ed6cc22c6443aa35e3602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 8 May 2018 02:00:23 +0200 Subject: [PATCH 87/93] Remove tex warnings --- doc/chalmerstitle.sty | 12 +++++------- doc/cubical.tex | 24 ++++++++++++++---------- doc/introduction.tex | 2 +- doc/main.tex | 3 ++- doc/packages.tex | 2 +- 5 files changed, 23 insertions(+), 20 deletions(-) diff --git a/doc/chalmerstitle.sty b/doc/chalmerstitle.sty index 631eaa8..a31e8a2 100644 --- a/doc/chalmerstitle.sty +++ b/doc/chalmerstitle.sty @@ -38,12 +38,11 @@ \newcommand*{\department}[1]{\gdef\@department{#1}} \newcommand*{\researchgroup}[1]{\gdef\@researchgroup{#1}} \newcommand*{\subtitle}[1]{\gdef\@subtitle{#1}} +%% FRONTMATTER +\newcommand*{\myfrontmatter}{% \newgeometry{top=3cm, bottom=3cm,left=2.25 cm, right=2.25cm} \begingroup \thispagestyle{empty} -\usepackage{noto} -\fontseries{sb} -%% \fontfamily{noto}\selectfont {\Huge\@title}\\[.5cm] {\Large A formalization of category theory in Cubical Agda}\\[2.5cm] \begin{center} @@ -55,17 +54,16 @@ {\Large\@author}\\[.5cm] Master's thesis in Computer Science \endgroup -%% \renewcommand{\familydefault}{\rmdefault} \normalfont % Reset standard font %% \end{titlepage} % BACK OF COVER PAGE (BLANK PAGE) \newpage -\newgeometry{a4paper} % Temporarily change margins -\restoregeometry +%% \newgeometry{a4paper} % Temporarily change margins +%% \restoregeometry \thispagestyle{empty} \null - +} \renewcommand*{\maketitle}{% \begin{titlepage} diff --git a/doc/cubical.tex b/doc/cubical.tex index db3ffbb..96a67ef 100644 --- a/doc/cubical.tex +++ b/doc/cubical.tex @@ -89,10 +89,12 @@ interest. With this definition we can also recover reflexivity. That is, for any $A \tp \MCU$ and $a \tp A$: % -\begin{align} +\begin{equation} +\begin{aligned} \refl & \tp \Path (\lambda i \to A)\ a\ a \\ \refl & \defeq \lambda i \to a -\end{align} +\end{aligned} +\end{equation} % Or, in other terms; reflexivity is the path in $A$ that is $a$ at the left endpoint as well as at the right endpoint. It is inhabited by the path which @@ -113,10 +115,12 @@ structure''. At the bottom of this hierarchy we have the set of contractible types: % \begin{equation} -\begin{alignat}{2} +\begin{aligned} +%% \begin{split} & \isContr && \tp \MCU \to \MCU \\ & \isContr\ A && \defeq \sum_{c \tp A} \prod_{a \tp A} a \equiv c -\end{alignedat} +%% \end{split} +\end{aligned} \end{equation} % The first component of $\isContr\ A$ is called ``the center of contraction''. @@ -127,10 +131,10 @@ contractible, then it is isomorphic to the unit-type $\top$. The next step in the hierarchy is the set of mere propositions: % \begin{equation} -\begin{alignat}{2} +\begin{aligned} & \isProp && \tp \MCU \to \MCU \\ & \isProp\ A && \defeq \prod_{a_0, a_1 \tp A} a_0 \equiv a_1 -\end{alignedat} +\end{aligned} \end{equation} % $\isProp\ A$ can be thought of as the set of true and false propositions. It is @@ -144,10 +148,10 @@ stress that we have $\isProp\ A$. Then comes the set of homotopical sets: % \begin{equation} -\begin{alignat}{2} +\begin{aligned} & \isSet && \tp \MCU \to \MCU \\ & \isSet\ A && \defeq \prod_{a_0, a_1 \tp A} \isProp\ (a_0 \equiv a_1) -\end{alignedat} +\end{aligned} \end{equation} % At this point it should be noted that the term ``set'' is somewhat conflated; @@ -158,10 +162,10 @@ if $\isSet\ A$ is inhabited. The next step in the hierarchy is, as the reader might've guessed, the type: % \begin{equation} -\begin{alignat}{2} +\begin{aligned} & \isGroupoid && \tp \MCU \to \MCU \\ & \isGroupoid\ A && \defeq \prod_{a_0, a_1 \tp A} \isSet\ (a_0 \equiv a_1) -\end{alignedat} +\end{aligned} \end{equation} % And so it continues. In fact we can generalize this family of types by indexing diff --git a/doc/introduction.tex b/doc/introduction.tex index 7a5d1a0..231097c 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -195,7 +195,7 @@ Name & Agda & Notation \\ \nomen{Type} & \texttt{Set} & $\Type$ \\ \nomen{Set} & \texttt{Σ Set IsSet} & $\Set$ \\ Function, morphism, map & \texttt{A → B} & $A → B$ \\ -Dependent- ditto & \texttt{(a : A) → B} & $∏_{a \tp A} → B$ \\ +Dependent- ditto & \texttt{(a : A) → B} & $∏_{a \tp A} B$ \\ \nomen{Arrow} & \texttt{Arrow A B} & $\Arrow\ A\ B$ \\ \nomen{Object} & \texttt{C.Object} & $̱ℂ.Object$ \\ Definition & \texttt{=} & $̱\defeq$ \\ diff --git a/doc/main.tex b/doc/main.tex index bdf4b49..a74978c 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -25,6 +25,7 @@ %% department=Department of Computer Science and Engineering, %% researchgroup=Programming Logic Group %% ]{chalmerstitle} + \usepackage{chalmerstitle} \subtitle{A formalization of category theory in Cubical Agda} \authoremail{hanghj@student.chalmers.se} @@ -48,7 +49,7 @@ \newcommand*{\rom}[1]{\expandafter\@slowroman\romannumeral #1@} \makeatother \begin{document} - +\myfrontmatter \pagenumbering{roman} \maketitle \addtocontents{toc}{\protect\thispagestyle{empty}} diff --git a/doc/packages.tex b/doc/packages.tex index 120699d..f592a65 100644 --- a/doc/packages.tex +++ b/doc/packages.tex @@ -45,7 +45,7 @@ %% \setmonofont{FreeMono.otf} -\pagestyle{fancyplain} +%% \pagestyle{fancyplain} \setlength{\headheight}{15pt} \renewcommand{\chaptermark}[1]{\markboth{\textsc{Chapter \thechapter. #1}}{}} \renewcommand{\sectionmark}[1]{\markright{\textsc{\thesection\ #1}}} From 6a3e7390d7a4ff26bb856d67a8167b7d9e17f649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 8 May 2018 02:01:17 +0200 Subject: [PATCH 88/93] Do not use colon directly for typing judgments --- doc/cubical.tex | 4 ++-- doc/implementation.tex | 2 +- doc/introduction.tex | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/cubical.tex b/doc/cubical.tex index 96a67ef..d25054d 100644 --- a/doc/cubical.tex +++ b/doc/cubical.tex @@ -47,7 +47,7 @@ heterogeneous paths respectively. In Cubical Agda judgmental equality is encapsulated with the type: % $$ -\Path \tp (P : I → \MCU) → P\ 0 → P\ 1 → \MCU +\Path \tp (P \tp I → \MCU) → P\ 0 → P\ 1 → \MCU $$ % $I$ is a special data-type (\TODO{that also has special computational properties @@ -244,7 +244,7 @@ $\lemPropF$ can be used to boil this complexity down to showing that the dependent parts of the type are mere propositions. For instance, saw we have a type: % $$ -T \defeq \sum_{a : A} P\ a +T \defeq \sum_{a \tp A} P\ a $$ % For some proposition $P \tp A \to \MCU$. If we want to prove $t_0 \equiv t_1$ diff --git a/doc/implementation.tex b/doc/implementation.tex index a5ae42b..c5f01f7 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -85,7 +85,7 @@ Moreover, due to substitution for paths we can construct an isomorphism from \emph{any} path: % \begin{equation} -\var{idToIso} : A ≡ B → A ≊ B +\var{idToIso} \tp A ≡ B → A ≊ B \end{equation} % The univalence criterion for categories states that this map must be an diff --git a/doc/introduction.tex b/doc/introduction.tex index 231097c..a8c19b5 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -21,10 +21,10 @@ Consider the functions: \begin{multicols}{2} \noindent \begin{equation*} - f \defeq (n : \bN) \mapsto (0 + n : \bN) + f \defeq (n \tp \bN) \mapsto (0 + n \tp \bN) \end{equation*} \begin{equation*} - g \defeq (n : \bN) \mapsto (n + 0 : \bN) + g \defeq (n \tp \bN) \mapsto (n + 0 \tp \bN) \end{equation*} \end{multicols} % @@ -35,7 +35,7 @@ which is: % \newcommand{\suc}[1]{\mathit{suc}\ #1} \begin{align*} - + & : \bN \to \bN \to \bN \\ + + & \tp \bN \to \bN \to \bN \\ n + 0 & \defeq n \\ n + (\suc{m}) & \defeq \suc{(n + m)} \end{align*} @@ -154,7 +154,7 @@ still have univalence and functional extensionality. One option is to postulate these as axioms. This approach, however, has other shortcomings, e.g.; you lose \nomen{canonicity} (\TODO{Pageno!} \cite{huber-2016}). Canonicity means that any well-typed term evaluates to a \emph{canonical} form. For example for a closed -term $e : \bN$ it will be the case that $e$ reduces to $n$ applications of +term $e \tp \bN$ it will be the case that $e$ reduces to $n$ applications of $\mathit{suc}$ to $0$ for some $n$; $e = \mathit{suc}^n\ 0$. Without canonicity terms in the language can get ``stuck'' -- meaning that they do not reduce to a canonical form. @@ -195,7 +195,7 @@ Name & Agda & Notation \\ \nomen{Type} & \texttt{Set} & $\Type$ \\ \nomen{Set} & \texttt{Σ Set IsSet} & $\Set$ \\ Function, morphism, map & \texttt{A → B} & $A → B$ \\ -Dependent- ditto & \texttt{(a : A) → B} & $∏_{a \tp A} B$ \\ +Dependent- ditto & \texttt{(a \tp A) → B} & $∏_{a \tp A} B$ \\ \nomen{Arrow} & \texttt{Arrow A B} & $\Arrow\ A\ B$ \\ \nomen{Object} & \texttt{C.Object} & $̱ℂ.Object$ \\ Definition & \texttt{=} & $̱\defeq$ \\ From 10c3c36305aa07872c2f18a3efb971651a215002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 8 May 2018 02:02:13 +0200 Subject: [PATCH 89/93] Fix typos --- CHANGELOG.md | 10 +++++----- src/Cat/Categories/Free.agda | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42ab3e0..6bd4bc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -Changelog +Change log ========= Version 1.4.1 @@ -29,12 +29,12 @@ Adds an "equality principle" for categories and monads. Prove that `IsMonad` is a mere proposition. Provides the yoneda embedding without relying on the existence of a category of -categories. This is acheived by providing some of the data needed to make a ccc +categories. This is achieved by providing some of the data needed to make a ccc out of the category of categories without actually having such a category. Renames functors object map and arrow map to `omap` and `fmap`. -Prove that kleisli- and monoidal- monads are equivalent! +Prove that Kleisli- and monoidal- monads are equivalent! [WIP] Started working on the proofs for univalence for the category of sets and the category of functors. @@ -42,7 +42,7 @@ the category of functors. Version 1.3.0 ------------- Removed unused modules and streamlined things more: All specific categories are -in the namespace `Cat.Categories`. +in the name space `Cat.Categories`. Lemmas about categories are now in the appropriate record e.g. `IsCategory`. Also changed how category reexports stuff. @@ -53,7 +53,7 @@ Rename Opposite to opposite Add documentation in Category-module -Formulation of monads in two ways; the "monoidal-" and "kleisli-" form. +Formulation of monads in two ways; the "monoidal-" and "Kleisli-" form. WIP: Equivalence of these two formulations diff --git a/src/Cat/Categories/Free.agda b/src/Cat/Categories/Free.agda index 8fe148a..b55face 100644 --- a/src/Cat/Categories/Free.agda +++ b/src/Cat/Categories/Free.agda @@ -1,4 +1,4 @@ -{-# OPTIONS --allow-unsolved-metas #-} +{-# OPTIONS --allow-unsolved-metas --cubical #-} module Cat.Categories.Free where open import Cat.Prelude hiding (Path ; empty) From 4e7506f06ae31e905075b5fa545a4bb25fe620f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 8 May 2018 14:50:45 +0200 Subject: [PATCH 90/93] Decrease line-width --- src/Cat/Category.agda | 56 ++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 95db7ee..1561aab 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -658,14 +658,9 @@ module Opposite {ℓa ℓb : Level} where open IsPreCategory isPreCategory module _ {A B : ℂ.Object} where - k : TypeIsomorphism (ℂ.idToIso A B) - k = toIso _ _ ℂ.univalent - open Σ k renaming (fst to η ; snd to inv-η) - open AreInverses {f = ℂ.idToIso A B} {η} inv-η - - genericly : {ℓa ℓb ℓc : Level} {a : Set ℓa} {b : Set ℓb} {c : Set ℓc} - → a × b × c → b × a × c - genericly (a , b , c) = (b , a , c) + open Σ (toIso _ _ (ℂ.univalent {A} {B})) + renaming (fst to idToIso* ; snd to inv*) + open AreInverses {f = ℂ.idToIso A B} {idToIso*} inv* shuffle : A ≊ B → A ℂ.≊ B shuffle (f , g , inv) = g , f , inv @@ -673,37 +668,38 @@ module Opposite {ℓa ℓb : Level} where shuffle~ : A ℂ.≊ B → A ≊ B shuffle~ (f , g , inv) = g , f , inv - -- Shouldn't be necessary to use `arrowsAreSets` here, but we have it, - -- so why not? lem : (p : A ≡ B) → idToIso A B p ≡ shuffle~ (ℂ.idToIso A B p) lem p = isoEq refl - ζ : A ≊ B → A ≡ B - ζ = η ∘ shuffle + isoToId* : A ≊ B → A ≡ B + isoToId* = idToIso* ∘ shuffle - -- inv : AreInverses (ℂ.idToIso A B) f - inv-ζ : AreInverses (idToIso A B) ζ - -- recto-verso : ℂ.idToIso A B <<< f ≡ idFun (A ℂ.≊ B) - inv-ζ = record - { fst = funExt (λ x → begin - (ζ ∘ idToIso A B) x ≡⟨⟩ - (η ∘ shuffle ∘ idToIso A B) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → η ∘ shuffle ∘ φ) (funExt lem)) ⟩ - (η ∘ shuffle ∘ shuffle~ ∘ ℂ.idToIso A B) x ≡⟨⟩ - (η ∘ ℂ.idToIso A B) x ≡⟨ (λ i → verso-recto i x) ⟩ + inv : AreInverses (idToIso A B) isoToId* + inv = + ( funExt (λ x → begin + (isoToId* ∘ idToIso A B) x + ≡⟨⟩ + (idToIso* ∘ shuffle ∘ idToIso A B) x + ≡⟨ cong (λ φ → φ x) (cong (λ φ → idToIso* ∘ shuffle ∘ φ) (funExt lem)) ⟩ + (idToIso* ∘ shuffle ∘ shuffle~ ∘ ℂ.idToIso A B) x + ≡⟨⟩ + (idToIso* ∘ ℂ.idToIso A B) x + ≡⟨ (λ i → verso-recto i x) ⟩ x ∎) - ; snd = funExt (λ x → begin - (idToIso A B ∘ η ∘ shuffle) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → φ ∘ η ∘ shuffle) (funExt lem)) ⟩ - (shuffle~ ∘ ℂ.idToIso A B ∘ η ∘ shuffle) x ≡⟨ cong (λ φ → φ x) (cong (λ φ → shuffle~ ∘ φ ∘ shuffle) recto-verso) ⟩ - (shuffle~ ∘ shuffle) x ≡⟨⟩ + , funExt (λ x → begin + (idToIso A B ∘ idToIso* ∘ shuffle) x + ≡⟨ cong (λ φ → φ x) (cong (λ φ → φ ∘ idToIso* ∘ shuffle) (funExt lem)) ⟩ + (shuffle~ ∘ ℂ.idToIso A B ∘ idToIso* ∘ shuffle) x + ≡⟨ cong (λ φ → φ x) (cong (λ φ → shuffle~ ∘ φ ∘ shuffle) recto-verso) ⟩ + (shuffle~ ∘ shuffle) x + ≡⟨⟩ x ∎) - } - - h : TypeIsomorphism (idToIso A B) - h = ζ , inv-ζ + ) isCategory : IsCategory opRaw IsCategory.isPreCategory isCategory = isPreCategory - IsCategory.univalent isCategory = univalenceFromIsomorphism h + IsCategory.univalent isCategory + = univalenceFromIsomorphism (isoToId* , inv) opposite : Category ℓa ℓb Category.raw opposite = opRaw From e5d55c7b2b115483c3a39222f3b58cb1a346245c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 8 May 2018 16:22:51 +0200 Subject: [PATCH 91/93] Include appendices --- doc/cubical.tex | 3 + doc/implementation.tex | 5 + doc/introduction.tex | 2 +- doc/main.tex | 1 + doc/packages.tex | 31 ++- doc/sources.tex | 428 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 468 insertions(+), 2 deletions(-) create mode 100644 doc/sources.tex diff --git a/doc/cubical.tex b/doc/cubical.tex index d25054d..8ccd666 100644 --- a/doc/cubical.tex +++ b/doc/cubical.tex @@ -10,6 +10,9 @@ Cubical Agda extends the underlying type system (\TODO{Cite someone smarter than me with a good resource on this}) but introduces a data-type within the languages. +Exceprts of the source code relevant to this section can be found in appendix +\ref{sec:app-cubical}. + \subsection{The equality type} The usual notion of judgmental equality says that given a type $A \tp \MCU$ and two points of $A$; $a_0, a_1 \tp A$ we can form the type: diff --git a/doc/implementation.tex b/doc/implementation.tex index c5f01f7..2ce0d4e 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -50,6 +50,11 @@ where one can reason about two categories by simply focusing on the data. This is achieved by creating a function embodying the ``equality principle'' for a given type. +For the rest of this chapter I will present some of these results. For didactic +reasons no source-code has been included in this chapter. To see the formal +definitions excerpts of the implementation have been included in appendix +\ref{ch:app-sources}. + \section{Categories} The data for a category consist of a type for the sort of objects; a type for the sort of arrows; an identity arrow and a composition operation for arrows. diff --git a/doc/introduction.tex b/doc/introduction.tex index a8c19b5..12ad3b3 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -195,7 +195,7 @@ Name & Agda & Notation \\ \nomen{Type} & \texttt{Set} & $\Type$ \\ \nomen{Set} & \texttt{Σ Set IsSet} & $\Set$ \\ Function, morphism, map & \texttt{A → B} & $A → B$ \\ -Dependent- ditto & \texttt{(a \tp A) → B} & $∏_{a \tp A} B$ \\ +Dependent- ditto & \texttt{(a : A) → B} & $∏_{a \tp A} B$ \\ \nomen{Arrow} & \texttt{Arrow A B} & $\Arrow\ A\ B$ \\ \nomen{Object} & \texttt{C.Object} & $̱ℂ.Object$ \\ Definition & \texttt{=} & $̱\defeq$ \\ diff --git a/doc/main.tex b/doc/main.tex index a74978c..917f74d 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -69,6 +69,7 @@ \begin{appendices} \setcounter{page}{1} \pagenumbering{roman} +\input{sources.tex} %% \input{planning.tex} %% \input{halftime.tex} \end{appendices} diff --git a/doc/packages.tex b/doc/packages.tex index f592a65..19837af 100644 --- a/doc/packages.tex +++ b/doc/packages.tex @@ -15,7 +15,7 @@ \usepackage{amssymb,amsmath,amsthm,stmaryrd,mathrsfs,wasysym} \usepackage[toc,page]{appendix} \usepackage{xspace} -\usepackage{geometry} +\usepackage[a4paper]{geometry} % \setlength{\parskip}{10pt} @@ -37,6 +37,7 @@ \usepackage{lmodern} \usepackage{enumerate} +\usepackage{verbatim} \usepackage{fontspec} \usepackage[light]{sourcecodepro} @@ -56,3 +57,31 @@ %% \RequirePackage{kvoptions} \usepackage{pgffor} +\lstset + {basicstyle=\ttfamily + ,columns=fullflexible + ,breaklines=true + ,inputencoding=utf8 + ,extendedchars=true + %% ,literate={á}{{\'a}}1 {ã}{{\~a}}1 {é}{{\'e}}1 + } + +\usepackage{newunicodechar} + +%% \setmainfont{PT Serif} +\newfontfamily{\fallbackfont}{FreeMono.otf}[Scale=MatchLowercase] +%% \setmonofont[Mapping=tex-text]{FreeMono.otf} +\DeclareTextFontCommand{\textfallback}{\fallbackfont} +\newunicodechar{∨}{\textfallback{∨}} +\newunicodechar{∧}{\textfallback{∧}} +\newunicodechar{⊔}{\textfallback{⊔}} +\newunicodechar{≊}{\textfallback{≊}} +\newunicodechar{∈}{\textfallback{∈}} +\newunicodechar{ℂ}{\textfallback{ℂ}} +\newunicodechar{∘}{\textfallback{∘}} +\newunicodechar{⟨}{\textfallback{⟨}} +\newunicodechar{⟩}{\textfallback{⟩}} +\newunicodechar{∎}{\textfallback{∎}} +\newunicodechar{𝒜}{\textfallback{?}} +\newunicodechar{ℬ}{\textfallback{?}} +%% \newunicodechar{≊}{\textfallback{≊}} diff --git a/doc/sources.tex b/doc/sources.tex new file mode 100644 index 0000000..d270c1f --- /dev/null +++ b/doc/sources.tex @@ -0,0 +1,428 @@ +\chapter{Source code} +\label{ch:app-sources} +In the following a few of the definitions mentioned in the report are included. +The following is \emph{not} a verbatim copy of individual modules from the +implementation. Rather, this is a redacted and pre-formatted designed for +presentation purposes. It's provided here as a convenience. The actual sources +are the only authoritative source. Is something is not clear, please refer to +those. +\clearpage +\section{Cubical} +\label{sec:app-cubical} +\begin{figure}[h] +\begin{Verbatim} +postulate + PathP : ∀ {ℓ} (A : I → Set ℓ) → A i0 → A i1 → Set ℓ + +module _ {ℓ} {A : Set ℓ} where + _≡_ : A → A → Set ℓ + _≡_ {A = A} = PathP (λ _ → A) + + refl : {x : A} → x ≡ x + refl {x = x} = λ _ → x +\end{Verbatim} +\caption{Excerpt from the cubical library. Definition of the path-type.} +\end{figure} +% +\begin{figure}[h] +\begin{Verbatim} +module _ {ℓ : Level} (A : Set ℓ) where + isContr : Set ℓ + isContr = Σ[ x ∈ A ] (∀ y → x ≡ y) + + isProp : Set ℓ + isProp = (x y : A) → x ≡ y + + isSet : Set ℓ + isSet = (x y : A) → (p q : x ≡ y) → p ≡ q + + isGrpd : Set ℓ + isGrpd = (x y : A) → (p q : x ≡ y) → (a b : p ≡ q) → a ≡ b +\end{Verbatim} +\caption{Excerpt from the cubical library. Definition of the first few + homotopy-levels.} +\end{figure} +% +\begin{figure}[h] +\begin{Verbatim} +module _ {ℓ ℓ'} {A : Set ℓ} {x : A} + (P : ∀ y → x ≡ y → Set ℓ') (d : P x ((λ i → x))) where + pathJ : (y : A) → (p : x ≡ y) → P y p + pathJ _ p = transp (λ i → uncurry P (contrSingl p i)) d +\end{Verbatim} +\clearpage +\caption{Excerpt from the cubical library. Definition of based path-induction.} +\end{figure} +% +\begin{figure}[h] +\begin{Verbatim} +module _ {ℓ ℓ'} {A : Set ℓ} {B : A → Set ℓ'} where + propPi : (h : (x : A) → isProp (B x)) → isProp ((x : A) → B x) + propPi h f0 f1 = λ i → λ x → (h x (f0 x) (f1 x)) i + + lemPropF : (P : (x : A) → isProp (B x)) {a0 a1 : A} + (p : a0 ≡ a1) {b0 : B a0} {b1 : B a1} → PathP (λ i → B (p i)) b0 b1 + lemPropF P p {b0} {b1} = λ i → P (p i) + (primComp (λ j → B (p (i ∧ j)) ) (~ i) (λ _ → λ { (i = i0) → b0 }) b0) + (primComp (λ j → B (p (i ∨ ~ j)) ) (i) (λ _ → λ{ (i = i1) → b1 }) b1) i + + lemSig : (pB : (x : A) → isProp (B x)) + (u v : Σ A B) (p : fst u ≡ fst v) → u ≡ v + lemSig pB u v p = λ i → (p i) , ((lemPropF pB p) {snd u} {snd v} i) + + propSig : (pA : isProp A) (pB : (x : A) → isProp (B x)) → isProp (Σ A B) + propSig pA pB t u = lemSig pB t u (pA (fst t) (fst u)) +\end{Verbatim} +\caption{Excerpt from the cubical library. A few combinators.} +\end{figure} +\clearpage +\section{Categories} +\label{sec:app-categories} +\begin{figure}[h] +\begin{Verbatim} +record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where + field + Object : Set ℓa + Arrow : Object → Object → Set ℓb + identity : {A : Object} → Arrow A A + _<<<_ : {A B C : Object} → Arrow B C → Arrow A B → Arrow A C + + _>>>_ : {A B C : Object} → (Arrow A B) → (Arrow B C) → Arrow A C + f >>> g = g <<< f + + IsAssociative : Set (ℓa ⊔ ℓb) + IsAssociative = ∀ {A B C D} {f : Arrow A B} {g : Arrow B C} {h : Arrow C D} + → h <<< (g <<< f) ≡ (h <<< g) <<< f + + IsIdentity : ({A : Object} → Arrow A A) → Set (ℓa ⊔ ℓb) + IsIdentity id = {A B : Object} {f : Arrow A B} + → id <<< f ≡ f × f <<< id ≡ f + + ArrowsAreSets : Set (ℓa ⊔ ℓb) + ArrowsAreSets = ∀ {A B : Object} → isSet (Arrow A B) + + IsInverseOf : ∀ {A B} → (Arrow A B) → (Arrow B A) → Set ℓb + IsInverseOf = λ f g → g <<< f ≡ identity × f <<< g ≡ identity + + Isomorphism : ∀ {A B} → (f : Arrow A B) → Set ℓb + Isomorphism {A} {B} f = Σ[ g ∈ Arrow B A ] IsInverseOf f g + + _≊_ : (A B : Object) → Set ℓb + _≊_ A B = Σ[ f ∈ Arrow A B ] (Isomorphism f) + + IsTerminal : Object → Set (ℓa ⊔ ℓb) + IsTerminal T = {X : Object} → isContr (Arrow X T) + + Terminal : Set (ℓa ⊔ ℓb) + Terminal = Σ Object IsTerminal +\end{Verbatim} +\caption{Excerpt from module \texttt{Cat.Category}. The definition of a category.} +\end{figure} +\clearpage +\begin{figure}[h] +\begin{Verbatim} +module Univalence (isIdentity : IsIdentity identity) where + idIso : (A : Object) → A ≊ A + idIso A = identity , identity , isIdentity + + idToIso : (A B : Object) → A ≡ B → A ≊ B + idToIso A B eq = subst eq (idIso A) + + Univalent : Set (ℓa ⊔ ℓb) + Univalent = {A B : Object} → isEquiv (A ≡ B) (A ≊ B) (idToIso A B) +\end{Verbatim} +\caption{Excerpt from module \texttt{Cat.Category}. Continued from previous. Definition of univalence.} +\end{figure} +\begin{figure}[h] +\begin{Verbatim} +module _ {ℓa ℓb : Level} (ℂ : RawCategory ℓa ℓb) where + record IsPreCategory : Set (lsuc (ℓa ⊔ ℓb)) where + open RawCategory ℂ public + field + isAssociative : IsAssociative + isIdentity : IsIdentity identity + arrowsAreSets : ArrowsAreSets + open Univalence isIdentity public + + record PreCategory : Set (lsuc (ℓa ⊔ ℓb)) where + field + isPreCategory : IsPreCategory + open IsPreCategory isPreCategory public + + record IsCategory : Set (lsuc (ℓa ⊔ ℓb)) where + field + isPreCategory : IsPreCategory + open IsPreCategory isPreCategory public + field + univalent : Univalent +\end{Verbatim} +\caption{Excerpt from module \texttt{Cat.Category}. Records with inhabitants for + the laws defined in the previous listings.} +\end{figure} +\clearpage +\begin{figure}[h] +\begin{Verbatim} +module Opposite {ℓa ℓb : Level} where + module _ (ℂ : Category ℓa ℓb) where + private + module _ where + module ℂ = Category ℂ + opRaw : RawCategory ℓa ℓb + RawCategory.Object opRaw = ℂ.Object + RawCategory.Arrow opRaw = flip ℂ.Arrow + RawCategory.identity opRaw = ℂ.identity + RawCategory._<<<_ opRaw = ℂ._>>>_ + + open RawCategory opRaw + + isPreCategory : IsPreCategory opRaw + IsPreCategory.isAssociative isPreCategory = sym ℂ.isAssociative + IsPreCategory.isIdentity isPreCategory = swap ℂ.isIdentity + IsPreCategory.arrowsAreSets isPreCategory = ℂ.arrowsAreSets + + open IsPreCategory isPreCategory + + ---------------------------- + -- NEXT LISTING GOES HERE -- + ---------------------------- + + isCategory : IsCategory opRaw + IsCategory.isPreCategory isCategory = isPreCategory + IsCategory.univalent isCategory + = univalenceFromIsomorphism (isoToId* , inv) + + opposite : Category ℓa ℓb + Category.raw opposite = opRaw + Category.isCategory opposite = isCategory + + module _ {ℂ : Category ℓa ℓb} where + open Category ℂ + private + rawInv : Category.raw (opposite (opposite ℂ)) ≡ raw + RawCategory.Object (rawInv _) = Object + RawCategory.Arrow (rawInv _) = Arrow + RawCategory.identity (rawInv _) = identity + RawCategory._<<<_ (rawInv _) = _<<<_ + + oppositeIsInvolution : opposite (opposite ℂ) ≡ ℂ + oppositeIsInvolution = Category≡ rawInv +\end{Verbatim} +\caption{Excerpt from module \texttt{Cat.Category}. Showing that the opposite + category is a category. Part of this listing has been cut out and placed in + the next listing.} +\end{figure} +\clearpage +For reasons of formatting the following listing is continued from the above with +fewer levels of indentation. +% +\begin{figure}[h] +\begin{Verbatim} +module _ {A B : ℂ.Object} where + open Σ (toIso _ _ (ℂ.univalent {A} {B})) + renaming (fst to idToIso* ; snd to inv*) + open AreInverses {f = ℂ.idToIso A B} {idToIso*} inv* + + shuffle : A ≊ B → A ℂ.≊ B + shuffle (f , g , inv) = g , f , inv + + shuffle~ : A ℂ.≊ B → A ≊ B + shuffle~ (f , g , inv) = g , f , inv + + isoToId* : A ≊ B → A ≡ B + isoToId* = idToIso* ∘ shuffle + + inv : AreInverses (idToIso A B) isoToId* + inv = + ( funExt (λ x → begin + (isoToId* ∘ idToIso A B) x + ≡⟨⟩ + (idToIso* ∘ shuffle ∘ idToIso A B) x + ≡⟨ cong (λ φ → φ x) + (cong (λ φ → idToIso* ∘ shuffle ∘ φ) (funExt (isoEq refl))) ⟩ + (idToIso* ∘ shuffle ∘ shuffle~ ∘ ℂ.idToIso A B) x + ≡⟨⟩ + (idToIso* ∘ ℂ.idToIso A B) x + ≡⟨ (λ i → verso-recto i x) ⟩ + x ∎) + , funExt (λ x → begin + (idToIso A B ∘ idToIso* ∘ shuffle) x + ≡⟨ cong (λ φ → φ x) + (cong (λ φ → φ ∘ idToIso* ∘ shuffle) (funExt (isoEq refl))) ⟩ + (shuffle~ ∘ ℂ.idToIso A B ∘ idToIso* ∘ shuffle) x + ≡⟨ cong (λ φ → φ x) + (cong (λ φ → shuffle~ ∘ φ ∘ shuffle) recto-verso) ⟩ + (shuffle~ ∘ shuffle) x + ≡⟨⟩ + x ∎) + ) +\end{Verbatim} +\caption{Excerpt from module \texttt{Cat.Category}. Proving univalence for the opposite category.} +\end{figure} +\clearpage +\section{Products} +\label{sec:app-products} +\begin{figure}[h] +\begin{Verbatim} +module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where + open Category ℂ + + module _ (A B : Object) where + record RawProduct : Set (ℓa ⊔ ℓb) where + no-eta-equality + field + object : Object + fst : ℂ [ object , A ] + snd : ℂ [ object , B ] + + record IsProduct (raw : RawProduct) : Set (ℓa ⊔ ℓb) where + open RawProduct raw public + field + ump : ∀ {X : Object} (f : ℂ [ X , A ]) (g : ℂ [ X , B ]) + → ∃![ f×g ] (ℂ [ fst ∘ f×g ] ≡ f P.× ℂ [ snd ∘ f×g ] ≡ g) + + record Product : Set (ℓa ⊔ ℓb) where + field + raw : RawProduct + isProduct : IsProduct raw + + open IsProduct isProduct public + +\end{Verbatim} +\caption{Excerpt from module \texttt{Cat.Category.Product}. Definition of products.} +\end{figure} +% +\begin{figure}[h] +\begin{Verbatim} +module _{ℓa ℓb : Level} {ℂ : Category ℓa ℓb} + (let module ℂ = Category ℂ) {A* B* : ℂ.Object} where + + module _ where + raw : RawCategory _ _ + raw = record + { Object = Σ[ X ∈ ℂ.Object ] ℂ.Arrow X A* × ℂ.Arrow X B* + ; Arrow = λ{ (A , a0 , a1) (B , b0 , b1) + → Σ[ f ∈ ℂ.Arrow A B ] + ℂ [ b0 ∘ f ] ≡ a0 + × ℂ [ b1 ∘ f ] ≡ a1 + } + ; identity = λ{ {X , f , g} + → ℂ.identity {X} , ℂ.rightIdentity , ℂ.rightIdentity + } + ; _<<<_ = λ { {_ , a0 , a1} {_ , b0 , b1} {_ , c0 , c1} + (f , f0 , f1) (g , g0 , g1) + → (f ℂ.<<< g) + , (begin + ℂ [ c0 ∘ ℂ [ f ∘ g ] ] ≡⟨ ℂ.isAssociative ⟩ + ℂ [ ℂ [ c0 ∘ f ] ∘ g ] ≡⟨ cong (λ φ → ℂ [ φ ∘ g ]) f0 ⟩ + ℂ [ b0 ∘ g ] ≡⟨ g0 ⟩ + a0 ∎ + ) + , (begin + ℂ [ c1 ∘ ℂ [ f ∘ g ] ] ≡⟨ ℂ.isAssociative ⟩ + ℂ [ ℂ [ c1 ∘ f ] ∘ g ] ≡⟨ cong (λ φ → ℂ [ φ ∘ g ]) f1 ⟩ + ℂ [ b1 ∘ g ] ≡⟨ g1 ⟩ + a1 ∎ + ) + } + } +\end{Verbatim} +\caption{Excerpt from module \texttt{Cat.Category.Product}. Definition of ``pair category''.} +\end{figure} +\clearpage +\section{Monads} +\label{sec:app-monads} +\begin{figure}[h] +\begin{Verbatim} +module Cat.Category.Monad.Kleisli + {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where + +record RawMonad : Set ℓ where + field + omap : Object → Object + pure : {X : Object} → ℂ [ X , omap X ] + bind : {X Y : Object} → ℂ [ X , omap Y ] → ℂ [ omap X , omap Y ] + + fmap : ∀ {A B} → ℂ [ A , B ] → ℂ [ omap A , omap B ] + fmap f = bind (pure <<< f) + + _>=>_ : {A B C : Object} + → ℂ [ A , omap B ] → ℂ [ B , omap C ] → ℂ [ A , omap C ] + f >=> g = f >>> (bind g) + + join : {A : Object} → ℂ [ omap (omap A) , omap A ] + join = bind identity + + IsIdentity = {X : Object} + → bind pure ≡ identity {omap X} + IsNatural = {X Y : Object} (f : ℂ [ X , omap Y ]) + → pure >=> f ≡ f + IsDistributive = {X Y Z : Object} + (g : ℂ [ Y , omap Z ]) (f : ℂ [ X , omap Y ]) + → (bind f) >>> (bind g) ≡ bind (f >=> g) + +record IsMonad (raw : RawMonad) : Set ℓ where + open RawMonad raw public + field + isIdentity : IsIdentity + isNatural : IsNatural + isDistributive : IsDistributive +\end{Verbatim} +\caption{Excerpt from module \texttt{Cat.Category.Monad.Kleisli}. Definition of + Kleisli monads.} +\end{figure} +% +\begin{figure}[h] +\begin{Verbatim} +module Cat.Category.Monad.Monoidal + {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where + +private + ℓ = ℓa ⊔ ℓb + +open Category ℂ using (Object ; Arrow ; identity ; _<<<_) + +record RawMonad : Set ℓ where + field + R : EndoFunctor ℂ + pureNT : NaturalTransformation Functors.identity R + joinNT : NaturalTransformation F[ R ∘ R ] R + + Romap = Functor.omap R + fmap = Functor.fmap R + + pureT : Transformation Functors.identity R + pureT = fst pureNT + + pure : {X : Object} → ℂ [ X , Romap X ] + pure = pureT _ + + pureN : Natural Functors.identity R pureT + pureN = snd pureNT + + joinT : Transformation F[ R ∘ R ] R + joinT = fst joinNT + join : {X : Object} → ℂ [ Romap (Romap X) , Romap X ] + join = joinT _ + joinN : Natural F[ R ∘ R ] R joinT + joinN = snd joinNT + + bind : {X Y : Object} → ℂ [ X , Romap Y ] → ℂ [ Romap X , Romap Y ] + bind {X} {Y} f = join <<< fmap f + + IsAssociative : Set _ + IsAssociative = {X : Object} + → joinT X <<< fmap join ≡ join <<< join + IsInverse : Set _ + IsInverse = {X : Object} + → join <<< pure ≡ identity {Romap X} + × join <<< fmap pure ≡ identity {Romap X} + +record IsMonad (raw : RawMonad) : Set ℓ where + open RawMonad raw public + field + isAssociative : IsAssociative + isInverse : IsInverse +\end{Verbatim} +\caption{Excerpt from module \texttt{Cat.Category.Monad.Monoidal}. Definition of + Monoidal monads.} +\end{figure} From 32e7290fe9283663fcdd5145330d3fcd9846c945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 8 May 2018 18:01:34 +0200 Subject: [PATCH 92/93] Prove missing link for univalence via new branch of `cubical` --- libs/agda-stdlib | 2 +- libs/cubical | 2 +- src/Cat/Category.agda | 9 ++++----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/libs/agda-stdlib b/libs/agda-stdlib index fbd8ba7..4493cf2 160000 --- a/libs/agda-stdlib +++ b/libs/agda-stdlib @@ -1 +1 @@ -Subproject commit fbd8ba7ea84c4b643fd08797b4031b18a59f561d +Subproject commit 4493cf249a1648be2ad365fe94ece337bfbcb5d9 diff --git a/libs/cubical b/libs/cubical index 5b35333..4e5d43a 160000 --- a/libs/cubical +++ b/libs/cubical @@ -1 +1 @@ -Subproject commit 5b35333dbbd8fa523e478c1cfe60657321ca38fe +Subproject commit 4e5d43a9c75286b3a8750567d75a930674d7720d diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 1561aab..749ba42 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -137,11 +137,10 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where Univalent[Contr] : Set _ Univalent[Contr] = ∀ A → isContr (Σ[ X ∈ Object ] A ≊ X) - -- From: Thierry Coquand - -- Date: Wed, Mar 21, 2018 at 3:12 PM - -- - -- This is not so straight-forward so you can assume it - postulate from[Contr] : Univalent[Contr] → Univalent + from[Contr] : Univalent[Contr] → Univalent + from[Contr] = ContrToUniv.lemma _ _ + where + open import Cubical.Fiberwise univalenceFrom≃ : Univalent≃ → Univalent univalenceFrom≃ = from[Contr] ∘ step From d1981ec0fa203f9fe1bd4fac0ba0157776199d18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 8 May 2018 18:34:12 +0200 Subject: [PATCH 93/93] Update CHANGELOG and remove --allow-unsolved-metas pragma --- BACKLOG.md | 16 ++----------- CHANGELOG.md | 26 +++++++++++++++++++++ src/Cat/Categories/Sets.agda | 2 +- src/Cat/Category.agda | 2 +- src/Cat/Category/Monad.agda | 2 +- src/Cat/Category/Monad/Kleisli.agda | 2 +- src/Cat/Category/Monad/Monoidal.agda | 2 +- src/Cat/Category/Monad/Voevodsky.agda | 2 +- src/Cat/Category/NaturalTransformation.agda | 2 +- src/Cat/Category/Product.agda | 4 ++-- src/Cat/Category/Yoneda.agda | 2 +- src/Cat/Equivalence.agda | 2 +- 12 files changed, 39 insertions(+), 25 deletions(-) diff --git a/BACKLOG.md b/BACKLOG.md index 9a72a1d..af3f622 100644 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -1,24 +1,12 @@ Backlog ======= -Prove postulates in `Cat.Wishlist`: - * `ntypeCommulative : n ≤ m → HasLevel ⟨ n ⟩₋₂ A → HasLevel ⟨ m ⟩₋₂ A` - -Prove that these two formulations of univalence are equivalent: - - ∀ A B → isEquiv (A ≡ B) (A ≅ B) (idToIso A B) - ∀ A → isContr (Σ[ X ∈ Object ] A ≅ X) - Prove univalence for the category of * functors and natural transformations -Prove: - * `isProp (Product ...)` - * `isProp (HasProducts ...)` +In AreInverses, dont use the "point-free" version. I.e.: -Rename composition in categories - -In stead of using AreInverses, just use a sigma-type + `∀ x → f x ≡ g x` rather than `f ≡ g` Ideas for future work --------------------- diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bd4bc4..6bb631b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,32 @@ Change log ========= +Version 1.5.0 +------------- +Prove postulates in `Cat.Wishlist`: + + * `ntypeCommulative : n ≤ m → HasLevel ⟨ n ⟩₋₂ A → HasLevel ⟨ m ⟩₋₂ A` + +Prove that these two formulations of univalence are equivalent: + + ∀ A B → isEquiv (A ≡ B) (A ≅ B) (id-to-iso A B) + ∀ A → isContr (Σ[ X ∈ Object ] A ≅ X) + +Prove univalence for the category of... + + * the opposite category + * sets + * "pair" category + +Finish the proof that products are propositional: + + * `isProp (Product ...)` + * `isProp (HasProducts ...)` + +Remove --allow-unsolved-metas pragma from various files + +Also renamed a lot of different projections. E.g. arrow-composition, etc.. + Version 1.4.1 ------------- Defines a module to work with equivalence providing a way to go between diff --git a/src/Cat/Categories/Sets.agda b/src/Cat/Categories/Sets.agda index 3fa14ce..e707b55 100644 --- a/src/Cat/Categories/Sets.agda +++ b/src/Cat/Categories/Sets.agda @@ -1,5 +1,5 @@ -- | The category of homotopy sets -{-# OPTIONS --allow-unsolved-metas --cubical --caching #-} +{-# OPTIONS --cubical --caching #-} module Cat.Categories.Sets where open import Cat.Prelude as P diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 749ba42..274f94e 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -24,7 +24,7 @@ -- ------ -- -- Propositionality for all laws about the category. -{-# OPTIONS --allow-unsolved-metas --cubical #-} +{-# OPTIONS --cubical #-} module Cat.Category where diff --git a/src/Cat/Category/Monad.agda b/src/Cat/Category/Monad.agda index e071d92..8d5abc6 100644 --- a/src/Cat/Category/Monad.agda +++ b/src/Cat/Category/Monad.agda @@ -17,7 +17,7 @@ These two formulations are proven to be equivalent: The monoidal representation is exposed by default from this module. ---} -{-# OPTIONS --cubical --allow-unsolved-metas #-} +{-# OPTIONS --cubical #-} module Cat.Category.Monad where open import Cat.Prelude diff --git a/src/Cat/Category/Monad/Kleisli.agda b/src/Cat/Category/Monad/Kleisli.agda index 75e5a22..e0ebf86 100644 --- a/src/Cat/Category/Monad/Kleisli.agda +++ b/src/Cat/Category/Monad/Kleisli.agda @@ -1,7 +1,7 @@ {--- The Kleisli formulation of monads ---} -{-# OPTIONS --cubical --allow-unsolved-metas #-} +{-# OPTIONS --cubical #-} open import Agda.Primitive open import Cat.Prelude diff --git a/src/Cat/Category/Monad/Monoidal.agda b/src/Cat/Category/Monad/Monoidal.agda index 86111b6..f5b20ad 100644 --- a/src/Cat/Category/Monad/Monoidal.agda +++ b/src/Cat/Category/Monad/Monoidal.agda @@ -1,7 +1,7 @@ {--- Monoidal formulation of monads ---} -{-# OPTIONS --cubical --allow-unsolved-metas #-} +{-# OPTIONS --cubical #-} open import Agda.Primitive open import Cat.Prelude diff --git a/src/Cat/Category/Monad/Voevodsky.agda b/src/Cat/Category/Monad/Voevodsky.agda index e5ff355..abc8438 100644 --- a/src/Cat/Category/Monad/Voevodsky.agda +++ b/src/Cat/Category/Monad/Voevodsky.agda @@ -1,7 +1,7 @@ {- This module provides construction 2.3 in [voe] -} -{-# OPTIONS --cubical --allow-unsolved-metas --caching #-} +{-# OPTIONS --cubical --caching #-} module Cat.Category.Monad.Voevodsky where open import Cat.Prelude diff --git a/src/Cat/Category/NaturalTransformation.agda b/src/Cat/Category/NaturalTransformation.agda index 1a7223d..3771643 100644 --- a/src/Cat/Category/NaturalTransformation.agda +++ b/src/Cat/Category/NaturalTransformation.agda @@ -17,7 +17,7 @@ -- Functions for manipulating the above: -- -- * A composition operator. -{-# OPTIONS --allow-unsolved-metas --cubical #-} +{-# OPTIONS --cubical #-} open import Cat.Prelude open import Data.Nat using (_≤′_ ; ≤′-refl ; ≤′-step) diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index c0c68c3..4856668 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -1,4 +1,4 @@ -{-# OPTIONS --allow-unsolved-metas --cubical --caching #-} +{-# OPTIONS --cubical --caching #-} module Cat.Category.Product where open import Cat.Prelude as P hiding (_×_ ; fst ; snd) @@ -299,7 +299,7 @@ module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} open Σ ump renaming (fst to f') open Σ (snd ump) renaming (fst to f'-cond) 𝒻 : Arrow 𝒴 𝒳 - 𝒻 = f' , {!f'-cond!} + 𝒻 = f' , f'-cond contractible : (f : Arrow 𝒴 𝒳) → 𝒻 ≡ f contractible ff@(f , f-cond) = res where diff --git a/src/Cat/Category/Yoneda.agda b/src/Cat/Category/Yoneda.agda index afea823..c02274b 100644 --- a/src/Cat/Category/Yoneda.agda +++ b/src/Cat/Category/Yoneda.agda @@ -1,4 +1,4 @@ -{-# OPTIONS --allow-unsolved-metas --cubical #-} +{-# OPTIONS --cubical #-} module Cat.Category.Yoneda where diff --git a/src/Cat/Equivalence.agda b/src/Cat/Equivalence.agda index 1103b9f..6e55cbf 100644 --- a/src/Cat/Equivalence.agda +++ b/src/Cat/Equivalence.agda @@ -1,4 +1,4 @@ -{-# OPTIONS --allow-unsolved-metas --cubical #-} +{-# OPTIONS --cubical #-} module Cat.Equivalence where open import Cubical.Primitives