mathlib documentation

data.list.big_operators

Sums and products from lists #

This file provides basic results about list.prod and list.sum, which calculate the product and sum of elements of a list. These are defined in data.list.defs.

@[simp]
theorem list.sum_nil {α : Type u_1} [add_monoid α] :
@[simp]
theorem list.prod_nil {α : Type u_1} [monoid α] :
theorem list.sum_singleton {α : Type u_1} [add_monoid α] {a : α} :
[a].sum = a
theorem list.prod_singleton {α : Type u_1} [monoid α] {a : α} :
[a].prod = a
@[simp]
theorem list.sum_cons {α : Type u_1} [add_monoid α] {l : list α} {a : α} :
(a :: l).sum = a + l.sum
@[simp]
theorem list.prod_cons {α : Type u_1} [monoid α] {l : list α} {a : α} :
(a :: l).prod = a * l.prod
@[simp]
theorem list.prod_append {α : Type u_1} [monoid α] {l₁ l₂ : list α} :
(l₁ ++ l₂).prod = (l₁.prod) * l₂.prod
@[simp]
theorem list.sum_append {α : Type u_1} [add_monoid α] {l₁ l₂ : list α} :
(l₁ ++ l₂).sum = l₁.sum + l₂.sum
theorem list.sum_concat {α : Type u_1} [add_monoid α] {l : list α} {a : α} :
(l.concat a).sum = l.sum + a
theorem list.prod_concat {α : Type u_1} [monoid α] {l : list α} {a : α} :
(l.concat a).prod = (l.prod) * a
@[simp]
theorem list.sum_join {α : Type u_1} [add_monoid α] {l : list (list α)} :
@[simp]
theorem list.prod_join {α : Type u_1} [monoid α] {l : list (list α)} :
theorem list.prod_eq_zero {M₀ : Type u_1} [monoid_with_zero M₀] {L : list M₀} (h : 0 L) :
L.prod = 0

If zero is an element of a list L, then list.prod L = 0. If the domain is a nontrivial monoid with zero with no divisors, then this implication becomes an iff, see list.prod_eq_zero_iff.

@[simp]
theorem list.prod_eq_zero_iff {M₀ : Type u_1} [monoid_with_zero M₀] [nontrivial M₀] [no_zero_divisors M₀] {L : list M₀} :
L.prod = 0 0 L

Product of elements of a list L equals zero if and only if 0 ∈ L. See also list.prod_eq_zero for an implication that needs weaker typeclass assumptions.

theorem list.prod_ne_zero {M₀ : Type u_1} [monoid_with_zero M₀] [nontrivial M₀] [no_zero_divisors M₀] {L : list M₀} (hL : 0 L) :
L.prod 0
theorem list.sum_eq_foldr {α : Type u_1} [add_monoid α] {l : list α} :
theorem list.prod_eq_foldr {α : Type u_1} [monoid α] {l : list α} :
theorem list.prod_hom_rel {α : Type u_1} {β : Type u_2} {γ : Type u_3} [monoid β] [monoid γ] (l : list α) {r : β → γ → Prop} {f : α → β} {g : α → γ} (h₁ : r 1 1) (h₂ : ∀ ⦃a : α⦄ ⦃b : β⦄ ⦃c : γ⦄, r b cr ((f a) * b) ((g a) * c)) :
r (list.map f l).prod (list.map g l).prod
theorem list.sum_hom_rel {α : Type u_1} {β : Type u_2} {γ : Type u_3} [add_monoid β] [add_monoid γ] (l : list α) {r : β → γ → Prop} {f : α → β} {g : α → γ} (h₁ : r 0 0) (h₂ : ∀ ⦃a : α⦄ ⦃b : β⦄ ⦃c : γ⦄, r b cr (f a + b) (g a + c)) :
r (list.map f l).sum (list.map g l).sum
theorem list.sum_hom {α : Type u_1} {β : Type u_2} [add_monoid α] [add_monoid β] (l : list α) (f : α →+ β) :
theorem list.prod_hom {α : Type u_1} {β : Type u_2} [monoid α] [monoid β] (l : list α) (f : α →* β) :
theorem list.sum_is_unit {β : Type u_2} [add_monoid β] {L : list β} (u : ∀ (m : β), m Lis_add_unit m) :
theorem list.prod_is_unit {β : Type u_2} [monoid β] {L : list β} (u : ∀ (m : β), m Lis_unit m) :
@[simp]
theorem list.sum_take_add_sum_drop {α : Type u_1} [add_monoid α] (L : list α) (i : ) :
(list.take i L).sum + (list.drop i L).sum = L.sum
@[simp]
theorem list.prod_take_mul_prod_drop {α : Type u_1} [monoid α] (L : list α) (i : ) :
((list.take i L).prod) * (list.drop i L).prod = L.prod
@[simp]
theorem list.sum_take_succ {α : Type u_1} [add_monoid α] (L : list α) (i : ) (p : i < L.length) :
(list.take (i + 1) L).sum = (list.take i L).sum + L.nth_le i p
@[simp]
theorem list.prod_take_succ {α : Type u_1} [monoid α] (L : list α) (i : ) (p : i < L.length) :
(list.take (i + 1) L).prod = ((list.take i L).prod) * L.nth_le i p
theorem list.length_pos_of_prod_ne_one {α : Type u_1} [monoid α] (L : list α) (h : L.prod 1) :
0 < L.length

A list with product not one must have positive length.

theorem list.length_pos_of_sum_ne_zero {α : Type u_1} [add_monoid α] (L : list α) (h : L.sum 0) :
0 < L.length
theorem list.prod_update_nth {α : Type u_1} [monoid α] (L : list α) (n : ) (a : α) :
(L.update_nth n a).prod = (((list.take n L).prod) * ite (n < L.length) a 1) * (list.drop (n + 1) L).prod
theorem list.sum_update_nth {α : Type u_1} [add_monoid α] (L : list α) (n : ) (a : α) :
(L.update_nth n a).sum = (list.take n L).sum + ite (n < L.length) a 0 + (list.drop (n + 1) L).sum
theorem list.prod_inv_reverse {α : Type u_1} [group α] (L : list α) :
(L.prod)⁻¹ = (list.map (λ (x : α), x⁻¹) L).reverse.prod

This is the list.prod version of mul_inv_rev

theorem list.sum_neg_reverse {α : Type u_1} [add_group α] (L : list α) :
-L.sum = (list.map (λ (x : α), -x) L).reverse.sum

This is the list.sum version of add_neg_rev

theorem list.prod_reverse_noncomm {α : Type u_1} [group α] (L : list α) :
L.reverse.prod = ((list.map (λ (x : α), x⁻¹) L).prod)⁻¹

A non-commutative variant of list.prod_reverse

theorem list.sum_reverse_noncomm {α : Type u_1} [add_group α] (L : list α) :
L.reverse.sum = -(list.map (λ (x : α), -x) L).sum

A non-commutative variant of list.sum_reverse

@[simp]
theorem list.sum_drop_succ {α : Type u_1} [add_group α] (L : list α) (i : ) (p : i < L.length) :
(list.drop (i + 1) L).sum = -L.nth_le i p + (list.drop i L).sum

Counterpart to list.sum_take_succ when we have an negation operation

@[simp]
theorem list.prod_drop_succ {α : Type u_1} [group α] (L : list α) (i : ) (p : i < L.length) :
(list.drop (i + 1) L).prod = (L.nth_le i p)⁻¹ * (list.drop i L).prod

Counterpart to list.prod_take_succ when we have an inverse operation

theorem list.sum_neg {α : Type u_1} [add_comm_group α] (L : list α) :
-L.sum = (list.map (λ (x : α), -x) L).sum

This is the list.sum version of add_neg

theorem list.prod_inv {α : Type u_1} [comm_group α] (L : list α) :
(L.prod)⁻¹ = (list.map (λ (x : α), x⁻¹) L).prod

This is the list.prod version of mul_inv

theorem list.prod_update_nth' {α : Type u_1} [comm_group α] (L : list α) (n : ) (a : α) :
(L.update_nth n a).prod = (L.prod) * dite (n < L.length) (λ (hn : n < L.length), (L.nth_le n hn)⁻¹ * a) (λ (hn : ¬n < L.length), 1)

Alternative version of list.prod_update_nth when the list is over a group

theorem list.sum_update_nth' {α : Type u_1} [add_comm_group α] (L : list α) (n : ) (a : α) :
(L.update_nth n a).sum = L.sum + dite (n < L.length) (λ (hn : n < L.length), -L.nth_le n hn + a) (λ (hn : ¬n < L.length), 0)

Alternative version of list.sum_update_nth when the list is over a group

theorem list.eq_of_sum_take_eq {α : Type u_1} [add_left_cancel_monoid α] {L L' : list α} (h : L.length = L'.length) (h' : ∀ (i : ), i L.length(list.take i L).sum = (list.take i L').sum) :
L = L'
theorem list.monotone_sum_take {α : Type u_1} [canonically_ordered_add_monoid α] (L : list α) :
monotone (λ (i : ), (list.take i L).sum)
theorem list.sum_nonneg {α : Type u_1} [ordered_add_comm_monoid α] {l : list α} (hl₁ : ∀ (x : α), x l0 x) :
0 l.sum
theorem list.one_le_prod_of_one_le {α : Type u_1} [ordered_comm_monoid α] {l : list α} (hl₁ : ∀ (x : α), x l1 x) :
1 l.prod
theorem list.one_lt_prod_of_one_lt {α : Type u_1} [ordered_comm_monoid α] (l : list α) (hl : ∀ (x : α), x l1 < x) (hl₂ : l list.nil) :
1 < l.prod
theorem list.sum_pos {α : Type u_1} [ordered_add_comm_monoid α] (l : list α) (hl : ∀ (x : α), x l0 < x) (hl₂ : l list.nil) :
0 < l.sum
theorem list.single_le_sum {α : Type u_1} [ordered_add_comm_monoid α] {l : list α} (hl₁ : ∀ (x : α), x l0 x) (x : α) (H : x l) :
x l.sum
theorem list.single_le_prod {α : Type u_1} [ordered_comm_monoid α] {l : list α} (hl₁ : ∀ (x : α), x l1 x) (x : α) (H : x l) :
x l.prod
theorem list.all_zero_of_le_zero_le_of_sum_eq_zero {α : Type u_1} [ordered_add_comm_monoid α] {l : list α} (hl₁ : ∀ (x : α), x l0 x) (hl₂ : l.sum = 0) {x : α} (hx : x l) :
x = 0
theorem list.all_one_of_le_one_le_of_prod_eq_one {α : Type u_1} [ordered_comm_monoid α] {l : list α} (hl₁ : ∀ (x : α), x l1 x) (hl₂ : l.prod = 1) {x : α} (hx : x l) :
x = 1
theorem list.sum_eq_zero_iff {α : Type u_1} [canonically_ordered_add_monoid α] (l : list α) :
l.sum = 0 ∀ (x : α), x lx = 0
theorem list.length_le_sum_of_one_le (L : list ) (h : ∀ (i : ), i L1 i) :

If all elements in a list are bounded below by 1, then the length of the list is bounded by the sum of the elements.

theorem list.length_pos_of_sum_pos {α : Type u_1} [ordered_cancel_add_comm_monoid α] (L : list α) (h : 0 < L.sum) :
0 < L.length

A list with positive sum must have positive length.

theorem list.sum_le_foldr_max {α : Type u_1} {β : Type u_2} [add_monoid α] [add_monoid β] [linear_order β] (f : α → β) (h0 : f 0 0) (hadd : ∀ (x y : α), f (x + y) max (f x) (f y)) (l : list α) :
@[simp]
theorem list.sum_erase {α : Type u_1} [decidable_eq α] [add_comm_monoid α] {a : α} {l : list α} :
a la + (l.erase a).sum = l.sum
@[simp]
theorem list.prod_erase {α : Type u_1} [decidable_eq α] [comm_monoid α] {a : α} {l : list α} :
a la * (l.erase a).prod = l.prod
theorem list.dvd_prod {α : Type u_1} [comm_monoid α] {a : α} {l : list α} (ha : a l) :
a l.prod
@[simp]
theorem list.sum_const_nat (m n : ) :
(list.repeat m n).sum = m * n
theorem list.dvd_sum {α : Type u_1} [comm_semiring α] {a : α} {l : list α} (h : ∀ (x : α), x la x) :
a l.sum
theorem list.exists_lt_of_sum_lt {α : Type u_1} {β : Type u_2} [linear_ordered_cancel_add_comm_monoid β] {l : list α} (f g : α → β) (h : (list.map f l).sum < (list.map g l).sum) :
∃ (x : α) (H : x l), f x < g x
theorem list.exists_le_of_sum_le {α : Type u_1} {β : Type u_2} [linear_ordered_cancel_add_comm_monoid β] {l : list α} (hl : l list.nil) (f g : α → β) (h : (list.map f l).sum (list.map g l).sum) :
∃ (x : α) (H : x l), f x g x
theorem list.nth_zero_add_tail_sum {α : Type u_1} [add_monoid α] (l : list α) :
(l.nth 0).get_or_else 0 + l.tail.sum = l.sum
theorem list.nth_zero_mul_tail_prod {α : Type u_1} [monoid α] (l : list α) :
((l.nth 0).get_or_else 1) * l.tail.prod = l.prod

We'd like to state this as L.head * L.tail.prod = L.prod, but because L.head relies on an inhabited instance to return a garbage value on the empty list, this is not possible. Instead, we write the statement in terms of (L.nth 0).get_or_else 1 and state the lemma for as

theorem list.head_add_tail_sum_of_ne_nil {α : Type u_1} [add_monoid α] [inhabited α] (l : list α) (h : l list.nil) :
l.head + l.tail.sum = l.sum
theorem list.head_mul_tail_prod_of_ne_nil {α : Type u_1} [monoid α] [inhabited α] (l : list α) (h : l list.nil) :
(l.head) * l.tail.prod = l.prod

Same as nth_zero_mul_tail_prod, but avoiding the list.head garbage complication by requiring the list to be nonempty.

theorem list.prod_pos {α : Type u_1} [ordered_semiring α] [nontrivial α] (l : list α) (h : ∀ (a : α), a l0 < a) :
0 < l.prod

The product of a list of positive natural numbers is positive, and likewise for any nontrivial ordered semiring.

Several lemmas about sum/head/tail for list. These are hard to generalize well, as they rely on the fact that default ℕ = 0. If desired, we could add a class stating that default α = 0.

theorem list.head_add_tail_sum (L : list ) :
L.head + L.tail.sum = L.sum

This relies on default ℕ = 0.

theorem list.head_le_sum (L : list ) :

This relies on default ℕ = 0.

theorem list.tail_sum (L : list ) :
L.tail.sum = L.sum - L.head

This relies on default ℕ = 0.

@[simp]
@[simp]
@[simp]
theorem list.alternating_prod_singleton {G : Type u_4} [comm_group G] (g : G) :
@[simp]
theorem list.alternating_sum_singleton {G : Type u_4} [add_comm_group G] (g : G) :
@[simp]
theorem list.alternating_sum_cons_cons' {G : Type u_4} [add_comm_group G] (g h : G) (l : list G) :
@[simp]
theorem list.alternating_prod_cons_cons {G : Type u_4} [comm_group G] (g h : G) (l : list G) :
theorem list.alternating_sum_cons_cons {G : Type u_1} [add_comm_group G] (g h : G) (l : list G) :
theorem monoid_hom.map_list_prod {α : Type u_1} {β : Type u_2} [monoid α] [monoid β] (f : α →* β) (l : list α) :
theorem add_monoid_hom.map_list_sum {α : Type u_1} {β : Type u_2} [add_monoid α] [add_monoid β] (f : α →+ β) (l : list α) :
theorem monoid_hom.unop_map_list_prod {α : Type u_1} {β : Type u_2} [monoid α] [monoid β] (f : α →* βᵐᵒᵖ) (l : list α) :

A morphism into the opposite monoid acts on the product by acting on the reversed elements

theorem list.prod_map_hom {α : Type u_1} {β : Type u_2} {γ : Type u_3} [monoid β] [monoid γ] (L : list α) (f : α → β) (g : β →* γ) :
(list.map (g f) L).prod = g (list.map f L).prod
theorem list.sum_map_hom {α : Type u_1} {β : Type u_2} {γ : Type u_3} [add_monoid β] [add_monoid γ] (L : list α) (f : α → β) (g : β →+ γ) :
(list.map (g f) L).sum = g (list.map f L).sum
theorem list.sum_map_mul_left {α : Type u_1} {β : Type u_2} [semiring α] (L : list β) (f : β → α) (r : α) :
(list.map (λ (b : β), r * f b) L).sum = r * (list.map f L).sum
theorem list.sum_map_mul_right {α : Type u_1} {β : Type u_2} [semiring α] (L : list β) (f : β → α) (r : α) :
(list.map (λ (b : β), (f b) * r) L).sum = ((list.map f L).sum) * r