Zulip Chat Archive

Stream: Is there code for X?

Topic: finsum over product of types


Oliver Nash (Apr 30 2021 at 08:24):

I'm using the finsum API for the first time. Do we have this anywhere?

import algebra.big_operators.finprod

open_locale big_operators

example {α β M : Type*} [add_comm_monoid M] (f : α  β  M) :
  ∑ᶠ (ab : α × β), f ab.fst ab.snd = ∑ᶠ a b, f a b := sorry

Eric Wieser (Apr 30 2021 at 08:53):

I think it's not true

Eric Wieser (Apr 30 2021 at 08:55):

Consider f (x : bool) (y : nat) = if (x and y = 0) or not x then 1 else 0

Eric Wieser (Apr 30 2021 at 08:56):

I think your example then reduces to 0 = 1

Oliver Nash (Apr 30 2021 at 09:09):

LOL, thanks.

Eric Wieser (Apr 30 2021 at 09:21):

Although proving that was awful:

example : ¬  {α β M : Type*} [add_comm_monoid M] (f : α  β  M), by exactI
  ∑ᶠ (ab : α × β), f ab.fst ab.snd = ∑ᶠ a b, f a b :=
begin
  intro h,
  let f := λ (b : bool) (n : nat), if b then 1 else (if n = 0 then 1 else 0),
  let f' := λ (p : bool × nat), f p.1 p.2,
  have : (function.support f').infinite,
  { refine set.infinite_of_injective_forall_mem (prod.mk.inj_left tt) (λ n : , _),
    dsimp [function.support, f', f],
    simp },
  specialize h f,
  rw finsum_of_infinite_support this at h,
  rw finsum_eq_sum_of_fintype at h,
  rw [fintype.sum_eq_single ff] at h,
  { dsimp [f] at h,
    rw @finsum_eq_sum_of_support_subset _ _ _ _ {0} at h,
    { rw finset.sum_singleton at h,
      simpa using h,},
    simp, },
  { rintros (b | b) hb,
    exact (hb rfl).elim,
    apply finsum_of_infinite_support,
    refine set.infinite_of_injective_forall_mem (@nat.succ.inj) (λ n : , _),
    simp [function.support,f], }
end

Oliver Nash (Apr 30 2021 at 09:22):

This is brilliant. Refutation by formal proof :joy:

Eric Wieser (Apr 30 2021 at 09:23):

How hard would it be to have a counterexample notation do you think?

Eric Wieser (Apr 30 2021 at 09:23):

That handles the ¬ and by exactI

Oliver Nash (Apr 30 2021 at 09:24):

I have no idea but it's an interesting thought.

Oliver Nash (Apr 30 2021 at 09:25):

Vaguely related thought: I have occasionally thought that if the machine learning people really are to have any chance of getting somewhere using Mathlib as a dataset then they would need a wealth of counterexamples.

Eric Wieser (Apr 30 2021 at 09:25):

This does sort of make me worry that the finsum API is awkward, in that "infinities" don't propagate

Oliver Nash (Apr 30 2021 at 09:25):

Like that's probably how we secretly reason about mathematics more than half the time.

Oliver Nash (Apr 30 2021 at 09:26):

Eric Wieser said:

This does sort of make me worry that the finsum API is awkward

I'm currently thinking about this too.

Eric Wieser (Apr 30 2021 at 09:26):

For instance, perhaps it should return with_top M instead

Oliver Nash (Apr 30 2021 at 09:26):

Exactly what I'm asking myself!

Eric Wieser (Apr 30 2021 at 09:27):

Although you need something clever somewhere to avoid ending up with with_top (with_top M)

Kevin Buzzard (Apr 30 2021 at 09:28):

@Damiano Testa had a counterexamples branch (but pre the huge changes so it might have rotted by now). I wonder if we could have a directory of counterexamples but not in src?

Yaël Dillies (Apr 30 2021 at 09:29):

Maybe it belongs to archive?

Oliver Nash (Apr 30 2021 at 09:30):

I'd be in favour of at least experimenting with a counterexamples section of archive.

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

Damiano has a branch with exactly that name (-;
(Edit: I now see that Kevin wrote this 3 posts up :face_palm:)

David Wärn (Apr 30 2021 at 09:39):

Eric Wieser said:

Although you need something clever somewhere to avoid ending up with with_top (with_top M)

This is what the option monad is for

Oliver Nash (Apr 30 2021 at 09:41):

I think with_top is just option.

David Wärn (Apr 30 2021 at 09:42):

Yes, so the monad multiplication takes you from with_top (with_top X) to with_top X

Oliver Nash (Apr 30 2021 at 09:42):

Agreed. I think this should work.

Eric Wieser (Apr 30 2021 at 09:44):

I don't really see how to apply that here - what would the signature of finsum become?

David Wärn (Apr 30 2021 at 09:44):

The first step would be to make its output option M

Eric Wieser (Apr 30 2021 at 09:44):

Currently its

finsum : Π {α : Sort u_1} {M : Type u_2} [_inst_3 : add_comm_monoid M], (α  M)  M

Kevin Buzzard (Apr 30 2021 at 09:45):

@David Wärn with_top := option

Oliver Nash (Apr 30 2021 at 09:45):

I think Eric's point is that the input would have to be with_top M also.

Eric Wieser (Apr 30 2021 at 09:45):

If you made it

finsum : Π {α : Sort u_1} {M : Type u_2} [_inst_3 : add_comm_monoid M], (α  M)  option M

then how do you prevent ∑ᶠ a b, f a b having type option (option m))?

Eric Wieser (Apr 30 2021 at 09:46):

That's certainly what my point should have been! Indeed,

finsum : Π {α : Sort u_1} {M : Type u_2} [_inst_3 : add_comm_monoid M], (α  option M)  option M

would solve the problem

Eric Wieser (Apr 30 2021 at 09:47):

I think we'd want to use def finsum.result M := option M rather than option directly

Eric Wieser (Apr 30 2021 at 09:47):

And then we could add a coercion from finsum.result M to M that sends top to 0

Eric Wieser (Apr 30 2021 at 09:48):

Which would preserve the current API in some form

Oliver Nash (Apr 30 2021 at 09:48):

If that last coercion trick works, it would be really neat. Best of all worlds.

David Wärn (Apr 30 2021 at 10:10):

You can sort of get the second signature from the first:

import data.option.basic
noncomputable theory
open_locale classical

def whats_this_called {α β : Type*} (f : α  option β) : option (α  β) :=
if h :  a, (f a).is_some then some (λ a, option.get (h a)) else none

variables {α M : Type} (finsum : (α  M)  option M)
def finsum' (f : α  option M) : option M :=
whats_this_called f >>= finsum

David Wärn (Apr 30 2021 at 10:12):

The option monad is basically a principled way of making sure undefined values propagate. But mathlib generally prefers to use 0 for undefined values

Yakov Pechersky (Apr 30 2021 at 13:11):

For undefined values of add_monoid, 1 for monoid for finprod, of course

Yakov Pechersky (Apr 30 2021 at 13:17):

What's this called is ((>>= f) o pure) I think

Mario Carneiro (Apr 30 2021 at 13:22):

The whole point of this function is that it doesn't have undefinedness handling

Mario Carneiro (Apr 30 2021 at 13:22):

because that handling is exactly what causes all the pain

Eric Wieser (Apr 30 2021 at 13:24):

But we still have all that handling as obligations in the lemmas anyway

Eric Wieser (Apr 30 2021 at 13:25):

And the compromise finsum makes seems to make a bunch of "obvious" statements not true without annoying side conditions

Mario Carneiro (Apr 30 2021 at 13:25):

The statements are true as long as you ignore the fact that finsum is defined on useless inputs

Mario Carneiro (Apr 30 2021 at 13:25):

just assume everything is reasonable in the lemmas

Mario Carneiro (Apr 30 2021 at 13:26):

finsum is not actually any different from finset.sum in terms of assumptions

Mario Carneiro (Apr 30 2021 at 13:26):

it's just possible to state theorems that lie outside those assumptions now

Mario Carneiro (Apr 30 2021 at 13:27):

your first response to

example {α β M : Type*} [add_comm_monoid M] (f : α  β  M) :
  ∑ᶠ (ab : α × β), f ab.fst ab.snd = ∑ᶠ a b, f a b := sorry

should be "that doesn't typecheck, let me add assumptions so I don't have to deal with places where the function is crazy"

Mario Carneiro (Apr 30 2021 at 13:28):

for example [fintype α] [fintype β]

Eric Wieser (Apr 30 2021 at 13:29):

Oh, I guess an argument for why option wouldn't really help is the sum over f (z : units int \times int) := z.1 * z.2

Mario Carneiro (Apr 30 2021 at 13:29):

this is a little bit overconstrained, but the nice thing about finsum is that it is defined whenever it can possibly be defined so you can later revisit and generalize the theorem to any context where it remains reasonable. But the fully general statement is probably not the first thing you want

Mario Carneiro (Apr 30 2021 at 13:30):

You will need monads everywhere with the option approach

Mario Carneiro (Apr 30 2021 at 13:30):

plus it's not even computable, you need to use whats_this_called which is more naturally stated on roption

Mario Carneiro (Apr 30 2021 at 13:32):

If you want to propagate a well definedness condition through multiple operations, I would suggest roption instead of option. The latter is better when the function itself can tell you whether or not it is defined

Mario Carneiro (Apr 30 2021 at 13:33):

But at a certain point this starts to look like the situation with integrals and derivatives where you have to do everything twice, first prove that the value is defined and then prove it is equal to something (and neither implies the other)

Mario Carneiro (Apr 30 2021 at 13:34):

The nice thing about finset.sum is that it is always defined, so the first part is absent. It's still possible to have this with finsum provided the definedness proof is "easy" or typeclassable

Eric Wieser (Apr 30 2021 at 13:35):

Presumably having finsum match the design of integrals makes a lot of sense?

Mario Carneiro (Apr 30 2021 at 13:36):

not if it makes the easy case harder

Mario Carneiro (Apr 30 2021 at 13:36):

because the whole reason it exists is to make dealing with finite sums easier than the existing method using finset.sum

Mario Carneiro (Apr 30 2021 at 13:43):

It is a bit funny to me that finsum is converging on the design of finite sums that I did in metamath, df-gsum. The idea behind it is that it is defined to be the sum if it is at all reasonable to call a unique thing "the sum" of a function. It's still a bit more crazy than finsum since it also special cases when the summing set is a sequence of integers, in which case it is the left-associative ordered sum; otherwise it is the sum of the nonzero values up to associativity and commutativity

Mario Carneiro (Apr 30 2021 at 13:43):

doing something like that would be harder in lean since type equality tests don't work very well

David Wärn (Apr 30 2021 at 14:19):

My armchair understanding is that using roption / option for partial values like these could be really nice, if only we had some nice way of dealing with all the monad stuff (as well as whats_this_called, which I guess can't be defined in terms of monad operations since it's noncomputable). For example the false theorem at the start of this thread is a true unconditional equality in roption M. A lot of other lemmas, like finsum (f + g) = finsum f + finsum g aren't equalities since the LHS can be defined even when the RHS isn't. Here there's a directedness to the lemma: if you know the values offinsum f and finsum g, then you also know the value of finsum (f + g). Of course this is still easy to express with roption. Fubini's theorem for infinite sums is worse: knowing that some x = ∑ a b, f a b doesn't tell you that ∑ ab, f ab.fst ab.snd exists. Still the way you compute the latter sum in practice is that you compute the former sum, and during these computations observe that ∑ a b, |f a b| is finite...

Eric Wieser (Apr 30 2021 at 14:21):

If you go too far in this direction you end up at docs#tsum

Mario Carneiro (Apr 30 2021 at 14:29):

and during these computations observe that ∑ a b, |f a b| is finite...

This of course assumes that |f a b| is a thing

Mario Carneiro (Apr 30 2021 at 14:30):

If the target type is canonically ordered, then I think you do have Fubini's theorem (with suitable undefinedness preserving sum operations)

David Wärn (Apr 30 2021 at 14:30):

Yes, the problem is with negative terms

Mario Carneiro (Apr 30 2021 at 14:31):

But eric is right that if you want to handle convergence of absolute values that's what tsum does

Mario Carneiro (Apr 30 2021 at 14:32):

Personally, I think the lemmas should just assume the indexing set is finite because that's the easy case where all the lemmas go through

Mario Carneiro (Apr 30 2021 at 14:32):

There will be a second series of lemmas with more subtle conditions when you only have finite support

David Wärn (Apr 30 2021 at 14:41):

This sounds like a reasonable pragmatic approach

David Wärn (Apr 30 2021 at 14:41):

BTW, a sum where some term is ill-defined should be thought of as ill-defined. This is why you should be able to factor the sum of f : A -> roption B through whats_this_called as sketched above. This is not true of integrals: the integral of f : A -> roption B should only require f to be a.e. well-defined.

Mario Carneiro (Apr 30 2021 at 14:42):

You should be able to do so, since I think roption A is a comm monoid if A is

Mario Carneiro (Apr 30 2021 at 14:43):

maybe that instance doesn't exist

Mario Carneiro (Apr 30 2021 at 14:44):

I guess that's what with_top will do for you

David Wärn (Apr 30 2021 at 14:44):

Aha, that's nice!

Mario Carneiro (Apr 30 2021 at 14:45):

Oh, actually if there are infinitely many tops then you will get 0 instead of top

Mario Carneiro (Apr 30 2021 at 14:45):

so the finsum implementation has to be aware of the top element

Mario Carneiro (Apr 30 2021 at 14:47):

BTW here's the roption version of whats_this_called

import data.pfun

def pfun.totalize {α β} (f : α →. β) : roption (α  β) :=
 a, (f a).1, λ h a, (f a).2 (h a)⟩

David Wärn (Apr 30 2021 at 14:50):

But pfun.totalize isn't in mathlib yet right?

Mario Carneiro (Apr 30 2021 at 14:51):

no, I just made it up

Damiano Testa (Apr 30 2021 at 17:40):

Dear All,

I have not followed the discussion yet, but indeed there is a counterexamples branch to mathlib. I have maintained it by merging master into it every once in a whole, but have not done so after the two big nat/int refactors.

The branch might break now, but I would still love to have more counterexamples! Feel free to push something onto it: in the branch counterexamples, there is a counterexamples folder in src.

Damiano Testa (Apr 30 2021 at 17:41):

I am on holidays for a week, so I will not have a chance to update master soon, but will do so as soon as I can!

Oliver Nash (Apr 30 2021 at 19:25):

Thanks @Damiano Testa Enjoy your holidays. I will keep the counterexamples branch in mind.

Aaron Anderson (May 01 2021 at 01:01):

I’ve also wanted a Fubini for finsum for my work on Hahn series, and an analog of finset.sum_sigma. An option version would be great because you could use simp and only have to check finiteness at the beginning and end, but it would also be awful because yet. another. API.

Oliver Nash (May 01 2021 at 11:54):

I don't have time right now but I might at least try to prove this version (which would suffice for my purposes) this evening:

import algebra.big_operators.finprod

open_locale big_operators

example {α β M : Type*} [add_comm_monoid M] (s : finset (α × β)) (f : α × β  M) :
  ∑ᶠ ab (h : ab  s), f ab = ∑ᶠ a b (h : (a, b)  s), f (a, b) := sorry

Oliver Nash (May 01 2021 at 20:30):

(On the off chance some good citizen was going to work on :point_up: I now have a proof of this which I will PR tomorrow)

Oliver Nash (May 02 2021 at 13:26):

Just pushed up my attempt as #7439


Last updated: Dec 20 2023 at 11:08 UTC