Zulip Chat Archive

Stream: new members

Topic: Choosing dummy variable inside summation


Harry Richman (May 16 2025 at 09:10):

When working with a summation in a proof, is there a way to explicitly choose a name for the variable indexing the sum?

The context here is that some tactics, i.e. simp_rw, will helpfully rewrite terms inside sums and products, but as a side effect seems to change the name of the index variable. In the example below, the outer sum has σ vary over all permutations, but after using simp_rw the σ is replaced with x. The inner product index i is replaced with x_1.

The choice of name of the dummy variable is in a sense non-essential, but having a way to enforce conventions like σ for permutations would help with readability in the infoview.

import Mathlib

variable {M N : Type} [Fintype M] [Fintype N] [DecidableEq M] [DecidableEq N] [LinearOrder M] [LinearOrder N]

theorem Matrix.det_mul' (A : Matrix M N ) (B : Matrix N M ) :
  det (A * B) =  f : M o N, det (A.submatrix id f) * det (B.submatrix f id) := by
  -- expand determinant in matrix entries as sum over permutations, on LHS
  rw [Matrix.det_apply (A * B)] -- uses σ for summing permutations
  -- expand entries of matrix product A*B
  simp_rw [Matrix.mul_apply] -- uses x for summing permutations :(

  sorry

Luigi Massacci (May 16 2025 at 09:20):

This should work: change ∑ f, Equiv.Perm.sign f • ∏ x_1, ∑ j, A (f x_1) j * B j x_1 = _

Luigi Massacci (May 16 2025 at 09:21):

replace f with whatever you want

Luigi Massacci (May 16 2025 at 09:22):

I don't know if it's the best solution though

Eric Wieser (May 16 2025 at 10:38):

This probably makes sense as aconv tactic

Luigi Massacci (May 16 2025 at 11:59):

I had thought of using conv, but this was the best I could do:

conv =>
    enter [-2, 2, x]
    tactic => rename Equiv.Perm M => t

which is uglier, even if rename was a conv tactic (which it probably should be, or change as you said. Assuming I understand what a conv tactic is ; ) I can still image it might be useful for bigger terms

Robin Arnez (May 16 2025 at 12:31):

Harry Richman schrieb:

but as a side effect seems to change the name of the index variable

For this reason binderNameHint exists. But mathlib doesn't seem to use it...

Eric Wieser (May 16 2025 at 12:33):

It looks like the use of docs#Finset.sum_congr is to blame

Robin Arnez (May 16 2025 at 12:35):

Yeah right it should use binderNameHint there probably

Robin Arnez (May 16 2025 at 12:36):

although I'm not certain it even works for congruence theorems

Eric Wieser (May 16 2025 at 12:41):

-- replaces `Finset.sum_congr
@[congr]
theorem Finset.sum_congr_binder {ι M : Type*} {s₁ s₂ : Finset ι} [AddCommMonoid M] {f g : ι  M}
  (h : s₁ = s₂) : ( x  s₂, f x = binderNameHint x g (g x)) 
    s₁.sum f = s₂.sum g :=
  Finset.sum_congr h

is not legal

Eric Wieser (May 16 2025 at 12:43):

cc @Joachim Breitner

Joachim Breitner (May 16 2025 at 12:53):

I’d have expected

@[congr]
theorem Finset.sum_congr_binder {ι M : Type*} {s₁ s₂ : Finset ι} [AddCommMonoid M] {f g : ι  M}
  (h : s₁ = s₂) : ( x  s₂, binderNameHint x f (f x = g x)) 
    s₁.sum f = s₂.sum g :=
  Finset.sum_congr h

i.e. the binderNameHint should take the binder from f, not g. If this doesn't work, a MWE might help.

The hint should work in congruence assumptions since https://github.com/leanprover/lean4/pull/7053

Robin Arnez (May 16 2025 at 13:02):

Hmm no apparently simp can't use that?
It just says: [Meta.Tactic.simp.congr] Finset.sum_congr_binder not modified

Joachim Breitner (May 16 2025 at 13:03):

What about

@[congr]
theorem Finset.sum_congr_binder {ι M : Type*} {s₁ s₂ : Finset ι} [AddCommMonoid M] {f g : ι  M}
  (h : s₁ = s₂) : ( x  s₂, binderNameHint x f (f x) = g x) 
    s₁.sum f = s₂.sum g :=
  Finset.sum_congr h

(that's the form I used in the test case for the PR)

Eric Wieser (May 16 2025 at 13:04):

That works!

Robin Arnez (May 16 2025 at 13:05):

I guess this should probably be the form present in mathlib then

Eric Wieser (May 16 2025 at 13:06):

#24957

Robin Arnez (May 16 2025 at 13:08):

Well the only complaint I have about binderNameHint is that it makes theorem statements a bit annoying to read

Robin Arnez (May 16 2025 at 13:08):

maybe it's fine to

@[app_unexpander binderNameHint]
def unexpandBinderNameHint : Lean.PrettyPrinter.Unexpander
  | `($_ $_ $_ $x) => pure x
  | _ => throw ()

but that might hide too much..?

Joachim Breitner (May 16 2025 at 13:09):

I fully agree. And that it’s a game of whack-a-mole to adjust all the tactics that should heed the hint.

It’s a hack that I’m not proud of (but still prefer to not having that hack at all).

Robin Arnez (May 16 2025 at 13:11):

Hmm would it be fine to make it an abbrev? It seems like that could be part of why #24957 failed to build

Kevin Buzzard (May 16 2025 at 13:11):

Yes it would be great to fix this. Thanks for the work above! It's especially annoying when simp_rw or whatever replaces the variable being summed over with i when you already have an i, because then you randomly get an i_1 which you almost never want.

Joachim Breitner (May 16 2025 at 13:12):

Robin Arnez said:

Hmm would it be fine to make it an abbrev? It seems like that could be part of why #24957 failed to build

Probably; do you want to try that and make a PR for that to find out?

Robin Arnez (May 16 2025 at 13:14):

Should I then also add an unexpander? Although again it's probably not best to hide details...

Eric Wieser (May 16 2025 at 13:14):

I forget why we didn't make it an Expr.mdata; could you remind me?

Joachim Breitner (May 16 2025 at 13:14):

Robin Arnez said:

Should I then also add an unexpander? Although again it's probably not best to hide details...

I’d be hesitant, it may cause confusion

Joachim Breitner (May 16 2025 at 13:15):

Eric Wieser said:

I forget why we didn't make it an Expr.mdata; could you remind me?

Because the value of .mdata cannot refer to expressions, can it?

Robin Arnez (May 16 2025 at 13:15):

Eric Wieser schrieb:

I forget why we didn't make it an Expr.mdata; could you remind me?

I think the problem is that mdata can't refer to variables like f and x

Eric Wieser (May 16 2025 at 13:18):

Are things any better if the syntax instead becomes:

(h :  x : binderNameHint f _, x  s₂  f x = g x)

Eric Wieser (May 16 2025 at 13:20):

Or maybe even

(h : binderNameHint f ( x  s₂, f x = g x))

Eric Wieser (May 16 2025 at 13:20):

That last one is far more likely to be unfolded before it causes trouble, since intro is enough to do it

Robin Arnez (May 16 2025 at 13:23):

We probably also want to allow ∃ x, p x to have a binder name hint so the last one doesn't work too well I don't think (because the x is nested in the Exists)

Eric Wieser (May 16 2025 at 13:24):

I guess that becomes Exists (binderNameHint p fun x => p x)

Eric Wieser (May 16 2025 at 13:25):

You could envisage a custom delaborator along the lines of ∃ x%$p, p x that expands to this, sort of matching %$tk in syntax antiquotations

Robin Arnez (May 16 2025 at 13:28):

∃ x, binderNameHint _ _ (p x) doesn't need support like that though

Harry Richman (May 17 2025 at 17:36):

Thanks @Luigi Massacci for the quick fix and everyone else for working on sorting out the underlying problem!


Last updated: Dec 20 2025 at 21:32 UTC