Zulip Chat Archive
Stream: general
Topic: How to understand why grind doesn't work?
Riccardo Brasca (Jul 11 2025 at 09:32):
grind is able to prove the following
example (a b c : Nat) (h : a = b) : a + c = c + b := by
grind
But not the following
import Mathlib
variable {R : Type*} [CommSemiring R] [IsCancelAdd R]
example (a b c : R) (h : a = b) : a + c = c + b := by
grind
(it is enough to add rw [add_comm a c] to make it working). How can I understand why it is smarter with ℕ? In particular, how can I make it as smart as for ℕ but for MyNat, my copy of the natural numbers (of course I've defined all the relevant instances, but still grind is better with ℕ)?
Henrik Böving (Jul 11 2025 at 09:46):
Have people in mathlib already established a connection between IsCancelAdd and grinds internal type classes?
Junyan Xu (Jul 11 2025 at 09:49):
I don't think IsCancelAdd is needed ...
Riccardo Brasca (Jul 11 2025 at 09:52):
Oh sorry, of course it's not (I minimized too much my original example where it was needed).
Riccardo Brasca (Jul 11 2025 at 09:53):
The question makes even more sense, with Nat grind realized that has to use add_comm, but not in general.
Henrik Böving (Jul 11 2025 at 12:56):
You need another grind typeclass for this to work:
variable {R : Type} [Lean.Grind.CommSemiring R] [Lean.Grind.AddRightCancel R]
example (a b c : R) (h : a = b) : a + c = c + b := by
grind
so someone needs to build that connection in mathlib
Riccardo Brasca (Jul 11 2025 at 13:06):
I see. This is still confusing though, why grind needs Lean.Grind.AddRightCancel R? As pointed out this is completely useless for the result at hand.
Rémy Degenne (Jul 11 2025 at 13:07):
But IsCancelAdd or Lean.Grind.AddRightCancel should not be needed to prove this.
variable {R : Type} [Lean.Grind.CommSemiring R]
example (a b c : R) (h : a = b) : a + c = c + b := by rw [h]; grind --succeeds
example (a b c : R) (h : a = b) : a + c = c + b := by grind -- fails
Is this expected? Shouldn't grind be able to use h? (I know nothing about what grind does)
Riccardo Brasca (Jul 11 2025 at 13:27):
Well, even the following does not work
variable {A : Type} [Lean.Grind.AddCommMonoid A]
example (a b : A) : a + b = b + a := by
grind
Riccardo Brasca (Jul 11 2025 at 13:28):
But I don't know if it is expected or not.
Henrik Böving (Jul 11 2025 at 14:46):
Riccardo Brasca said:
Well, even the following does not work
variable {A : Type} [Lean.Grind.AddCommMonoid A] example (a b : A) : a + b = b + a := by grind
The algebraic structure section of the manual has information on this. There is no built-in solver provided for monoids but only what is described in the manual.
Note that you can do the following:
variable {A : Type} [Lean.Grind.AddCommMonoid A]
example (a b : A) : a + b = b + a := by
grind [Lean.Grind.AddCommMonoid.add_comm]
As grind has the capability to instantiate theorems (see the section on e matching), keep in mind that it is not necessarily a good idea to just mark everything grind as grind cannot scale infinitely.
Riccardo Brasca (Jul 11 2025 at 14:50):
What I still don't get is why it works for Nat. Is it the case that Nat has special support?
Henrik Böving (Jul 11 2025 at 14:55):
Because Nat has the instance it needs to make the construction mentioned in the reference manual work:
#synth Lean.Grind.AddRightCancel Nat
Riccardo Brasca (Jul 11 2025 at 14:56):
But this is has to do with cancellativity.
Jireh Loreaux (Jul 11 2025 at 15:07):
Agreed, this is just congr and commutativity.
Riccardo Brasca (Jul 11 2025 at 15:10):
Anyway, the question is more generally the following: I have theorem that grind is able to prove immediately for Nat (where the equality is a consequence of a linear combination of the assumptions), but not for a blah semiring, where blah is a class that is enough for the theorem (in practice the goal is a linear combination of the assumptions, and indeed linar_combination does it).
Is there a way to make grind smart enough to prove it for blah semirings?
Riccardo Brasca (Jul 11 2025 at 15:13):
One example is
example {R : Type*} [CommSemiring R] [IsCancelAdd R] (a b c d e f : R) (h1 : a + d = b + c)
(h2 : c + f = d + e) : a + f = b + e := by
linear_combination h1 + h2
Riccardo Brasca (Jul 11 2025 at 15:18):
OK, I understood what's missing here: there is no instance that relates mathlb with Lean.Grind.AddRightCancel.
Riccardo Brasca (Jul 11 2025 at 15:20):
We surely want this, right?
Jireh Loreaux (Jul 11 2025 at 15:51):
But that still doesn't explain the problem in the OP right?
Riccardo Brasca (Jul 11 2025 at 15:51):
Yes
Jireh Loreaux (Jul 11 2025 at 16:00):
But yes, we definitely want that. This is what Henrik was suggesting above.
Riccardo Brasca (Jul 11 2025 at 16:18):
Asei Inoue (Jul 13 2025 at 06:07):
I see same issue
open Lean Grind
variable {M : Type} [AddCommMonoid M]
example (l m n : M) : l + m + n = (l + m) + n := by
-- This can be proven
grind
set_option warn.sorry false in
example (l m n : M) : l + m = m + l := by
-- I think `grind` *should* be able to close this goal, but currently it cannot.
fail_if_success grind
sorry
Jovan Gerbscheid (Jul 14 2025 at 00:49):
I was trying out grind, and was surprised it couldn't solve the following:
import Mathlib
example {f : ℝ → ℝ} {a b : ℝ} (h1 : 2 * a + b = 0) (h2 : b = 0) : f a = f 0 := by
grind
Jovan Gerbscheid (Jul 15 2025 at 14:20):
In the above example, if I add a completely irrelevant extra variable x and hypothis a = x + 1, then the example does work.
Jovan Gerbscheid (Jul 15 2025 at 14:21):
So I guess grind needs to be given some sort of hint that a should be normalized using the Gröbner basis
Damiano Testa (Jul 15 2025 at 14:33):
In fact, it looks like simply adding set c := a also allows grind to solve the goal!
Robin Carlier (Jul 15 2025 at 19:29):
I have trouble debugging the following grind failure. The example is from mathlib and is not quite minimal. I’ve included all attributes I’ve added when stumbling on this.
aesop_cat solves this with no issues.
From what I see in the diagnostic, it has trouble using once more that (𝟙 _).app _ = 𝟙 _.
import Mathlib.CategoryTheory.Whiskering
namespace CategoryTheory.Functor
universe u₁ v₁ u₂ v₂ u₃ v₃ u₄ v₄
variable {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₂} D] {E : Type u₃}
[Category.{v₃} E]
attribute [grind =] Category.comp_id Category.id_comp
attribute [grind _=_] Category.assoc
attribute [grind _=_] NatTrans.naturality NatTrans.vcomp_app'
attribute [grind =] NatTrans.id_app
attribute [grind _=_] Functor.map_comp
attribute [grind =] Functor.map_id Functor.comp_obj Functor.comp_map Functor.id_obj Functor.id_map
attribute [grind] whiskerLeft_app
@[simps]
def whiskeringLeft' : (C ⥤ D) ⥤ (D ⥤ E) ⥤ C ⥤ E where
obj F :=
{ obj G := F ⋙ G
map := fun α => whiskerLeft F α }
map τ :=
{ app H :=
{ app x := H.map (τ.app x)
naturality := by intros; grind }
naturality := by intros; ext; grind }
map_id x := by
ext F t
grind (gen := 10) (ematch := 20) -- fails
end CategoryTheory.Functor
Is there a magic trick/lemma/pattern that I’m missing?
grind_pattern NatTrans.id_app => (𝟙 F : F ⟶ F).app X does nothing.
Robin Carlier (Jul 15 2025 at 19:37):
:man_facepalming: [grind _=_] NatTrans.id_app works, I thought I had tried this...
Last updated: Dec 20 2025 at 21:32 UTC