Zulip Chat Archive

Stream: new members

Topic: iterating over subscripts & generalizing products


Alena Gusakov (Jun 24 2020 at 20:24):

So if I want to prove a statement like (a₁ * a₂ * ... * a_n)⁻¹ = a_n⁻¹ *...*a₂⁻¹ *a₁⁻¹, how would I write it out?

Jalex Stark (Jun 24 2020 at 20:25):

check out docs#finset.prod

Aniruddh Agarwal (Jun 24 2020 at 20:26):

Jalex beat me to it :P

Jalex Stark (Jun 24 2020 at 20:26):

it has many useful lemmas :)

Jalex Stark (Jun 24 2020 at 20:27):

you can win the race next time if you use the linkifier

Jalex Stark (Jun 24 2020 at 20:30):

ah this won't work, finset.prod is about commutative multiplication

Alex J. Best (Jun 24 2020 at 20:32):

docs#inv_prod ?

Jalex Stark (Jun 24 2020 at 20:33):

that looks like the theorem alena asked about

Aniruddh Agarwal (Jun 24 2020 at 20:34):

docs#list.prod

Alena Gusakov (Jun 24 2020 at 20:34):

Yeah I'm trying to prove it

Alena Gusakov (Jun 24 2020 at 20:35):

list.prod takes care of the product, but I still don't get how to iterate over subscripts. Is there some list constructor for that?

Jalex Stark (Jun 24 2020 at 20:36):

(list.map a (list.range n)), where (a : ℕ → G) and G is your group. I don't think we have something like python list comprehensions, if that's what you're asking

Yakov Pechersky (Jun 24 2020 at 20:38):

example {a b c d : } : (a * b * c * d)⁻¹ = d⁻¹ * c⁻¹ * b⁻¹ * a⁻¹ :=
by { simp [mul_inv', mul_assoc] }

Alena Gusakov (Jun 24 2020 at 20:38):

I don't know exactly how to phrase my question haha sorry, though I do think what you gave me is what I'm looking for

Alena Gusakov (Jun 24 2020 at 20:39):

I'm trying to solve it for all n so it's an induction type proof

Alena Gusakov (Jun 24 2020 at 20:39):

Gonna have to tinker with the list.map thing

Yakov Pechersky (Jun 24 2020 at 20:40):

Do you have an example of the place you need to do it at in a #mwe?

Alena Gusakov (Jun 24 2020 at 20:41):

Like the proof itself? It's just an exercise, I'm trying to go through Dummit and Foote and prove basic stuff

Jalex Stark (Jun 24 2020 at 20:42):

I think this is mathematically the right statement

import tactic

variables (G : Type*) [group G] (n : ) (a :   G)

example :
(list.map a (list.range n)).prod⁻¹ = (list.map (λ x, (a x)⁻¹) (list.range n).reverse).prod :=
begin
  sorry
end

Yakov Pechersky (Jun 24 2020 at 20:42):

From what I've learned on this channel is that statements about general a_1, ... a_i, ..., a_n aren't very Lean friendly

Alena Gusakov (Jun 24 2020 at 20:43):

Oof okay, good to know

Yakov Pechersky (Jun 24 2020 at 20:43):

I could be totally wrong though.

Jalex Stark (Jun 24 2020 at 20:44):

i think working with a list is slightly harder than working with a finset, but i think working with lists in lean is not much more awkward than working with lists in haskell

Alex J. Best (Jun 24 2020 at 20:44):

Its probably best when doing problems like this to use a list L and do induction on L instead of indices directly.

Alena Gusakov (Jun 24 2020 at 20:45):

Oh no this one is gonna be really tedious

Alena Gusakov (Jun 24 2020 at 20:45):

@Alex J. Best so like, append elements?

Alena Gusakov (Jun 24 2020 at 20:46):

I don't really know how that would look

Jalex Stark (Jun 24 2020 at 20:46):

I think Alex is suggesting that the statement you want to prove is literally docs#inv_prod

Alena Gusakov (Jun 24 2020 at 20:48):

Ahh okay I see

Jalex Stark (Jun 24 2020 at 20:48):

here's the statement, for anyone that doesn't follow the link

lemma inv_prod {G : Type*} [group G] (l : list G) :
(l.prod)⁻¹ = (list.map (λ x , x⁻¹) l.reverse).prod

Alex J. Best (Jun 24 2020 at 20:48):

So yeah the lemma is in mathlib, but you should totally try and prove it still!
Yes, lists are defined as an inductive type, so the empty list is a list, and if L is a list and a is an element, then a :: L is also a list, this notation means append a to the start of L, so a :: [b,c] is [a, b, c], or this is a :: b :: c :: [].
Because its an inductive type doing the induction on lists of different lengths works well, just call induction L to split into these two cases the empty list and a :: L for some a  and L.

Alena Gusakov (Jun 24 2020 at 20:50):

In this case would it be a good idea to start with an a :: [] appended already since the statement doesn't really mean anything on an empty list? Or is that a perfectly valid thing to do?

Jalex Stark (Jun 24 2020 at 20:51):

list.prod is defined for the empty list

Jalex Stark (Jun 24 2020 at 20:51):

and your theorem is true for it

Alena Gusakov (Jun 24 2020 at 20:51):

Okay yeah fair

Alex J. Best (Jun 24 2020 at 20:51):

Well the advantage of the empty list is that a lot of statements are trivial for that, compared to a :: [], [].prod =1 for example.
BTW the setup for induction would be like this:

lemma inv_prod {α : Type*} [group α] (L : list α) : L.prod⁻¹ = (L.reverse.map (λ x, x⁻¹)).prod :=
begin
  induction L,
  { sorry },
  { sorry },
end

Alena Gusakov (Jun 24 2020 at 20:52):

Gotcha, thank you!

Jalex Stark (Jun 24 2020 at 20:55):

If you want to start from a black box and work backwards, simp can do all the bits, and squeeze_simp will tell you what simp found

import tactic

lemma inv_prod {G : Type*} [group G] (l : list G) :
(list.prod l)⁻¹ = (list.map (λ x, x⁻¹) l.reverse).prod :=
begin
  induction l with hd tl h,
  squeeze_simp,
  squeeze_simp [h],
end

Yakov Pechersky (Jun 24 2020 at 20:55):

fin version seems more natural to me

import tactic
import algebra.big_operators
import data.fintype.card

open_locale big_operators

variables (G : Type*) [comm_group G] (n : ) (a : fin n.succ  G)

example :
( i, (a i))⁻¹ =  i, (a i)⁻¹ :=
begin
  induction n with k hk,
  simp,
  simp [fin.prod_univ_succ, mul_inv],
end

Yakov Pechersky (Jun 24 2020 at 20:57):

It doesn't have the reversal going on, though

Jalex Stark (Jun 24 2020 at 20:57):

you're proving an easier lemma

Yakov Pechersky (Jun 24 2020 at 20:58):

Yeah, using comm

Jalex Stark (Jun 24 2020 at 20:58):

you're taking an unordered product of elements of a commutative group

Yakov Pechersky (Jun 24 2020 at 20:58):

And Prod requires comm_monoid

Jalex Stark (Jun 24 2020 at 20:59):

right, that's why we were not using the big operator stuff

Yakov Pechersky (Jun 24 2020 at 20:59):

Gotcha

Jalex Stark (Jun 24 2020 at 20:59):

it might not be hard to define big operators over lists, but afaik nobody has done it

Bryan Gin-ge Chen (Jun 24 2020 at 21:06):

Patrick is fond of recommending the paper on Coq's big operator library: https://hal.inria.fr/inria-00331193/PDF/main.pdf

Jalex Stark (Jun 24 2020 at 21:44):

This works for doing list.prod through notation (though there's an embarrassingly simple sorry)

import tactic

localized "notation `∏` binders ` in ` l `, ` r:(scoped:67 f, (list.map f l).prod) := r" in big_list_prod

variables (G : Type*) [comm_group G] (n : ) (a :   G)

open list
open_locale big_list_prod

@[simp]
lemma range_zero : range 0 = nil := rfl

@[simp]
lemma range_succ (n : ) : range n.succ = n :: range n := sorry

example (n : ) :
 i in range n, (a i)⁻¹ = ( i in (range n).reverse, a i)⁻¹ :=
begin
  induction n with d hd,
  { simp },
  simp [hd],
end

Last updated: Dec 20 2023 at 11:08 UTC