Zulip Chat Archive

Stream: maths

Topic: ideals in non-comm rings


Winston Yin (Sep 06 2021 at 02:47):

I'm thinking about how to extend ring_theory.ideal.basic to cover two-sided ideals for non-commutative rings. Until recently, ideal was only defined for comm_semirings, and now it is defined as left-ideals of (non-commutative) semirings as submodule R R. What would be a good way to define two-sided ideals for semirings? I can think of two options:

  • Define a new structure lrideal, so that lots of lemmas for submodule would have to be copied over.
  • Treat two-sided ideals as left-ideals (ideal) with an additional hypothesis that it's closed under right multiplication by ring elements.
    Are there more approaches? I'm not experienced enough to tell which is a better approach.

Scott Morrison (Sep 06 2021 at 04:33):

To make matters worse, there is the third option of defining two sided ideals to be left ideals under the R (x) R^op action.

Winston Yin (Sep 06 2021 at 04:55):

Do you mean forall (x in I) (r in R), r * x * r in I? Isn't that a bit weaker than a two-sided ideal?

Winston Yin (Sep 06 2021 at 04:57):

I might go with defining a new structure and show equivalence for other approaches

Johan Commelin (Sep 06 2021 at 05:02):

Scott means (r,s)R×Rop,xI,(r,s)xI\forall (r,s) \in R \times R^{\text{op}}, \forall x \in I, (r,s) \bullet x \in I, which unfolds to rxsIr * x * s \in I.

Winston Yin (Sep 06 2021 at 05:04):

Actually I'll try using this for the moment to avoid defining new things, and see how annoying it gets down the road

Julian Külshammer (Sep 06 2021 at 05:45):

I think the agreement before was that (two-sided) ideals should be defined as a special case of bimodules (like left ideals are defined as a special class of modules). Let me paste some private communication with Aaron here: "Bimodules could be easy (smul_comm_class is already there) but subbimodules are confusing. Basically, I think we might have to go down to the bottom of that hierarchy, going through bi_mul_action etc. Here's the discussion from last December: https://leanprover.zulipchat.com/#narrow/stream/116395-maths/topic/Bimodules "

Johan Commelin (Sep 06 2021 at 05:48):

Hmm, that's an interesting idea, to start all the way down at bi_mul_action.

Winston Yin (Sep 06 2021 at 06:19):

Just looked through the thread you linked. Very interesting! So the idea is to implement bi_mul_action, etc, bi_module, as well as their corresponding sub-objects? Then, two-sided ideal would just be sub_bi_module R R^op R?

Johan Commelin (Sep 06 2021 at 06:21):

bi_submodule R R^op R, I guess.

Winston Yin (Sep 06 2021 at 06:21):

Yes, of course

Winston Yin (Sep 06 2021 at 06:22):

Sounds like a lot of work but I'm happy to look into this a bit

Winston Yin (Sep 06 2021 at 06:23):

And at every stage, we define type class instances for the corresponding "non-bi" objects for the left multiplication and right multiplication

Scott Morrison (Sep 06 2021 at 07:29):

I would be very happy to have a proper theory of bimodules. They are, of course, the fundamental objects. (The R (x) R^op trick I mentioned of course only works in a braided category. :-)

Eric Wieser (Sep 06 2021 at 08:43):

https://m.youtube.com/watch?v=GsDGvwhxq5U has a discussion of right actions and bimodules in the future work section

Scott Morrison (Sep 06 2021 at 10:30):

I like your proposed notation <• for the right scalar action. Maybe we should even introduce •> as an alias for .

Winston Yin (Sep 06 2021 at 10:54):

Mirroring module and submodule, this would be the overall structure of bimodule and sub_bimodule:

import group_theory.group_action.defs
import group_theory.submonoid.basic
import algebra.opposites
import algebra.module.basic

notation m ` •ᵣ `:72 a:72 := (opposite.op a)  m

class bi_mul_action (α : Type*) (β : Type*) (γ : Type*) [monoid α] [monoid β] [has_scalar α γ] [has_scalar βᵒᵖ γ]
  extends smul_comm_class α βᵒᵖ γ :=
(one_smul_l :  c : γ, (1 : α)  c = c)
(one_smul_r :  c : γ, c •ᵣ (1 : β) = c)
(mul_smul_l :  (x y : α) (c : γ), (x * y)  c = x  y  c)
(mul_smul_r :  (x y : β) (c : γ), c •ᵣ (x * y) = c •ᵣ y •ᵣ x)

class bi_distrib_mul_action (M : Type*) (N : Type*) (A : Type*) [monoid M] [monoid N] [add_monoid A] [has_scalar M A] [has_scalar Nᵒᵖ A]
  extends bi_mul_action M N A :=
(smul_add_l :  (r : M) (x y : A), r  (x + y) = r  x + r  y)
(smul_zero_l :  (r : M), r  (0 : A) = 0)
(smul_add_r :  (r : N) (x y : A), (x + y) •ᵣ r = x •ᵣ r + y •ᵣ r)
(smul_zero_r :  (r : N), (0 : A) •ᵣ r = 0)

class bimodule (R : Type*) (S : Type*) (M : Type*) [semiring R] [semiring S] [add_comm_monoid M] [has_scalar R M] [has_scalar Sᵒᵖ M] extends bi_distrib_mul_action R S M :=
(add_smul_l :  (r s : R) (x : M), (r + s)  x = r  x + s  x)
(zero_smul_l :  (x : M), (0 : R)  x = 0)
(add_smul_r :  (r s : S) (x : M), x •ᵣ (r + s) = x •ᵣ r + x •ᵣ s)
(zero_smul_r :  (x : M), x •ᵣ (0 : S) = 0)

section
set_option old_structure_cmd true

structure sub_bi_mul_action (R : Type*) (S : Type*) (M : Type*) [has_scalar R M] [has_scalar Sᵒᵖ M] :=
(carrier : set M)
(smul_mem_l' :  (c : R) {x : M}, x  carrier  c  x  carrier)
(smul_mem_r' :  (c : S) {x : M}, x  carrier  x •ᵣ c  carrier)

structure sub_bimodule (R : Type*) (S : Type*) (M : Type*) [semiring R] [semiring S] [add_comm_monoid M] [module R M] [module Sᵒᵖ M] extends add_submonoid M, sub_bi_mul_action R S M

end

def lrideal (R : Type*) [semiring R] := sub_bimodule R R R

How does this look? Btw, the <• suggestion is great!

Scott Morrison (Sep 06 2021 at 11:01):

Hopefully Eric will give an opinion: I suspect he's thought about this the most so far.

A minor request: could we write bimodule R M S instead (i.e. the rings on either side of the bimodule), just like in the mathematical notation RMS{}_R M_S?

Eric Wieser (Sep 06 2021 at 12:50):

https://m.youtube.com/watch?v=GsDGvwhxq5U has a discussion of right actions and bimodules in the future work section

Yakov Pechersky (Sep 06 2021 at 13:41):

The classes should probably extend has_scalar, similar to how mul_action does.

Yakov Pechersky (Sep 06 2021 at 13:42):

And should be generalized to "mul_one_class" etc

Eric Wieser (Sep 06 2021 at 13:55):

(apologies, I have no idea why zulip sent that twice hours apart)

Eric Wieser (Sep 06 2021 at 14:40):

I think having a separate bimodule R S M typeclass is probably as reasonable as having integral_domain in that it is just a shorthand for a collection of typeclasses. But most lemmas would probably end up stated about the three separate typeclasses, since then you can relax them individually. If we have it, it should provide a bimodule.to_module : module R M and bimodule.to_right_module : module Sᵒᵖ M

Eric Wieser (Sep 06 2021 at 14:41):

So not as you have it written above

Eric Wieser (Sep 06 2021 at 14:42):

Can we make open_locale bimodule change the pretty printer to use •> for and add the other notation?

Johan Commelin (Sep 06 2021 at 14:45):

Ooh, that would be sweet!

Eric Wieser (Sep 06 2021 at 23:10):

(for the record, I think that having docs#integral_domain is annoying because if you have only comm_ring, no_zero_divisors and nontrivial you have to insert an awkward letI because typeclass search can't deal with the loops formed by two different ways to express the same thing; but there's clear pedagogical value to integral_domain as a spelling - the same view applies to bimodule)

Eric Wieser (Sep 06 2021 at 23:19):

My above comment about bimodule.to_module is wrong; it produces a dangerous instance. I think the best approach would be

abbreviation right_module (R M) := module Rᵒᵖ M

abbreviation bimodule (R S M) := smul_comm_class R Sᵒᵖ M

Winston Yin (Sep 07 2021 at 02:14):

What I've tried so far is to define bimodule as

class bimodule (R : Type*) (M : Type*) (S : Type*)
[semiring R] [semiring S] [add_comm_monoid M]
[module R M] [module Sᵒᵖ M]
extends smul_comm_class R Sᵒᵖ M

Winston Yin (Sep 07 2021 at 02:18):

This way, writing bimodule R M S would require first module R M and module Sᵒᵖ M

Winston Yin (Sep 07 2021 at 02:19):

I then defined

variables
... [module_RM : module R M] [module_SM : module Sᵒᵖ M] [bimodule R M S]

def to_left_module : module R M := module_RM
def to_right_module : module Sᵒᵖ M := module_SM

Winston Yin (Sep 07 2021 at 02:20):

Avoiding dangerous type class instances

Winston Yin (Sep 07 2021 at 02:23):

sub_bimodule is defined as

structure sub_bimodule (R : Type*) (M : Type*) (S : Type*)
[semiring R] [semiring S] [add_comm_monoid M]
[module R M] [module Sᵒᵖ M] [bimodule R M S]
extends add_submonoid M :=
(smul_mem_l' :  (c : R) {x : M}, x  carrier  c  x  carrier)
(smul_mem_r' :  (c : S) {x : M}, x  carrier  x <• c  carrier)

Then some lemmas for submodule just have to be duplicated with _l and _r versions

Johan Commelin (Sep 07 2021 at 04:36):

Winston Yin said:

I then defined

variables
... [module_RM : module R M] [module_SM : module Sᵒᵖ M] [bimodule R M S]

def to_left_module : module R M := module_RM
def to_right_module : module Sᵒᵖ M := module_SM

What is the benefit of this? After all the instance was already there as assumption.
This would make sense if you extends module R M, module Sᵒᵖ M, smul_comm_class R Sᵒᵖ M

Winston Yin (Sep 07 2021 at 07:31):

You're right...

Eric Wieser (Sep 07 2021 at 07:42):

I would mildly caution against having bimodule actually take [module R M] assumptions; I think there's a lower risk of pain down the road (like we experienced with the old module/semimodule split) if you simply assume [has_scalar R M] instead, even though that's somewhat misleading

Jakob von Raumer (Oct 29 2021 at 08:33):

@Winston Yin Has this made it into a PR yet?

Jakob von Raumer (Oct 30 2021 at 12:17):

Any opinions on changing compatible_smul to

class compatible_smul [distrib_mul_action R'ᵒᵖ N] :=
(op_smul_tmul :  (r : R') (m : M) (n : N), (r  m) ⊗ₜ n = m ⊗ₜ[R] (op r  n))

in the long run, given we make sure that op r properly simplifies to r in the case of commutative rings?

Eric Wieser (Oct 30 2021 at 13:07):

docs#tensor_product.compatible_smul for reference

Eric Wieser (Oct 30 2021 at 13:09):

Presumably once we start thinking about tensor products of bimodules, we first need to change docs#tensor_product.eqv.of_smul to

| of_smul :  (r : R) (m : M) (n : N), eqv
    (free_add_monoid.of (op r  m, n)) (free_add_monoid.of (m, r  n))

and have tensor products require [module Rᵒᵖ M] [module R N]

Eric Wieser (Oct 30 2021 at 13:11):

Or do I have the convention backwards? It seems natural to me to put the scalar in the middle so that (m <• r) ⊗ₜ n = m ⊗ₜ[R] (r •> n) where r : R, but convention wins over my personal opinion of what is natural

Eric Wieser (Oct 30 2021 at 13:30):

Hmm, I think we have a problem here. In the bimodule world where M is an S-R bimodule and N is an R-T bimodule, we presumably want

   s  (m ⊗ₜ[R] n) = (s  m) ⊗ₜ[R] n
op t  (m ⊗ₜ[R] n) =       m ⊗ₜ[R] (op t  n)

However, the latter case matches the former case with s = op t, and while probably gives a propositionally equal action in the cases where typeclasses match, certainly does not give a definitionally equal one.

Jakob von Raumer (Oct 30 2021 at 14:30):

I don't necessaily need bimodules, just the tensor product for modules on non-commutative rings, even if it doesn't bear an R-action itself

Jakob von Raumer (Oct 30 2021 at 14:31):

Eric Wieser said:

Presumably once we start thinking about tensor products of bimodules, we first need to change docs#tensor_product.eqv.of_smul to

| of_smul :  (r : R) (m : M) (n : N), eqv
    (free_add_monoid.of (op r  m, n)) (free_add_monoid.of (m, r  n))

and have tensor products require [module Rᵒᵖ M] [module R N]

Yes, that's a change I also did locally

Jakob von Raumer (Oct 30 2021 at 14:33):

The issue is that in the commutative case we have everything cluttered with op and ᵒᵖ then :pensive:

Jakob von Raumer (Oct 30 2021 at 15:56):

Maybe changing the definition of tensor_product but creating an instance of compatible_smul R R M N for the commutative case could be an option. (The instance requires transfering all sorts of classes, like module R M to module Rᵒᵖ M)

Jakob von Raumer (Oct 30 2021 at 19:50):

I think this issue is part of a bigger one: How do we reconcile commutative algebraic structures with their ops? Since opposite is irreducible we can't state r = opposite.op r without a cast...

Jakob von Raumer (Oct 30 2021 at 20:22):

section comm_op

local attribute [reducible] opposite

@[simp] def comm_op {R : Type*} [comm_semiring R] (r : R) : opposite.op r = r := rfl

end comm_op

This seems to be a way?

Eric Wieser (Oct 30 2021 at 21:26):

That's solving the wrong problem

Eric Wieser (Oct 30 2021 at 21:26):

You want lean to know that op r • m = r • m

Eric Wieser (Oct 30 2021 at 21:28):

Rewriting op r to r just makes things worse, because your statement was originally

@has_scalar (opposite R) M opposite.has_scalar (op r) m = @has_scalar R M _ r m

but your lemma turns it into the very wrong

@has_scalar (opposite R) M opposite.has_scalar r m = @has_scalar R M _ r m

which is using R, but the action from opposite R

Eric Wieser (Oct 30 2021 at 21:28):

We need a typeclass that says the left and right actions are the same

Eric Wieser (Oct 30 2021 at 21:31):

class is_symmetric_smul (R M) [has_scalar R M] [has_scalar (opposite R) M] :=
(op_smul_eq_smul : forall r m, op r  m = r  m)

You'll then want to add instances for:

  • is_symmetric_smul R R when comm_semigroup R
  • is_symmetric_smul R (prod A B) when is_symmetric_smul R A and is_symmetric_smul R B
  • pi
  • ulift
  • ...
  • probably most of the things we currently have has_scalar instances for.

Jakob von Raumer (Oct 31 2021 at 09:23):

Do you think it's still reasonable to have both

class compatible_smul_op [distrib_mul_action R'ᵒᵖ N] :=
(smul_tmul_op :  (r : R') (m : M) (n : N), (r  m) ⊗ₜ n = m ⊗ₜ[R] (op r  n))

and

class compatible_smul [distrib_mul_action R' N] :=
(smul_tmul :  (r : R') (m : M) (n : N), (r  m) ⊗ₜ n = m ⊗ₜ[R] (r  n))

with is_symmetric_smul present?

Jakob von Raumer (Oct 31 2021 at 10:58):

Eric Wieser said:

class is_symmetric_smul (R M) [has_scalar R M] [has_scalar (opposite R) M] :=
(op_smul_eq_smul : forall r m, op r  m = r  m)

You'll then want to add instances for:

  • is_symmetric_smul R R when comm_semigroup R

You mean what we need is the following?

instance {R α : Type*} [comm_semigroup R] [has_scalar R α] : is_symmetric_smul R α := _

But then at this point we do need a (low priority? local?) instance forhas_scalar (opposite R) α

Jakob von Raumer (Oct 31 2021 at 10:59):

Eric Wieser said:

class is_symmetric_smul (R M) [has_scalar R M] [has_scalar (opposite R) M] :=
(op_smul_eq_smul : forall r m, op r  m = r  m)

You'll then want to add instances for:

  • is_symmetric_smul R R when comm_semigroup R

You mean what we need is the following?

instance {R α : Type*} [comm_semigroup R] [has_scalar R α] : is_symmetric_smul R α := _

But then at this point we do need a (low priority? local? we want to keep the option of having a right action that's different from the left action, even if R is commutative, right?) instance forhas_scalar (opposite R) α

Eric Wieser (Oct 31 2021 at 11:10):

I'm not sure we need both, I'd focus on adding the first one and then reassess

Eric Wieser (Oct 31 2021 at 11:11):

The is_symmetric_smul R α instance you suggest doesn't type check, there's no has_scalar Rᵒᵖ α for it to be about

Eric Wieser (Oct 31 2021 at 11:11):

Which is why I said you only want the R R instance

Jakob von Raumer (Oct 31 2021 at 11:17):

Eric Wieser said:

The is_symmetric_smul R α instance you suggest doesn't type check, there's no has_scalar Rᵒᵖ α for it to be about

Yes, an instance for has_scalar Rᵒᵖ α given has_scalar R α what I suggested adding...

Eric Wieser (Oct 31 2021 at 11:20):

Oh, we do not need that instance

Eric Wieser (Oct 31 2021 at 11:20):

has_scalar Rᵒᵖ R is enough, and we already have that

Eric Wieser (Oct 31 2021 at 11:21):

For instance, has_scalar Rᵒᵖ (fin 3 → R) can be found today via docs#pi.has_scalar

Oliver Nash (Oct 31 2021 at 11:27):

Jakob von Raumer said:

I don't necessaily need bimodules, just the tensor product for modules on non-commutative rings, even if it doesn't bear an R-action itself

Right, just like for linear maps. Even when the scalars are non-commuative we have docs#linear_map.add_comm_monoid but we need some form of commutativity for docs#linear_map.module

Oliver Nash (Oct 31 2021 at 11:30):

I haven't studied this thread carefully enough to understand your objectives beyond noting you want tensor product with non-commutative scalars (which I too would love to have) but this old thread of mine might also be food for thought:
https://leanprover.zulipchat.com/#narrow/stream/144837-PR-reviews/topic/.234773.20base.20change/near/240929318

Jakob von Raumer (Oct 31 2021 at 11:32):

Eric Wieser said:

has_scalar Rᵒᵖ R is enough, and we already have that

I think I don't quite get the connection yet. Does this involve defining op r • m by (op r • (1 : R)) • m?

Eric Wieser (Oct 31 2021 at 11:34):

No, what I said above doesn't; but we can use that to almost get away without is_symmetric_smul:

import group_theory.group_action.basic
import algebra.module.opposites
import algebra.module.prod

open opposite

instance comm_semigroup.op_is_scalar_tower {R} [comm_semigroup R] : is_scalar_tower Rᵒᵖ R R :=
λ a b c, opposite.rec (by exact λ a', mul_right_comm b a' c) a

-- this works around a typeclass bug in pi types
instance comm_monoid.op_is_scalar_tower {R} [comm_monoid R] : is_scalar_tower Rᵒᵖ R R :=
comm_semigroup.op_is_scalar_tower

-- we were able to prove this without `is_symmetric_smul`
lemma op_smul_eq_smul {R M} [monoid R] [mul_action R M] [mul_action Rᵒᵖ M]
  [is_scalar_tower Rᵒᵖ R M] (r : R) (m : M) :
  op r  m = r  m :=
by rw [one_smul R m, smul_assoc (op r) (1 : R) m, op_smul_eq_mul, smul_smul, one_mul, mul_one]

variables {R : Type*} [comm_monoid R] (r : R)

example (m : R) : op r  m = r  m := op_smul_eq_smul _ _
example (m : R × R) : op r  m = r  m := op_smul_eq_smul _ _
example (m : fin 3  R) : op r  m = r  m := op_smul_eq_smul _ _  -- needs the workaround above

we still need it if we want to talk about actions by non-monoids

Eric Wieser (Oct 31 2021 at 11:35):

I think I don't quite get the connection yet

Can you give me an example of something that doesn't have a right action today, but should?

Eric Wieser (Oct 31 2021 at 11:35):

My claim is that the instance you suggest would just conflict with ones we already have, and there's no situation that you need it anyway

Jakob von Raumer (Oct 31 2021 at 11:37):

Eric Wieser said:

I think I don't quite get the connection yet

Can you give me an example of something that doesn't have a right action today, but should?

No I was just saying that I don't quite understand yet how the has_scalar Rᵒᵖ R instance actually helps making sense of op r • m

Eric Wieser (Oct 31 2021 at 11:38):

Because for almost every choice of m you make, there's already an actionhas_scalar Rᵒᵖ M defined in terms of has_scalar Rᵒᵖ R

Jakob von Raumer (Oct 31 2021 at 11:39):

Where is it defined?

Eric Wieser (Oct 31 2021 at 11:39):

In the same place as has_scalar R M

Eric Wieser (Oct 31 2021 at 11:39):

The location of which depends on your choice of M. See for instance docs#prod.has_scalar, docs#pi.has_scalar

Jakob von Raumer (Oct 31 2021 at 11:42):

I'm completely lost.

Eric Wieser (Oct 31 2021 at 11:42):

Pick a concrete example of R and M and I can show you

Jakob von Raumer (Oct 31 2021 at 11:46):

What do you mean by concrete? I want to M to be an arbitrary R-module

Jakob von Raumer (Oct 31 2021 at 11:47):

I just don't get what has_scalar Rᵒᵖ R has to do with this if we don't have a full scalar_tower Rᵒᵖ R M

Eric Wieser (Oct 31 2021 at 11:51):

By concrete I mean M = R × R, M = polynomial R etc. I don't understand the question you're asking

Eric Wieser (Oct 31 2021 at 11:52):

Under the original proposal:

class is_symmetric_smul (R M : Type*) [has_scalar R M] [has_scalar (opposite R) M] :=
(op_smul_eq_smul :  (r : R) (m : M), op r  m = r  m)

open is_symmetric_smul (op_smul_eq_smul)

instance comm_semigroup.is_symmetric_smul {R} [comm_semigroup R] : is_symmetric_smul R R :=
λ r m, mul_comm _ _

instance prod.is_symmetric_smul {R α β}
  [has_scalar R α] [has_scalar R β] [has_scalar Rᵒᵖ α] [has_scalar Rᵒᵖ β]
  [is_symmetric_smul R α] [is_symmetric_smul R β] : is_symmetric_smul R (α × β) :=
λ r m, prod.ext (op_smul_eq_smul _ _) (op_smul_eq_smul _ _)⟩

instance pi.is_symmetric_smul {R} {ι : Type*} {α : ι  Type*}
  [Π i, has_scalar R (α i)] [Π i, has_scalar Rᵒᵖ (α i)] [Π i, is_symmetric_smul R (α i)] :
  is_symmetric_smul R (Π i, α i) :=
λ r m, funext $ λ i, op_smul_eq_smul _ _

-- hack that hopefully lean4 doesn't need
instance function.is_symmetric_smul {R} {ι : Type*} {α : Type*}
  [has_scalar R α] [has_scalar Rᵒᵖ α] [is_symmetric_smul R (α)] :
  is_symmetric_smul R (ι  α) :=
pi.is_symmetric_smul

Any lemma about a symmetric bimodule would be stated as:

lemma some_lemma [module R M] [module Rᵒᵖ M] [is_symmetric_smul R M] : sorry

Eric Wieser (Oct 31 2021 at 11:53):

You don't need to worry about where module Rᵒᵖ M comes from, that's the caller's problem

Eric Wieser (Oct 31 2021 at 11:54):

And the caller either:

  1. Is working with a concrete type, and so has the instance available
  2. Is working on a variable type, so passes the obligation on to their caller

Jakob von Raumer (Oct 31 2021 at 11:54):

(deleted)

Jakob von Raumer (Oct 31 2021 at 11:57):

I thought you meant that in order to have

instance {R α : Type*} [comm_semigroup R] [has_scalar R α] : is_symmetric_smul R α := _

instead of adding an argument has_scalar Rᵒᵖ α, an argument has_scalar Rᵒᵖ R would be enough.

Jakob von Raumer (Oct 31 2021 at 11:59):

But I guess you said we shouldn't have that instance at all? So everyone using tensor products as before would have to supply the is_symmetric_smul?

Eric Wieser (Oct 31 2021 at 12:01):

You don't need is_symmetric_smul to use tensor_product; only the lemmas that require it

Jakob von Raumer (Oct 31 2021 at 12:02):

Okay, I guess now I get it. I'll see how much need for refactoring this causes outside of linear_algebra.tensor_product...

Eric Wieser (Oct 31 2021 at 12:05):

Unfortunately there's a nasty typeclass issue that looks like it makes both is_symmetric_smul and [is_scalar_tower Rᵒᵖ R M] non-viable quite annoying (until lean4)

Eric Wieser (Oct 31 2021 at 12:06):

I edited the message above with some is_symmetric_smul instances to get you started

Jakob von Raumer (Nov 01 2021 at 09:45):

Thanks for all the help!

Jakob von Raumer (Nov 01 2021 at 09:50):

One thing that's not obvious to me is how to fix the following: The current construction of compatible_smul.is_scalar_tower now needs the following instance to go through:

instance has_scalar_op_op {R R' : Type*} [has_scalar R' R] : has_scalar R'ᵒᵖ Rᵒᵖ :=
λ r' r, opposite.op (opposite.unop r'  opposite.unop r)⟩

It fails if the instance of has_scalar R'ᵒᵖ Rᵒᵖ is anything other than this, because we need op (r • b) = op r • op b. But then, compatible_smul.is_scalar_tower doesn't generalise to compatible_smul R R M N anymore because mul_action.is_scalar_tower.left uses an instance of has_scalar Rᵒᵖ Rᵒᵖ which is not defeq to has_scalar_op_op. I solved this by just adding a manual compatible_smul.self : compatible_smul R R M N, but the previous construction was obviously a bit nicer...

Eric Wieser (Nov 01 2021 at 12:32):

Your has_scalar_op_op instance looks dangerous to me

Jakob von Raumer (Nov 01 2021 at 13:13):

Well it's needed to make sense of is_scalar_tower R'ᵒᵖ Rᵒᵖ N in this context. But maybe we should keep it local?

Eric Wieser (Nov 01 2021 at 16:05):

My hunch is that you probably should take [has_scalar R'ᵒᵖ R ] as an argument there too; and if you need it to satisfy op (r • b) = op r • op b, then work out a way to express that with typeclasses

Eric Wieser (Nov 01 2021 at 16:06):

Adding compatible_smul.self seems like a much more conservative bet than adding your instance

Eric Wieser (Nov 01 2021 at 16:13):

then work out a way to express that with typeclasses

Here's that way:

-- you need this instance
instance (R M) [has_scalar R M] [has_scalar Rᵒᵖ M] [is_symmetric_smul R M] :
  is_symmetric_smul R Mᵒᵖ := λ r m, unop_injective (op_smul_eq_smul r m.unop : _)⟩

example (R M) [has_scalar R M] [has_scalar Rᵒᵖ M] [is_symmetric_smul R M] (r : R) (m : M) :
  op (r  m) = op r  op m :=
(op_smul_eq_smul r (op m)).symm

Eric Wieser (Nov 01 2021 at 16:15):

Perhaps it's worth pointing out the difference between your "add an instance" and my "add an instance"; you're adding data instances which can introduce diamonds and incompatible actions, my instances are only proofs, so can't introduce these things.

Jakob von Raumer (Nov 01 2021 at 17:01):

That's a neat idea.

Jakob von Raumer (Nov 01 2021 at 17:09):

It does away with the need for the double-op instance. I doesn't solve the issue of needing a separate compatible_smul.self : compatible_smul R R M N, though since that would require is_symmetric_smul R R which sounds like a bad idea for non-commutative rings

Eric Wieser (Nov 01 2021 at 18:10):

is_symmetric_smul R R isn't true on non-commutative rings

Eric Wieser (Nov 01 2021 at 18:10):

And I don't think compatible_smul R R M N is either, although I don't know what your new definition of compatible_smul is

Eric Wieser (Nov 01 2021 at 18:15):

Do you have a branch you're working on this in?

Jakob von Raumer (Nov 01 2021 at 18:48):

Not yet, I'll push it later on

Jakob von Raumer (Nov 03 2021 at 10:08):

I pushed my state of things here, but there's so much left do be done, and I haven't even started to check where things break in other files

Jakob von Raumer (Nov 04 2021 at 12:33):

Ah, I just noticed it's more canonical to assume that R operates on the right on M and not on N, so I made some bad choices here...

Eric Wieser (Nov 04 2021 at 13:52):

I thought that was what you had?

Eric Wieser (Nov 04 2021 at 13:52):

Ah nevermind, you fixed it in https://github.com/javra/mathlib/commit/efea1e30f00a9237590e134bb029ee2d67a5d75b

Jakob von Raumer (Nov 04 2021 at 14:44):

Now for add_comm_monoid we'd need a right action of on M, that doesen't seems unnatural either :unamused:

Yury G. Kudryashov (Nov 04 2021 at 18:55):

Will this create yet another diamond in case M = nat?

Yury G. Kudryashov (Nov 04 2021 at 18:55):

Because we already have an action of opposite nat on nat.

Yury G. Kudryashov (Nov 04 2021 at 19:00):

I wonder if there is a way to deal with these diamonds without adding lots of fields to monoid.

Jakob von Raumer (Nov 04 2021 at 19:07):

Yury G. Kudryashov said:

Will this create yet another diamond in case M = nat?

I think they both reduce to the inverted multiplication, so should be definitionally equal

Yury G. Kudryashov (Nov 04 2021 at 19:11):

How do you define the new action?

Yury G. Kudryashov (Nov 04 2021 at 19:11):

Isn't it just nsmul?

Jakob von Raumer (Nov 04 2021 at 19:15):

Good question. That _does_ yield the wrong operation on M = nat...

Eric Wieser (Nov 04 2021 at 19:27):

Eric Wieser said:

Hmm, I think we have a problem here. In the bimodule world where M is an S-R bimodule and N is an R-T bimodule, we presumably want

   s  (m ⊗ₜ[R] n) = (s  m) ⊗ₜ[R] n
op t  (m ⊗ₜ[R] n) =       m ⊗ₜ[R] (op t  n)

However, the latter case matches the former case with s = op t, and while probably gives a propositionally equal action in the cases where typeclasses match, certainly does not give a definitionally equal one.

I think my message above was describing a more general case of this diamond?

Edit: nevermind, but this is another diamond to worry about.

Notification Bot (Nov 04 2021 at 19:54):

This topic was moved by Eric Wieser to #general > right actions by nat

Eric Wieser (Nov 04 2021 at 20:09):

(to clarify, just the nat diamond bit was)

Jakob von Raumer (Nov 04 2021 at 20:11):

(deleted)

Jakob von Raumer (Nov 04 2021 at 20:12):

It's still super hard to adapt that file. The annoying thing is that the most general conditions for the tensor product having a left action and having a right action are so asymmetric. There's one of the actions on M and N thats requirted to be a distrib_mul_action while the other one can be an arbitrary has_scalar, depending on whether it comes from tensor_product.left_has_scalar or from tensor_product.right_has_scalar, and these are of course not separated well in the current state of the file :tired:

Jakob von Raumer (Nov 04 2021 at 21:55):

Currently thinking of just splitting the files. I had to separate linear_algebra.tensor_product and linear_algebra.tensor_product_basis a while ago anyway due to cyclic dependencies, might as well make a folder with a file for the defn, the left module structure coming from the left module N, the right module structure coming from the right module M

Jakob von Raumer (Nov 05 2021 at 09:32):

Jakob von Raumer said:

It's still super hard to adapt that file. The annoying thing is that the most general conditions for the tensor product having a left action and having a right action are so asymmetric. There's one of the actions on M and N thats requirted to be a distrib_mul_action while the other one can be an arbitrary has_scalar, depending on whether it comes from tensor_product.left_has_scalar or from tensor_product.right_has_scalar, and these are of course not separated well in the current state of the file :tired:

Oh right, that's exactly the diamond you were talking about, @Eric Wieser

Jakob von Raumer (Nov 05 2021 at 09:34):

The overlap could be solved in the manner we solved additive vs multiplicative operations. Stating lemmas for smul explicitely and transfer them automatically to lemmas about rsmul...

Jakob von Raumer (Nov 09 2021 at 09:55):

Eric Wieser said:

Oh, we do not need that instance

Are you sure about that? I still think in the commutative algebra world such an instance should be at least inferrable since user will not want to worry about which side of a module a commutative ring acts on?

Eric Wieser (Nov 09 2021 at 10:59):

Yes, I'm pretty sure, because having that instance would create diamonds. Can you give an example of a case you're thinking of?

Jakob von Raumer (Nov 09 2021 at 11:14):

I meant from a user point of view where the current approach would be to require [has_scalar R M] [has_scalar (opposite R) M] [is_symmetric_smul R M] every time, which does seem unwieldy. This would e.g. pop up every time one wants (r • m) ⊗ₜ n = m ⊗ₜ (r • m) instead of (m <• r) ⊗ₜ n = m ⊗ₜ (r • m). I'm not depp into commutative algebra, but I think that's what they want?

Eric Wieser (Nov 09 2021 at 11:49):

Yes, they would indeed need to do that when working over an arbitrary R and M

Jakob von Raumer (Nov 09 2021 at 12:32):

Maybe collecting the three instances into has_symmetric_scalar R M could be an option. It's just a use case that pops up a lot in mathlib

Eric Wieser (Nov 09 2021 at 12:36):

That would be super annoying, because you'd then need has_symmetric_mul_action, has_symmetric_distrib_mul_action, has_symmetric_module, ...

Jakob von Raumer (Nov 09 2021 at 12:40):

Hm, you're right

Eric Wieser (Nov 09 2021 at 13:02):

Maybe all that users really care about is has_symmetric_module, but if we had that we'd still end up stating the lemmas in mathlib about is_symmetric_smul to be maximally general

Jakob von Raumer (Nov 10 2021 at 12:39):

This is probably quite a useful instance, right?

instance is_scalar_tower.is_symmetric_smul {R α} [monoid R] [mul_action R α] [has_scalar Rᵒᵖ α]
  [is_scalar_tower Rᵒᵖ R α] : is_symmetric_smul R α :=
λ r a, by rw [one_smul R a, smul_assoc, one_smul, op_smul_eq_mul, one_mul]⟩

Jakob von Raumer (Nov 10 2021 at 12:41):

Do you think it's okay for users who use right scalars to be confronted with the fact that if they want to prove something about all r : Rᵒᵖ, they'll be confronted with left scalars instead until they rewrite along ←op_unop?

Eric Wieser (Nov 10 2021 at 15:10):

I'm not sure; is it also true in the other direction?

Jakob von Raumer (Nov 10 2021 at 16:46):

Only in the commutative case

Eric Wieser (Nov 10 2021 at 16:46):

Are all the other assumptions equally strong, or can some be weakened?

Jakob von Raumer (Nov 10 2021 at 16:52):

I think we need them all:

instance is_symmetric_smul.is_scalar_tower {R α} [comm_monoid R] [mul_action R α] [has_scalar Rᵒᵖ α]
  [is_symmetric_smul R α] : is_scalar_tower Rᵒᵖ R α :=
λ r' r a, by { rw [unop_smul_eq_smul r' (r  a), smul_smul],
                change (_ * _)  _ = _, rw [mul_comm] } 

Eric Wieser (Nov 10 2021 at 17:01):

Then it sounds like the first instance is harmless, but I'm not sure how useful it is

Jakob von Raumer (Nov 11 2021 at 15:05):

It wasn't harmless :grinning:

Jakob von Raumer (Nov 11 2021 at 15:10):

I'm slowly making progress. One thing I'm not too happy about is that tensor_product.left_has_scalar in the commutative case automatically induces an action of opposite R (a right action on the tensor product by a right action on M), while it only induces a left action if M is really a bimodule. I think that's a bit confusing.

Jakob von Raumer (Nov 11 2021 at 15:12):

If RR is commutative, do people still want asymmetric RR-RR-bimodules?

Eric Wieser (Nov 11 2021 at 15:15):

Probably not, but remember you need to not create instance diamonds in places where you don't know if R is commutative

Jakob von Raumer (Nov 11 2021 at 15:26):

Well, this is about deleting instances, not adding some...

Eric Wieser (Nov 11 2021 at 15:34):

Which instance are you considering deleting?

Jakob von Raumer (Nov 11 2021 at 15:35):

smul_comm_class R R M for commutative R, that would solve the issue...

Jakob von Raumer (Nov 11 2021 at 15:36):

...but probably cause other issues

Jakob von Raumer (Nov 11 2021 at 15:38):

The alternative is to just make all the constructions in the commutative case depend on an instance [is_symmetric_smul R M], which prevents us from ending up in the confusing situation I described above

Julian Külshammer (Nov 11 2021 at 17:32):

Regarding the question whether one wants asymmetric actions for R-R-bimodules even if R is commutative, definitely yes for some people. A typical example I'm not an expert on, but have seen is if R is a field of characteristic p and the right action is given by twisting with the Frobenius xxpx\mapsto x^p while the left action is regular. Another example I am more familiar with is to consider k-linear categories with finitely many objects as monoid objects in the category of L-L-bimodules where L is a product of fields, as many as objects in the category. Also the action here is not central.

Jakob von Raumer (Nov 12 2021 at 10:51):

Okay, I now did some changes based on the following situation:

  • In some situations, even when RR is commutative, we want a left action on MRNM \otimes_R N where MM is a potentially asymmetric RR-RR-bimodule.
  • In other cases we want to have r(mn)=(rm)n(=(mr)n)=m(rn)r (m \otimes n) = (rm) \otimes n (= (mr) \otimes n) = m \otimes (rn), this is encapsulated in the fact that we have an instance of is_symmetric_smul on the tensor product whenever we have one on MM.

I do think this accomodates all users, but since some constructions, especially the UMP of the tensor product, seem to lie in the second case, this sometimes requires a ridiculous amount of instance arguments, like here:

theorem ext_fourfold
  [module Rᵒᵖ (Q →ₗ[R] S)] [is_symmetric_smul R (Q →ₗ[R] S)]
  [module Rᵒᵖ (P →ₗ[R] Q →ₗ[R] S)] [is_symmetric_smul R (P →ₗ[R] Q →ₗ[R] S)]
  {g h : ((M [R] N) [R] P) [R] Q →ₗ[R] S}
  (H :  w x y z, g (((w ⊗ₜ x) ⊗ₜ y) ⊗ₜ z) = h (((w ⊗ₜ x) ⊗ₜ y) ⊗ₜ z)) : g = h :=
begin
  ext w x y z,
  exact H w x y z,
end

What's your thoughts on this?

Jakob von Raumer (Nov 16 2021 at 10:21):

So the current state is this. There's just one lemma missing from the old file, which requires me to come up with a good solution on how to derive has_scalar (opposite (units S)) M from has_scalar (opposite S) M(probably can't avoid to do it manually)...

Do you think I should PR this already to get more people to look at it? I'm afraid of already putting too much time in this...

Oliver Nash (Nov 16 2021 at 10:23):

@Jakob von Raumer I see you're working from a fork. Are you aware that you can request permission to create branches on the Mathlib repo and save yourself the overhead of managing a fork?

Oliver Nash (Nov 16 2021 at 10:27):

Glancing at your work, I see it already comprises over 1000 lines. The code looks great so I'm sure we'll be able to get this merged but this is a large amount of code so the sooner you start PRing the better. For example the results about bases of tensor products (which I actually wanted for something else recently) look like a PR on their own.

Jakob von Raumer (Nov 16 2021 at 10:27):

Yes, I do have the permission

Oliver Nash (Nov 16 2021 at 10:27):

OK cool, if you prefer a fork then that's fine too!

Jakob von Raumer (Nov 16 2021 at 10:28):

Oliver Nash said:

Glancing at your work, I see it already comprises over 1000 lines. The code looks great so I'm sure we'll be able to get this merged but this is a large amount of code so the sooner you start PRing the better. For example the results about bases of tensor products (which I actually wanted for something else recently) look like a PR on their own.

None of this is new, it's just the old linear_algebra.tensor_product and linear_algebra.tensor_product_basis reorganized and partly generalised to non-commutative rings. Some proofs had to be adapted by most of it is just copied over.

Oliver Nash (Nov 16 2021 at 10:30):

Ah OK I see. I couldn't easily figure out how to get a diff and made the wrong assumption.

Oliver Nash (Nov 16 2021 at 10:30):

Incidentally since we're finally talking seriously about tensor products over non-commutative rings, is anyone thinking about the corresponding results for linear maps?

Oliver Nash (Nov 16 2021 at 10:30):

E.g.,

import linear_algebra.basic

variables (R M N : Type*) [semiring R]
variables [add_comm_monoid M] [module R M] [add_comm_monoid N] [module R N]

example : add_comm_monoid (M →ₗ[R] N) := by apply_instance -- works

example : module R (M →ₗ[R] N) := by apply_instance -- fails because `R` not commutative!

Oliver Nash (Nov 16 2021 at 10:31):

I wondered if this would come up as part of the tensor product work. Did it?

Jakob von Raumer (Nov 16 2021 at 10:36):

The fact that these are missing actually prevents some generalisations!

Jakob von Raumer (Nov 16 2021 at 10:45):

The current implementation doesn't really depend on R being commutative, but having a commutative action on N.

Oliver Nash (Nov 16 2021 at 10:45):

Yes but if R is not commutative the definition will not provide a linear map.

Oliver Nash (Nov 16 2021 at 10:46):

Oh sorry, misread your remark.

Jakob von Raumer (Nov 16 2021 at 10:52):

Made a pull request.

Oliver Nash (Nov 16 2021 at 10:53):

Mathematically, if R, S, T are rings, M is an (R, S)-bimodule, and N is an (R, T)-bimodule then we can speak of R-linear maps M → N and these are an (S, T)-bimodule. I'd love to have this in Mathlib.

Oliver Nash (Nov 16 2021 at 10:54):

Jakob von Raumer said:

Made a pull request.

Thanks! I'll review this evening.

Jakob von Raumer (Nov 16 2021 at 10:56):

Oliver Nash said:

Mathematically, if R, S, T are rings, M is an (R, S)-bimodule, and N is an (R, T)-bimodule then we can speak of R-linear maps M → N and these are an (S, T)-bimodule. I'd love to have this in Mathlib.

Isn't this here?

Jakob von Raumer (Nov 16 2021 at 10:57):

Ah, nevermind, that's weaker than what you said.

Oliver Nash (Nov 16 2021 at 10:58):

I'm definitely a bit of out date as I haven't touched this stuff in ages. We might be much closer to this than I realise.

Jakob von Raumer (Nov 16 2021 at 11:01):

Staring at it a bit more it does use the left action on both the domain and the codomain, which prevents your generalisation, it's roughly the same problem as with the tensor product.

Jakob von Raumer (Nov 16 2021 at 11:02):

(Which I guess shouldn't be surprising with them being adjoints and all...)

Oliver Nash (Nov 16 2021 at 11:03):

I suspected this might be a prerequisite for tensor products but perhaps not.

Jakob von Raumer (Nov 16 2021 at 11:04):

I guess it's a prerequesite from freeing the lemmas which mix tensor products and linear maps from the commutativity presumption, which I haven't done. Maybe it should be done and both go in the same huge PR :scared:

Oliver Nash (Nov 16 2021 at 11:07):

Huge PRs should be a last resort. I've often been surprised at how easy it is to package up something like this into smaller pieces.

Oliver Nash (Nov 16 2021 at 11:07):

Btw this generalisation is well worth fighting for and very valuable. I suspect many people here are quite excited about the theory of bimodules coming to life.

Jakob von Raumer (Nov 16 2021 at 11:15):

Thanks for the encouragement! this actually came out of me wanting to teach Lean to some non-commutative algebraists, and I was a bit suprised about how much of mathlib relies on commutativity.

Jakob von Raumer (Nov 16 2021 at 11:29):

In order to fix the files depending on the tensor product: Is there a way to get a list of all files that depend on a certain file by transitivity?

Oliver Nash (Nov 16 2021 at 11:33):

This is probably possible with https://github.com/leanprover-community/leancrawler but I think you'll probably end up with a far bigger list than you want because if one little lemma in a file low down in the dependency tree uses tensor products you'll get a huge chunk of Mathlib.

Alex J. Best (Nov 16 2021 at 11:37):

You can also use leanproject for this and run some tools on the output of https://leanprover-community.github.io/leanproject.html#import-graphs

Alex J. Best (Nov 16 2021 at 11:40):

If you tell me a specific list of filenames I can do this for you too fairly easily, me and Johan have some WIP tools that will help with this, and I'm happy to run them

Jakob von Raumer (Nov 16 2021 at 12:36):

It's just linear_algebra.tensor_product on the current master branch

Alex J. Best (Nov 16 2021 at 12:42):

I think that list is way too big to do anything useful with, there are 590 files there

Alex J. Best (Nov 16 2021 at 12:42):

I can't even paste it into a zulip message

Alex J. Best (Nov 16 2021 at 12:43):

tensorlist

Alex J. Best (Nov 16 2021 at 12:44):

Probably you're best off just letting lean --make src or CI tell you what breaks

Jakob von Raumer (Nov 16 2021 at 12:52):

That's what would have been my plan otherwise. I guess it does trigger a lot of big recompilations to just start at at random spot, though. Maybe the best heuristic is to start with the direct descendants and hope that most of the indirect imports don't break.

Alex J. Best (Nov 16 2021 at 12:54):

Those are:

 linear_algebra.direct_sum.tensor_product,
 algebra.category.Module.monoidal,
 topology.algebra.affine,
 linear_algebra.affine_space.affine_equiv,
 algebra.algebra.bilinear,
 topology.algebra.continuous_affine_map,
 linear_algebra.multilinear.tensor_product

I guess grep can also find this list though!

Jakob von Raumer (Nov 16 2021 at 12:56):

The mathlibs docs show them as well :)

Scott Morrison (Nov 16 2021 at 20:29):

Jakob von Raumer said:

Thanks for the encouragement! this actually came out of me wanting to teach Lean to some non-commutative algebraists, and I was a bit suprised about how much of mathlib relies on commutativity.

Certain people wandering around on zulip, pretending they've never met a noncommutative ring...

Jakob von Raumer (Nov 16 2021 at 21:07):

One thing I noticed is that at many points it would be more elegant to separate the lemmas about commutative rings from the non-commutative ones, if e.g. instead of semiring R we would assume comm_semigroup R and the_other_ring_axioms R separately, with the drawback that this would make usage more verbose.
@Sebastian Ullrich mentioned that in Lean 4 it should be possible to infer one of these from the other and vice versa which seems to make separating the assumptions more attractive...

Kevin Buzzard (Nov 16 2021 at 21:29):

Commutative ring theory has been one of the success stories of mathlib.

Kevin Buzzard (Nov 16 2021 at 21:32):

I wonder whether this would have been the case if we'd tried to take the noncommutative story into account at the time. Historically what happened was that very early on I was pushing for schemes, a story where we needed a lot of commutative ring stuff, and there was nobody arguing for the noncommutative case at the time so me and my minions just defined ideals of commutative rings and then prime ideals etc etc and just kept PRing stuff

Kevin Buzzard (Nov 16 2021 at 21:34):

It was pointed out that there would be trouble ahead but I could never get straight from the noncommutative people whether ideal was supposed to mean left ideal or bi-ideal so I just kept pushing the commutative story, and then other people showed up and joined in (Justus Springer, Devon Tuma, the Berkeley graduate students, others I've forgotten, and now the new crowd doing products of schemes) and the commutative story just kept growing

Scott Morrison (Nov 16 2021 at 21:46):

Kevin has a good point. I think a great way to build a good library is to build an extremely tall and pointy lopsided one, and then hope that people come along to stop it from falling over. :-)

Scott Morrison (Nov 16 2021 at 21:47):

Happily in mathlib that happens.

Patrick Massot (Nov 16 2021 at 21:49):

This happens only if the tower builders PR to mathlib... :rolling_eyes:

Kevin Buzzard (Nov 16 2021 at 21:49):

I do genuinely feel guilty that this approach has caused trouble down the line, especially as I was warned that this would happen, but ultimately as Scott says we made some really tall stuff and that has had advantages because it got us noticed.

Scott Morrison (Nov 16 2021 at 21:52):

(I wasn't even counting non-mathlib stuff as part of the tower. They are just ephemeral dreams. :-)

Patrick Massot (Nov 16 2021 at 21:53):

I know, I was only trying to remind the perfectoid spaces projects authors that they should feel guilty.

Yaël Dillies (Nov 16 2021 at 21:53):

But I also feel very attacked with my two 5k lines branches.

Scott Morrison (Nov 16 2021 at 21:55):

Hopefully "attacked" in the most constructive and loving way. :-) Otherwise, sorry!

Jakob von Raumer (Nov 16 2021 at 22:01):

Kevin Buzzard said:

It was pointed out that there would be trouble ahead but I could never get straight from the noncommutative people whether ideal was supposed to mean left ideal or bi-ideal so I just kept pushing the commutative story, and then other people showed up and joined in (Justus Springer, Devon Tuma, the Berkeley graduate students, others I've forgotten, and now the new crowd doing products of schemes) and the commutative story just kept growing

I will definitvely quiz additional non-commutative people on their customs :D

Kevin Buzzard (Nov 16 2021 at 22:03):

Oh thanks!

Jakob von Raumer (Nov 17 2021 at 14:54):

I need to write a version of the bundled Module with a symmetric action (i.e. Module extended by an is_symmetric_smul). Any naming ideas?

Eric Wieser (Nov 17 2021 at 15:12):

SymmetricBiModule?

Jakob von Raumer (Nov 18 2021 at 15:39):

How about this: I shelve the current PR for now and do the following PRs separately and in order:

  1. Create a PR fixing the use of modules towards more compatibility with non-comm algebra, meaning replacing occurrences of module R M by a symmetric R-R-action or (weaker) an R-R-bimodule wherever the non-comm generalisation would currently require it.
  2. Generalise the module structure on linear maps in the way @Oliver Nash proposed it above.
  3. Generalise the tensor product (the current PR).

Kevin Buzzard (Nov 18 2021 at 15:42):

Will this mean that whenever an undergraduate wants to talk about a vector space they'll have to say a k-k-bimodule?

Oliver Nash (Nov 18 2021 at 15:42):

This sounds like a very good plan to me except that I don't have a clear picture of what you have in mind for 1. Is there a simple example of such a fix?

Oliver Nash (Nov 18 2021 at 15:42):

(Or rather of such a situation, requiring a fix.)

Jakob von Raumer (Nov 18 2021 at 15:43):

Kevin Buzzard said:

Will this mean that whenever an undergraduate wants to talk about a vector space they'll have to say a k-k-bimodule?

Would symm_module k V be acceptable?

Oliver Nash (Nov 18 2021 at 15:45):

I presume we could have typeclass instances that provide symm_module k V from module k V + comm_ring k?

Jakob von Raumer (Nov 18 2021 at 15:47):

Oliver Nash said:

(Or rather of such a situation, requiring a fix.)

Well a good part of this entire thread is about such a situation: Every point where r(mn)r (m \otimes n) would mean (rm)n(r m) \otimes n instead of (mr)n(m r) \otimes n, for example, and by exension any situation which requires the tensor product of two RR-modules to be an RR-module.

Jakob von Raumer (Nov 18 2021 at 15:49):

Oliver Nash said:

I presume we could have typeclass instances that provide symm_module k V from module k V + comm_ring k?

It would be a great help in the usage if we could have such an instance. @Julian Külshammer above said, that we might have situations, even with commutative kk, where the canonical left and right action don't coincide. So if at all, we'd make your proposed instance low priority?

Oliver Nash (Nov 18 2021 at 15:52):

Jakob von Raumer said:

It would be a great help in the usage if we could have such an instance. Julian Külshammer above said, that we might have situations, even with commutative kk, where the canonical left and right action don't coincide. So if at all, we'd make your proposed instance low priority?

Hmm this is a good point. I'm less confident we could do this and it would indeed require some care with priorities.

Jakob von Raumer (Nov 18 2021 at 15:52):

(It would make all the fixes needed for the current tensor product PR tremendously easier ;))

Jakob von Raumer (Nov 18 2021 at 15:56):

(And the usage by people like @Kevin Buzzard's linear algebra students, if kk is commutative)

Oliver Nash (Nov 18 2021 at 15:57):

Wait though, why won't we still have just plain left modules still?

Jakob von Raumer (Nov 18 2021 at 16:01):

We will, we just don't have the instance of their tensor product or the space of linear maps being a plain left module.

Oliver Nash (Nov 18 2021 at 16:01):

Right!

Oliver Nash (Nov 18 2021 at 16:02):

OK so the problem to be solved should only be at the level of the instances and not at the types.

Oliver Nash (Nov 18 2021 at 16:03):

I think this should work, subject to carefully-chosen instance priorities.

Jakob von Raumer (Nov 18 2021 at 16:04):

The core of the problem is that we have two different conventions in the commutative and the non-commutative world, and the best way to solve the dilemma seems to be to say "okay, let's assume the commutative case as a special situation of bimodules where needed"

Jakob von Raumer (Nov 18 2021 at 16:05):

Oliver Nash said:

I think this should work, subject to carefully-chosen instance priorities.

Do you mean the whole thing or the symmetry-instance in the commutative case?

Oliver Nash (Nov 18 2021 at 16:05):

I meant the whole thing but of course it's hard to really be sure.

Jakob von Raumer (Nov 18 2021 at 16:08):

Something concrete that needs to be made symmetric in order for the changes linear_algebra.tensor_product to go through is to have the action on a module to be symmetric, since otherwise compatible_smul.int and thus the actiono n the tensor product doesn't work.

Oliver Nash (Nov 18 2021 at 16:15):

I'm not precisely sure what this means. If m, n are elements of additive groups M, N, then there are three different things that are all mathematically equal:

  • m ⊗ₜ n + m ⊗ₜ n + ... + m ⊗ₜ n
  • m ⊗ₜ (n + n + ... + n)
  • (m + m + ... + m) ⊗ₜ n

and at most two of these can be definitionally equal. Is this related to your question?

Jakob von Raumer (Nov 18 2021 at 16:21):

Not entirely. The definitional equality will always be between the first and the third term. It's just that this equality comes out of the general statement of "if MM is an SS-RR-bimodule, then MRNM \otimes_R N is an SS-module", so we need to play the role of both RR and SS and thus act symmetrically on the left and on the right of MM.

Reid Barton (Nov 18 2021 at 16:22):

I haven't been following this discussion closely but it seems like this encoding using opposite is causing a lot of trouble, how about having left_module, right_module with separate operations, bimodule, and then module R M extends bimodule R R M with the "symmetry" compatibility law?

Reid Barton (Nov 18 2021 at 16:24):

this is a slightly weird definition in the commutative case but it's similar to "a metric space has a metric and a topology that agree"

Jakob von Raumer (Nov 18 2021 at 16:26):

The intuitive argument against that for me was that it is a way bigger change. But maybe that's not a good argument.

Jakob von Raumer (Nov 18 2021 at 16:27):

The annoying thing then is: module R M and left_module R M are equivalent and differ only by notation. For which one do we proof all the lemmas about arbitrary modules?

Reid Barton (Nov 18 2021 at 16:28):

module would be only for commutative rings

Jakob von Raumer (Nov 18 2021 at 16:29):

That then complicates the cases @Julian Külshammer mentions above, where we do want differeent left and right actions even if the ring is commutative.

Oliver Nash (Nov 18 2021 at 16:30):

I don't think so, they'd just be bimodules.

Reid Barton (Nov 18 2021 at 16:31):

I didn't really answer your question but my intended answer would be something like "if you're doing commutative algebra, use module otherwise use left_module"

Reid Barton (Nov 18 2021 at 16:33):

There's probably problems with this idea because I haven't thought this through at all

Jakob von Raumer (Nov 18 2021 at 16:34):

Oliver Nash said:

I don't think so, they'd just be bimodules.

But if both the left and the right action are somewhat canonical structures on some M, each will make M a module and to get the desired bimodule, we'll have to locally downgrade them to a left_module and a right_module respectively, right?

Jakob von Raumer (Nov 18 2021 at 16:35):

Reid Barton said:

There's probably problems with this idea because I haven't thought this through at all

I think it would be the preferred idea if there was less overlap between non-commutative and commutative algebra. The overlap, I guess, is where things can go wrong.

Oliver Nash (Nov 18 2021 at 16:35):

Reid Barton said:

There's probably problems with this idea because I haven't thought this through at all

I think it's very hard / impossible to foresee what problems any approach may encounter. Your suggestion has the very tempting sociological advantage that it's how most / all of us actually think about this.

Jakob von Raumer (Nov 18 2021 at 16:37):

Reid Barton said:

I haven't been following this discussion closely but it seems like this encoding using opposite is causing a lot of trouble, how about having left_module, right_module with separate operations, bimodule, and then module R M extends bimodule R R M with the "symmetry" compatibility law?

This raises the question on whether we'd need a transfer command to create right_module lemmas from left module lemmas?

Jakob von Raumer (Nov 18 2021 at 16:40):

Maybe I should head over to #mathlib4 and ask whether to_additive has been ported already...

Reid Barton (Nov 18 2021 at 16:42):

Jakob von Raumer said:

Oliver Nash said:

I don't think so, they'd just be bimodules.

But if both the left and the right action are somewhat canonical structures on some M, each will make M a module and to get the desired bimodule, we'll have to locally downgrade them to a left_module and a right_module respectively, right?

I don't think this one is a problem in practice, basically because the math situation is the same. You just won't define a module structure for one or both of the actions

Jakob von Raumer (Nov 18 2021 at 16:46):

Reid Barton said:

I don't think this one is a problem in practice, basically because the math situation is the same. You just won't define a module structure for one or both of the actions

If it's not already there. Maybe you first want to tread each action separately and happily use module before, in a more specialised setting, wanting to use both. But yes, there are ways around this and it might be a super rare occasion anyway.

Reid Barton (Nov 18 2021 at 16:46):

M would be something you just created to describe this specific object, though.

Reid Barton (Nov 18 2021 at 16:47):

So the instances aren't there

Reid Barton (Nov 18 2021 at 16:48):

Like one construction is you have a complex vector space VV and you let zz act by zz on the left and by z\overline{z} on the right. You need a new name for this guy no matter what, and that's what gets the bimodule instance

Jakob von Raumer (Nov 18 2021 at 16:49):

Julian Külshammer said:

A typical example I'm not an expert on, but have seen is if R is a field of characteristic p and the right action is given by twisting with the Frobenius xxpx\mapsto x^p while the left action is regular.

Here maybe the left action is the one that's already a full module already, right?

Jakob von Raumer (Nov 18 2021 at 16:50):

Reid Barton said:

Like one construction is you have a complex vector space VV and you let zz act by zz on the left and by z\overline{z} on the right. You need a new name for this guy no matter what, and that's what gets the bimodule instance

Ah, okay, yes, changing the name of the carrier is a good solution.

Jakob von Raumer (Nov 18 2021 at 19:04):

On a slight tangent, am I the only one who thinks that smul_comm_class is a really bad name? We usually dont include "class" in the name of a type class?

Johan Commelin (Nov 18 2021 at 19:06):

I agree. But the lemma is already called smul_comm. So we need another name for the class. Suggestions welcome!

Yaël Dillies (Nov 18 2021 at 19:07):

To be fair, I much more regret has_scalar_tower. I'd be happy to have them called smul_comm_class and smul_assoc_class. But if you want to get rid of the _class we can go for is_smul_comm/is_comm_smul and is_smul_assoc/is_assoc_smul.

Yaël Dillies (Nov 18 2021 at 19:09):

It follows the principle that Prop-valued classes should be called is_.

Jakob von Raumer (Nov 18 2021 at 19:10):

Isn't it is_scalar_tower?

Jakob von Raumer (Nov 18 2021 at 19:11):

Since it's has_scalar, maybe scalar_comm could be a name for the class, while smul_comm is the lemma?

Yaël Dillies (Nov 18 2021 at 19:18):

I think we should rename has_scalar to has_smul. It's has_add, not has_addition.

Eric Wieser (Nov 18 2021 at 19:55):

I think "rename all the typeclasses" is reasonable, but probably deserves it's own thread

Eric Wieser (Nov 18 2021 at 19:56):

Also it will mean my scalar actions paper refers to things that no longer exist!

Jakob von Raumer (Nov 18 2021 at 20:21):

has_lsmul and has_rsmul?

Yaël Dillies (Nov 18 2021 at 20:45):

Eric Wieser said:

Also it will mean my scalar actions paper refers to things that no longer exist!

Paper rot :scream:

Yaël Dillies (Nov 18 2021 at 20:48):

Jakob von Raumer said:

has_lsmul and has_rsmul?

Sounds reasonable

Eric Wieser (Nov 18 2021 at 20:54):

Jakob von Raumer said:

has_lsmul and has_rsmul?

Before embarking on such a change, I'd recommend collecting the rationale for doing so into a chunk of prose and making a github issue about it.

Eric Wieser (Nov 18 2021 at 20:55):

(my current stance is mild opposition, mainly because I think we need a clear argument for it being useful before doubling the amount of work we do)

Eric Wieser (Nov 18 2021 at 20:57):

I'd also be tempted to go ahead and PR the is_symmetric_smul stuff, since I found a number of other places where I wanted it

Jakob von Raumer (Nov 18 2021 at 20:59):

Did you read the thread above? What's your opinion in changing the current definition of module?

Eric Wieser (Nov 18 2021 at 21:12):

Are you actually suggesting changing module, or just renaming it to left_module and creating something new to replace module?

Jakob von Raumer (Nov 18 2021 at 21:20):

Well it was @Reid Barton's suggestion at first, but I tend to agree with it the more I think about where I'd otherwise need to plug in is_symmetric_smul R M. Make module R M mean symmetric R-R-bimodule, and derive an instance for it from left_module R M whenever R is commutative.

Eric Wieser (Nov 18 2021 at 21:56):

Surely we want to derive a left_module instance from module though too (module.to_left_module), since all bi-modules are unimodules? We can't have both directions.

Jakob von Raumer (Nov 18 2021 at 22:02):

Ah, damn, you're right. Sounds pretty promising that in Lean 4 we will be able to have both...

Jakob von Raumer (Nov 18 2021 at 22:02):

But then maybe we should stick to the previous plan and lazily add is_symmetric_smul where needed?

Jakob von Raumer (Nov 18 2021 at 22:02):

Eric Wieser said:

I'd also be tempted to go ahead and PR the is_symmetric_smul stuff, since I found a number of other places where I wanted it

What other places for example?

Jakob von Raumer (Nov 18 2021 at 22:05):

But I'd be happy for you to PR it, happy for everything that breaks my PR into smaller pieces ^^

Jakob von Raumer (Nov 18 2021 at 22:09):

There's a few additional closure properties in here

Eric Wieser (Nov 18 2021 at 22:19):

what other places for example?

IMO docs#star_module should be stated in terms of a right action on one side, but that's annoying in commutative actions without is_symmetric_smul

Jakob von Raumer (Nov 18 2021 at 22:25):

Eric Wieser said:

IMO docs#star_module should be stated in terms of a right action on one side, but that's annoying in commutative actions without is_symmetric_smul

Oh, does that also contain the potential of having issues opposite (opposite R)when applied twice? :thinking:

Heather Macbeth (Nov 18 2021 at 22:31):

Jakob von Raumer said:

Oh, does that also contain the potential of having issues opposite (opposite R)when applied twice? :thinking:

Let me advertise two theories for a refactor that could deal with this:

Jakob von Raumer (Nov 18 2021 at 22:39):

Ah, thanks. is "eta for structures" really a solution? We won't have eta for structures in Lean 4 either

Heather Macbeth (Nov 18 2021 at 22:40):

I think it was under consideration?
https://github.com/leanprover/lean4/issues/777#issuecomment-964207928

Jakob von Raumer (Nov 19 2021 at 08:22):

Oh cool :) I proposed it to Sebastian a while ago, and he didn't sound like Leo and him liked it

Eric Wieser (Nov 19 2021 at 12:12):

See the topic on left vs right modules in tensor products for some related discussion about left and right modules (which was moved from here)

Jireh Loreaux (Mar 13 2022 at 04:14):

What's the current status of this discussion? It would be nice to have a way to talk about bimodules and two-sided ideals in non-commutative rings sometime soon.

Yaël Dillies (Mar 13 2022 at 13:12):

cc @Christopher Hoskin :grinning:

Eric Wieser (Mar 13 2022 at 15:49):

R-S-Bimodules are possible as [module R M] [module Sᵐᵒᵖ M] [smul_comm_class R Sᵐᵒᵖ M], what we're missing is sub-bimodules

Jireh Loreaux (Mar 13 2022 at 16:15):

Ah, okay. I only looked for two-sided ideals. Silly me. Should I define those, or wait for something else someone is working on?

Eric Wieser (Mar 13 2022 at 20:50):

I think we probably want subbimodule R S M and then can define biideal R as subbimodule R R R

Eric Wieser (Mar 13 2022 at 20:50):

Likely with better names

Jireh Loreaux (Mar 13 2022 at 21:19):

ah, I was thinking just bimodule R R I but I see now why sub-bimodule makes more sense.

Oliver Nash (May 26 2022 at 18:00):

I just opened #14399 which defines right ideals. I confess I have lost track of where we are with this. Other than code duplication, is there any reason why this is a silly approach?

Actually I just wanted the result that a division ring is Artinian but I got annoyed when I realised I could only handle the left case so I copied near-minimal amount of left ideal API to allow me do what I wanted. The PR is thus a silly mixture of two things; I'm happy to split it up but first I thought I'd check here.

Is this crazy? Do we actually want to go in this direction?

Oliver Nash (May 26 2022 at 18:42):

(the obvious alternative is just to work with ideal Rᵐᵒᵖ but then all elements live in a different type which will be pain)

Yaël Dillies (May 26 2022 at 18:44):

Coming from the order theory library where everything is dualized by hand (still longing for a to_dual attribute), I would say that you should duplicate everything. It's not twice harder to write twice almost the same thing.

Yaël Dillies (May 26 2022 at 18:45):

The only problem I see is that docs#mul_opposite is irreducible, so you can't use it to easily dualize lemmas as we do with docs#order_dual.

Yaël Dillies (May 26 2022 at 18:45):

Maybe you can make it locally reducible when dualizing lemmas?

Yaël Dillies (May 26 2022 at 18:46):

... and left_ideal and right_ideal are different structures, so you can't rely on that trick when the statement mentions them.

Eric Wieser (May 26 2022 at 21:03):

the obvious alternative is just to work with ideal Rᵐᵒᵖ but then all elements live in a different type which will be pain

My vague memory was that this doesn't actually mean the right thing; but perhaps I told @Haruhisa Enomoto something wrong in their PR

Oliver Nash (May 27 2022 at 11:15):

IIUC, you are referring to this comment on #13862. I agree with your comment there.

Oliver Nash (May 27 2022 at 11:15):

For the sake of definiteness, given a (semi)ring R there are four things one can consider:

  1. submodule R R -- Left ideal of R
  2. submodule Rᵐᵒᵖ R -- Right ideal of R
  3. submodule Rᵐᵒᵖ Rᵐᵒᵖ -- Left ideal of Rᵐᵒᵖ (corresponds to right ideal of R)
  4. submodule R Rᵐᵒᵖ -- Right ideal of Rᵐᵒᵖ (corresponds to left ideal of R)

Oliver Nash (May 27 2022 at 11:16):

And you were correctly pointing out that 2 and 3 are not equal (though they do "correspond" --- mathematically, the point is that when Rᵐᵒᵖ appears as the second argument in submodule, its multiplicative structure has been forgotten so there's no difference between it and R).

Oliver Nash (May 27 2022 at 11:18):

Looking this morning, we are very nearly able to work with sub-bimodules. The only missing piece is:

import ring_theory.tensor_product

open_locale tensor_product

variables (R S M : Type*) [semiring R] [semiring S]
variables [add_comm_monoid M] [module R M] [module Sᵐᵒᵖ M] [_i : smul_comm_class R Sᵐᵒᵖ M]

example : module (R [] Sᵐᵒᵖ) M := by apply_instance -- Currently fails

Oliver Nash (May 27 2022 at 11:20):

I'll try to PR something that fixes this (today if I get time, though I'm travelling so it could be Monday).

Oliver Nash (May 27 2022 at 11:21):

For emphasis, we just need to fill the sorry below:

import ring_theory.tensor_product

open_locale tensor_product

variables (R S M : Type*) [semiring R] [semiring S]
variables [add_comm_monoid M] [module R M] [module Sᵐᵒᵖ M] [_i : smul_comm_class R Sᵐᵒᵖ M]

instance foo : module (R [] Sᵐᵒᵖ) M := sorry

-- YAY: a subbimodule:
#check submodule (R [] Sᵐᵒᵖ) M

/-- A two-sided ideal. -/
def bi_ideal := submodule (R [] Rᵐᵒᵖ) R

Oliver Nash (May 27 2022 at 11:23):

However I think we should still have a definition of def right_ideal := submodule Rᵐᵒᵖ R as proposed in my #14399.

Oliver Nash (May 27 2022 at 11:24):

(my only mild concern is that when we have true rings as opposed to semirings we might want to work with R ⊗[ℤ] Sᵐᵒᵖ but I think this shouldn't really be a problem)

Eric Wieser (May 27 2022 at 12:10):

Do we run into trouble with diamonds when M = (R ⊗[ℕ] Sᵐᵒᵖ)?

Eric Wieser (May 27 2022 at 12:11):

Oliver Nash said:

And you were correctly pointing out that 2 and 3 are not equal (though they do "correspond" --- mathematically, the point is that when Rᵐᵒᵖ appears as the second argument in submodule, its multiplicative structure has been forgotten so there's no difference between it and R).

I think I was confused when I wrote this and thought they didn't even correspond, but you're obviously right that they do. Indeed, the definition of docs#mul_opposite.has_scalar confirms that the multiplicative structure is forgotten.

Julian Külshammer (May 27 2022 at 14:38):

I should probably emphasise again that a two-sided ideal should not be called a bi-ideal. That is something else: https://ncatlab.org/nlab/show/biideal Personally, my preference would be to to rename the current ideal to left_ideal, and name a two-sided ideal just ideal, but if that is not wished for, just call it a two_sided_ideal.

Oliver Nash (May 27 2022 at 14:59):

Thanks @Julian Külshammer I do now remember you making this important point before. I'm hoping finally to push through definitions of right- and two-sided ideals in the next few days and will make sure to remember not to say "bi-ideal" anywhere.

Oliver Nash (May 27 2022 at 15:01):

As to the terminology, I wonder if we could have notation, localized to commutative/non-commutative locales that controlled whether ideal meant two-sided or left. For now I think we'll probably have to stick with ideal meaning left though.

Oliver Nash (May 30 2022 at 16:24):

I've just pushed #14465 which I think should provide a convenient theory for two-sided submodules of bimodules and in particular allow us to define two-sided ideals easily.

Oliver Nash (May 30 2022 at 16:26):

Eric Wieser said:

Do we run into trouble with diamonds when M = (R ⊗[ℕ] Sᵐᵒᵖ)?

In fact we don't because (R ⊗[ℕ] Sᵐᵒᵖ) is not a module over Sᵐᵒᵖ because our definition of tensor product only picks up auxiliary actions from the left factor. However even if we did I think this would be a diamond we could live with.

Oliver Nash (Jun 16 2022 at 13:36):

Highlighting a related discussion from GitHub in case anyone wants to comment.

Oliver Nash (Jun 16 2022 at 13:48):

The nub is that if MM and NN are AA-modules and AA is an RR-algebra, then MRNM \otimes_R N is naturally an AA-module in two different ways, depending on whether we define: a(mn)=(am)na \cdot (m \otimes n) = (a \cdot m) ⊗ n (the "left option") or a(mn)=m(an)a \cdot (m \otimes n) = m \otimes (a \cdot n) (the "right option").

If we want to work with these two different AA-module structures using typeclasses, we need two different types indicating whether we want to pick up the left or right AA-action. Currently in Mathlib, we just arbitrarily always take the left action (thus ignoring the action of AA on NN).

I sketched out some thoughts about how to resolve this ages ago here https://leanprover.zulipchat.com/#narrow/stream/144837-PR-reviews/topic/.234773.20base.20change/near/240929258

Oliver Nash (Jun 16 2022 at 13:55):

In the case at hand, we are defining an ARBA \otimes_R B-module structure on a module MM that carries commuting AA-module and BB-module structures (for RR-algebras AA, BB over a commutative ring RR). This fine except for the case M=ARAM = A \otimes_R A (for AA commutative) when our left-only convention makes ARAA \otimes_R A admissible and get a weird module structure on ARAA \otimes_R A such that (ab)(ab)=(aba)b(a \otimes b) \cdot (a' \otimes b') = (aba') \otimes b'.

Haruhisa Enomoto (Jun 18 2022 at 04:44):

Oliver Nash said:

The nub is that if MM and NN are AA-modules and AA is an RR-algebra, then MRNM \otimes_R N is naturally an AA-module in two different ways, depending on whether we define: a(mn)=(am)na \cdot (m \otimes n) = (a \cdot m) ⊗ n (the "left option") or a(mn)=m(an)a \cdot (m \otimes n) = m \otimes (a \cdot n) (the "right option").

My naive mathematical feeling is that, in this case, MRNM \otimes_R N should be considered as a left ARAA \otimes_R A-module, and picking up left or right AA-action corresponds to considering ring morphisms AARAA \to A \otimes_R A defined by aa1a \mapsto a \otimes 1 and a1aa \mapsto 1 \otimes a.

Oliver Nash (Jun 20 2022 at 09:18):

@Haruhisa Enomoto I agree and I have a plan that should make this work (though it's not my current priority).

Oliver Nash (Aug 02 2022 at 10:07):

Oliver Nash said:

I've just pushed #14465 which I think should [...] allow us to define two-sided ideals easily.

I just returned to this PR and have put it up for review again.

Jireh Loreaux (Aug 02 2022 at 14:21):

I missed this during my hiatus. I'm super excited. I'll review it, but I'm not sure I'll have anything intelligent to say. I definitely would have missed that diamond previously mentioned.

Eric Wieser (Aug 02 2022 at 14:23):

I should have some time to look on Thursday

Oliver Nash (Aug 02 2022 at 14:47):

Thank you both. No rush but any comments very gratefully received!

Oliver Nash (Aug 12 2022 at 18:17):

Now that #14465 has been merged, it might be a good time for somebody to develop the theory of two-sided ideals. Here is how I imagine one might start:

import algebra.module.bimodule

open_locale tensor_product
open mul_opposite

local attribute [instance] tensor_product.algebra.module

/-- A two-sided ideal in a semiring `R` is a left `submodule` of `R` as a `module` over
`R ⊗[ℕ] Rᵐᵒᵖ`. -/
@[reducible] def two_sided_ideal (R : Type*) [semiring R] := submodule (R [] Rᵐᵒᵖ) R

namespace two_sided_ideal

variables (R : Type*) [semiring R] (I : two_sided_ideal R) {a b : R}

lemma mul_mem_left (h : b  I) : a * b  I :=
begin
  convert I.smul_mem (a ⊗ₜ 1) h,
  simp [tensor_product.algebra.smul_def],
end

lemma mul_mem_right (h : a  I) : a * b  I :=
begin
  convert I.smul_mem (1 ⊗ₜ op b) h,
  simp [tensor_product.algebra.smul_def],
end

/-- Forgetting the right action, a `two_sided_ideal` is just a left `ideal`. -/
def to_ideal : ideal R := subbimodule.to_submodule I

-- TODO Lots more boilerplate, presumably can be modelled on existing `ideal` API.

end two_sided_ideal

Oliver Nash (Aug 12 2022 at 18:17):

Note that these still require the ring to be unital but it's still some progress.

Jireh Loreaux (Aug 12 2022 at 18:53):

Speaking of needing the rings to be unital: this is because of the module restriction, right? We also need modules over non-unital rings. My student is currently developing the theory of Hilbert modules but currently she is doing it over a unital C*-algebra because of this requirement.

Oliver Nash (Aug 12 2022 at 21:22):

Yes, unitality is forced on us with the proposed setup because docs#module requires a docs#semiring rather than a docs#non_unital_semiring . To remove this I suppose we'd have to introduce some sort of non_unital_module class with the same axioms as docs#module except without the one_smul axiom (ultimately coming from docs#mul_action). And then I guess docs#submodule would then be redefined using non_unital_module (since the identity plays no role for docs#submodule) and then we would be able to have non-unital docs#submodule and left docs#ideal s.

Oliver Nash (Aug 12 2022 at 21:25):

I think that should do it in terms of changes to the typeclass hierarchy (just one new class) but there would also be some more work to do so that we know that A ⊗[R] B is a docs#non_unital_comm_semiring when A and B are: we currently only know this for docs#comm_semiring.

Oliver Nash (Aug 12 2022 at 21:25):

Hopefully that's all correct, I'm typing this off the top of my head late just before I fall asleep.

Eric Wieser (Aug 12 2022 at 22:16):

Is it likely that we need to generalize mul_actions too?

Jireh Loreaux (Aug 12 2022 at 22:35):

Let's only define non-unital mul_actions if we need to. I suspect it's less (or not at all?) necessary, but I've been wrong before!

Junyan Xu (Aug 12 2022 at 23:07):

How about simply define non_unital_module R M as module (unitization ℕ R) M? By the way someone should fix src#unitization.comm_semiring now that we have docs#non_unital_comm_semiring.

Jireh Loreaux (Aug 13 2022 at 00:20):

I'll fix docs#unitization.comm_semiring tonight. I think the unitization trick might work, and it could actually be fairly convenient.

Junyan Xu (Aug 13 2022 at 02:54):

If unitization is a trick then defining bimodules using action of the tensor product is definitely a bigger trick :)

Jireh Loreaux (Aug 14 2022 at 06:40):

#16048 for the docs#unitization.comm_semiring fix. Somebody can pop it on the queue once it passes CI (just waiting for the linter).

Julian Külshammer (Aug 16 2022 at 18:04):

@Oliver Nash How much of the boilerplate do you think is necessary to make your draft a valid PR? I'm imagening that some stuff would already benefit from just being able to talk about two-sided ideals, e. g. the definition of the Jacobson radical of a two-sided ideal in #13862.

Jireh Loreaux (Aug 16 2022 at 18:17):

Regarding the unitization trick for modules over non-unital rings: what I really want in order to make this nice is an instance module (unitization 𝕜 R) M given a hypothesis module (unitization ℕ R) M where 𝕜 is a comm_ring. In other words, in practice I want to be able to replace the ring unitization with the C⋆-algebra unitization (where 𝕜 = ℂ and R is a non-unital C⋆-algebra). Is this feasible?

Oliver Nash (Aug 16 2022 at 18:40):

@Julian Külshammer I'm not sure. Certainly such a PR should include lemmas like zero_mem, add_mem, sub_mem, ext, ... I'd take a careful look at the existing API for docs#submodule and docs#ideal and probably add quite a lot of what they have since code like this is fairly uncontroversial (and easy to write).

However I think there are two questions to answer before embarking on such a task:

  1. Should we make two_sided_ideal a specialisation of a new subbimodule R S M structure? [probably]
  2. Should we wait till we've resolved the issue that submodule R M currently requires R to be unital? [probably not]

Oliver Nash (Aug 16 2022 at 18:42):

If I ever get a chance to return to this PR #14399 (defining right ideals) then it should give an example of a minimal API for a new definition like this.

Oliver Nash (Aug 16 2022 at 18:48):

@Jireh Loreaux I think that would not be feasible because the carrier type 𝕜 in such an instance would be undetermined.

Oliver Nash (Aug 16 2022 at 18:49):

IIUC if you wanted to pursue this you would have to introduce a type synonym for M and use that in the instance.

Jireh Loreaux (Aug 16 2022 at 18:50):

Yeah, it definitely felt like this instance was "going the wrong way"

Oliver Nash (Aug 16 2022 at 18:51):

It makes mathematical sense though and I think we'll be able to do this sort of thing in Lean 4.

Oliver Nash (Aug 16 2022 at 18:51):

For now a type synonym (that captures 𝕜) should work.

Jireh Loreaux (Aug 16 2022 at 18:53):

Well, I'm certainly wondering at what point it makes sense to specialize all (okay, I only mean most) of the C⋆-algebra theory to , and this might be one situation.


Last updated: Dec 20 2023 at 11:08 UTC