Zulip Chat Archive
Stream: maths
Topic: bundling mul_homs
Kevin Buzzard (Jul 18 2019 at 04:21):
Mathlib has the unbundled is_mul_hom
class (a Prop), and then it has mul_equiv
which references this unbundled is_mul_hom
. If we were to bundle mul_hom
s, how would we define mul_equiv
?
import data.equiv.basic algebra.group import data.equiv.algebra variables {α : Type*} {β : Type*} {γ : Type*} [has_mul α] [has_mul β] [has_mul γ] (M : Type*) (N : Type*) (P : Type*) [has_mul M] [has_mul N] [has_mul P] /- Mathlib: class is_mul_hom {α β : Type*} [has_mul α] [has_mul β] (f : α → β) : Prop := (map_mul : ∀ x y, f (x * y) = f x * f y) structure mul_equiv (α β : Type*) [has_mul α] [has_mul β] extends α ≃ β := (hom : is_mul_hom to_fun) notation ≃* for mul_equiv, proved to be reflexive, symmetric and transitive -- not yet found a use for this instance. Should `is_mul_hom` be a structure? instance (h : α ≃* β) : is_mul_hom h.to_equiv := h.hom -/ namespace mul /-- bundled homs FTW -/ structure hom (M N : Type*) [has_mul M] [has_mul N] := (f : M → N) (map_mul : ∀ x y, f (x * y) = f x * f y) -- but now if I delete `is_mul_hom`, how do I define `mul_equiv`? -- notation for homs infix ` →* `:25 := hom
Mario Carneiro (Jul 18 2019 at 04:22):
mul_equiv A B extends equiv A B, mul_hom A B
Kevin Buzzard (Jul 18 2019 at 04:23):
Should I be using old or new structures for these things?
Mario Carneiro (Jul 18 2019 at 04:23):
old structures FTW
Kevin Buzzard (Jul 18 2019 at 04:23):
Is what you call mul_hom
what I called mul.hom
?
Kevin Buzzard (Jul 18 2019 at 04:23):
Did I name it wrong?
Mario Carneiro (Jul 18 2019 at 04:23):
I don't think so
Mario Carneiro (Jul 18 2019 at 04:24):
mul_hom A B
for me is the type of augmented functions from A to B
Kevin Buzzard (Jul 18 2019 at 04:24):
but mul.hom
has got a field f
and equiv
has got a field to_fun
and these are supposed to be defeq and have the same name.
Mario Carneiro (Jul 18 2019 at 04:24):
I don't see mul.hom
in the example
Mario Carneiro (Jul 18 2019 at 04:25):
Oh there it is
Kevin Buzzard (Jul 18 2019 at 04:25):
I'm talking about my attempt to bundle homs.
Mario Carneiro (Jul 18 2019 at 04:25):
I think that should be mul_hom
Mario Carneiro (Jul 18 2019 at 04:25):
mul
isn't a namespace
Mario Carneiro (Jul 18 2019 at 04:26):
mul_hom
should have a field called to_fun
Mario Carneiro (Jul 18 2019 at 04:26):
so that mul_equiv
works
Kevin Buzzard (Jul 18 2019 at 04:31):
to_fun
is such a horrible name for a function. I guess its canonical name is the coercion so maybe it doesn't matter. Wait -- the map from mul_equiv X Y
to mul_hom X Y
-- that is no longer an instance, because mul_hom
isn't a class. Is this still done with coercions somehow?
Mario Carneiro (Jul 18 2019 at 04:32):
it's a function called to_mul_hom
Mario Carneiro (Jul 18 2019 at 04:32):
You can try using a coercion but this one tends to trigger rarely
Mario Carneiro (Jul 18 2019 at 04:34):
given that the parent functions are always called to_*
, to_fun
seems to match that naming convention
Kevin Buzzard (Jul 18 2019 at 04:55):
structure mul_hom (M N : Type*) [has_mul M] [has_mul N] := (to_fun : M → N) (map_mul : ∀ x y, to_fun (x * y) = to_fun x * to_fun y)
Should this have a coercion to fun?
Mario Carneiro (Jul 18 2019 at 04:56):
yes
Kevin Buzzard (Jul 18 2019 at 05:03):
My map_mul
is crappy:
set_option old_structure_cmd true /-- bundled homs FTW -/ structure mul_hom (M N : Type*) [has_mul M] [has_mul N] := (to_fun : M → N) (map_mul : ∀ x y, to_fun (x * y) = to_fun x * to_fun y) -- notation for homs infix ` →* `:25 := mul_hom instance : has_coe_to_fun (M →* N) := { F := λ _, M → N, coe := mul_hom.to_fun } #check mul_hom.map_mul /- mul_hom.map_mul : ∀ (c : ?M_1 →* ?M_2) (x y : ?M_1), c.to_fun (x * y) = c.to_fun x * c.to_fun y -- yeah but I want it to be the coercion, not `c.to_fun` -/
It has come out non-canonically. Am I supposed to be doing this:
def mul_hom.map_mul' : ∀ (f : M →* N) (x y : M), f (x * y) = f x * f y := mul_hom.map_mul
?
Mario Carneiro (Jul 18 2019 at 05:04):
with the primes inverted
Kevin Buzzard (Jul 18 2019 at 05:04):
So you're saying I need to change mathlib
Kevin Buzzard (Jul 18 2019 at 05:04):
no
Kevin Buzzard (Jul 18 2019 at 05:05):
you're saying I need to change my structure field's name.
Mario Carneiro (Jul 18 2019 at 05:05):
yes
Kevin Buzzard (Jul 18 2019 at 05:25):
Should this
structure mul_equiv' (A B) [has_mul A] [has_mul B] extends equiv A B, mul_hom A B
have a coercion to fun?
Mario Carneiro (Jul 18 2019 at 05:31):
yes
Kevin Buzzard (Jul 18 2019 at 05:56):
import data.equiv.basic algebra.group import data.equiv.algebra variables {α : Type*} {β : Type*} {γ : Type*} [has_mul α] [has_mul β] [has_mul γ] (M : Type*) (N : Type*) (P : Type*) [has_mul M] [has_mul N] [has_mul P] -- Recall that the unbundled definition of a mul_hom -- and the definition of a mul_equiv, with notation ≃*, are in mathlib. /- Mathlib: -- in root namespace class is_mul_hom {α β : Type*} [has_mul α] [has_mul β] (f : α → β) : Prop := (map_mul : ∀ x y, f (x * y) = f x * f y) -- root namespace structure mul_equiv (α β : Type*) [has_mul α] [has_mul β] extends α ≃ β := (hom : is_mul_hom to_fun) notation ≃*, proved to be reflexive, symmetric and transitive (note: it is not a Prop) -/ --. We will define -- bundled homomorphisms of muls, with notation →*, and bundled -- equivs, with notation ≃*' set_option old_structure_cmd true /-- bundled homs -/ structure mul_hom (M N : Type*) [has_mul M] [has_mul N] := (to_fun : M → N) (map_mul' : ∀ x y, to_fun (x * y) = to_fun x * to_fun y) -- notation for homs infix ` →* `:25 := mul_hom -- I want to think of a hom as a function sometimes instance : has_coe_to_fun (M →* N) := { F := λ _, M → N, coe := mul_hom.to_fun } /-- the statement that mul_homs preserve mul, in its canonical form -/ def mul_hom.map_mul : ∀ (f : α →* β) (x y : α), f (x * y) = f x * f y := mul_hom.map_mul' -- for structures like this you need to prove `id` and `comp` next. namespace mul_hom /-- the identity is a mul_hom-/ def id : M →* M := {to_fun := id, map_mul' := λ _ _, rfl} /-- composite of mul_homs is a mul_hom -/ def comp (f : α →* β) (g : β →* γ) : α →* γ := { to_fun := λ m, g (f m), map_mul' := λ x y, by rw [map_mul f, map_mul g] } end mul_hom /-- mul_equiv' (bundled mul_equiv -- the name mul_equiv is currently nicked by unbundled mul_equiv) -/ structure mul_equiv' (A B) [has_mul A] [has_mul B] extends equiv A B, mul_hom A B -- notation for mul_equiv' infix ` ≃*' `:25 := mul_equiv' instance : has_coe_to_fun (M ≃*' N) := { F := _, coe := mul_equiv'.to_fun } def mul_equiv'.map_mul : ∀ (f : α ≃*' β) (x y : α), f (x * y) = f x * f y := mul_equiv'.map_mul' -- now need reflexive, symmetric and transitive namespace mul_equiv' @[refl] def refl (α : Type*) [has_mul α] : α ≃*' α := { map_mul' := λ x y, rfl, ..equiv.refl α} -- this one did not go so well. @[symm] def symm (h : α ≃*' β) : β ≃*' α := { map_mul' := λ n₁ n₂, function.injective_of_left_inverse h.left_inv begin show h.to_fun (h.inv_fun (n₁ * n₂)) = h (h.inv_fun n₁ * h.inv_fun n₂), -- annoying to have to `show` rw h.right_inv, rw h.map_mul, convert rfl, -- annoying to have to `convert`. This should surely just be rewrites. exact h.right_inv _, exact h.right_inv _, end, ..h.to_equiv.symm} @[trans] def trans (h1 : α ≃*' β) (h2 : β ≃*' γ) : (α ≃*' γ) := { map_mul' := λ x y, show h2 (h1 (x * y)) = h2 (h1 x) * h2 (h1 y), by rw [h1.map_mul, h2.map_mul], ..equiv.trans h1.to_equiv h2.to_equiv } -- an ≃*' is a hom def equiv'.to_hom (h : M ≃*' N) : M →* N := { to_fun := h.to_equiv, map_mul' := h.map_mul' } def equiv'.inv_hom (h : M ≃*' N) : N →* M := { to_fun := h.symm.to_equiv, map_mul' := h.symm.map_mul } end mul_equiv'
equiv'.symm
didn't go well but most of the other stuff looks OK to me
Mario Carneiro (Jul 18 2019 at 06:00):
People will complain about the order of arguments to comp
Johan Commelin (Jul 18 2019 at 06:01):
@Kevin Buzzard You probably know this but mul_hom.map_mul
should be a lemma, and it is a very good simp-lemma.
Mario Carneiro (Jul 18 2019 at 06:01):
What's wrong with symm
? It looks like that's the sort of thing that is mathematically substantive anyway
Johan Commelin (Jul 18 2019 at 06:02):
In fact, that's the most important reason for bundling in the first place. That this is a simp-lemma that actually triggers.
Johan Commelin (Jul 18 2019 at 06:02):
Also, we'll want simp-lemmas id_apply
and comp_apply
.
Kevin Buzzard (Jul 18 2019 at 06:25):
Kevin Buzzard You probably know this but
mul_hom.map_mul
should be a lemma, and it is a very good simp-lemma.
I'm not very good at simp
still.
Kevin Buzzard (Jul 18 2019 at 11:49):
So anyway, there is a bunch of structure most of which is correctly named, and hopefully defined sensibly. Do we want all all of this in mathlib? And then there's the equivalent stuff for semigroup
, for monoid
and for group
. I don't care about the mul
stuff really, I was just practicing. I do care about equivs of monoids and of groups and would like some students to prepare a mathlib PR.
What are we looking for in such a PR? Should the students try and define everything for semigroup
when we don't really need it? Is a PR of this nature for group
welcome? @Chris Hughes do you have any opinions on this? I've talked to you before about it and you seem to have a clear head about what should be there.
Kevin Buzzard (Jul 18 2019 at 11:50):
Note that we can define group.hom
to be mul_hom
Kevin Buzzard (Jul 18 2019 at 11:50):
I think the last time we talked about this, you liked that idea.
Chris Hughes (Jul 18 2019 at 12:08):
Don't bother with semigroup
stuff unless it's virtually no effort. I'd actually prefer group_hom
and monoid_hom
to be the same, since these are the two that are actually used. You could write a custom constructor without the unnecessary axiom.
Same idea goes for ring_hom
and semiring_hom
Kevin Buzzard (Jul 18 2019 at 12:16):
so you're saying you want group.hom
to be called group_hom
and to demand that f(1)=1
?
Kevin Buzzard (Jul 18 2019 at 12:16):
What should the custom constructor be called?
Chris Hughes (Jul 18 2019 at 12:26):
Yes @[reducible] def group_hom := monoid_hom
.
group_hom.mk
Chris Hughes (Jul 18 2019 at 12:27):
That way, simp lemmas you prove about monoid_hom
s will work with group homs.
Kevin Buzzard (Jul 18 2019 at 18:15):
And should this be reducible too? [sorry for prime on mul_equiv, mathlib has a slightly more unbundled one]
def monoid_equiv (M N) [monoid M] [monoid N] := mul_equiv' M N
Johan Commelin (Jul 18 2019 at 18:18):
Is it clear that making some of these definitions does not create leakage?
Kevin Buzzard (Jul 18 2019 at 18:19):
I am just experimenting. I will certainly report back.
Johan Commelin (Jul 18 2019 at 18:21):
Also, I think Lean is quite bad at dealing with situations like this:
I have M1 M2 : Type
and [monoid M1] [monoid M2]
I also have f : monoid_hom M1 M2
.
Then, for some reason, it happens that I can actually prove that M1
and M2
are groups.
Now I need to work to turn f
into a group hom. And if I don't do that, certain lemma's can't be applied, and simp
gets stuck etc...
Kevin Buzzard (Jul 18 2019 at 18:22):
This won't happen with Chris' suggesting of defining group_hom
to be equal to monoid_hom
Johan Commelin (Jul 18 2019 at 18:22):
I know it is not very beginner-friendly. But I'm becoming more and more of the opinion that we shouldn't have these "shadowing" classes. Like vector_space
(and even module
). And so, maybe we should also just get rid of group_hom
s
Johan Commelin (Jul 18 2019 at 18:22):
Nope, that's not true.
Kevin Buzzard (Jul 18 2019 at 18:22):
and making it reducible
Johan Commelin (Jul 18 2019 at 18:22):
If I have a module over a field, I can't apply linear algebra results.
Johan Commelin (Jul 18 2019 at 18:23):
Even if vector_space
is reducibly defined to be a module.
Johan Commelin (Jul 18 2019 at 18:23):
This has bitten me several times.
Kevin Buzzard (Jul 18 2019 at 18:24):
We need some way of being able to talk about group homomorphisms. What is your suggestion? Unbundled homs? I thought this had problems too?
Johan Commelin (Jul 18 2019 at 18:24):
No, it's somewhat orthogonal to bundling, but it's very much related to refactoring.
Johan Commelin (Jul 18 2019 at 18:24):
I want to propose/discuss just ditching group_hom
altogether.
Johan Commelin (Jul 18 2019 at 18:25):
Just write monoid_hom.mk'
for the case that you construct monoid homs between groups.
Johan Commelin (Jul 18 2019 at 18:25):
It doesn't look nice... but it is more flexible.
Kevin Buzzard (Jul 18 2019 at 18:26):
This has bitten me several times.
If you try to fix it by making the actual object you want from the object you have (e.g. the vector space over the field from the module), then you then have two objects which mathematicians find completely indistinguishable, but for which Lean finds it hard to port results about one object to results from the other. This sounds like a good place to try out a transfer tactic, no?
Johan Commelin (Jul 18 2019 at 18:27):
Meh... I would rather let the problem go away.
Johan Commelin (Jul 18 2019 at 18:27):
Maybe group_hom
can be an abbreviation
?? I still don't know what this does exactly.
Johan Commelin (Jul 18 2019 at 18:28):
But it seems to be something like hyper-super-duper-reducible
.
Chris Hughes (Jul 18 2019 at 18:28):
And should this be reducible too? [sorry for prime on mul_equiv, mathlib has a slightly more unbundled one]
def monoid_equiv (M N) [monoid M] [monoid N] := mul_equiv' M N
That shouldn't exist
Johan Commelin (Jul 18 2019 at 18:29):
For the same reason that vector_space
shouldn't exist?
Kevin Buzzard (Jul 18 2019 at 18:34):
I want to propose/discuss just ditching
group_hom
altogether.
If we ditch group_hom
altogether, what will be the canonical way of representing the concept of with with , groups?
Kevin Buzzard (Jul 18 2019 at 18:35):
def monoid_equiv (M N) [monoid M] [monoid N] := mul_equiv' M NThat shouldn't exist
If that doesn't exist at all, then what happens to the poor newbie who shows up with their two monoids and wants to know where the equiv is?
Johan Commelin (Jul 18 2019 at 18:37):
We tell them to use M1 =* M2
.
Johan Commelin (Jul 18 2019 at 18:37):
If we ditch group_hom
you just write f : G →m H
Johan Commelin (Jul 18 2019 at 18:37):
Or whatever the notation for monoid homs will be.
Chris Hughes (Jul 18 2019 at 18:41):
I started on ->1*
, but I propose ->*
, and screw mul homs notation.
Kevin Buzzard (Jul 18 2019 at 19:11):
So notation can attempt to solve the issue. Chris are you proposing the notation with no 1 to be overloaded? I am mostly interested in group homs and isoms because a student of mine needs them asap
Chris Hughes (Jul 18 2019 at 19:16):
I'm proposing no notation for mul homs, since they're rarely used.
Kevin Buzzard (Jul 18 2019 at 20:12):
then what term is ->*
notation for?
Kevin Buzzard (Jul 18 2019 at 20:12):
I am happy to implement your idea but I don't understand it yet. I would just like isomorphisms and bundled homomorphisms of groups sooner rather than later.
Kevin Buzzard (Jul 18 2019 at 20:13):
I want to do more experiments with the bundled morphisms approach.
Chris Hughes (Jul 18 2019 at 20:13):
monoid homs
Kevin Buzzard (Jul 18 2019 at 20:14):
A monoid hom has this extra condition that 1 goes to 1. So we define monoid_hom
, and we can make \equiv\_g
be notation for monoid_hom
.
Johan Commelin (Jul 18 2019 at 20:15):
Sure, so Chris is saying →*
for monoid homs and group homs. No notation for mul_hom
.
Kevin Buzzard (Jul 18 2019 at 20:15):
and we could also make \equiv\_m
be notation for monoid_hom
for when we're working with moniods, and then Lean's prettyprinter would have an impossible notation problem to solve.
Johan Commelin (Jul 18 2019 at 20:15):
And \equiv*
might be a nice fit for mul_equiv
(and we don't need monoid_equiv
or group_equiv
).
Kevin Buzzard (Jul 18 2019 at 20:16):
So we just tell the user in comments in the group section: "the notation for group homomorphisms is ->*
and the notation for group isomorphisms is \equiv*
"
Johan Commelin (Jul 18 2019 at 20:17):
Sure... and because the notation is somewhat natural it is even avoiding the awkard f : monoid_hom G H
for group homs.
Johan Commelin (Jul 18 2019 at 20:17):
I think this is quite a nice solution.
Kevin Buzzard (Jul 18 2019 at 20:19):
That's quite interesting that the force of the mathematical interpretation ->*
is "I preserve everything relevant to multiplication that is present"
Johan Commelin (Jul 18 2019 at 20:19):
The special constructor could be
def group_hom {G H : Type} [group G] [group H] (h : f (x*y) = f x * f y) : G →* H := sorry
Kevin Buzzard (Jul 18 2019 at 20:20):
If you defined monoids to mathematicians and then said "OK now what do you think means?" they'd be like "monoid hom I guess"
Johan Commelin (Jul 18 2019 at 20:20):
(That example didn't type check, but you get the idea.)
Kevin Buzzard (Jul 18 2019 at 20:21):
But Chris seems to be explictly suggesting that the name group_hom
is never assigned. Is this what you think @Chris Hughes ?
Johan Commelin (Jul 18 2019 at 20:21):
What I'm saying is that monoid_hom.mk
is a bad name for constructing monoid homs between groups.
Kevin Buzzard (Jul 18 2019 at 20:22):
These are all such irrelevances, there must be some solution with automation or something. Mathematically we are doing absolutely nothing at all.
Johan Commelin (Jul 18 2019 at 20:22):
I've been saying time and again that Fabian can auto-generate all of these.
Johan Commelin (Jul 18 2019 at 20:22):
But people don't really seem to care.
Kevin Buzzard (Jul 18 2019 at 20:26):
@Mario Carneiro we need computer science help. We have a very rigorous notion of "the same" here -- this seems to me like this is type class inference in a tangle. Do you understand why we are struggling? Why can't Johan do linear algebra with a module over a field? @Johan Commelin can you give a MWE? We need to get good at this.
Mario Carneiro (Jul 18 2019 at 20:41):
I think that more names for the same thing is bad for formalization, although I understand why it is mathematically desirable. I am on board with Chris's suggestions
Kevin Buzzard (Jul 18 2019 at 20:44):
We also need the additive
version of everything, I suppose? That entire process can be automated. Can you literally to a regex on the file to generate its additive version? And then you can look observe the funny fact that there are two olean files which are exactly the same
Mario Carneiro (Jul 18 2019 at 20:44):
While I don't want to minimize Fabian's work, the proofs are not the hard part here. This is all API design questions
Kevin Buzzard (Jul 18 2019 at 20:44):
Right. I'm trying really hard to make a mathematician's API.
Kevin Buzzard (Jul 18 2019 at 20:45):
I now have a much better understanding of the issues here and I think it's a really important question for drawing mathematicians in. We want to make it look easy.
Kevin Buzzard (Jul 18 2019 at 20:47):
I think we might be losing half our audience at
inductive nat | zero : what does all this weird stuff mean
We just want to say "The naturals are , typed \N
and they work exactly as you would expect them to". Implementing this is not a trivial thing at all!
Mario Carneiro (Jul 18 2019 at 20:50):
I heartily disagree
Kevin Buzzard (Jul 18 2019 at 20:50):
"It goes without saying that if and are isomorphic comm_ring
s then is Gorenstein iff is. It does not need a proof. "
Kevin Buzzard (Jul 18 2019 at 20:50):
that one is not proving trivial to implement
Mario Carneiro (Jul 18 2019 at 20:50):
hardcoding what "they work exactly as you would expect" means is just making lean more "magical" and less comprehensible
Mario Carneiro (Jul 18 2019 at 20:51):
which is setting yourself up for failure
Kevin Buzzard (Jul 18 2019 at 20:51):
You guys worry too much about these tedious implementation issues
Mario Carneiro (Jul 18 2019 at 20:52):
That's not an implementation issue, it's a pedagogy issue
Kevin Buzzard (Jul 18 2019 at 20:52):
We're never going to run the code we're making, you don't need to optimise it
Kevin Buzzard (Jul 18 2019 at 20:52):
We just want to eat every proposition and every proof bit by bit
Mario Carneiro (Jul 18 2019 at 20:52):
if lean has tons of special cases then it's big and complicated to learn. This is not an exaggeration, it's already the case
Mario Carneiro (Jul 18 2019 at 20:56):
implementing transfer
is hard because type theory is big and complicated
Kevin Buzzard (Jul 18 2019 at 20:57):
You should just solve it with pointers or something
Mario Carneiro (Jul 18 2019 at 21:03):
:expressionless:
Mario Carneiro (Jul 18 2019 at 21:05):
That said, transfer
is already implemented and mostly works. As I've said many times, what is needed is not a tactic but lemmas for it to use
Kevin Buzzard (Jul 18 2019 at 21:08):
So mathematicians have a gigantic list of abstract mathematical ideas. And for each of these ideas computer scientists have developed some term in type theory, or perhaps some token (the mathematical symbol of isomorphism comes to mind), and said "look here it is", and then we say "Thanks. Does it do this, this, that and this?" and you guys go "Yes of course. And it does a gazillion other things too like look you can see inside it and you can do that if you want" and we say "no thanks, we just need this this that and this. We will now promise that any future terms will be built using that interface. In return, you must understand our notion of equality, which you can work out from the interface I suppose"
Examples: the real numbers, a group, the localisation of a ring, the module of one-forms for an algebra over a ring, or a sheaf on a space.
Mario Carneiro (Jul 18 2019 at 21:09):
Except that sometimes you break the interface and pretend you didn't
Mario Carneiro (Jul 18 2019 at 21:11):
Reading the MO question I was amused that no one noticed that is not an isomorphism-invariant statement. They say "we know isomorphisms don't matter so we may as well assume it's the case" but then it's not isomorphism invariant anymore
Kevin Buzzard (Jul 18 2019 at 21:12):
I find those endless comments very hard to read.
Mario Carneiro (Jul 18 2019 at 21:13):
I think that statement showed up in one of the answers
Kevin Buzzard (Jul 18 2019 at 21:13):
Was it the one I accepted?
Mario Carneiro (Jul 18 2019 at 21:15):
https://mathoverflow.net/a/336233/34444
Mario Carneiro (Jul 18 2019 at 21:16):
Relatedly, we can assume that because we only care about the axiomatized properties of , which are preserved under isomorphism. One could manually preserve the original as an actual subset of its quadratic extension, but that is unnecessary for the reason I just stated.
This reasoning fails to take into account that by taking advantage of isomorphism invariance you break it
Kevin Buzzard (Jul 18 2019 at 21:16):
There are also two deleted answers with positive scores which degenerated into flamewars resulting in the OP just deleting everything
Mario Carneiro (Jul 18 2019 at 21:17):
I saw the comment but I'm not high rep on MO so I can't read it :(
Mario Carneiro (Jul 18 2019 at 21:17):
Andrej usually has interesting things to say
Mario Carneiro (Jul 18 2019 at 21:20):
To me the process is tedious but straightforward. We need equiv.rel
in mathlib, and then a bunch of isomorphism builders, and a bunch of isomorphism statements, and then this will be easy
Mario Carneiro (Jul 18 2019 at 21:22):
Don't come to me about making a tactic to do it until you've already done it 10 times and know what it looks like
Kevin Buzzard (Jul 18 2019 at 21:22):
I think Andrej and I follow each other on Twitter; I'll prod him.
Kevin Buzzard (Jul 18 2019 at 21:32):
What is the role that this predicate should play? We define the Cauchy reals, and we prove that they are a complete arch field, and then we prove that any two complete arch fields are uniquely isomorphic as ordered fields. We then have this type real
and this promise that we will only use complete_archimedean_ordered_field real
or whatever. We have given you a precise interface here. What you now need to do somehow is to make this a primitive object -- I would quite happily be in an environment where the real type and its instance as a complete archimedean ordered field was some structure and a bunch of axioms. Why can't we use this abstraction for the reals and only have access to this interface?
Kevin Buzzard (Jul 18 2019 at 21:34):
It would presumably be easier to reason about proof transportability if you knew the proof had stuck to the interface.
Mario Carneiro (Jul 18 2019 at 21:34):
I'm talking about transfer specifically. This is independent of any interface to the reals you may or may not be adhering to
Kevin Buzzard (Jul 18 2019 at 21:34):
I want a little bit of HoTT magic at exactly this point
Kevin Buzzard (Jul 18 2019 at 21:34):
So tell me again what transfer specifically means?
Mario Carneiro (Jul 18 2019 at 21:35):
To me the process is tedious but straightforward. We need
equiv.rel
in mathlib, and then a bunch of isomorphism builders, and a bunch of isomorphism statements, and then this will be easy
Mario Carneiro (Jul 18 2019 at 21:36):
The only way to get, provably in lean, invariance from syntax generically is if you have a deeply embedded language and express all your properties in that language. I'm sure we don't want to do that
Kevin Buzzard (Jul 18 2019 at 21:36):
Will this tedious but straightforward process be easier to do in Lean 4?
Mario Carneiro (Jul 18 2019 at 21:36):
not particularly
Kevin Buzzard (Jul 18 2019 at 21:36):
So we may as well start right away :-)
Mario Carneiro (Jul 18 2019 at 21:37):
like I said, stop thinking of tactics and start thinking about the problem
Kevin Buzzard (Jul 18 2019 at 21:37):
Isn't the immediate problem that someone has to write some meta code?
Mario Carneiro (Jul 18 2019 at 21:37):
Once you know what the problem is and what the solution is the tactic writes itself
Mario Carneiro (Jul 18 2019 at 21:37):
no
Mario Carneiro (Jul 18 2019 at 21:37):
meta code comes later
Mario Carneiro (Jul 18 2019 at 21:38):
proofs come first
Mario Carneiro (Jul 18 2019 at 21:40):
Tactics never allow you to prove something you couldn't prove before. They just make it easier to do things you already knew how to do
Kevin Buzzard (Jul 18 2019 at 21:40):
So maybe a tactic which does this would be interesting: I will define the Dedekind reals in Lean, prove they're a complete arch ordered field, and then demand from you a copy of the Bochner integral but all with Dedekind reals instead of Cauchy reals.
Kevin Buzzard (Jul 18 2019 at 21:40):
Do I "know how to do that"? Is this one we're going to solve with tags?
Mario Carneiro (Jul 18 2019 at 21:41):
You don't, that's the problem
Kevin Buzzard (Jul 18 2019 at 21:41):
the idea is that any PR to mathlib which didn't use the allowable interface would not be accepted.
Kevin Buzzard (Jul 18 2019 at 21:42):
So you just have to write some regex to check that people aren't fiddling with the real's privates
Kevin Buzzard (Jul 18 2019 at 21:42):
and run all PR's through the regex to check for safety
Mario Carneiro (Jul 18 2019 at 21:42):
The safety check is not the problem, the equivalence proofs are
Kevin Buzzard (Jul 18 2019 at 21:42):
and if they pass you can accept the PR and then some Lean code generates a proof that all the stuff in mathlib is still "safe"
Mario Carneiro (Jul 18 2019 at 21:43):
Even if we know everything is safe that doesn't provide a proof of equivalence
Kevin Buzzard (Jul 18 2019 at 21:43):
So what formally is the problem?
Mario Carneiro (Jul 18 2019 at 21:43):
You have already stated it: Given a concrete predicate P on rings prove that if A and B are isomorphic rings then P(A) iff P(B)
Kevin Buzzard (Jul 18 2019 at 21:43):
Surely it provides a proof that the term exists, it just doesn't actually make the term.
Kevin Buzzard (Jul 18 2019 at 21:44):
Why isn't that P(A) iff P(B) thing easy?
Mario Carneiro (Jul 18 2019 at 21:44):
It is
Kevin Buzzard (Jul 18 2019 at 21:44):
You just peel P apart and do it by induction
Mario Carneiro (Jul 18 2019 at 21:44):
Yes, so do it
Kevin Buzzard (Jul 18 2019 at 21:44):
You mean it's hard to implement?
Mario Carneiro (Jul 18 2019 at 21:44):
No, it's easy
Mario Carneiro (Jul 18 2019 at 21:44):
but it's work
Kevin Buzzard (Jul 18 2019 at 21:45):
I can't do it, I have my decency.
Mario Carneiro (Jul 18 2019 at 21:45):
and it needs to actually be in mathlib
Kevin Buzzard (Jul 18 2019 at 21:45):
It's not maths.
Mario Carneiro (Jul 18 2019 at 21:45):
transfer
will not work until mathlib is full of theorems like that
Kevin Buzzard (Jul 18 2019 at 21:45):
that's an axiom, you guys have to do that one :-) I would have no idea how to do it. Is it the sort of thing a novice tactic-writer could try?
Mario Carneiro (Jul 18 2019 at 21:46):
If you don't know how to do it, how would a novice know?
Kevin Buzzard (Jul 18 2019 at 21:46):
I mean maybe they can just read Programming In Lean and then just do it
Mario Carneiro (Jul 18 2019 at 21:46):
A novice tactic writer can generalize from examples, but we have none
Mario Carneiro (Jul 18 2019 at 21:46):
once we have done it by hand 10 times a novice tactic writer can do the rest
Kevin Buzzard (Jul 18 2019 at 21:46):
So what needs doing in practice?
Kevin Buzzard (Jul 18 2019 at 21:47):
What's the first thing that needs to be done?
Mario Carneiro (Jul 18 2019 at 21:47):
equiv.rel
, isomorphism builders, and theorems of the form A ~= B -> P(A) <-> P(B)
Kevin Buzzard (Jul 18 2019 at 21:47):
Are there some sorts of milestones which you can see to making this transfer
tactic?
Kevin Buzzard (Jul 18 2019 at 21:47):
So what is the type of equiv.rel
?
Mario Carneiro (Jul 18 2019 at 21:48):
equiv.rel (e : A ~= B) : A -> B -> Prop := \lam a b, e a = b
Mario Carneiro (Jul 18 2019 at 21:49):
This allows you to state a theorem of the form A ~= B -> P(A) <-> P(B)
as e.rel => iff
where =>
is that funny relator operation
Kevin Buzzard (Jul 18 2019 at 21:49):
oh so that one's done now, right?
Mario Carneiro (Jul 18 2019 at 21:50):
You need a few theorems about it
Mario Carneiro (Jul 18 2019 at 21:50):
the most important ones for transfer is that it is left and right unique
Kevin Buzzard (Jul 18 2019 at 21:50):
OK so is there some structure I need to make on equiv.rel?
Mario Carneiro (Jul 18 2019 at 21:50):
and the converse is given by equiv.rel of the inverse equiv
Mario Carneiro (Jul 18 2019 at 21:51):
I think left_unique
and right_unique
are typeclasses
Mario Carneiro (Jul 18 2019 at 21:52):
If you look at logic.relator
there are several functions related to this sort of thing
Kevin Buzzard (Jul 18 2019 at 21:57):
Just to be clear -- the e : A =~ B
notation -- the type of e
is just some random type T A B
, or does it have to have some sort of equivalence relation properties?
Mario Carneiro (Jul 18 2019 at 21:58):
e
is an equiv
Mario Carneiro (Jul 18 2019 at 21:59):
not a fancy equiv, just an equiv
Mario Carneiro (Jul 18 2019 at 22:00):
More complicated things would have something like (e.to_equiv.rel => iff) Gorenstein Gorenstein
where e
is a ring equiv
Jeremy Avigad (Jul 18 2019 at 22:00):
@Kevin Buzzard I can't resist a bit of history here. Read Dedekind's Was sind und was sollen die Zahlen (1888), roughly "What are the [natural] numbers and what should they be." See especially the introduction. (It is the second essay here: http://www.gutenberg.org/files/21016/21016-pdf.pdf.) The answer to the question posed in the title is expressed more clearly in his letter to Keferstein: http://www.bris.ac.uk/media-library/sites/structuralism/migrated/documents/kerfstein.pdf. It is as you say: We don't care what they are, as long as they satisfy the properties we want. We only need to construct one to show that the notion is coherent. Then, if as long as we respect the interface, anything we say about one will be true of the other. (The part about respecting the interface is in Section 134 on page 48 of the essay.) In modern terms, he gave an axiomatic characterization of the natural numbers, a set theoretic construction (from the assumption that there exists an infinite set), and a proof that any two systems satisfying the axioms are isomorphic.
Dedekind was an early proponent of a modern, structural view of mathematics, at a time when the subject had a much more calculational style. According to van der Waerden, Emmy Noether used to say "Es steht alles schon bei Dedekind," i.e. everything is already there, in Dedekind.
Kevin Buzzard (Jul 18 2019 at 22:11):
I have seen all this stuff before but I just never really understood its depth until recently
Kevin Buzzard (Jul 18 2019 at 23:10):
But in some sense it really is not mathematics. This whole thing is just a tedious implementation issue.
Kevin Buzzard (Jul 18 2019 at 23:10):
Everything is already there, in Dedekind.
Andrew Ashworth (Jul 19 2019 at 10:57):
Maybe the old usage of transfer
to prove properties about ints-as-pairs-of-naturals should be the in mathlib docs, i.e. https://github.com/leanprover/lean/blob/6ab792733d09878d82ce98d88f6f476c8e0f34d8/library/init/data/int/basic.lean
Kevin Buzzard (Jul 19 2019 at 18:22):
import data.equiv.basic import logic.relator def equiv.rel {A B : Type*} (e : A ≃ B) : A → B → Prop := λ a b, e a = b variables {A : Type*} {B : Type*} (e : A ≃ B) instance : relator.left_unique (equiv.rel e) := λ a₁ b a₂ h1 h2, equiv.injective e $ eq.trans h1 h2.symm instance : relator.right_unique (equiv.rel e) := λ a b₁ b₂ h1 h2, eq.trans h1.symm h2
What next?
Mario Carneiro (Jul 19 2019 at 18:24):
pick a simple predicate or construction and try to prove its isomorphism theorem
Kevin Buzzard (Jul 19 2019 at 19:02):
lemma rel_imp : (iff ⇒ (iff ⇒ iff)) implies implies :=
this logic.relator
file is pretty cool :-)
But didn't @Scott Morrison and/or @Simon Hudon write a bunch of this sort of code years ago?
Kevin Buzzard (Jul 19 2019 at 19:02):
the lemma below looks like some experimental new one way traffic system
Kevin Buzzard (Jul 19 2019 at 19:02):
lemma rel_iff : ((↔) ⇒ (↔) ⇒ (↔)) (↔) (↔) := ...
Mario Carneiro (Jul 19 2019 at 19:03):
It's a new way to write *_congr
lemmas
Mario Carneiro (Jul 19 2019 at 19:04):
For the proof, I would just unfold the notations straight away until I know what I'm doing. The transfer
tactic knows how to put the lemmas together without unfolding them
Kevin Buzzard (Jul 19 2019 at 19:06):
Kevin Buzzard (Jul 19 2019 at 19:07):
We've talked about this stuff before and I have just about enough control of Zulip search to be able to find some of it.
Mario Carneiro (Jul 19 2019 at 19:08):
There's another old post where I prove isomorphism theorem for maximal ideals this way
Mario Carneiro (Jul 19 2019 at 19:08):
Kevin Buzzard (Jul 19 2019 at 19:09):
And there was definitely one where I started talking about this sort of thing and was asking how to make a transfer tactic, and Simon and Scott just talked about it for a while and then I think Scott wrote a tonne of code, and there was quite an active period during which you (Mario) were asleep, and then you woke up and checked Zulip and were like "wooah you guys have moved fast" or something. I'd really like to find that thread.
Kevin Buzzard (Jul 19 2019 at 19:10):
At the time I just remember not understanding the issues well enough, and hence being unable to understand the code properly
Kevin Buzzard (Jul 19 2019 at 19:11):
It was some code which went through a fair few primitives and proved a lemma about each of them, and then started proving lemmas about other things all hands-on.
Kevin Buzzard (Jul 19 2019 at 19:12):
Maybe there was also talk about using tags for transfer, and using typeclass resolution to tag more and more stuff as "still OK if replaced by isomorphic thing"
Mario Carneiro (Jul 19 2019 at 19:12):
oh that's right there was a respects_isomorphism
typeclass IIRC
Mario Carneiro (Jul 19 2019 at 19:13):
I forget the actual name
Kevin Buzzard (Jul 19 2019 at 19:13):
Each time this transfer conversation occurs I learn quite a lot about the idea, but I still have work to do.
Kevin Buzzard (Jul 19 2019 at 23:55):
import data.real.basic instance notation.sub_eq_add_neg (X : Type) [has_add X] [has_neg X] : has_sub X := ⟨λ a b, a + -b⟩ class has_field_notation (X : Type) extends has_zero X, has_one X, has_mul X, has_add X, has_neg X -- note: don't use has_sub -- because it might cause a diamond now instance : has_field_notation ℝ := by refine {};apply_instance class complete_ordered_archimedean_field (X : Type) [has_field_notation X] : Prop := (all_the_axioms : ∀ x y : X, x + y = y + x) -- ... (etc : ∀ x : X, 1 * x = 1) -- boring proof omitted instance cauchy_reals_are_complete : complete_ordered_archimedean_field ℝ := sorry structure Reals := (X : Type) [h : has_field_notation X] (e : complete_ordered_archimedean_field X) def CauchyReals : Reals := { X := ℝ, h := by apply_instance, e := cauchy_reals_are_complete } structure ordered_field_equiv (X Y : Type) [has_field_notation X] [has_field_notation Y] [complete_ordered_archimedean_field X] [complete_ordered_archimedean_field Y] extends equiv X Y -- add extra axioms here theorem all_reals_are_the_same (X : Type) [has_field_notation X] [complete_ordered_archimedean_field X] : ∃ e : ordered_field_equiv X ℝ, true := sorry -- boring proof omitted class platonist_friendly (P : set Reals) : Prop := (e : ∀ X : Reals, P X ↔ P CauchyReals) instance (P Q : set Reals) [platonist_friendly P] [platonist_friendly Q] : platonist_friendly (P ∩ Q) := ⟨λ X, begin show P X ∧ Q X ↔ P CauchyReals ∧ Q CauchyReals, rw [_inst_1.e, _inst_2.e] end⟩
I didn't look at your work yet, I just thought I'd try and work out some concepts with this Cauchy / Dedekind reals thing.
One could even play the same game with the Lau Rationals (the field of fractions of ) vs the computer science rationals in mathlib.
Kevin Buzzard (Jul 20 2019 at 00:02):
Is the idea that a tactic can generate instances of the platonist_friendly
class, by induction on P somehow? There are no relators above so they are also clearly offering something which I've not yet understood. And finally there is this question which does not appear to be addressed by the above -- if I prove some theorem about some Bochner integral of some function being equal to pi, how do I mark this theorem with the "there is a version of me for Dedekind reals and indeed for all terms of type Reals" tag?
Mario Carneiro (Jul 20 2019 at 00:22):
What relators bring to the table is the ability to deal with n-ary predicates, with a variety of equivalences on the inputs (one type might be in bijection, the other is a module and there's a module iso, and then relative to the first equiv some elements a and b are related)
Mario Carneiro (Jul 20 2019 at 00:23):
This is necessary for making the "proof by induction" go through
Mario Carneiro (Jul 20 2019 at 00:23):
which is why I'm not supportive of the typeclass approach
Mario Carneiro (Jul 20 2019 at 00:25):
The relator way to write platonist_friendly P
is (e.rel => iff) P P
where e
is an ordered field equiv
Mario Carneiro (Jul 20 2019 at 00:28):
well that's not quite accurate since you bundled Reals
. Normally you would use some relation R : Reals -> Reals -> Prop
asserting that the two elements of Reals
are isomorphic, but in the case of Reals
that's the trivially true relation
Kevin Buzzard (Jul 20 2019 at 08:55):
Yes, the reals are somehow an easier case, the universal predicate applies to types with field notation and is just the assertion that they're complete ordered Archimedean fields which is enough to make them "the same as" the platonic reals
Kevin Buzzard (Jul 21 2019 at 02:25):
I bundled subthings and morphisms of things!
import data.equiv.basic class thing (α : Type) : Type. -- insert data here (usually notation and some axioms) variables {α β γ: Type} [thing α] [thing β] [thing γ] class is_subthing (s : set α) : Prop := true -- this class should not exist. Sometimes you see it in mathlib though. set_option old_structure_cmd true structure subthing (α : Type) [thing α] := (carrier : set α) (proof : is_subthing carrier) -- replace with notation closure axioms e.g. one_mem, mul_mem etc. Note that is_subthing is never used again. instance : has_coe_to_sort (subthing α) := ⟨_, subthing.carrier⟩ instance : has_coe (subthing α) (set α) := ⟨subthing.carrier⟩ -- another deprecated class def is_thing_morphism (f : α → β) : Prop := true -- this class should not exist. Sometimes you see it in mathlib though. -- I won't bother making it into a class. It's deprecated. structure thing_morphism α β [thing α] [thing β]:= (to_fun : α → β) (h : is_thing_morphism to_fun) -- replace with notation-preserving axioms e.g. map_one, map_mul.... Note that `is_thing_morphism` never occurs again infixr ` →t `:25 := thing_morphism instance : has_coe_to_fun (α →t β) := { F := λ _, α → β, coe := thing_morphism.to_fun} lemma thing_morphism.ext (f g : α →t β) : (f : α → β) = g → f = g := begin intro h, cases f, cases g, rwa thing_morphism.mk.inj_eq, end -- bundled equivs using old structure command so no `to_fun` problems structure thing_equiv α β [thing α] [thing β] extends equiv α β, thing_morphism α β infix ` ≃t `:25 := thing_equiv namespace thing_equiv instance : has_coe_to_fun (thing_equiv α β) := { F := λ _, α → β, coe := to_fun} theorem ext {f g : thing_equiv α β} (h : (f : α → β) = g) : f = g := begin cases f, cases g, rw thing_equiv.mk.inj_eq, refine equiv.mk.inj _;try {assumption}, change f_to_fun = g_to_fun at h, refine equiv.ext _ _ _, exact congr_fun h, end lemma coe_inj : function.injective (thing_equiv.to_equiv : thing_equiv α β → equiv α β) := begin intros f g h, apply ext, -- is this idiomatic? show ⇑(to_equiv f) = _, rw h, refl, end @[refl] protected def refl (α : Type) [thing α] : α ≃t α := { h := trivial,..equiv.refl α} @[symm] protected def symm (e : α ≃t β) : β ≃t α := { h := trivial,..e.to_equiv.symm} @[trans] protected def trans (e1 : β ≃t γ) (e2 : α ≃t β) : α ≃t γ := { h := trivial,..e2.to_equiv.trans e1.to_equiv} -- perms def perm (α : Type) [thing α] := thing_equiv α α instance : has_one (perm α) := ⟨thing_equiv.refl α⟩ instance : has_mul (perm α) := ⟨thing_equiv.trans⟩ -- goodness knows if this is "right" or whether I should swap instance : has_inv (perm α) := ⟨thing_equiv.symm⟩ instance : group (perm α) := { mul := (*), one := 1, inv := λ x, x⁻¹, mul_assoc := λ _ _ _, ext rfl, one_mul := λ _, ext rfl, mul_one := λ _, ext rfl, mul_left_inv := λ f, ext $ begin funext x, exact f.left_inv x end} end thing_equiv
I got as far as the automorphism group of a thing.
Kevin Buzzard (Jul 21 2019 at 02:31):
Now someone can knock off a tactic and we can just bundle everything instantly.
Kevin Buzzard (Jul 21 2019 at 02:31):
@Sian Carey
Kevin Buzzard (Jul 21 2019 at 04:14):
@Chris Hughes my understanding is that you want bundled monoid_hom
but no definition of group_hom
. Could there still be a group_hom
namespace though?
Kevin Buzzard (Jul 21 2019 at 04:45):
I want to define field homomorphisms between $fields$ which I guess are called discrete_field
. Chris / @Mario Carneiro -- what do you people want the bundled class to be called (discrete_field_hom
, field_hom
, ring_hom
, semiring_hom
...) and exactly what instances to you want Lean to ask for in the actual definition of the structure? (e.g. map_zero
follows from map_add
because everything is a field in my case of interest, so we don't need it, but I don't care if map_zero
is a field or not, I just want to do it right).
Mario Carneiro (Jul 21 2019 at 04:47):
Are semiring_hom
, ring_hom
and field_hom
all the same?
Kevin Buzzard (Jul 21 2019 at 04:47):
yes but I thought Chris was arguing that some of these things shouldn't even be tokens.
Mario Carneiro (Jul 21 2019 at 04:48):
Of those ring_hom
is my favorite
Kevin Buzzard (Jul 21 2019 at 04:49):
I thought he suggested that group_hom
be not defined, ->*
be notation for monoid_hom
which also demands map_one
and just tell the user to use the right notation for group homs which happens to coincide with the notation for monoid homs. They will never have to make one with their bare hands hopefully :-)
Mario Carneiro (Jul 21 2019 at 04:50):
We can do the same thing with field homs - call it ring_hom
, but it's really a semiring hom and you use it for semirings and fields too
Kevin Buzzard (Jul 21 2019 at 04:50):
If field_hom
is not even defined, can there still be a field_hom
namespace? Does that ever happen in mathlib?
Mario Carneiro (Jul 21 2019 at 04:50):
There can be a namespace
Mario Carneiro (Jul 21 2019 at 04:51):
Although you will miss out on dot notation
Kevin Buzzard (Jul 21 2019 at 04:52):
but theorems which are specific for fields, such as injectivity of the underlying map, naturally live there I think...oh, I see your point.
Kevin Buzzard (Jul 21 2019 at 04:53):
Is ->*+
horrible notation for a ring hom?
Mario Carneiro (Jul 21 2019 at 04:54):
lgtm
Kevin Buzzard (Jul 21 2019 at 04:54):
I want a LaTeX right-arrow with a + and a * floating over it when we're doing the controlled natural language thing; this notation is just a temporary thing
Mario Carneiro (Jul 21 2019 at 04:56):
You don't have to convince me, I find this kind of notation more palatable than random selections from the unicode arrow palette
Kevin Buzzard (Jul 21 2019 at 04:56):
@Kenny Lau what is the categorification of subring R
?
Kenny Lau (Jul 21 2019 at 04:56):
mathematically?
Kevin Buzzard (Jul 21 2019 at 04:57):
Is it ring_hom A R
or injective_ring_hom A R
?
Kevin Buzzard (Jul 21 2019 at 04:57):
Is the question mathematically meaningful?
Kenny Lau (Jul 21 2019 at 04:57):
https://ncatlab.org/nlab/show/subobject
Kenny Lau (Jul 21 2019 at 04:57):
it's an isomorphism class of monomorphisms
Kevin Buzzard (Jul 21 2019 at 04:57):
Thanks.
Kevin Buzzard (Jul 21 2019 at 05:03):
So I think you're saying it's injective_ring_hom
.
Kevin Buzzard (Jul 21 2019 at 05:04):
injective
is a predicate on ring_hom
.
Kevin Buzzard (Jul 21 2019 at 05:04):
which implies monic
Kevin Buzzard (Jul 21 2019 at 05:05):
Is this something to do with topologies on categories?
Kevin Buzzard (Jul 21 2019 at 05:07):
These categories -- lattices -- are the best categories in Lean. Do we have topologies on these categories?
Kevin Buzzard (Jul 21 2019 at 05:23):
structure ring_equiv (R S : Type) [ring R] [ring S] extends (R ≃ S), (R →+* S)
Kevin Buzzard (Jul 21 2019 at 05:24):
end of definition
Kenny Lau (Jul 21 2019 at 05:41):
These categories -- lattices -- are the best categories in Lean. Do we have topologies on these categories?
we have... Groethendieck topologies
Kevin Buzzard (Jul 21 2019 at 06:47):
Is monic
an example?
Kenny Lau (Jul 21 2019 at 06:50):
of what?
Kevin Buzzard (Jul 21 2019 at 06:58):
Something that satisfies the axioms for the admissible morphisms in a grothendieck topology
Kenny Lau (Jul 21 2019 at 07:01):
grothendieck topology needs admissible families of morphisms right
Kenny Lau (Jul 21 2019 at 07:01):
I can say that { A_i -> A } is admissible if the images generate the whole ring
Scott Morrison (Jul 21 2019 at 08:14):
abbreviation ring_equiv (R S : Type) [ring R] [ring S] := Ring.of R ≅ Ring.of S
Yury G. Kudryashov (Jul 21 2019 at 09:10):
@Scott Morrison The definition with ≅
has two drawbacks.
1. It only works for R
and S
in the same universe.
2. It's harder to define elements of this type. Currently, ≃*
etc ask for a proof of to_fun
being a hom
, and automatically deduce that inv
is a hom
.
Kevin Buzzard (Jul 21 2019 at 12:10):
2 can be solved with a constructor. 1 I personally don't care about because I am a mathematician
Kevin Buzzard (Jul 21 2019 at 15:43):
Can we use function composition notation with bundled homs? If f : thing_hom A B
and g : thing_hom B C
then can we have f \circ g : thing_hom A C
or whichever way round you want it? Does one just overload notation in this situation?
Yury G. Kudryashov (Jul 21 2019 at 18:42):
Possibly, we can have something like has_comp
and use it.
Yury G. Kudryashov (Jul 21 2019 at 18:43):
Though it means overriding notation from core.
Yury G. Kudryashov (Jul 21 2019 at 18:44):
(of course, we can use some other symbol)
Scott Morrison (Jul 21 2019 at 20:13):
... Kevin, is bring able to talk about things in different universes so important to you that you're willing to give up the completely uniform notation for morphisms, composition, isomorphism, tensor product, etc, notation that the category theory API provides?
Kevin Buzzard (Jul 21 2019 at 21:04):
I know I know, but the category theory API bundles objects which makes it scary. I don't know how to glue sheaves using the category theory version of sheaves.
Kevin Buzzard (Jul 28 2019 at 18:42):
linear_equiv
is defined with the old structure command, and mul_equiv
with the new one. In practice this means that mul_equiv
just has a field to_equiv
and then all the equiv stuff like left_inv
comes off that:
import linear_algebra.basic #print linear_equiv -- long #print mul_equiv -- short #check linear_equiv.left_inv -- works #check mul_equiv.left_inv -- fails
Which is best?
Chris Hughes (Jul 28 2019 at 19:51):
Old structures are the best.
Andrew Ashworth (Jul 28 2019 at 19:51):
So the disadvantage with the new structure command is that if you want to use properties of equiv
, you have to explicitly write to_equiv
. The advantage of new structures is that they are faster.
Andrew Ashworth (Jul 28 2019 at 19:53):
My rule of thumb is: use old structures if the thing you are describing is a genuine mathematical object. Use a new structure if it's just a universal property.
Kevin Buzzard (Jul 28 2019 at 19:56):
So all the structures we built in the perfectoid project -- for example adic spaces -- should all be using the old structure command?
Kevin Buzzard (Jul 28 2019 at 19:57):
@Chris Hughes it's about time we started calling them "good old structures" and "the good old structure command".
Andrew Ashworth (Jul 28 2019 at 19:57):
well, they're equivalent, in a sense, so no need to rewrite things that don't need to be rewritten
Andrew Ashworth (Jul 28 2019 at 19:57):
in fact, if you've already done it using new structures
Andrew Ashworth (Jul 28 2019 at 19:57):
you should keep them that way. after all, they are faster
Andrew Ashworth (Jul 28 2019 at 20:01):
maybe a better rule of thumb is: use a new structure, unless you get annoyed with always having to write to_equiv
Andrew Ashworth (Jul 28 2019 at 20:03):
the most important difference is new structures can't have duplicate fields
Chris Hughes (Jul 28 2019 at 20:05):
It's just a pain to use the constructor for new structures.
Andrew Ashworth (Jul 28 2019 at 20:06):
yes, in the original description of new structures, Leo assumed a bunch of the tactics would be updated to transparently handle it all. Well, it didn't
Kevin Buzzard (Jul 28 2019 at 20:07):
We never really ran into these issues as far as I remember -- our main goal was a definition, and our structures just got bigger and bigger but we were lucky not to ever run into duplicate substructures.
Kevin Buzzard (Jul 28 2019 at 20:07):
The tactics didn't get updated, or they couldn't be updated?
Andrew Ashworth (Jul 28 2019 at 20:07):
didn't get updated
Andrew Ashworth (Jul 28 2019 at 20:09):
I guess also since we have no idea what's happening in Lean 4, maybe prefer and start with new structures and hope they are easier to work with whenever the new version gets released
Andrew Ashworth (Jul 28 2019 at 20:10):
ahh, so you see, in my last three paras I've given completely contradictory advise
Andrew Ashworth (Jul 28 2019 at 20:11):
I suppose I don't know which one to prefer either :)
Kevin Buzzard (Jul 29 2019 at 15:46):
Here's a question about mul_equiv
s. I really don't know how to set these up. So far I have gone for the old structure command, extending equiv
and adding a field map_mul
. The problem is with proving things like symmetry. I have goals like
h.to_fun ((equiv.symm (to_equiv h)).to_fun (n₁ * n₂)) = h.to_fun ((equiv.symm (to_equiv h)).to_fun n₁ * (equiv.symm (to_equiv h)).to_fun n₂)
which I really just want to put into a canonical form and then rewrite/simp to death. But the problem is that the canonical form of h.inv_fun
seems to be h.symm
when h
is an equiv
, and if I define symm
on mul_equiv
then I have to reprove stuff like symm_apply_apply
in this situation.
Kenny Lau (Jul 29 2019 at 15:48):
yeah but the proof is just equiv.symm_apply_apply
Kevin Buzzard (Jul 29 2019 at 15:48):
but I can't rewrite it
Kevin Buzzard (Jul 29 2019 at 15:49):
In fact my first question is what the canonical notation for the inverse bijection should be with h : mul_equiv G H
Chris Hughes (Jul 29 2019 at 15:51):
Prove that f.symm.to_equiv = f.to_equiv.symm
and make it simp
Kevin Buzzard (Jul 29 2019 at 15:51):
I think my issue is that I am in the middle of defining mul_equiv.symm
and I am complaining about not being able to use the canonical notation h.symm
when stating some intermediate result, but this is spurious because h.symm
is in the process of being defined.
Yury G. Kudryashov (Aug 09 2019 at 18:40):
Hi, I was away for some time. It seems that monoid_hom
and add_monoid_hom
are already bundled. I have a few questions about the implementation:
1. Why do we repeat all the proofs instead of using to_additive
? My guess is “to provide docstrings” but we can use tactic.add_doc_string
. Actually, the new docstring can be turned into the second optional argument to to_additive
.
2. I see that M
, N
, G
, H
is used for monoids/groups. Doesn't it break the naming conventions? I'm trying to understand how strict is the style guide w.r.t. naming convention.
3. If I want to migrate, say, polynomial.C
to monoid_hom
, the definition will look like def C {α} ... : α →* polynomial α
, and C (1 : α)
fails to coerce C
to a function. It works, if I make α
a mandatory argument but this is not convenient.
Kevin Buzzard (Aug 09 2019 at 18:43):
1. because I only really worked out the full power of to_additive
today (see a thread in #general).
2. Yes it breaks the naming conventions. Computer scientists get a lot of things right about names, but I believe that one of very few exceptions is here. If a computer scientist wants to a call a group alpha and a normal subgroup beta and then some auxiliary set gamma then that's fine by me, but if we call the group G and the normal subgroup N and the auxiliary set S then it is much easier to see at a glance what is happening, especially if variables are being used and the definitions of alpha and beta are 150 lines up.
3. Probably @Chris Hughes will have something to say on the matter.
Kevin Buzzard (Aug 09 2019 at 18:44):
https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/to_additive.20and.20tags
Kevin Buzzard (Aug 09 2019 at 18:45):
See https://github.com/leanprover-community/mathlib/blob/659533e1dc63074d3386ffb8b2fbed50151dd34c/src/group_theory/submonoid.lean#L344 for the kind of code I am writing now. I think this is better -- I repeat almost nothing.
Yury G. Kudryashov (Aug 09 2019 at 18:48):
@Kevin Buzzard Thanks for explanations. I'd like to help with migrating to bundled hom. What can I work on to avoid duplication of effort?
Kevin Buzzard (Aug 09 2019 at 18:50):
You would be more than welcome to help @Amelia Livingston and me with all the to_additive stuff. As you can see we got up to line 569. Amelia also refactored localisation.lean
in that branch, to see how things look with the changes, and they seemed fine. We did not think about polynomials though.
Yury G. Kudryashov (Aug 09 2019 at 18:51):
E.g., I can rewrite algebra/group/hom
using to_additive
. Is it OK?
Kevin Buzzard (Aug 09 2019 at 18:51):
Here's a message I sent Amelia earlier today:
So what I currently believe is this. Say you have made 10 definitions and proved 20 lemmas in the namespace submonoid and you want to get additive versions in add_submonoid. The one thing which can almost always be avoided is having to write out a proof twice, once in the multiplicative and once in the additive case.
The best possible scenario is when defining a lemma; in this case you can use @[to_additive add_submonoid.foo] and that might be almost all you need to do; this will hopefully generate the proof automatically. Unfortunately it doesn't generate the docstring automatically and you have to add it with this run_cmd which which I don't really understand. There are plenty of examples in the commit I pushed today (all in this bundled_submonoids branch of mathlib).
More complicated is a definition. I have been writing definition submonoid.foo ..., getting it working, and then writing #print prefix submonoid.foo (note that you need submonoid even if you're in the submonoid namespace). You then see submonoid.foo but also perhaps submonoid.foo.match_1 or submonoid.foo.equations_eqn3 or something. For structures you see loads of things. After the definition you can write to_additive [add_submonoid.foo.proof_3] submonoid.foo.proof_3 and this needs to be done for everything in the output. However it all has to be done in the right order. If you get red squiggles under a to_additive then look at the error, see if it mentions add_submonoid.foo.equation_2 and then move the corresponding to_additive line above the line with the error. In all cases I got this to work. And don't forget the docstring. Note that in one case the errors I got were errors involving functions which I had not defined -- other people had missed out the to_additive tags on other functions, so I had to add those in (they should probably be moved to the correct part of mathlib at some point).
Even more complicated is a structure. I have been defining the additive ones by hand. And there are some lemmas or definitions which don't port, for example those involving powers x^n turn into ones involving smultiples n \bub x and because the order got switched to_additive sometimes can't handle it. In these cases I leave the submonoid namespace immediately, define the additive one by hand (i.e. write the same code again), do all the to_additive tags and the docstring, and then go back into the submonoid namespace. You then have to re-input all the variables which you had open in that namespace. Variables outside a namespace survive inside it, but variables inside a namespace die once the namespace is closed, even if you go back in.
Kevin Buzzard (Aug 09 2019 at 18:53):
Everything we have done is in the bundled_submonoids
branch of mathlib and our plan was to finish submonoid.lean
and then make a PR.
Kevin Buzzard (Aug 09 2019 at 18:55):
We didn't touch the hom
file so it will be OK.
Yury G. Kudryashov (Aug 09 2019 at 18:55):
Probably, one of us should learn more about Lean tactic language, and let to_additive
handle mydef._proof_n
and all those mystruct.cases_on
etc.
Another idea is to have @[bundled_hom]
user attr that defines has_coe_to_fun
and restates all axioms using coe
instead of f.to_fun
.
Yury G. Kudryashov (Aug 09 2019 at 18:57):
OK, then I'll go through hom
, then I'll try to migrate concrete categories (Mon
etc.) to bundled homs.
Kevin Buzzard (Aug 09 2019 at 18:58):
Bundling group and monoid and ring stuff (subthings, homs and isomorphisms) is just a one-off job which needs to be done once. The reason I am motivated to do it now is because I think it makes it easier for mathematicians -- but I am not sure about this. Other people also believe it's best to do things like bundle homs and subobjects, for other reasons. What became clear to me was that the task of actually removing unbundled homs and replacing them with bundled ones is a vast task, because is_submonoid appears 200 times in the library and one of the appearances is in the definition of is_subgroup
which appears 200 more times, and then is_subring
uses both of these etc etc.
Kevin Buzzard (Aug 09 2019 at 19:01):
Furthermore, the switch would be one huge PR which would take a very long time to write and would have to constantly be playing catch-up with the library. This sounded very unappealing. So my plan is to bundle stuff, leave the unbundled stuff in for now (but mention that it is deprecated in docstrings) and then start changing leaf nodes to see if things work. Amelia changed localisation.lean
and it worked fine. But changing stuff deeper in mathlib is painful. So our plan is to work from the outside in. The disadvantage of our approach is that ultimately it will in some sense be more work, probably. The advantage is that we can access bundled homs immediately, which is what I wanted really.
Patrick Massot (Aug 09 2019 at 19:54):
I'm very worried about this thread. For the sensitivity conjecture project, I worked seriously with linear maps for the first time. They are bundled, and it simply does not work. The coercion to function works completely randomly, and there are instance search timeout all over the place. It's extremely time-consuming and frustrating to fight that
Mario Carneiro (Aug 09 2019 at 19:57):
Bundled maps have much lower pressure on the typeclass system, because you aren't inferring the fact that the function is a hom anymore
Mario Carneiro (Aug 09 2019 at 19:58):
I can believe that the coercion is problematic sometimes though. The alternative is to write .to_fun
Patrick Massot (Aug 09 2019 at 19:58):
but coercions are part of the type class system
Patrick Massot (Aug 09 2019 at 19:58):
The alternative doesn't work, because lemmas are stated without .to_fun
Mario Carneiro (Aug 09 2019 at 19:59):
Personally, I would happily live with to_fun
everywhere. I put the coercions in because you guys are always going on about nice looking notation and lean 3 provides few other opportunities for this kind of thing
Patrick Massot (Aug 09 2019 at 20:00):
This is really sad
Yury G. Kudryashov (Aug 09 2019 at 20:00):
/me prefers Python
-style obj.__call__
convention over typeclass resolution
Mario Carneiro (Aug 09 2019 at 20:01):
I agree completely (to both statements)
Yury G. Kudryashov (Aug 09 2019 at 20:09):
@Mario Carneiro What's are the other opportunities in Lean 3 for this kind of thing?
Mario Carneiro (Aug 09 2019 at 20:10):
for zero-notation functions, nothing, but if you are willing to accept a character or two you can use a notation
Yury G. Kudryashov (Aug 09 2019 at 20:12):
BTW, what's wrong with dropping has_coe_to_fun
and using f.1
?
Yury G. Kudryashov (Aug 09 2019 at 20:13):
Forgot to tag @Kevin Buzzard
Patrick Massot (Aug 09 2019 at 20:13):
This is really not how we think about maps
Yury G. Kudryashov (Aug 09 2019 at 20:22):
@Patrick Massot I see the following options:
1. the old way; pros: already implemented; easy to say that the same map can be is_mul_hom
or is_monoid_hom
under different assumptions; cons: need to find is_*_hom
instances here and there; what else?
2. bundled homs, implicit coercion; pros: map_mul
and map_one
are right there; M →* N
is exactly Mon.of M \--> Mon.of N
(not yet); cons: need to find has_coe_to_fun
every time; sometimes this coercion fails;
3. bundled homs, f.1
; pros: see 2 + no class instance resolution at all; cons: unnatural notation.
What do I miss?
Patrick Massot (Aug 09 2019 at 20:55):
I don't see what I could add here. Type class inference doesn't work in Lean 3, and it doesn't provide error messages
Patrick Massot (Aug 09 2019 at 21:02):
2. Yes it breaks the naming conventions. Computer scientists get a lot of things right about names, but I believe that one of very few exceptions is here. If a computer scientist wants to a call a group alpha and a normal subgroup beta and then some auxiliary set gamma then that's fine by me, but if we call the group G and the normal subgroup N and the auxiliary set S then it is much easier to see at a glance what is happening, especially if variables are being used and the definitions of alpha and beta are 150 lines up.
I also wanted to comment on that. The linear algebra library uses the random greek letter convention, and it's really a nightmare. They are lots of type involved, and not knowing which one is meant to be a base field, an indexing type or a vector space is really awful. They are tons of lemmas whose statements are very hard to parse, and would be very easy with reasonable type naming conventions.
Yury G. Kudryashov (Aug 09 2019 at 21:10):
Then maybe docs/contribute/naming.md
should be adjusted.
Yury G. Kudryashov (Aug 09 2019 at 21:10):
With some sensible theory-specific naming conventions.
Patrick Massot (Aug 09 2019 at 21:10):
I'd love that
Kevin Buzzard (Aug 09 2019 at 22:10):
+1 from me.
Kevin Buzzard (Aug 09 2019 at 22:12):
@Yury G. Kudryashov the reason I'm bundling is because the community seems to think it's the best idea. To a certain extent it might just be about experimenting to find out what works best. I have seen coercions fail before and you can just write (f : G -> H) to make them happen; I quite like that notation
Kevin Buzzard (Aug 09 2019 at 23:03):
The one place where I feel that the alpha beta notation is natural is when dealing with types that really are that -- just types. For example equiv alpha beta
seems fine to me because for all I know this is what computer scientists really call types. But types which are playing a mathematical role such as groups have got such a history of notation behind them and it's used to guide readers, and I don't see the point of throwing it away. Sure some people use for a number field and some use , but nobody uses . The number field library that will one day be written will need to choose a notation, but it should, in my opinion, use one which is already in use.
Andrew Ashworth (Aug 10 2019 at 00:50):
morally speaking isn't it [G : group alpha]
?
Scott Morrison (Aug 10 2019 at 01:07):
It is really unfortunate the coercions to function types barely work. I think this is the main pain point with bundling.
Yury G. Kudryashov (Aug 10 2019 at 08:44):
@Andrew Ashworth Groups are not bundled, so after [G : group α]
you still have to say x : α
, and this is not very readable, especially if you have, e.g., a group acting on a space.
Kevin Buzzard (Aug 10 2019 at 09:12):
Mathematicians read x : α
as and they are far more used to . In fact this is in some sense exactly the point -- if I see in the middle of a maths paper without any context then I would be likely to guess that was a group and an element. If I see x : α
in a library file then I have no clue.
Yury G. Kudryashov (Aug 15 2019 at 17:48):
@Kevin Buzzard I rewrote to_additive
to automatically take care of many things. I'll try to PR it tonight or tomorrow. Current state (no docs, WIP) is available at https://github.com/urkud/mathlib/blob/to_additive/src/algebra/group/to_additive.lean
Yury G. Kudryashov (Aug 15 2019 at 17:51):
Namely, (1) it automatically adds to_additive
attribute to structure fields; (2) it looks for prefixes in dict
instead of full names; (3) it automatically transfers decl._proof_1
, decl._match_1
etc . With (2), we don't need to have attribute [to_additive add_monoid_hom.cases_on] monoid_hom.cases_on
etc.
Kevin Buzzard (Aug 15 2019 at 17:52):
I'm away from Lean until Monday (camping)
Kevin Buzzard (Aug 15 2019 at 17:52):
Feel free to take a look at the bundled submonoids branch
Yury G. Kudryashov (Aug 15 2019 at 17:53):
@Kevin Buzzard Good luck with camping!
Kevin Buzzard (Aug 15 2019 at 17:53):
@Amelia Livingston did you push everything you have? The submonoid.lean file is half toadditiveised
Amelia Livingston (Aug 15 2019 at 17:55):
Not yet, I'm tidying things up a bit but I will push today. I've not toadditiveised anything yet.
Yury G. Kudryashov (Aug 15 2019 at 18:09):
@Amelia Livingston It should be easier to use @[to_additive]
with my changes, so you should probably postpone to_additive
isation for a day or two. I'll try to tidy my patch tonight.
Amelia Livingston (Aug 15 2019 at 18:10):
Okay. Thank you for working on it!
Yury G. Kudryashov (Aug 16 2019 at 14:49):
@Amelia Livingston I pushed a new version of @[to_additive]
to the to_additive
branch of urkud/mathlib
.
It automates:
- mapping of structure fields;
- mapping of hidden defs like
name._proof_1
,name._match_1
; - mapping of projections like
semigroup.to_has_mul
(relies on@[ancestor]
attributes); - mapping of
name.cases_on
by mapping prefixes instead of names.
Yury G. Kudryashov (Aug 16 2019 at 15:03):
Other items I want to add before making a PR:
- take docstring as an optional argument; alternative is to use
run_cmd add_doc_string
after each definition; - autogenerate target namespace using
to_additive_attr.get_param src.get_prefix
; ask for the suffix only; - make “target name” argument optional;
- simple: use the same suffix as in the source name, e.g.
monoid_hom.comp
→add_monoid_hom.comp
; - advanced: parse suffix replacing
mul→add
,one→zero
,prod→sum
(what else?).
- simple: use the same suffix as in the source name, e.g.
- automatically create
target.equations._eqn_1
.
Yury G. Kudryashov (Aug 16 2019 at 15:16):
@Mario Carneiro what is responsible for creating my_name.equations._eqn_1
? Is it intentional that this thing is called after normal def
s but not after add_decl
s?
Floris van Doorn (Aug 16 2019 at 15:35):
I think it's the equation compiler who adds those equalities. add_decl
(and its relatives, like add_inductive
) indeed doesn't have the same side effects (like creating auxiliary definitions) as adding a declaration normally. It's probably useful to have both the version with and without side-effects, and it was suggested previously to expose versions with side effects in the community fork of Lean.
Yury G. Kudryashov (Aug 16 2019 at 15:51):
@Floris van Doorn Then I'll postpone automatic handling of equations till we have add_decl_with_side_effects
.
Mario Carneiro (Aug 16 2019 at 16:58):
it's already available in community lean
Yury G. Kudryashov (Aug 18 2019 at 15:42):
See https://github.com/leanprover-community/mathlib/pull/1345 for the new to_additive
. It seems that I've broken compilation in one of the last commits. I'll fix it tonight.
Last updated: Dec 20 2023 at 11:08 UTC