Zulip Chat Archive

Stream: general

Topic: big ops


Johan Commelin (Apr 30 2020 at 09:07):

What do people think of

@[to_additive]
abbreviation fintype.prod (f : α  γ) := finset.univ.prod f

localized "notation `∑` binders `, ` r:(scoped f, fintype.sum f) := r" in big_operators
localized "notation `∏` binders `, ` r:(scoped f, fintype.prod f) := r" in big_operators

localized "notation `∑` binders ` in ` s `, ` r:(scoped f, finset.sum s f) := r" in big_operators
localized "notation `∏` binders ` in ` s `, ` r:(scoped f, finset.prod s f) := r" in big_operators

@Patrick Massot I know that this is a very meagre substitute for the big ops library in coq. But I think it's better to wait for Lean 4 before we start a big refactor. In the mean time, this notation seems like a cheap way to improve readability.

Patrick Massot (Apr 30 2020 at 09:30):

Does this actually work? I mean both the fintype and finset version at the same time.

Patrick Massot (Apr 30 2020 at 09:31):

Oh I see, the notation is subtly different

Patrick Massot (Apr 30 2020 at 09:31):

The question still stands, but I'm more optimistic

Johan Commelin (Apr 30 2020 at 09:36):

@Patrick Massot See https://github.com/leanprover-community/mathlib/pull/1564/files/88a5f988abd92ea699824d72dd8c0fcdd5cd4ac0..60f01102933198521d31c2d58ad07651a23dccec#diff-c5bb8de7cb26ae773e9bcb3fa594be6fL57-R230 for a short proof of concept

Patrick Massot (Apr 30 2020 at 09:41):

Yes, I saw, that's wonderful. My question is specifically about coexistence of the two variations. Do you use both in that file?

Johan Commelin (Apr 30 2020 at 09:48):

Yes, I do.

Johan Commelin (Apr 30 2020 at 09:49):

@Patrick Massot The first calc in the proof mixes them, for example.

Patrick Massot (Apr 30 2020 at 09:50):

amazing

Sebastien Gouezel (Apr 30 2020 at 10:12):

Would that conflict with

notation `` binders `, ` r:(scoped f, tsum f) := r

in topology/algebra/infinite_sum? (If necessary, we could also localize this one).

Patrick Massot (Apr 30 2020 at 10:18):

People will probably want to use both when discussing partial sums.

Sebastien Gouezel (Apr 30 2020 at 10:33):

I would be ok with ∑' for the infinite sum, and the other notations introduced by Johan.

Johan Commelin (Apr 30 2020 at 10:39):

Yes, I also thought about that, and I think the ' version would be best.

Johan Commelin (Apr 30 2020 at 10:40):

To what extent could this refactor be done with a regex? Because I fear it will be a lot of work if everything has to be done manually...

Johan Commelin (Apr 30 2020 at 10:41):

One thing I noticed with my experiment is that rw [finset.sum_lemma] doesn't play very well with abbreviation fintype.sum f := finset.sum univ f

Sebastien Gouezel (Apr 30 2020 at 10:42):

Just using search and replace in all files in vscode, replacing with ∑', should do it, hopefully.

Johan Commelin (Apr 30 2020 at 10:42):

But I wouldn't like restating a whole bunch of lemmas to fintype.sum. At the same time, I think ∑ x in univ, f x is ugly.

Johan Commelin (Apr 30 2020 at 10:42):

Sebastien Gouezel said:

Just using search and replace in all files in vscode, replacing with ∑', should do it, hopefully.

No, I meant the other refactor.

Johan Commelin (Apr 30 2020 at 10:43):

Replacing all finset.sum s f with ∑ x in s, f x

Sebastien Gouezel (Apr 30 2020 at 10:43):

You don't even need to introduce the abbreviation, just the notation should be enough.

Sebastien Gouezel (Apr 30 2020 at 10:43):

Ah, yes, the other refactor. Time for regexps, yes.

Johan Commelin (Apr 30 2020 at 10:43):

Or do we just introduce the notation, but not use it in the file...

Johan Commelin (Apr 30 2020 at 11:12):

#2571

Johan Commelin (Apr 30 2020 at 11:18):

If I change the notation to

localized "notation `∑` binders ` in ` s `, ` r:(scoped f, finset.sum s f) := r" in big_operators
localized "notation `∏` binders ` in ` s `, ` r:(scoped f, finset.prod s f) := r" in big_operators

localized "notation `∑` binders `, ` r:(scoped f, finset.univ.sum f) := r" in big_operators
localized "notation `∏` binders `, ` r:(scoped f, finset.univ.prod f) := r" in big_operators

then the second set of notation is not used in the tactic state. That's unfortunate. Is there some incantation that can move Lean to do a better job?

Johan Commelin (Apr 30 2020 at 11:43):

I've never really understood how priorities work for notation. Can that be used here?

Johan Commelin (Apr 30 2020 at 16:57):

Now that the tsum notation has been changed to ∑', I'm ready to start building a PR that introduces the notation above. Except that this notation doesn't really work yet. So what should I do? Introduce fintype.sum and fintype.prod?

Anne Baanen (May 01 2020 at 07:49):

From looking at the source code, the reverse lookups for notation head_map<notation_entry> notation_state::m_inv_map are stored without priority, since head_map<V> derives from head_map_prio<V, constant_priority_fn<V>>

Anne Baanen (May 01 2020 at 08:06):

In fact, according to the debugger the only notation returned for finset.sum is Σ _ in _, _

Johan Commelin (May 01 2020 at 08:13):

Hmm, but the other does seem to work :confused:

Anne Baanen (May 01 2020 at 08:23):

Aha: Σ := finset.univ.sum gets added as notation for the symbol (const lean::head_index &) @0x7ffff49083b8: {m_kind = lean::expr_kind::Macro, m_name = }, and Σ := finset.sum for (const lean::head_index &) @0x7fffdfffd3b8: {m_kind = lean::expr_kind::Constant, m_name = 'finset'.'sum'} (and the second thing is what we probably want)

Johan Commelin (May 01 2020 at 08:26):

Hmm... I have a hard time parsing this

Gabriel Ebner (May 01 2020 at 08:30):

I think Anne tells you to avoid the dot notation.

Johan Commelin (May 01 2020 at 08:30):

Aha.. you mean in the definition of the notation?

Gabriel Ebner (May 01 2020 at 08:32):

:+1:

Johan Commelin (May 01 2020 at 08:32):

Let me try that.

Anne Baanen (May 01 2020 at 08:34):

I think you want to change finset.univ.sum to finset.sum finset.univ and put the line defining finset.sum finset.univ first

Johan Commelin (May 01 2020 at 08:35):

Awesome

localized "notation `∑` binders `, ` r:(scoped f, finset.sum finset.univ f) := r" in big_operators
localized "notation `∏` binders `, ` r:(scoped f, finset.prod finset.univ f) := r" in big_operators

localized "notation `∑` binders ` in ` s `, ` r:(scoped f, finset.sum s f) := r" in big_operators
localized "notation `∏` binders ` in ` s `, ` r:(scoped f, finset.prod s f) := r" in big_operators

works. And the order is important.

Johan Commelin (May 01 2020 at 08:43):

This is great! I just fixed this in the chev-warn branch. Now I have some work to do to explain all of this to mathlib (-;

Anne Baanen (May 01 2020 at 08:45):

The explanation, as far as I understand it: when deciding how to pretty-print an expression, Lean looks up the notations associated to the head of the expression (e.g. finset.sum). It tries them one by one, until it finds a notation that matches the expression, then uses that to pretty-print. The order in which they are tried is the order in which they are stored in the environment structure, which in this case is the order in which they are defined. Apparently the priority information is thrown away (typically it would be highest-priority first, then by order of definition). This is why the order matters.

A notation definition is associated to the head of the expression it expands to, so notation binders , r:(scoped f, finset.sum finset.univ f) := r is associated to the head of the expansion of r, which is the head of finset.sum finset.univ f, which is finset.sum. But finset.univ.sum doesn't get expanded to finset.sum finset.univ at that point (maybe because it won't know if there is also a namespace finset.univ floating around somewhere?), so you have to write finset.sum finset.univ instead of finset.univ.sum.

Johan Commelin (May 01 2020 at 08:46):

Thanks a lot for explaining this!

Patrick Massot (May 01 2020 at 08:46):

Homework for Johan: write that long overdue docs/extras/notations.md

Mario Carneiro (May 01 2020 at 08:47):

notations don't go through name resolution until they are used, I think

Johan Commelin (May 01 2020 at 08:47):

/me has lots of homework

Johan Commelin (May 01 2020 at 08:48):

But we could start by just dumping Anne's explanation in that file. At least that would be a canonical place to find it again.

Johan Commelin (May 01 2020 at 08:48):

And then we can slowly improve that file.

Patrick Massot (May 01 2020 at 08:49):

Your sum notations also make great examples.

Johan Commelin (May 01 2020 at 08:52):

#2581

Johan Commelin (May 01 2020 at 08:53):

This is not ready for merging. And I welcome everyone to contribute.

Anne Baanen (May 01 2020 at 08:59):

I think there is some lookup of names going on at the point of definition though, if you define a notation before a name:

noncomputable theory

structure foo : Type

notation `` := foo.munge

def foo.munge :  := nat.zero

notation `` := foo.munge

def bar1 :=  -- unknown identifier `foo.munge`
def bar2 := 

Reid Barton (May 01 2020 at 09:00):

Anne Baanen said:

The explanation, as far as I understand it: when deciding how to pretty-print an expression, Lean looks up the notations associated to the head of the expression (e.g. finset.sum). It tries them one by one, until it finds a notation that matches the expression, then uses that to pretty-print. The order in which they are tried is the order in which they are stored in the environment structure, which in this case is the order in which they are defined. Apparently the priority information is thrown away (typically it would be highest-priority first, then by order of definition). This is why the order matters.

This is very helpful, thanks. It explains why what I suggested at https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/Show.20the.20objects.20for.20an.20equality.20of.20morphisms/near/194957595 did not work.

Reid Barton (May 01 2020 at 09:02):

I guess I was mixing up the method for resolving an overloaded notation (two different meanings for a # b) with the method for choosing a notation for the pretty-printer to display (two different notations for nat.add a b).

Johan Commelin (May 01 2020 at 09:04):

We still need tikzcd integration into the Lean tactic state

Reid Barton (May 01 2020 at 09:05):

How hard do you think it would be to use priority or at least prefer local notation over global notation in the pretty printer?

Anne Baanen (May 01 2020 at 09:07):

I think it shouldn't be too hard, since we already have a priority and a priority map

Anne Baanen (May 01 2020 at 09:10):

Looks like the code was written before priorities were available, so it seems like not a deliberate decision to leave out priorities here

Anne Baanen (May 01 2020 at 09:46):

Small complication: looks like priority for notation_entry is always set to a #defined value of 1000

Anne Baanen (May 01 2020 at 10:41):

It turns out that @[priority] and set_option default_priority don't interact with notation, but notation [priority 1] works as expected. PR made: https://github.com/leanprover-community/lean/pull/207

Johan Commelin (May 01 2020 at 10:58):

Cool. Thanks!

Johan Commelin (May 01 2020 at 11:00):

@Anne Baanen Does this also fix the problem that I currently need to write

( x in s, f x) = ...

because otherwise it gets parsed as

 x in s, (f x = ...)

Reid Barton (May 01 2020 at 11:01):

This use of in in notation hurts my brain. I noticed it in some filter stuff too.

Reid Barton (May 01 2020 at 11:02):

I always expect in to be a keyword...

Johan Commelin (May 01 2020 at 11:03):

Maybe I can use \mem. Let me try.

Johan Commelin (May 01 2020 at 11:04):

Nope... that doesn't work.

Johan Commelin (May 01 2020 at 11:05):

I guess binders has special support for \in and doesn't want you to mess around with it.

Johan Commelin (May 01 2020 at 11:05):

@Reid Barton Do you have another suggestion?

Reid Barton (May 01 2020 at 11:05):

I don't think binders has special support for \in per se

Reid Barton (May 01 2020 at 11:06):

Maybe I can just get used to in.

Anne Baanen (May 01 2020 at 11:06):

The change shouldn't affect the parser, (un)fortunately.

Reid Barton (May 01 2020 at 11:09):

Oh maybe it wasn't filters actually. There is in in the snippet from the perfectoid space project in Kevin's paper and I can't parse it.

Patrick Massot (May 01 2020 at 11:11):

They are also in filters

Patrick Massot (May 01 2020 at 11:11):

In the eventually and frequently notations

Reid Barton (May 01 2020 at 11:12):

BTW I think I saw let ... in is no longer the syntax in Lean 4 anyways

Reid Barton (May 01 2020 at 12:25):

I wonder why in lean-homotopy-theory I get nice notation for my morphism composition...

Reid Barton (May 01 2020 at 12:26):

I have local notation f ` ∘ `:80 g:80 := g ≫ f, and that is enough to make it work fine

Johan Commelin (May 01 2020 at 12:52):

#2582 introduces the notation and uses it everywhere in algebra/big_operators.

Johan Commelin (May 01 2020 at 12:52):

I haven't gone through all of mathlib. But I hope we can transition organically.

Johan Commelin (May 01 2020 at 12:57):

But let's first see whether CI likes this

Johan Commelin (May 01 2020 at 17:35):

We need to decide what the precendence of big ops should be. I've found some discussion over here: https://math.stackexchange.com/q/185538/30839
Also see https://github.com/leanprover-community/mathlib/pull/2582#discussion_r418569631 for the discussion that has been going on at github.
Does anyone have strong opinions on how formulas should be parsed?

Johan Commelin (May 01 2020 at 17:42):

@Gabriel Ebner suggests: I think we need to use 64 and 69 instead, then the following works as expected:

 x, x + x  =   x, (x + x)
 x, x - x  =   x, (x - x)
 x, x * x  =   x, (x * x)
 x, x + x  =  ( x, x) + x

What do others think? Personally I dislike the last example.

Kevin Buzzard (May 01 2020 at 17:44):

I think the question is not "how would a mathematician interpret these" (for which the answer is known to be "different mathematicians will interpret them in different ways") but "what is the convention we should use in order to minimise the number of brackets in mathlib", so that those who want to golf can golf.

Johan Commelin (May 01 2020 at 17:44):

The math.sx page linked to above gives the following example

kK(ak+bk)=kKak+kKbkkKakbk=(kKak)(kKbk).\sum_{k\in K}\left(a_k+b_k\right) = \sum_{k\in K}a_k+\sum_{k\in K}b_k \longleftrightarrow \prod_{k\in K}a_kb_k = \left(\prod_{k\in K}a_k\right)\left(\prod_{k\in K}b_k\right).

which is quoted from Knuth's Concrete mathematics.

Johan Commelin (May 01 2020 at 17:45):

That examples shows a lot of "assymetry".

Kevin Buzzard (May 01 2020 at 17:47):

The Lean conventions for \forall being super-greedy don't correspond with the way I use it in my undergraduate lectures, but I am happy to put extra brackets in. I don't even know which binds more out of \or and \and, I am just happy to put the brackets in to make my intentions clear. In short I'm arguing that this is not a question about the "correct" mathematical convention, it's about which convention will minimise the total number of brackets in mathlib.

Gabriel Ebner (May 01 2020 at 17:47):

It reminds me very much of the question whether ∀ x, p x → q should be (∀ x, p x) → q or ∀ x, (p x → q). I agree with Kevin, there are probably many right answers to this question.

Johan Commelin (May 01 2020 at 17:55):

Ok, I've reverted to 64/69

Reid Barton (May 01 2020 at 18:20):

The example you showed seems to suggest they should both be 69.

Reid Barton (May 01 2020 at 18:20):

More importantly, do they bind tighter than =?

Johan Commelin (May 01 2020 at 18:21):

Reid Barton said:

More importantly, do they bind tighter than =?

Yup. That's fixed (-;
Initially they didn't, which was really annoying.

Reid Barton (May 01 2020 at 18:31):

All example usages I can find suggest that both ∑ and ∏ bind more loosely than * but tighter than +, although I didn't find many relevant examples of products.

Johan Commelin (May 01 2020 at 18:35):

Well... we can still change it (-;
I'm fine with giving both 67 or 68.

Johan Commelin (May 01 2020 at 19:21):

What do people think of making both operators have level 67? If you like that idea, vote on this message with :thumbs_up:
If you want to keep it the way it is (which means 64/69), vote with :stop:

Kevin Buzzard (May 01 2020 at 19:27):

Can you try both, count the total number of necessary brackets in mathlib for each choice, and report back?

Kevin Buzzard (May 01 2020 at 19:27):

Hint: write a bracket linter first

Johan Commelin (May 01 2020 at 19:31):

Kevin Buzzard said:

Can you try both, count the total number of necessary brackets in mathlib for each choice, and report back?

Lol... I would rather not do that. It's already time consuming enough (-;

Kevin Buzzard (May 01 2020 at 19:38):

You posted what 64,69 did -- what does 67,67 do?

Johan Commelin (May 01 2020 at 19:39):

It should accomplish something like

kK(ak+bk)=kKak+kKbkkKakbk=(kKak)(kKbk).\sum_{k\in K}\left(a_k+b_k\right) = \sum_{k\in K}a_k+\sum_{k\in K}b_k \longleftrightarrow \prod_{k\in K}a_kb_k = \left(\prod_{k\in K}a_k\right)\left(\prod_{k\in K}b_k\right).

which is quoted from Knuth's Concrete mathematics.

Kevin Buzzard (May 01 2020 at 19:42):

Well the mathematician in me votes for this one, but the computer scientist is abstaining

Reid Barton (May 01 2020 at 20:29):

I voted for 67,67 but I don't actually know what the numbers mean.

Reid Barton (May 01 2020 at 20:31):

Oh, now I see the end of the stackexchange post you linked to says the same thing I said, I think.

Johan Commelin (May 01 2020 at 20:34):

+ : 65, * : 70. And you wanted something in between... Unfortunately, rat is not defined in core, so we can't go for the actual (65 + 70)/2 : rat as precedence. Hence I suggested the nat version of that fraction :oops:

Reid Barton (May 01 2020 at 20:35):

and -, / are the same as +, * respectively?

Johan Commelin (May 01 2020 at 20:36):

As far as I know, yes

Reid Barton (May 01 2020 at 20:36):

I think they have to be actually.

Yury G. Kudryashov (May 01 2020 at 21:27):

reserve infixl ` + `:65
reserve infixl ` - `:65
reserve infixl ` * `:70
reserve infixl ` / `:70
reserve infixl ` % `:70
reserve prefix `-`:100
reserve infixr ` ^ `:80

Yury G. Kudryashov (May 01 2020 at 21:29):

Sorry for offtopic: what is the precedence of notation f^[n] := iterate f n? It eats = on the left.

Johan Commelin (May 02 2020 at 05:14):

@Yury G. Kudryashov It probably defaults to 0. Seems like we need to change core to fix that...

Johan Commelin (May 02 2020 at 09:00):

I have now changed to 67/67 and added a bit of explanation about it (plus an example of how to parenthesise...)

Johan Commelin (May 02 2020 at 13:51):

And... the linter is happy.


Last updated: Dec 20 2023 at 11:08 UTC