Zulip Chat Archive

Stream: Is there code for X?

Topic: an algebra that is module-invertible is the base ring


Kenny Lau (Sep 24 2025 at 21:49):

import Mathlib

variable (R A : Type*) [CommRing R] [CommRing A] [Algebra R A] [Module.Invertible R A]

def algEquivOfInvertible : R ≃ₐ[R] A :=
  sorry

Kenny Lau (Sep 25 2025 at 00:54):

import Mathlib

def LinearEquiv.algEquiv {R A : Type*} [CommSemiring R] [CommSemiring A] [Algebra R A]
    (e : R ≃ₗ[R] A) : R ≃ₐ[R] A where
  __ := Algebra.ofId R A
  invFun := (e.symm : A →ₗ[R] R) ∘ₗ Algebra.lmul R A (e 1)
  left_inv x := calc
    e.symm (e 1 * (algebraMap R A) x)
      = e.symm (x  e 1) := by rw [Algebra.smul_def, mul_comm]
    _ = x := by rw [map_smul, e.symm_apply_apply, smul_eq_mul, mul_one]
  right_inv x := calc
    (algebraMap R A) (e.symm (e 1 * x))
      = (algebraMap R A) (e.symm (e 1 * x)) * e (e.symm 1  1) := by
          rw [smul_eq_mul, mul_one, e.apply_symm_apply, mul_one]
    _ = x := by rw [map_smul, Algebra.smul_def, mul_left_comm,  Algebra.smul_def _ (e 1),
           map_smul, smul_eq_mul, mul_one, e.apply_symm_apply,  mul_assoc,  Algebra.smul_def,
           map_smul, smul_eq_mul, mul_one, e.apply_symm_apply, one_mul]

instance isLocalizedModule_ofId {R : Type*} [CommSemiring R] (S : Submonoid R) :
    IsLocalizedModule S (Algebra.linearMap R (Localization S)) := by
  refine isLocalizedModule_iff_isLocalization.mpr ?_
  convert Localization.isLocalization
  exact S.map_id

theorem Module.Invertible.of_isLocalization (R R' M M' : Type*)
    [CommRing R] (S : Submonoid R) [CommRing R'] [Algebra R R'] [IsLocalization S R']
    [AddCommGroup M] [Module R M] [AddCommGroup M'] [Module R M']
    (f : M →ₗ[R] M') [IsLocalizedModule S f] [Module R' M'] [IsScalarTower R R' M']
    [Module.Invertible R M] : Module.Invertible R' M' :=
  .congr (IsBaseChange.equiv <| IsLocalizedModule.isBaseChange S R' f)

variable (R A : Type*) [CommRing R] [CommRing A] [Algebra R A] [Module.Invertible R A]

private theorem bijective_ofId_of_isLocalRing [IsLocalRing R] :
    Function.Bijective (Algebra.ofId R A) :=
  let e := (Module.Invertible.free_iff_linearEquiv (R := R) (M := A)).mp inferInstance
  e.symm.algEquiv.bijective

noncomputable def algEquivOfInvertible : R ≃ₐ[R] A :=
  .ofBijective (Algebra.ofId R A) <| by
    refine bijective_of_isLocalized_maximal
      (fun P _  Localization.AtPrime P)
      (fun P _  Algebra.linearMap R (Localization.AtPrime P))
      (fun P _  LocalizedModule P.primeCompl A)
      (fun P _  LocalizedModule.mkLinearMap _ _)
      (Algebra.linearMap R A)
      fun P _  ?_
    have : Module.Invertible (Localization.AtPrime P) (LocalizedModule P.primeCompl A) :=
      Module.Invertible.of_isLocalization _ _ _ _ P.primeCompl (LocalizedModule.mkLinearMap _ _)
    convert bijective_ofId_of_isLocalRing (Localization.AtPrime P) (LocalizedModule P.primeCompl A)
    ext x
    induction' x using Localization.induction_on with frac
    rw [Algebra.ofId_apply, Localization.mk_eq_mk', LocalizedModule.algebraMap_mk', IsLocalization.mk'_eq_mk', IsLocalizedModule.map_mk', IsLocalizedModule.mk_eq_mk']
    rfl

Kenny Lau (Sep 25 2025 at 01:00):

So #find_home! algEquivOfInvertible returned "Mathlib" which i take to mean that this belongs to a new file

Kenny Lau (Sep 25 2025 at 01:00):

@Aaron Liu would you agree?

Aaron Liu (Sep 25 2025 at 01:01):

Module.Invertible is defined in Mathlib.RingTheory.PicardGroup which is imported by no other files

Aaron Liu (Sep 25 2025 at 01:02):

if it doesn't massively increase the imports you could maybe put it there

Kenny Lau (Sep 25 2025 at 01:02):

i mean in general i'm in the camp of "let's split to as many files as possible to keep the imports small in each file"

Aaron Liu (Sep 25 2025 at 01:02):

or we move Module.Invertible somewhere else

Kenny Lau (Sep 25 2025 at 01:06):

Kenny Lau said:

i mean in general i'm in the camp of "let's split to as many files as possible to keep the imports small in each file"

image.png

never mind...

Kenny Lau (Sep 25 2025 at 02:08):

#29954

Ruben Van de Velde (Sep 25 2025 at 05:36):

It seems plausible that Module.Invertible could be defined in a separate, lighter file but the file isn't that big yet, so this is probably fine for now

Kenny Lau (Sep 25 2025 at 09:32):

so i realised that there is a more straightforward proof that should work for semirings

Kenny Lau (Sep 25 2025 at 11:19):

update: i realised while writing the proof on paper that I implicitly assumed for all x : A, 1 ⊗ₜ x = x ⊗ₜ 1, which is equivalent to the result (and equivalent to R -> A being an epimorphism of semirings)

Aaron Liu (Sep 25 2025 at 11:20):

Interesting

Aaron Liu (Sep 25 2025 at 11:20):

Can you fix it

Kenny Lau (Sep 25 2025 at 11:23):

so I'm able to make an R-linear map r : A -> R with r(1) = 1, so R -> A -> R is identity, but I can't prove that A -> R -> A is identity

Kenny Lau (Sep 25 2025 at 11:25):

fun fact, Nat is a local ring?!?!

Kenny Lau (Sep 25 2025 at 11:26):

and if you make 2 invertible, then 3/8 + 5/8 = 1, so the localization of a local ring is not a local ring?!?!

Aaron Liu (Sep 25 2025 at 11:28):

What's the definition of local ring again I think they might not be equivalent for semirings

Kenny Lau (Sep 25 2025 at 11:30):

/-- A semiring is local if it is nontrivial and `a` or `b` is a unit whenever `a + b = 1`.
Note that `IsLocalRing` is a predicate. -/
class IsLocalRing (R : Type*) [Semiring R] : Prop extends Nontrivial R where
  of_is_unit_or_is_unit_of_add_one ::
  /-- in a local ring `R`, if `a + b = 1`, then either `a` is a unit or `b` is a unit. In another
  word, for every `a : R`, either `a` is a unit or `1 - a` is a unit. -/
  isUnit_or_isUnit_of_add_one {a b : R} (h : a + b = 1) : IsUnit a  IsUnit b

Kenny Lau (Sep 25 2025 at 11:48):

so 2N is not a maximal ideal of N...

Aaron Liu (Sep 25 2025 at 11:49):

The maximal ideal is the nonzero nonone numbers

Kenny Lau (Sep 25 2025 at 11:49):

include 0

Aaron Liu (Sep 25 2025 at 11:49):

the nonone numbers

Aaron Liu (Sep 25 2025 at 11:50):

you need zero to be an ideal

Kenny Lau (Sep 25 2025 at 11:50):

so in fact there is exactly one maximal ideal of Nat :D

Kenny Lau (Sep 25 2025 at 11:50):

image.png

Kenny Lau (Sep 25 2025 at 11:51):

yeah, what on earth, this equivalence holds for comm semirings

Aaron Liu (Sep 25 2025 at 11:51):

Oh that's just great

Aaron Liu (Sep 25 2025 at 12:01):

I've realized I didn't actually have any nontrivial examples of invertible modules

Kenny Lau (Sep 25 2025 at 12:01):

and I have never thought about invertible modules over commutative semirings

Kenny Lau (Sep 25 2025 at 12:02):

Aaron Liu said:

I've realized I didn't actually have any nontrivial examples of invertible modules

it's related to class groups which is related to quadratic forms

Johan Commelin (Sep 25 2025 at 12:02):

Yeah, class group is the key concept here.

Kenny Lau (Sep 25 2025 at 12:02):

or you can use dedekind rings, from number fields

Aaron Liu (Sep 25 2025 at 12:02):

Sure but I don't know very much about those either

Kenny Lau (Sep 25 2025 at 12:02):

so you can use 2*3 = (1+r(-5))(1-r(-5)) (r = sqrt)

Aaron Liu (Sep 25 2025 at 12:03):

What does that do for me

Kenny Lau (Sep 25 2025 at 12:03):

and then the ideal (2, 1+sqrt(-5)) in Z[sqrt(-5)] is not principal

Aaron Liu (Sep 25 2025 at 12:03):

oh yes

Kenny Lau (Sep 25 2025 at 12:07):

@Aaron Liu you can search by class group on LMFDB

Kenny Lau (Sep 25 2025 at 12:13):

I think I have a proof now

Aaron Liu (Sep 25 2025 at 12:37):

Oh I think I figured out how to go from nonprincipal ideal to invertible module

Kenny Lau (Sep 25 2025 at 12:58):

import Mathlib

namespace Module.Invertible

variable {R M N : Type*} [CommSemiring R]
  [AddCommMonoid M] [Module R M] [Module.Invertible R M]
  [AddCommMonoid N] [Module R N] [Module.Invertible R N]

variable {f : M →ₗ[R] N} {g : N →ₗ[R] M}

theorem rightInverse_of_leftInverse (hfg : Function.LeftInverse f g) :
    Function.RightInverse f g :=
  Function.rightInverse_of_injective_of_leftInverse
    (bijective_of_surjective hfg.surjective).injective hfg

theorem leftInverse_of_rightInverse (hfg : Function.RightInverse f g) :
    Function.LeftInverse f g :=
  rightInverse_of_leftInverse hfg

variable (f g) in
theorem leftInverse_iff_rightInverse :
    Function.LeftInverse f g  Function.RightInverse f g :=
  rightInverse_of_leftInverse, leftInverse_of_rightInverse

def linearEquivOfLeftInverse (hfg : Function.LeftInverse f g) : M ≃ₗ[R] N :=
  .ofLinear f g (LinearMap.ext hfg) (LinearMap.ext <| rightInverse_of_leftInverse hfg)

def linearEquivOfRightInverse (hfg : Function.RightInverse f g) : M ≃ₗ[R] N :=
  .ofLinear f g (LinearMap.ext <| leftInverse_of_rightInverse hfg) (LinearMap.ext hfg)

variable (R) (A : Type*) [Semiring A] [Algebra R A] [Module.Invertible R A]

open TensorProduct

set_option synthInstance.maxHeartbeats 99999 in
/-- The algebra structure gives us a map `A ⊗ A → A`, which after tensoring by `Aᵛ` becomes a map
`A → R`, which is the inverse map we seek. -/
noncomputable def algEquivOfRing : R ≃ₐ[R] A :=
  let inv : A →ₗ[R] R :=
    linearEquiv R A ∘ₗ
      (LinearMap.mul' R A).lTensor (Dual R A) ∘ₗ
      (leftCancelEquiv A (linearEquiv R A)).symm
  have right : inv ∘ₗ Algebra.linearMap R A = LinearMap.id :=
    let s, hs := exists_finset ((linearEquiv R A).symm 1)
    LinearMap.ext_ring <| by simp [inv, hs, sum_tmul, map_sum,  (LinearEquiv.symm_apply_eq _).1 hs]
  { linearEquivOfRightInverse (f := Algebra.linearMap R A) (g := inv) (LinearMap.ext_iff.1 right),
    Algebra.ofId R A with }

end Module.Invertible

Kenny Lau (Sep 25 2025 at 13:15):

updated #29954

Aaron Liu (Sep 25 2025 at 14:08):

99999 is a bit as scary what's the usual number

Kenny Lau (Sep 25 2025 at 14:08):

20000

Kenny Lau (Sep 25 2025 at 14:09):

it's in the same order of magnitude

Aaron Liu (Sep 25 2025 at 14:09):

oh that's good

Kenny Lau (Sep 25 2025 at 14:47):

apparently it's only needed if i import Mathlib; in the PR where i work locally in the file, i don't need to set the max heartbeats


Last updated: Dec 20 2025 at 21:32 UTC