Zulip Chat Archive

Stream: mathlib4

Topic: Quotient ring basic issue


Khang (Aug 18 2025 at 10:22):

I'm trying to start work on quotient rings and ideals, but while trying to warm up on some basic lemmas I faced difficulty, which boils down to this:

import Mathlib.RingTheory.Ideal.Quotient.Defs

variable {R S : Type*} [Ring R] (I : Ideal R) [I.IsTwoSided] [Ring (R  I)]
  {a b : R}

example (a : R  I) : Ideal.Quotient.mk I a.out = a := Ideal.Quotient.mk_out a

example (a b : R  I) : a + b = Ideal.Quotient.mk I (a.out + b.out) := by
  rw [RingHom.map_add]
  rw [Ideal.Quotient.mk_out a, Ideal.Quotient.mk_out b]
  -- ⊢ a + b = a + b
  sorry

The first example works fine: I can recover a value a by Ideal.Quotient.mk I a.out = a. But when I try to throw addition into the mix things get strange. I tried using rfl in the place of sorry, it gives the error

tactic 'rfl' failed, the left-hand side
     @HAdd.hAdd (R  I) (R  I) (R  I)
       (@instHAdd (R  I)
         (@Distrib.toAdd (R  I)
           (@NonUnitalNonAssocSemiring.toDistrib (R  I) Ring.toNonAssocRing.toNonUnitalNonAssocSemiring)))
       a b
   is not definitionally equal to the right-hand side
     @HAdd.hAdd (R  I) (R  I) (R  I)
       (@instHAdd (R  I)
         (@Distrib.toAdd (R  I)
           (@NonUnitalNonAssocSemiring.toDistrib (R  I)
             (Ideal.Quotient.ring I).toNonAssocSemiring.toNonUnitalNonAssocSemiring)))
       a b

which, yes, I guess makes sense but why is it choosing two different ways of getting to a NonUnitalNonAssocSemiring?

Eric Wieser (Aug 18 2025 at 10:42):

[Ring (R ⧸ I)] is not a safe assumption, it adds a separate ring structure

Eric Wieser (Aug 18 2025 at 10:42):

Why did you add it?

Khang (Aug 18 2025 at 10:45):

I added it in hopes that Mathlib defined things like addition as ⟦a + b⟧ = ⟦a⟧ + ⟦b⟧ somewhere.

I find that if I type

#synth Ring (R  I)

then Lean would look into this to construct the Ring on R / I:

instance ring (I : Ideal R) [I.IsTwoSided] : Ring (R  I) := fast_instance%
  { __ : AddCommGroup (R  I) := inferInstance
    __ : Ring (Quotient.ringCon I).Quotient := inferInstance }

Khang (Aug 18 2025 at 10:51):

Also, if this separate ring structure is not what I'm going for, how should I go about implementing my own Ring structure over R ⧸ I so I can proceed?

Kenny Lau (Aug 18 2025 at 10:52):

why do you need your own ring structure

Khang (Aug 18 2025 at 10:53):

I want to be able to have

example {a b : R} : (a + b : R  I) = a + b := sorry

So I can move on, but with the Mathlib's default implementation of a ring over R ⧸ I doesn't allow me to prove that

Eric Wieser (Aug 18 2025 at 10:57):

import Mathlib.RingTheory.Ideal.Quotient.Defs

variable {R S : Type*} [Ring R] (I : Ideal R) [I.IsTwoSided]
  {a b : R}

example {a b : R} : (a + b : R  I) = (show R  I from a) + b := rfl -- works

Eric Wieser (Aug 18 2025 at 10:58):

You're not supposed to use ⟦ ⟧ here, you should use docs#Ideal.Quotient.mk instead

Eric Wieser (Aug 18 2025 at 10:58):

Which you can write as

example {a b : R} : ((a + b) : R  I) = a + b := rfl

Eric Wieser (Aug 18 2025 at 10:59):

This is all a notational mess that we should clean up, but if you ignore the notation mathlib uses you'll find the lemmas don't apply

Khang (Aug 18 2025 at 11:02):

Thanks @Eric Wieser ! These will definitely help me move forward.

Khang (Aug 18 2025 at 11:04):

I also noticed you used a show ... from ... idiom, something I've never seen before. How is

(show R  I from a) + b

different from

(a : R  I) + b

? I would assume it's the same, but the latter doesn't work when placed in your example.

Ruben Van de Velde (Aug 18 2025 at 12:20):

I'm fuzzy on the details myself, but I think show gives more guarantees that your term is of the correct type?

Eric Wieser (Aug 18 2025 at 12:34):

show leaves behind a record of what the requested type was, (_ : _) does not


Last updated: Dec 20 2025 at 21:32 UTC