New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(category_theory): basic definitions #152
feat(category_theory): basic definitions #152
Conversation
A note: the category theory library I have been developing relies heavily on automation, in particular my As an example of how much nicer things look with this automation, have a look at the before/after for this file in which I show that category of types has products, coproducts, equalizers, and coequalizers (to appear in a later PR). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly trivial comments. I can't really comment on the Lean.
category_theory/functor/default.lean
Outdated
variable {C : Type u₁} | ||
variable [category.{u₁ v₁} C] | ||
|
||
@[simp] lemma IdentityFunctor.onObjects {C : Type u₁} [category.{u₁ v₁} C] (X : C) : (IdentityFunctor C) +> X = X := by refl |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The colon doesn't algin with the line below, but it looks like you want it to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems there are duplicate variables {C : Type u₁} [category.{u₁ v₁} C]
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... and below here, as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't get it to align exactly (slight variations in character widths), so I've removed all the spurious spaces.
@spl, I don't think there was any actual duplication, because of sectioning commands, but in any case I've tidied the variables up.
|
||
@[simp,ematch] lemma vertical_composition_of_NaturalTransformations.components (α : F ⟹ G) (β : G ⟹ H) (X : C) : (α ⊟ β).components X = (α.components X) ≫ (β.components X) := by refl | ||
|
||
-- We'll want to be able to prove that two natural transformations are equal if they are componentwise equal. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like this is an intermezzo between vertical and horizontal composition of natural transformations. Is that on purpose?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it wasn't on purpose; I've rearranged now.
docs/theories/categories.md
Outdated
### Categories | ||
|
||
We use the `⟶` (`\hom`) arrow to denote sets of morphisms, as in `X ⟶ Y`. | ||
This leaves the actual category implicit; it is inferred from the type of X and Y but typeclass inference. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/but/by/ -- "by typeclass inference".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
category_theory/category.lean
Outdated
(right_identity : ∀ {X Y : Obj} (f : Hom X Y), compose f (identity Y) = f . obviously) | ||
(associativity : ∀ {W X Y Z : Obj} (f : Hom W X) (g : Hom X Y) (h : Hom Y Z), compose (compose f g) h = compose f (compose g h) . obviously) | ||
|
||
notation `𝟙` := category.identity -- type as \b1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can imagine that we will also love to have this notation for the unit object in a monoidal category. But then... we also want good notation for identity morphisms, and I don't have a good alternative in mind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Besides the double-struck 1, there are several other variant numeral 1s available in unicode:
"bold": 𝟏
"sans-serif": 𝟣
"sans-serif bold": 𝟭
"monospace": 𝟷
Currently none of these have shortcuts in VSCode, but those are easy to add. My monoidal categories library hasn't fixed on any notation for monoidal units. I'm not sure that having two slightly different 1s is a good idea.
docs/theories/categories.md
Outdated
We use `𝟙` (`\b1`) to denote identity morphisms, as in `𝟙 X`. | ||
|
||
We use `≫` (`\gg`) to denote composition of morphisms, as in `f ≫ g`, which means "`f` followed by `g`". | ||
This is the opposite order than the usual convention (which is lame). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mathematicians are going to love you for this [/sarcasm]. Is it possible to also have notation for "ordinary" composition? Would it even be possible to overload \circ
? Or will madness ensue? If so, then preferably something that reminds of \circ
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will investigate overloading \circ
, or finding something nearby.
I'd been hoping that everyone would be relieved that starting to write mathematics in Lean gave them a good opportunity to abandon the no-good-terrible-horrible \circ
notation after so many years. :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regardless of one's personal preferences, for the purpose of formalizing existing mathematics, it's greatly helpful if the Lean notation is as similar as possible to the source notation; and that will almost always require having some form of applicative-order composition notation available.
In my own project, I just write local notation f ` ∘ `:80 g:80 := g ≫ f
at the top of most files, and this works pretty well for me, though I occasionally need to write function.comp
for the usual ∘
operator. Not a very good solution for the library, though.
docs/theories/categories.md
Outdated
|
||
For now we just write out `τ.components X`. | ||
|
||
For vertical and horiztonal composition of natural transformations we "cutely" use `⊟` (`\boxminus`) and `◫` (currently untypeable, but we could ask for `\boxbar`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or maybe \boxvert
(?), which arguably has better mnemonics.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good suggestion, I've included that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Originally I thought it was inappropriate to put @[simp] on associativity, but it seems to work out okay.
Removing it here entirely changes some proofs; in some places we need to do rewrites (which can nevertheless be discovered automatically) instead of just simp,
(I don't think there were any actual errors, but I was sometimes using an argument when there was a variable of the same name available.)
I noticed that the composition notation |
I've recently been working with categories presented by graphs and relations, and I noticed your full category theory library also defines |
Some notation for the components of a natural transformation is necessary. I've been using notation t ` @> `:90 X:90 := t.components X |
Using `@>` per @rwbarton's suggestion.
@rwbarton, I've added How about we use |
@rwbarton, I did try having
Even though logically an extension works fine here, I don't think it's giving you much, and it's conceptually unclear. Given the fairly narrow payoff (i.e. only inside a file or two where we develop that adjunction between categories and graphs) I didn't like it. |
@semorrison, regarding |
Does anyone have more review comments? As far as I'm aware, this is ready to go. The travis failure is just due to a timeout (which on bad days mathlib is running up against), and as far as I can see does not indicate a problem with this PR. |
There is not even a travis failure on your last commit, right? |
You're right --- merging in master prompted travis to rebuild, and succeed this time. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we really break with the naming conventions we have in Lean? I especially don't like onObjects
and onMorphisms
. But I would prefer if most names are a lower case with _
.
category_theory/category.lean
Outdated
import tactic.make_lemma | ||
import tactic.interactive | ||
|
||
namespace categories |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about category_theory
instead?
category_theory/category.lean
Outdated
@@ -0,0 +1,44 @@ | |||
-- Copyright (c) 2017 Scott Morrison. All rights reserved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The header we use look like:
/-
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
notation, basic datatypes and type classes
-/
so use /--/
instead of --
. The difference looks minor, but might be helpful when we use scripts to analyze the header.
category_theory/functor/default.lean
Outdated
|
||
open categories | ||
|
||
namespace categories.functor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think everything should went into category_theory
.
category_theory/functor/default.lean
Outdated
structure Functor (C : Type u₁) [category.{u₁ v₁} C] (D : Type u₂) [category.{u₂ v₂} D] : Type (max u₁ v₁ u₂ v₂) := | ||
(onObjects : C → D) | ||
(onMorphisms : Π {X Y : C}, (X ⟶ Y) → ((onObjects X) ⟶ (onObjects Y))) | ||
(identities : ∀ (X : C), onMorphisms (𝟙 X) = 𝟙 (onObjects X) . obviously) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now you have categories.functor.Functor
, I think it should be just category_theory.functor
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @johoelzl, I've made all the changes you suggested. I'm very happy to adjust naming to match mathlib
conventions better, although would like to err on the side of longer names over ambiguous or not-immediately-obvious ones, where reasonable.
Further review:
|
(Later PRs will add more files to the functor/ directory, but that can wait.)
Some simple things:
|
I still don't like the syntax:
|
category_theory/functor.lean
Outdated
(obj : C → D) | ||
(map : Π {X Y : C}, (X ⟶ Y) → ((obj X) ⟶ (obj Y))) | ||
(map_id : ∀ (X : C), map (𝟙 X) = 𝟙 (obj X) . obviously) | ||
(functoriality : ∀ {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z), map (f ≫ g) = (map f) ≫ (map g) . obviously) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I will insist on this one. I know that literal description of axioms doesn't appeal to you, but there are just too many different ways of phrasing lemmas and it is a huge benefit to users that are bouncing between fields of mathematics that they may not know in detail the "traditional" way, to be able to guess names based solely on how they are written rather than what they mean. As a simple example, the symmetric version of this equality would also be called "functoriality" by a mathematician, as well as a hypothetical definition like commutes map (≫)
which unfolds to this equality. You have map
and comp
being applied; so it is called map_comp
.
category_theory/functor.lean
Outdated
{ F := λ F, C → D, | ||
coe := λ F, F.obj } | ||
|
||
@[simp] lemma unfold_obj_coercion (F : C ↝ D) (X : C) : F X = F.obj X := rfl |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer a name like coe_def
for this.
category_theory/functor.lean
Outdated
@[simp] lemma identity.on_objects (X : C) : (identity C) X = X := rfl | ||
@[simp] lemma identity.on_morphisms {X Y : C} (f : X ⟶ Y) : (identity C).map f = f := rfl | ||
@[simp] lemma has_one.on_objects (X : C) : (1 : C ↝ C) X = X := rfl | ||
@[simp] lemma has_one.on_morphisms {X Y : C} (f : X ⟶ Y) : (1 : C ↝ C).map f = f := rfl |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need both of these? I would prefer to have identity
simplify to 1
so that we only need the second set of lemmas. Unless you are having similar problems as with simp under coe, but I don't think this should happen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My inclination is to actually remove entirely the
has_one
instances. I think they're more cosmetic than useful. What do you think?
What is the relation between this identity
and the \b1
symbol? I would like to have some kind of symbol for this which is one-like. But it doesn't hurt to have a has_one
instance as well; just pick one or the other to be the "idiomatic" one and use it in all your statements, and have a simp lemma from any alternative ways to write it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I missed this comment. identity
is an "outside" identity, that is C.identity
is the identity functor from C
to itself. id
(and the \b1
symbol) are for the identities "inside" a category, e.g. category.id X
is a morphism from the object X
to itself.
I agree it would be nice to be clearer here. Suggestions for renamings very welcome!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about functor.id
(protected)? I can live with C.id
as a notation, does that work for you?
Edit: oh wait, C
is a category not a functor. I can still live with functor.id C
, unless there is a good reason to further abbreviate it.
My inclination is to actually remove entirely the `has_one` instances. I
think they're more cosmetic than useful. What do you think?
…On Tue, Aug 7, 2018 at 2:47 PM Mario Carneiro ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In category_theory/functor.lean
<#152 (comment)>:
> +
+definition identity : C ↝ C :=
+{ obj := λ X, X,
+ map := λ _ _ f, f,
+ map_id := begin /- `obviously'` says: -/ intros, refl end,
+ functoriality := begin /- `obviously'` says: -/ intros, refl end }
+
+instance has_one : has_one (C ↝ C) :=
+{ one := identity C }
+
+variable {C}
+
***@***.*** lemma identity.on_objects (X : C) : (identity C) X = X := rfl
***@***.*** lemma identity.on_morphisms {X Y : C} (f : X ⟶ Y) : (identity C).map f = f := rfl
***@***.*** lemma has_one.on_objects (X : C) : (1 : C ↝ C) X = X := rfl
***@***.*** lemma has_one.on_morphisms {X Y : C} (f : X ⟶ Y) : (1 : C ↝ C).map f = f := rfl
Do we need both of these? I would prefer to have identity simplify to 1
so that we only need the second set of lemmas. Unless you are having
similar problems as with simp under coe, but I don't think this should
happen.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#152 (review)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAdLBH11DTk66mfR6UlBDBAwzyvvJkV5ks5uORvjgaJpZM4UYZ19>
.
|
I have made the renamings you suggested. (The `functoriality` -> `map_comp`
renaming only under protest! :-)
…On Tue, Aug 7, 2018 at 3:00 PM Scott Morrison ***@***.***> wrote:
My inclination is to actually remove entirely the `has_one` instances. I
think they're more cosmetic than useful. What do you think?
On Tue, Aug 7, 2018 at 2:47 PM Mario Carneiro ***@***.***>
wrote:
> ***@***.**** commented on this pull request.
> ------------------------------
>
> In category_theory/functor.lean
> <#152 (comment)>:
>
> > +
> +definition identity : C ↝ C :=
> +{ obj := λ X, X,
> + map := λ _ _ f, f,
> + map_id := begin /- `obviously'` says: -/ intros, refl end,
> + functoriality := begin /- `obviously'` says: -/ intros, refl end }
> +
> +instance has_one : has_one (C ↝ C) :=
> +{ one := identity C }
> +
> +variable {C}
> +
> ***@***.*** lemma identity.on_objects (X : C) : (identity C) X = X := rfl
> ***@***.*** lemma identity.on_morphisms {X Y : C} (f : X ⟶ Y) : (identity C).map f = f := rfl
> ***@***.*** lemma has_one.on_objects (X : C) : (1 : C ↝ C) X = X := rfl
> ***@***.*** lemma has_one.on_morphisms {X Y : C} (f : X ⟶ Y) : (1 : C ↝ C).map f = f := rfl
>
> Do we need both of these? I would prefer to have identity simplify to 1
> so that we only need the second set of lemmas. Unless you are having
> similar problems as with simp under coe, but I don't think this should
> happen.
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <#152 (review)>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AAdLBH11DTk66mfR6UlBDBAwzyvvJkV5ks5uORvjgaJpZM4UYZ19>
> .
>
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's looking good. I think we are nearly there, just a few more nitpicks and then it will be ready.
|
||
structure natural_transformation (F G : C ↝ D) : Type (max u₁ v₂) := | ||
(components : Π X : C, (F X) ⟶ (G X)) | ||
(naturality : ∀ {X Y : C} (f : X ⟶ Y), (F.map f) ≫ (components Y) = (components X) ≫ (G.map f) . obviously) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we perhaps abbreviate these names? components
will appear a lot so I would suggest something with 3-5 characters, and natural_transformation
could be abbreviated to nat_trans
without much loss in readability. @johoelzl Thoughts? I don't even think it has to be an abbreviation of the word "components", something like f
or app
would work fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, nat_trans
coming up. I really don't understand the desire to abbreviate. Once upon a time memory was expensive, but it's not anymore, and code is so much more readable if you use unambiguous english words, particularly the explicit mathematical terms everyone is used to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've renamed components
to app
, though it makes me feel sick to obfuscate my code. :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I'm staring at a 30 line goal, long names make everything harder to look at. Lean already has significant term bloat, so I try to control what I can. Symbols are especially good at making things concise and readable, but they generally aren't an option when writing proofs. The names of major concepts have to be especially short because they appear as components in theorem names, and when you use a "name the symbols" approach to theorem naming those names can get long and repetitive, so short components pay for themselves.
I notice that this definition does not have a doc comment. I would much prefer you add all explanatory information to a doc comment rather than giving everything a long name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay! doc comments coming up.
variables {F G H : C ↝ D} | ||
|
||
-- We'll want to be able to prove that two natural transformations are equal if they are componentwise equal. | ||
@[extensionality] lemma componentwise_equal (α β : F ⟹ G) (w : ∀ X : C, α X = β X) : α = β := |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this theorem should be called ext
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
tactic/make_lemma.lean
Outdated
|
||
/- Make lemma takes a structure field, and makes a new, definitionally simplified copy of it, appending `_lemma` to the name. | ||
The main application is to provide clean versions of structure fields that have been tagged with an auto_param. -/ | ||
meta def make_lemma (d : declaration) (new_name : name) : tactic unit := |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name of this tactic is extremely generic. How about mk_structure_lemma
or restate_axiom
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done: restate_axiom
.
category_theory/category.lean
Outdated
make_lemma category.assoc | ||
restate_axiom category.id_comp | ||
restate_axiom category.comp_id | ||
restate_axiom category.assoc |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missed a spot (make_lemma
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
category_theory/functor.lean
Outdated
@[simp] lemma has_one.on_objects (X : C) : (1 : C ↝ C) X = X := rfl | ||
@[simp] lemma has_one.on_morphisms {X Y : C} (f : X ⟶ Y) : (1 : C ↝ C).map f = f := rfl | ||
@[simp] protected lemma has_one.on_objects (X : C) : (1 : C ↝ C) X = X := rfl | ||
@[simp] protected lemma has_one.on_morphisms {X Y : C} (f : X ⟶ Y) : (1 : C ↝ C).map f = f := rfl |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these don't all need to be protected, just id
itself (assuming you call it id
;) )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we don't have the option of calling it id
, as there's already a structure field category.id
, for the identity morphism on an object. This identity
is for the identity functor on the category itself.
(it was causing a problem on travis, but not locally? anyway it's useless)
category_theory/functor.lean
Outdated
variable {C} | ||
|
||
@[simp] lemma id.on_objects (X : C) : (functor.id C) X = X := rfl | ||
@[simp] lemma id.on_morphisms {X Y : C} (f : X ⟶ Y) : (functor.id C).map f = f := rfl |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these should be named id_obj
and id_map
to match the new functor names, same with comp
and vcomp
, hcomp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed, thanks!
{ app := λ X, 𝟙 (F X), | ||
naturality := begin /- `obviously'` says: -/ intros, dsimp, simp end } | ||
|
||
@[simp] lemma id.app (F : C ↝ D) (X : C) : (nat_trans.id F) X = 𝟙 (F X) := rfl |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we usually use _
instead of .
for theorems referring to a definition unless it makes sense with projection notation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
This is just the start of a PR of my category theory library.
I'm very happy to add components to this PR if it is easier to see more things in context.
I am not attached at all to any of the notational choices, and am quite happy to change these. (I do really want to keep a notation like the current
f ≫ g
for "do f, then g", but don't mind the symbol.)