Zulip Chat Archive
Stream: mathlib4
Topic: Destruction and big operators
Oliver Nash (Aug 12 2023 at 20:16):
Consider the following three examples:
import Mathlib.Data.Nat.Choose.Sum
open BigOperators Finset Nat
-- Example 1 [valid syntax]
example (h : Commute x y) (n : ℕ) :
(x + y) ^ n = ∑ m in antidiagonal n, choose n m.fst • (x ^ m.fst * y ^ m.snd) :=
h.add_pow' n
-- Example 2 [valid syntax]
example (h : Commute x y) (n : ℕ) :
(x + y) ^ n = (antidiagonal n).sum fun ⟨i, j⟩ ↦ choose n i • (x ^ i * y ^ j) :=
h.add_pow' n
-- Example 3 [invalid syntax]
example (h : Commute x y) (n : ℕ) :
(x + y) ^ n = ∑ ⟨i, j⟩ in antidiagonal n, choose n i • (x ^ i * y ^ j) :=
h.add_pow' n
Oliver Nash (Aug 12 2023 at 20:17):
Back in the Lean 3 days, only Example 1
was valid. Happily Example 2
now also works.
Is there any way we could get Example 3
to work?
Anatole Dedecker (Aug 12 2023 at 21:02):
I think this is related. From what I understand all big operators use the same type of binders, extBinder
(I'm not sure how to name what it is. A syntax category?). It allows the things like ∀ ε > 0
, but not the destructing thing.
Oliver Nash (Aug 12 2023 at 21:15):
Thanks! It would be really nice if we could somehow do this.
Eric Wieser (Aug 12 2023 at 21:43):
extBinder
seems entirely useless in big operators, since you can't have a finset
of proofs
Arend Mellendijk (Aug 12 2023 at 21:52):
I like your suggestion, but (perhaps as a workaround) would it make sense to have custom notation for sums over antidiagonal
? Something like
∑ i + j = n, choose n i • (x ^ i * y ^ j)
Eric Wieser (Aug 12 2023 at 22:03):
You can do that already with docs#Finsum
Oliver Nash (Aug 12 2023 at 22:04):
Eric Wieser said:
extBinder
seems entirely useless in big operators, since you can't have afinset
of proofs
I don’t understand this answer. Are you saying we can never have this notation?
Eric Wieser (Aug 12 2023 at 22:06):
I challenge you to find a situation where an extBinder
-style binder is not a type error with Finset.sum
Eric Wieser (Aug 12 2023 at 22:09):
And therefore we could just use a regular binder instead and would get the feature you want without losing any features that currently exist
Arend Mellendijk (Aug 12 2023 at 22:12):
Eric Wieser said:
You can do that already with docs#Finsum
Right, but you lose the bundled finiteness which makes doing things like commuting sums quite painful.
Oliver Nash (Aug 12 2023 at 22:12):
Eric Wieser said:
And therefore we could just use a regular binder instead and would get the feature you want without losing any features that currently exist
I’m afraid this is still way too technical for me to follow. Perhaps I’ll think about this again tomorrow.
Yaël Dillies (Aug 12 2023 at 22:21):
In LeanAPAP, we introduced notation for (s.filter p).sum f
. It's really lovely and is quite close to your suggestion, Arend.
Yaël Dillies (Aug 12 2023 at 22:24):
Btw, are we sure that examples 2 and 3 above are syntactically as general as example 1? I would expect not, but maybe defeq eta struct is saving the day.
Anatole Dedecker (Aug 12 2023 at 22:33):
(deleted)
Eric Wieser (Aug 12 2023 at 22:33):
Defeq isn't relevant for syntactic generality unfortunately; so there absolutely still is a reason to worry about that
Eric Wieser (Aug 12 2023 at 22:35):
Hmm, maybe I'm wrong about that
Eric Wieser (Aug 12 2023 at 22:36):
Yes, this is fine:
import Mathlib.Data.Nat.Choose.Sum
open BigOperators Finset Nat
-- Example 1 [valid syntax]
lemma nice (h : Commute x y) (n : ℕ) :
(x + y) ^ n = ∑ m in antidiagonal n, choose n m.fst • (x ^ m.fst * y ^ m.snd) :=
h.add_pow' n
-- Example 2 [valid syntax]
lemma ugly (h : Commute x y) (n : ℕ) :
(x + y) ^ n = (antidiagonal n).sum fun ⟨i, j⟩ ↦ choose n i • (x ^ i * y ^ j) :=
h.add_pow' n
#print nice
#print ugly
example (h : Commute x y) (n : ℕ) :
(x + y) ^ n = ∑ m in antidiagonal n, choose n m.fst • (x ^ m.fst * y ^ m.snd) := by
rw [←ugly h]
Eric Wieser (Aug 12 2023 at 22:36):
So it looks like rw
knows to unfold match
statements
Eric Wieser (Aug 12 2023 at 23:00):
Oliver Nash said:
Eric Wieser said:
And therefore we could just use a regular binder instead and would get the feature you want without losing any features that currently exist
I’m afraid this is still way too technical for me to follow. Perhaps I’ll think about this again tomorrow.
Looking more closely, the code in Lean.Elab.Binders
doesn't seem to be written in a way that makes it particularly easy to insert Finset.sum
between binders
Kyle Miller (Aug 21 2023 at 02:23):
extBinder
is sort of a red herring here. The big sum notation only uses it to get ident
and ident : type
syntax.
In principle it should be easy to support destructuring by changing it to term
. You just lose ident : type
without parentheses before the in
(does anyone use that?)
Kyle Miller (Aug 21 2023 at 02:26):
It'd be nice to get big operators to use notation3
someday; if that's done, we'd want to improve extBinder
to support destructuring.
Kyle Miller (Aug 26 2023 at 01:18):
#6795 has a custom modification to extBinder
to experiment with destructuring
Kyle Miller (Aug 26 2023 at 01:19):
These all work:
import Mathlib.Data.Nat.Choose.Sum
variable (α : Type*) [Ring α] (x y : α)
open BigOperators Finset Nat
-- Example 1
example (h : Commute x y) (n : ℕ) :
(x + y) ^ n = ∑ m ∈ antidiagonal n, choose n m.fst • (x ^ m.fst * y ^ m.snd) :=
h.add_pow' n
-- Example 2
example (h : Commute x y) (n : ℕ) :
(x + y) ^ n = (antidiagonal n).sum fun ⟨i, j⟩ ↦ choose n i • (x ^ i * y ^ j) :=
h.add_pow' n
-- Example 3
example (h : Commute x y) (n : ℕ) :
(x + y) ^ n = ∑ ⟨i, j⟩ ∈ antidiagonal n, choose n i • (x ^ i * y ^ j) :=
h.add_pow' n
-- Example 4
example (h : Commute x y) (n : ℕ) :
(x + y) ^ n = ∑ (i + j = n), choose n i • (x ^ i * y ^ j) :=
h.add_pow' n
Kyle Miller (Aug 26 2023 at 01:20):
Example 4 is @Arend Mellendijk's, but it needs parentheses around the i + j = n
because it's parsed at max precedence
Damiano Testa (Aug 26 2023 at 01:27):
This is great!
It looks like a series of snapshots from least informal to almost handwritten!
Kyle Miller (Aug 26 2023 at 01:35):
Examples 3 and 4 both elaborate to the same thing, which involves a match
expression:
∑ x_1 ∈ antidiagonal n,
match x_1 with
| (i, j) => Nat.choose n i • (x ^ i * y ^ j)
A dsimp
at least turns this into ∑ x_1 ∈ antidiagonal n, Nat.choose n x_1.fst • (x ^ x_1.fst * y ^ x_1.snd)
, which is Example 1. Nice that it's defeq.
Oliver Nash (Aug 26 2023 at 12:37):
This is awesome!
Kevin Buzzard (Aug 26 2023 at 12:42):
Yeah this is a very nice step forwards towards code readability!
Kyle Miller (Aug 26 2023 at 15:05):
I actually can't get ∑ (i + j = n), choose n i • (x ^ i * y ^ j)
to be parseable while simultaneously being able to parse sums with multiple binders. The best I have is ∑ ((i + j = n)), choose n i • (x ^ i * y ^ j)
.
The problem is more-or-less that parentheses are used to switch into multiple binder mode, so you need two layers of parentheses to get it to parse as a term.
It's probably possible to get this working with fewer parentheses by re-engineering how binder predicates work, but while ∑ (i + j = n), ...
is cute, I'm not sure it's very high priority...
Eric Wieser (Aug 26 2023 at 17:04):
I worry that making all this magic syntax makes it much harder to see the terms after which the lemmas are named
Oliver Nash (Aug 26 2023 at 17:38):
I'd be willing to pay quite a high price for having syntax that is similar to traditional mathematics and if there are costs associated with having this (e.g., obscuring terms) then I would advocate keeping the notation but build better tooling.
Eric Wieser (Aug 26 2023 at 20:02):
One reasonable option might be to have the notation be more magic than the pretty-printer
Damiano Testa (Aug 26 2023 at 20:10):
Or also having two different defaults for pretty-printing, one more math-like and one more Lean-like, and a button in the infoview to toggle between the two. So you could "see" the meaning with one view and read the term to guess the next lemma name with the other.
Kyle Miller (Aug 26 2023 at 20:33):
The pretty printer in #6795 is certainly less magical than the notation. That's an easy default because writing featureful pretty printers takes work :wink:
Kyle Miller (Aug 26 2023 at 20:38):
set_option pp.mathemagic true
Arend Mellendijk (Aug 26 2023 at 23:37):
What made me consider this kind of notation was sums over divisorsAntidiagonal
. Consider Dirichlet convolution:
(f * g) n = ∑ x in divisorsAntidiagonal n, f x.fst * g x.snd
This is really long! The first time I came across these antidiagonal sums I was worried they'd be a pain to write out and work with, and I was really tempted to use the more readable
(f * g) n = ∑ d in divisors n, f d * g (n/d)
wherever possible. But the entire point of divisorsAntidiagonal
is to sidestep natural division. If there were optional notation along the lines of
(f * g) n = ∑ (d * e = n), f d * g e
then I might have been less afraid to use the preferred definition. In a sense I think it could serve as a hint to users saying "the preferred way to express is as a sum over divisorsAntidiagonal
."
Last updated: Dec 20 2023 at 11:08 UTC