Zulip Chat Archive

Stream: Is there code for X?

Topic: Invariant subMonoid/AddMonoid/Module


Kevin Buzzard (Mar 23 2025 at 18:11):

import Mathlib

variable {G : Type*} [Group G] {A : Type*} [AddCommMonoid A]
    [DistribMulAction G A] {g : G} {V : Subgroup G}

#synth AddCommMonoid {a : A //  γ  V, γ  a = a} -- fails

Do we have the type of invariants of a group action, as a monoid or submonoid? Similarly if [Ring R] [Module R A] [SMulCommClass R G A] do we have Module R {a : A // ∀ γ ∈ V, γ • a = a} in some form? I know we have docs#groupCohomology.H0 but honestly I am reluctant to drag category theory into this.

Edward van de Meent (Mar 23 2025 at 18:18):

afaict, no

Edward van de Meent (Mar 23 2025 at 18:20):

or actually, FixedPoints.subgroup?

Edward van de Meent (Mar 23 2025 at 18:27):

specifically, the incantation seems to be FixedPoints.addSubmonoid V A

Edward van de Meent (Mar 23 2025 at 18:31):

import Mathlib

variable {G : Type*} [Group G] {A : Type*} [AddCommMonoid A]
    [DistribMulAction G A] {g : G} {V : Subgroup G}

#synth AddCommMonoid (FixedPoints.addSubmonoid V A) -- success

example (a:A) : a  FixedPoints.addSubmonoid V A   v  V, v  a = a := by
  simp? says simp only [FixedPoints.mem_addSubmonoid, Subtype.forall, Subgroup.mk_smul]

Jireh Loreaux (Mar 23 2025 at 18:50):

When I read the title, I thought you meant docs#Module.End.invtSubmodule. FixedPoints definitely seems like the appropriate name for your object.

Yury G. Kudryashov (Mar 23 2025 at 18:59):

We have docs#LinearMap.eqLocus which you can use with id as one of the arguments.

Yury G. Kudryashov (Mar 23 2025 at 19:01):

Sorry, this is for 1 map, not for a group action.

Kevin Buzzard (Mar 23 2025 at 19:33):

docs#FixedPoints.addSubmonoid

Michał Mrugała (Mar 23 2025 at 19:57):

Do we have a proof that this is the 0th cohomology group?

Kevin Buzzard (Mar 24 2025 at 01:08):

No but it would be a nice exercise to add. You'd have to choose whether to make it an isomorphism in the category or an apppropriate equiv.

Kevin Buzzard (Mar 24 2025 at 01:13):

I realise that I am in a situation where I really don't want the fixed points as a submonoid, I want them as a monoid. Do you think that this sort of code would be appropriate for mathlib:

import Mathlib.Algebra.Ring.Action.Submonoid

variable (M α : Type*) [Monoid M] [AddMonoid α] [DistribMulAction M α]

def FixedPoints.AddMonoid : Type _ := FixedPoints.addSubmonoid M α

instance : AddMonoid (FixedPoints.AddMonoid M α) :=
  inferInstanceAs <| AddMonoid (FixedPoints.addSubmonoid M α)

and similar definitions for AddGroup, Module etc. Or should I keep it in FLT? I have had bad experiences with typeclass inference when treating terms as types via (for example the refactor of docs#NumberField.RingOfIntegers to be a type rather than a term, even though it's defined as a the coercion-to-sort of a term, solved a lot of timeouts). I know that I want my invariants to be types; it's like docs#DedekindDomain.FiniteAdeleRing where the main object (the finite adele ring) is defined as a subobject of an auxiliary object K_hat R K, but the main object has all the structure. Here I am defining spaces of modular forms which should really be types as they will need a lot of API, but they're fixed points of a group action in my context so they are subobjects of an auxiliary thing which we don't care about once we've made the API.

Eric Wieser (Mar 24 2025 at 01:44):

I think that would be reasonable if the type was just FixedPoints

Eric Wieser (Mar 24 2025 at 01:45):

(docs#FixedPoints just in case)

Kevin Buzzard (Mar 25 2025 at 23:49):

So something like this?

import Mathlib

-- or def?
abbrev FixedPoints (M A : Type*) [SMul M A] : Type _ :=
  {a : A //  m : M, m  a = a}

namespace FixedPoints

variable {M A : Type*}

@[ext]
lemma ext [SMul M A] (a b : FixedPoints M A) (h : a.1 = b.1) : a = b := by
  cases a; cases b; subst h; rfl

instance addZeroClass [AddZeroClass A] [DistribSMul M A] : AddZeroClass (FixedPoints M A) where
  zero := 0, smul_zero
  add a b := a.1 + b.1, by
    intro m
    rw [smul_add m a.1 b.1, a.2 m, b.2 m]
  zero_add a := by
    ext
    exact zero_add a.1
  add_zero a := by
    ext
    exact add_zero a.1

lemma zero_def [AddZeroClass A] [DistribSMul M A] : (0 : FixedPoints M A) = 0, smul_zero := rfl

lemma coe_add [AddZeroClass A] [DistribSMul M A] (a b : FixedPoints M A) :
    (a + b : FixedPoints M A).1 = a.1 + b.1 := rfl

instance addMonoid [AddMonoid A] [DistribSMul M A] : AddMonoid (FixedPoints M A) where
  __ := addZeroClass
  add_assoc a b c := by
    ext
    exact add_assoc a.1 b.1 c.1
  nsmul n a := AddMonoid.nsmul n a.1, by
    intro m
    induction n with
    | zero =>
      rw [AddMonoid.nsmul_zero]
      exact smul_zero m
    | succ n IH =>
      rw [AddMonoid.nsmul_succ, smul_add, IH, a.2]
  
  nsmul_zero a := by
    simp [zero_def]
  nsmul_succ n a := by
    ext
    simp [succ_nsmul, coe_add]

instance addCommMonoid [AddCommMonoid A] [DistribSMul M A] : AddCommMonoid (FixedPoints M A) where
  __ := addMonoid
  add_comm a b := by
    ext
    exact add_comm a.1 b.1

instance subNegMonoid [SubNegMonoid A] [DistribSMul M A] : SubNegMonoid (FixedPoints M A) where
  __ := addMonoid
  neg a := ⟨-a.1, sorry
  zsmul n a := SubNegMonoid.zsmul n a.1, sorry
  zsmul_zero' a := sorry
  zsmul_succ' n a := sorry
  zsmul_neg' n a := sorry

-- ...

instance module {R : Type*} [Semiring R] [AddCommMonoid A] [Module R A] [Monoid M]
  [DistribMulAction M A] [SMulCommClass M R A] [Module R A] : Module R (FixedPoints M A) := sorry

-- ...

Yury G. Kudryashov (Mar 25 2025 at 23:54):

A few suggestions:

  • please use def, not abbrev;
  • please put it in the MulAction namespace, because
    • we will need an additive version
    • it makes sense to study fixed points of a single map.

Yury G. Kudryashov (Mar 25 2025 at 23:55):

If you use a Subtype, then you can get AddMonoid etc instances "for free" by forcing defeq to docs#FixedPoints.addSubmonoid etc

Eric Wieser (Mar 26 2025 at 00:03):

I think it might need to be abbrev unless you also promise to never write .1

Eric Wieser (Mar 26 2025 at 00:03):

Otherwise the .1 is ill-typed

Kevin Buzzard (Mar 26 2025 at 00:04):

I changed abbrev to def and nothing broke?

Eric Wieser (Mar 26 2025 at 00:14):

Here's another approach:

import Mathlib

structure FixedPointsType (M A : Type*)

def fixedPoints (M A : Type*) [SMul M A] : FixedPointsType M A := ⟨⟩

instance (M A : Type*) [SMul M A] : SetLike (FixedPointsType M A) A where
  coe _ := {a : A |  m : M, m  a = a}
  coe_injective' x y _ := by cases x; cases y; rfl

variable {A M}

instance [Zero A] [SMulZeroClass M A] : ZeroMemClass (FixedPointsType M A) A where
  zero_mem _ := smul_zero

instance [AddMonoid A] [DistribSMul M A] : AddSubmonoidClass (FixedPointsType M A) A where
  add_mem _ {a b} ha hb := fun m => (smul_add m a b).trans congr($(ha m) + $(hb m))

instance [Monoid M] [AddMonoid A] [DistribMulAction M A] : AddSubmonoidClass (FixedPointsType M A) A where

instance [Monoid M] [AddGroup A] [DistribMulAction M A] : AddSubgroupClass (FixedPointsType M A) A where
  neg_mem _ {_} hx := (FixedPoints.addSubgroup M A).neg_mem hx

instance [Monoid M] [Monoid A] [MulDistribMulAction M A] : SubmonoidClass (FixedPointsType M A) A where
  mul_mem _ {a b} ha hb := fun m => (smul_mul' m a b).trans congr($(ha m) * $(hb m))
  one_mem _ := smul_one

instance [Monoid M] [Semiring A] [MulSemiringAction M A] : SubsemiringClass (FixedPointsType M A) A where
instance [Monoid M] [Ring A] [MulSemiringAction M A] : SubringClass (FixedPointsType M A) A where
-- test it works: we get all the `Comm` instance for free because of the `*Class` machinery above
variable [Monoid M] [AddCommMonoid A] [DistribMulAction M A] in
#synth AddCommMonoid (fixedPoints M A)
variable [Monoid M] [CommRing A] [MulSemiringAction M A] in
#synth CommRing (fixedPoints M A)

Eric Wieser (Mar 26 2025 at 00:14):

This one has the nice benefit that (fixedPoints M A) can be cast to a AddSubmonoid or an AddSubgroup

Eric Wieser (Mar 26 2025 at 00:16):

Though it breaks being able to write fixedPoints M A = fixedPoints N A without inserting coercions

Yury G. Kudryashov (Mar 26 2025 at 00:32):

Eric Wieser said:

I think it might need to be abbrev unless you also promise to never write .1

Or you can use a 2-field structure (but you can't use lemmas about Subtype in this case).

Eric Wieser (Mar 26 2025 at 00:53):

Edited above to include all the instances up to CommRing

Kevin Buzzard (Mar 26 2025 at 15:24):

Eric Wieser said:

Here's another approach:

I am not clear about whether this solves the problem which I'm worried about, and I'm also not clear about whether I should be worrying about this problem.

With your approach:

variable [Monoid M] [CommRing A] [MulSemiringAction M A] in
#check Module (fixedPoints M A) (fixedPoints M A)
-- Module ↥(fixedPoints M A) ↥(fixedPoints M A) : Type u_1

#count_heartbeats in -- 6629 heartbeats
variable [Monoid M] [CommRing A] [MulSemiringAction M A] in
#synth Module (fixedPoints M A) (fixedPoints M A)

Here we still see the . The is exactly what I want to get rid of, because of the awful experience we had with rings of integers of number fields, where Lean would constantly be trying to solve SMul (↥A) B with A : Subring X by searching for SMul X B (which often didn't exist, leading to very slow code and timeouts).

With my approach:

#count_heartbeats in -- 1812 heartbeats
variable [Monoid M] [CommRing A] [MulSemiringAction M A] in
#synth Module (FixedPoints M A) (FixedPoints M A)

My code is far more verbose than yours though, e.g.

instance commRing [Monoid M] [CommRing A] [MulSemiringAction M A] : CommRing (FixedPoints M A) where
  __ := subNegMonoid
  add_comm a b := by ext; push_cast; simp [add_comm]
  left_distrib a b c := by ext; push_cast; simp [left_distrib]
  right_distrib a b c := by ext; push_cast; simp [right_distrib]
  zero_mul a := by ext; push_cast; simp
  mul_zero a := by ext; push_cast; simp
  mul_assoc a b c := by ext; push_cast; simp [mul_assoc]
  neg_add_cancel a := by ext; push_cast; simp
  one_mul a := by ext; push_cast; simp
  mul_one a := by ext; push_cast; simp
  mul_comm a b := by ext; push_cast; simp [mul_comm]

I would like to go ahead with this in FLT because this construction is on the critical path to my next short-term goal, but ideally I'd like to choose the implentation which is mathlib-suitable. Any comments?

Eric Wieser (Mar 26 2025 at 15:26):

The verbosity is independently fixable by using Function.Injective.commRing etc

Jireh Loreaux (Mar 26 2025 at 15:28):

But doesn't that also run into performance issues? Or did that get fixed with the %fast_instance hack?

Eric Wieser (Mar 26 2025 at 15:28):

fast_instance% makes those go away

Eric Wieser (Mar 26 2025 at 15:28):

(and may also make lesser versions of those issues do so if used with Kevin's manual approach)

Kevin Buzzard (Mar 26 2025 at 15:28):

The other thing worth saying is that in my application the fixed points are modules, not monoids, so they are unlikely to be acting on something via SMul. But I could envisage people using this construction in e.g. Galois theory, where there is a constant tension between using IntermediateFields and Types in complex mathematical arguments.

Eric Wieser (Mar 26 2025 at 15:29):

(deleted)

Eric Wieser (Mar 26 2025 at 15:30):

In the galois theory case we already have docs#FixedPoints.intermediateField

Kevin Buzzard (Mar 26 2025 at 15:30):

Yes and this is a term, not a type, so we run into slowdowns because of the "ring of integers phenomenon"

Eric Wieser (Mar 26 2025 at 15:31):

My inclination would be to ignore the until you've actually written half of the code that works with the fixedpoints in the way you care about, and then see whether switching to what you've discussed in this thread makes thing faster

Kevin Buzzard (Mar 26 2025 at 15:33):

I don't quite understand "the way you care about" but I'm interpreting your message as "stick to coerced terms for now, and see what happens" (sorry, on a Eurostar with crappy WiFi for the next 3 hours)

Kevin Buzzard (Mar 26 2025 at 15:35):

(it's the perfect time for writing some Hecke algebra code without being told off for working on holiday though!)

Junyan Xu (Mar 26 2025 at 15:36):

Notice that we already have docs#Representation.invariants (the name was decided here).

Edison Xie (Mar 28 2025 at 01:41):

Michał Mrugała said:

Do we have a proof that this is the 0th cohomology group?

I need it :smiling_face_with_tear: if anyone has done it will be much appreciated... if no one else then I guess I'll have to make this one


Last updated: May 02 2025 at 03:31 UTC