Zulip Chat Archive

Stream: general

Topic: group with zero


Johan Commelin (Mar 24 2020 at 12:01):

For the perfectoid project we need gadgets of the form Γ{0}\Gamma \cup \{0\}, and we formalised this using a type class group_with_zero. Examples are (i) fields and division rings, (ii) nnreal, (iii) with_zero G for any group G.

It would be very helpful if we could inject this structure below field in the algebraic hierarchy. What is the best way to do this? Should I make a PR to core lean? Can this be done without touching core? Should fields be moved out of core to mathlib?

Mario Carneiro (Mar 24 2020 at 12:10):

Would it suffice to have a typeclass instance?

Mario Carneiro (Mar 24 2020 at 12:11):

instance [field F] : group_with_zero F := ...

Mario Carneiro (Mar 24 2020 at 12:12):

(also, I think this should assume division_ring instead, no? field would give you a comm_group_with_zero)

Johan Commelin (Mar 24 2020 at 12:12):

Yes, division_ring is better.

Mario Carneiro (Mar 24 2020 at 12:15):

what are the axioms of group_with_zero?

Johan Commelin (Mar 24 2020 at 12:16):

class group_with_zero (α : Type*)
  extends monoid α, has_inv α, zero_ne_one_class α, mul_zero_class α :=
[has_decidable_eq : decidable_eq α]
(inv_zero : (0 : α)⁻¹ = 0)
(mul_inv_cancel :  a:α, a  0  a * a⁻¹ = 1)

Johan Commelin (Mar 24 2020 at 12:16):

The decidable_eq is an artifact

Mario Carneiro (Mar 24 2020 at 12:17):

I forget where we ended up regarding decidable_eq for division_ring

Mario Carneiro (Mar 24 2020 at 12:17):

I think we just use classical logic, in which case it would be consistent to do the same here

Johan Commelin (Mar 24 2020 at 12:18):

Yes, this is old code

Johan Commelin (Mar 24 2020 at 12:31):

@Mario Carneiro The reason that it would be really nice to inject it below division_ring is that lemmas like inv_zero could have a nice name and work for both of the cases. Currently we need to use group_with_zero.inv_zero because the assumptions on inv_zero are "too strong".

Mario Carneiro (Mar 24 2020 at 12:31):

meh, that's already done in core in a few places

Johan Commelin (Mar 24 2020 at 12:31):

Idem dito for

@[simp] lemma mul_inv_cancel' (a : G) (h : a  0) : a * a⁻¹ = 1 :=
group_with_zero.mul_inv_cancel a h

@[simp] lemma mul_inv_cancel_assoc_left (a b : G) (h : b  0) :
  (a * b) * b⁻¹ = a :=
calc (a * b) * b⁻¹ = a * (b * b⁻¹) : mul_assoc _ _ _
               ... = a             : by simp [h]

@[simp] lemma mul_inv_cancel_assoc_right (a b : G) (h : a  0) :
  a * (a⁻¹ * b) = b :=
calc a * (a⁻¹ * b) = (a * a⁻¹) * b : (mul_assoc _ _ _).symm
               ... = b             : by simp [h]

lemma inv_ne_zero' (a : G) (h : a  0) : a⁻¹  0 :=
assume a_eq_0, by simpa [a_eq_0] using mul_inv_cancel' a h

@[simp] lemma inv_mul_cancel' (a : G) (h : a  0) : a⁻¹ * a = 1 :=
calc a⁻¹ * a = (a⁻¹ * a) * a⁻¹ * a⁻¹⁻¹ : by simp [inv_ne_zero' _ h]
         ... = a⁻¹ * a⁻¹⁻¹             : by simp [h]
         ... = 1                       : by simp [inv_ne_zero' _ h]

@[simp] lemma inv_mul_cancel_assoc_left (a b : G) (h : b  0) :
  (a * b⁻¹) * b = a :=
calc (a * b⁻¹) * b = a * (b⁻¹ * b) : mul_assoc _ _ _
               ... = a             : by simp [h]

@[simp] lemma inv_mul_cancel_assoc_right (a b : G) (h : a  0) :
  a⁻¹ * (a * b) = b :=
calc a⁻¹ * (a * b) = (a⁻¹ * a) * b : (mul_assoc _ _ _).symm
               ... = b             : by simp [h]

Mario Carneiro (Mar 24 2020 at 12:32):

for example most of the division_ring lemmas have namespace division_ring because they conflict with group lemmas

Johan Commelin (Mar 24 2020 at 12:32):

Is there a reason why field and division_ring should stay in core?

Johan Commelin (Mar 24 2020 at 12:32):

Mario Carneiro said:

for example most of the division_ring lemmas have namespace division_ring because they conflict with group lemmas

Right, and now we'll have a third conflict. Why not reduce them?

Johan Commelin (Mar 24 2020 at 13:20):

mk0 will also be duplicated.

Johan Commelin (Mar 24 2020 at 13:20):

Although that one is in mathlib. So we could deduplicate, I guess.

Kevin Buzzard (Mar 24 2020 at 13:42):

Johan Commelin said:

Mario Carneiro said:

for example most of the division_ring lemmas have namespace division_ring because they conflict with group lemmas

Right, and now we'll have a third conflict. Why not reduce them?

I don't think there will be a third conflict. For lemmas about division there are two kinds -- those that work under no assumptions about zero-ness (perhaps because they are theorems about monoids or groups, which don't have a zero) and those which have explicit assumptions that something has to be non-zero. The group ones v the field ones, basically.

In fact can you just load all the group_with_zero lemmas into monoid but just ask for the typeclass with_zero on your monoid, and also with_inv if you want it to be a group with 0. How many of them work with that set-up?

Johan Commelin (Mar 24 2020 at 13:54):

I meant a third naming conflict.

Johan Commelin (Mar 24 2020 at 16:17):

@Mario Carneiro We will get two definitions of has_div on division rings...

Mario Carneiro (Mar 24 2020 at 16:18):

that are defeq?

Kevin Buzzard (Mar 24 2020 at 16:24):

You can't just do some old structure command magic?

Johan Commelin (Mar 24 2020 at 16:25):

The fields of the has_div structure are defeq

Johan Commelin (Mar 24 2020 at 16:25):

But that's not good enough, right?

Johan Commelin (Mar 24 2020 at 16:26):

What is the reason that we try to keep fields in core?

Johan Commelin (Mar 24 2020 at 16:26):

I understand that nat has to be in core. And hence add_monoid must be in core. But everything starting from rings and beyond?? Could go in mathlib, I think.

Yury G. Kudryashov (Mar 24 2020 at 16:28):

nat is a linear_ordered_semiring. Not sure if core needs to know about this.

Bryan Gin-ge Chen (Mar 24 2020 at 16:37):

My impression from this thread is that it's not a big deal to move stuff out of core now and indeed might be a good idea given that Lean 4 core will have much less math. If there's some consensus on what should be done, I'd be happy to help out too.

Kevin Buzzard (Mar 24 2020 at 18:24):

ring is to monoid as division_ring is to group_with_zero as comm_ring is to comm_monoid as field is to comm_group_with_zero. This makes it sound like all of them are fundamental. Johan has just basically discovered a fundamental structure which is often ignored by mathematicians but which is helpful for formalisation.

Kevin Buzzard (Mar 24 2020 at 18:26):

@Cyril Cohen have you ever heard of a group with 0? Could you just drop them into Coq's algebra heirarchy without any difficulty?

Mario Carneiro (Mar 24 2020 at 18:27):

There isn't any problem adding a new element in the middle of the hierarchy later, you just add a couple instances and that's it

Mario Carneiro (Mar 24 2020 at 18:28):

The main reason you might not want to do this is because some theorems will generalize and there will be duplication there

Johan Commelin (Mar 24 2020 at 18:30):

@Mario Carneiro So you say it's not a problem that there are two paths to has_div?

Mario Carneiro (Mar 24 2020 at 18:30):

not if they are defeq

Johan Commelin (Mar 24 2020 at 18:30):

def div {G : Type*} [group_with_zero G] (g h : G) := g * h⁻¹

/-- The division operation on a group with zero element. -/
instance group_with_zero.has_div {G : Type*} [group_with_zero G] :
  has_div G := div

Johan Commelin (Mar 24 2020 at 18:31):

And exactly the same definition exists for division rings in core.

Mario Carneiro (Mar 24 2020 at 18:31):

What's the definition in core?

Johan Commelin (Mar 24 2020 at 18:32):

Also, the "some theorems" turn out to be several hundreds lines of duplication...

Mario Carneiro (Mar 24 2020 at 18:32):

I think the definition in core could be generalized to a has_mul has_inv

Mario Carneiro (Mar 24 2020 at 18:32):

well, that's expensive...

Johan Commelin (Mar 24 2020 at 18:33):

What do you think of taking all of it out of core and putting it in mathlib?

Mario Carneiro (Mar 24 2020 at 18:33):

It is used by tactic.norm_num

Mario Carneiro (Mar 24 2020 at 18:34):

and possibly some bits of algebraic normalizer that no one has touched in years

Johan Commelin (Mar 24 2020 at 18:34):

What? division_rings are used in core?

Johan Commelin (Mar 24 2020 at 18:34):

But can't we move the stuff that uses it to mathlib as well?

Johan Commelin (Mar 24 2020 at 18:35):

I can't imagine that there is C++ code that depends on division_ring

Mario Carneiro (Mar 24 2020 at 18:36):

there is

Johan Commelin (Mar 24 2020 at 18:36):

Oooh, wow

Mario Carneiro (Mar 24 2020 at 18:37):

There are examples of using norm_num to do numeric simplification in fields

Mario Carneiro (Mar 24 2020 at 18:41):

this bit of C++ uses this theorem about fields

Johan Commelin (Mar 25 2020 at 10:05):

#2240

Bryan Gin-ge Chen (Mar 25 2020 at 10:30):

Monoids with zero appear in some approaches to "the field with one element" (see 2.1.1 on page 12 of "F_1 for everyone"). (I found this stuff via a paper by Baker and Lorscheid about the moduli spaces of matroids.)

Patrick Massot (Mar 25 2020 at 10:32):

By the way, what happened to your matroid formalization? Was it ever PR'ed to mathlib?

Bryan Gin-ge Chen (Mar 25 2020 at 10:34):

It's still pending some big refactor. I'm still not happy with the way I deal with submatroids.

Johan Commelin (Mar 25 2020 at 10:35):

@Bryan Gin-ge Chen In group_with_zero I require that 0 ≠ 1. Should that also be done for monoid_with_zero?

Johan Commelin (Mar 25 2020 at 10:36):

It seems that the page you linked to doesn't want that requirement.

Johan Commelin (Mar 25 2020 at 10:36):

But it would be satisfied by F_1

Bryan Gin-ge Chen (Mar 25 2020 at 10:48):

Should that also be done for monoid_with_zero?

Hmm, I'm not sure. I think ease of doing things in Lean would be most important here, and I don't have enough experience with algebra to say.

Bryan Gin-ge Chen (Mar 25 2020 at 11:19):

Chapter 3 of Lorscheid's lecture notes "Blueprints and tropical scheme theory" does algebra over monoids with zero, including prime ideals and localization.

Johan Commelin (Mar 25 2020 at 11:25):

@Bryan Gin-ge Chen Thanks. I can try to refactor to include monoid_with_zero in the hierarchy.

Kevin Buzzard (Mar 25 2020 at 11:42):

Then you can start on diistrib_with_zero

Kevin Buzzard (Mar 25 2020 at 11:43):

Asking if 0 ne 1 feels a bit like asking if the zero ring is a field

Kevin Buzzard (Mar 25 2020 at 11:45):

But my instincts are not helping. I guess the idea is that we should just concentrate on the objects which are of use to us, and for group_with_zero we definitely want 0 ne 1 because I don't want to the zero ring to have any valuations

Kevin Buzzard (Mar 25 2020 at 11:59):

For monoid_with_zero I don't think I care -- the issue is simply what people need. I guess if you don't assume it then you can prove that every ring is a monoid with 0

Kevin Buzzard (Mar 25 2020 at 11:59):

So this seems natural.

Johan Commelin (Mar 25 2020 at 15:06):

So... I changed some things, and now I get this build error

mathlib/src/data/complex/basic.lean:28:4: error: definition 'of_real' is noncomputable, it depends on 'real.division_ring'

Johan Commelin (Mar 25 2020 at 15:07):

But as far as I know, I didn't change the computability of anything

Johan Commelin (Mar 25 2020 at 15:07):

How do I debug this issue?

Gabriel Ebner (Mar 25 2020 at 15:28):

I think it pulls in the wrong type class instance somewhere. I'd add noncomputable to of_real and then stare at the term with pp.all enabled. Is this in the PR that you've just closed?

Johan Commelin (Mar 25 2020 at 15:29):

Let me try.

Johan Commelin (Mar 25 2020 at 15:32):

noncomputable def complex.of_real : real  complex :=
λ (r : real),
  {re := r,
   im := @has_zero.zero.{0} real
           (@no_zero_divisors.to_has_zero.{0} real
              (@gwz.no_zero_divisors.{0} real (@division_ring.to_group_with_zero.{0} real real.division_ring)))}

Johan Commelin (Mar 25 2020 at 15:32):

So, it's now using this group_with_zero stuff

Johan Commelin (Mar 25 2020 at 15:33):

Hmm, I guess I should lower some instance priorities?

Gabriel Ebner (Mar 25 2020 at 15:34):

We've had similar problems when we removed the decidable_eq parent from fields.

Gabriel Ebner (Mar 25 2020 at 15:37):

The problem there was that every field with decidable equality is a Euclidean ring (and every Euclidean ring is a ring, etc.). But if you use this instance with open_locale classical, then you get instances using classical decidability. And suddenly multiplication is noncomputable.

Gabriel Ebner (Mar 25 2020 at 15:37):

I've put low priority on that instance and it seems to work.

Gabriel Ebner (Mar 25 2020 at 15:39):

Ok, this can be a bit subtle. I lowered the priority of euclidean_domain.to_nonzero_comm_ring instead: https://github.com/leanprover-community/mathlib/blob/e719f8ee3b0de0f02e3e32ff2a196f9703b63083/src/algebra/euclidean_domain.lean#L14

Johan Commelin (Mar 25 2020 at 15:40):

Ok, I've lowered some priorities. Let's see what happens

Gabriel Ebner (Mar 25 2020 at 15:48):

Do you know which one of the instances is noncomputable? They all seem fine to me.

Johan Commelin (Mar 25 2020 at 15:49):

I have no clue

Johan Commelin (Mar 25 2020 at 15:49):

But lowering the priorities helped

Gabriel Ebner (Mar 25 2020 at 15:49):

That said, both no_zero_divisors.to_has_zero and gwz.no_zero_divisors should have a lower priority. I believe #lint should complain.

Johan Commelin (Mar 25 2020 at 21:15):

@Bryan Gin-ge Chen I've factored out monoid with zero. But I didn't prove many lemmas for them.

Bryan Gin-ge Chen (Mar 25 2020 at 21:19):

OK, thanks! To be quite honest the algebraic hierarchy intimidates me still so I don't know that I'll have any intelligent comments on your code.


Last updated: Dec 20 2023 at 11:08 UTC