File: Mathlib/Data/Multiset/Bind.lean

full_name: Multiset.join
code: /-- `join S`, where `S` is a multiset of multisets, is the lift of the list join
  operation, that is, the union of all the sets.
     join {{1, 2}, {1, 2}, {0, 1}} = {0, 1, 1, 1, 2, 2} -/
def join : Multiset (Multiset α) → Multiset α 
goal: Multiset (Multiset α) → Multiset α

full_name: Multiset.coe_join
code: theorem coe_join :
    ∀ L : List (List α), join (L.map ((↑) : List α → Multiset α) : Multiset (Multiset α)) = L.join
  
goal: (↑(List.map Multiset.ofList L)).join = ↑L.join

full_name: Multiset.join_zero
code: @[simp]
theorem join_zero : @join α 0 = 0 
goal: Multiset.join 0 = 0

full_name: Multiset.join_cons
code: @[simp]
theorem join_cons (s S) : @join α (s ::ₘ S) = s + join S 
goal: (s ::ₘ S).join = s + S.join

full_name: Multiset.join_add
code: @[simp]
theorem join_add (S T) : @join α (S + T) = join S + join T 
goal: (S + T).join = S.join + T.join

full_name: Multiset.singleton_join
code: @[simp]
theorem singleton_join (a) : join ({a} : Multiset (Multiset α)) = a 
goal: {a}.join = a

full_name: Multiset.mem_join
code: @[simp]
theorem mem_join {a S} : a ∈ @join α S ↔ ∃ s ∈ S, a ∈ s 
goal: a ∈ S.join ↔ ∃ s ∈ S, a ∈ s

full_name: Multiset.card_join
code: @[simp]
theorem card_join (S) : card (@join α S) = sum (map card S) 
goal: Multiset.card S.join = (Multiset.map (⇑Multiset.card) S).sum

full_name: Multiset.map_join
code: @[simp]
theorem map_join (f : α → β) (S : Multiset (Multiset α)) :
    map f (join S) = join (map (map f) S) 
goal: Multiset.map f S.join = (Multiset.map (Multiset.map f) S).join

full_name: Multiset.sum_join
code: @[to_additive (attr := simp)]
theorem prod_join [CommMonoid α] {S : Multiset (Multiset α)} :
    prod (join S) = prod (map prod S) 
goal: S.join.sum = (Multiset.map Multiset.sum S).sum

full_name: Multiset.prod_join
code: @[to_additive (attr := simp)]
theorem prod_join [CommMonoid α] {S : Multiset (Multiset α)} :
    prod (join S) = prod (map prod S) 
goal: S.join.prod = (Multiset.map Multiset.prod S).prod

full_name: Multiset.rel_join
code: theorem rel_join {r : α → β → Prop} {s t} (h : Rel (Rel r) s t) : Rel r s.join t.join 
goal: Multiset.Rel r s.join t.join

full_name: Multiset.bind
code: /-- `s.bind f` is the monad bind operation, defined as `(s.map f).join`. It is the union of `f a` as
`a` ranges over `s`. -/
def bind (s : Multiset α) (f : α → Multiset β) : Multiset β 
goal: Multiset β

full_name: Multiset.coe_bind
code: @[simp]
theorem coe_bind (l : List α) (f : α → List β) : (@bind α β l fun a => f a) = l.bind f 
goal: ((↑l).bind fun a => ↑(f a)) = ↑(l.bind f)

full_name: Multiset.zero_bind
code: @[simp]
theorem zero_bind : bind 0 f = 0 
goal: Multiset.bind 0 f = 0

full_name: Multiset.cons_bind
code: @[simp]
theorem cons_bind : (a ::ₘ s).bind f = f a + s.bind f 
goal: (a ::ₘ s).bind f = f a + s.bind f

full_name: Multiset.singleton_bind
code: @[simp]
theorem singleton_bind : bind {a} f = f a 
goal: {a}.bind f = f a

full_name: Multiset.add_bind
code: @[simp]
theorem add_bind : (s + t).bind f = s.bind f + t.bind f 
goal: (s + t).bind f = s.bind f + t.bind f

full_name: Multiset.bind_zero
code: @[simp]
theorem bind_zero : s.bind (fun _ => 0 : α → Multiset β) = 0 
goal: (s.bind fun x => 0) = 0

full_name: Multiset.bind_add
code: @[simp]
theorem bind_add : (s.bind fun a => f a + g a) = s.bind f + s.bind g 
goal: (s.bind fun a => f a + g a) = s.bind f + s.bind g

full_name: Multiset.bind_cons
code: @[simp]
theorem bind_cons (f : α → β) (g : α → Multiset β) :
    (s.bind fun a => f a ::ₘ g a) = map f s + s.bind g 
goal: (s.bind fun a => f a ::ₘ g a) = Multiset.map f s + s.bind g

full_name: Multiset.bind_singleton
code: @[simp]
theorem bind_singleton (f : α → β) : (s.bind fun x => ({f x} : Multiset β)) = map f s 
goal: (s.bind fun x => {f x}) = Multiset.map f s

full_name: Multiset.mem_bind
code: @[simp]
theorem mem_bind {b s} {f : α → Multiset β} : b ∈ bind s f ↔ ∃ a ∈ s, b ∈ f a 
goal: b ∈ s.bind f ↔ ∃ a ∈ s, b ∈ f a

full_name: Multiset.card_bind
code: @[simp]
theorem card_bind : card (s.bind f) = (s.map (card ∘ f)).sum 
goal: Multiset.card (s.bind f) = (Multiset.map (⇑Multiset.card ∘ f) s).sum

full_name: Multiset.bind_congr
code: theorem bind_congr {f g : α → Multiset β} {m : Multiset α} :
    (∀ a ∈ m, f a = g a) → bind m f = bind m g 
goal: (∀ a ∈ m, f a = g a) → m.bind f = m.bind g

full_name: Multiset.bind_hcongr
code: theorem bind_hcongr {β' : Type v} {m : Multiset α} {f : α → Multiset β} {f' : α → Multiset β'}
    (h : β = β') (hf : ∀ a ∈ m, HEq (f a) (f' a)) : HEq (bind m f) (bind m f') 
goal: HEq (m.bind f) (m.bind f')

full_name: Multiset.map_bind
code: theorem map_bind (m : Multiset α) (n : α → Multiset β) (f : β → γ) :
    map f (bind m n) = bind m fun a => map f (n a) 
goal: Multiset.map f (m.bind n) = m.bind fun a => Multiset.map f (n a)

full_name: Multiset.bind_map
code: theorem bind_map (m : Multiset α) (n : β → Multiset γ) (f : α → β) :
    bind (map f m) n = bind m fun a => n (f a) 
goal: (Multiset.map f m).bind n = m.bind fun a => n (f a)

full_name: Multiset.bind_assoc
code: theorem bind_assoc {s : Multiset α} {f : α → Multiset β} {g : β → Multiset γ} :
    (s.bind f).bind g = s.bind fun a => (f a).bind g 
goal: (s.bind f).bind g = s.bind fun a => (f a).bind g

full_name: Multiset.bind_bind
code: theorem bind_bind (m : Multiset α) (n : Multiset β) {f : α → β → Multiset γ} :
    ((bind m) fun a => (bind n) fun b => f a b) = (bind n) fun b => (bind m) fun a => f a b 
goal: (m.bind fun a => n.bind fun b => f a b) = n.bind fun b => m.bind fun a => f a b

full_name: Multiset.bind_map_comm
code: theorem bind_map_comm (m : Multiset α) (n : Multiset β) {f : α → β → γ} :
    ((bind m) fun a => n.map fun b => f a b) = (bind n) fun b => m.map fun a => f a b 
goal: (m.bind fun a => Multiset.map (fun b => f a b) n) = n.bind fun b => Multiset.map (fun a => f a b) m

full_name: Multiset.sum_bind
code: @[to_additive (attr := simp)]
theorem prod_bind [CommMonoid β] (s : Multiset α) (t : α → Multiset β) :
    (s.bind t).prod = (s.map fun a => (t a).prod).prod 
goal: (s.bind t).sum = (Multiset.map (fun a => (t a).sum) s).sum

full_name: Multiset.prod_bind
code: @[to_additive (attr := simp)]
theorem prod_bind [CommMonoid β] (s : Multiset α) (t : α → Multiset β) :
    (s.bind t).prod = (s.map fun a => (t a).prod).prod 
goal: (s.bind t).prod = (Multiset.map (fun a => (t a).prod) s).prod

full_name: Multiset.rel_bind
code: theorem rel_bind {r : α → β → Prop} {p : γ → δ → Prop} {s t} {f : α → Multiset γ}
    {g : β → Multiset δ} (h : (r ⇒ Rel p) f g) (hst : Rel r s t) :
    Rel p (s.bind f) (t.bind g) 
goal: Multiset.Rel p (s.bind f) (t.bind g)

full_name: Multiset.count_sum
code: theorem count_sum [DecidableEq α] {m : Multiset β} {f : β → Multiset α} {a : α} :
    count a (map f m).sum = sum (m.map fun b => count a <| f b) 
goal: Multiset.count a (Multiset.map f m).sum = (Multiset.map (fun b => Multiset.count a (f b)) m).sum

full_name: Multiset.count_bind
code: theorem count_bind [DecidableEq α] {m : Multiset β} {f : β → Multiset α} {a : α} :
    count a (bind m f) = sum (m.map fun b => count a <| f b) 
goal: Multiset.count a (m.bind f) = (Multiset.map (fun b => Multiset.count a (f b)) m).sum

full_name: Multiset.le_bind
code: theorem le_bind {α β : Type*} {f : α → Multiset β} (S : Multiset α) {x : α} (hx : x ∈ S) :
    f x ≤ S.bind f 
goal: f x ≤ S.bind f

full_name: Multiset.attach_bind_coe
code: theorem attach_bind_coe (s : Multiset α) (f : α → Multiset β) :
    (s.attach.bind fun i => f i) = s.bind f 
goal: (s.attach.bind fun i => f ↑i) = s.bind f

full_name: Multiset.nodup_bind
code: @[simp] lemma nodup_bind :
    Nodup (bind s f) ↔ (∀ a ∈ s, Nodup (f a)) ∧ s.Pairwise fun a b => Disjoint (f a) (f b) 
goal: (s.bind f).Nodup ↔ (∀ a ∈ s, (f a).Nodup) ∧ Multiset.Pairwise (fun a b => (f a).Disjoint (f b)) s

full_name: Multiset.dedup_bind_dedup
code: @[simp]
lemma dedup_bind_dedup [DecidableEq α] [DecidableEq β] (s : Multiset α) (f : α → Multiset β) :
    (s.dedup.bind f).dedup = (s.bind f).dedup 
goal: (s.dedup.bind f).dedup = (s.bind f).dedup

full_name: Multiset.product
code: /-- The multiplicity of `(a, b)` in `s ×ˢ t` is
  the product of the multiplicity of `a` in `s` and `b` in `t`. -/
def product (s : Multiset α) (t : Multiset β) : Multiset (α × β) 
goal: Multiset (α × β)

full_name: Multiset.instSProd
code: instance instSProd : SProd (Multiset α) (Multiset β) (Multiset (α × β)) 
goal: SProd (Multiset α) (Multiset β) (Multiset (α × β))

full_name: Multiset.coe_product
code: @[simp]
theorem coe_product (l₁ : List α) (l₂ : List β) :
    (l₁ : Multiset α) ×ˢ (l₂ : Multiset β) = (l₁ ×ˢ l₂) 
goal: ↑l₁ ×ˢ ↑l₂ = ↑(l₁ ×ˢ l₂)

full_name: Multiset.zero_product
code: @[simp]
theorem zero_product : (0 : Multiset α) ×ˢ t = 0 
goal: 0 ×ˢ t = 0

full_name: Multiset.cons_product
code: @[simp]
theorem cons_product : (a ::ₘ s) ×ˢ t = map (Prod.mk a) t + s ×ˢ t 
goal: (a ::ₘ s) ×ˢ t = Multiset.map (Prod.mk a) t + s ×ˢ t

full_name: Multiset.product_zero
code: @[simp]
theorem product_zero : s ×ˢ (0 : Multiset β) = 0 
goal: s ×ˢ 0 = 0

full_name: Multiset.product_cons
code: @[simp]
theorem product_cons : s ×ˢ (b ::ₘ t) = (s.map fun a => (a, b)) + s ×ˢ t 
goal: s ×ˢ (b ::ₘ t) = Multiset.map (fun a => (a, b)) s + s ×ˢ t

full_name: Multiset.product_singleton
code: @[simp]
theorem product_singleton : ({a} : Multiset α) ×ˢ ({b} : Multiset β) = {(a, b)} 
goal: {a} ×ˢ {b} = {(a, b)}

full_name: Multiset.add_product
code: @[simp]
theorem add_product (s t : Multiset α) (u : Multiset β) : (s + t) ×ˢ u = s ×ˢ u + t ×ˢ u 
goal: (s + t) ×ˢ u = s ×ˢ u + t ×ˢ u

full_name: Multiset.product_add
code: @[simp]
theorem product_add (s : Multiset α) : ∀ t u : Multiset β, s ×ˢ (t + u) = s ×ˢ t + s ×ˢ u 
goal: s ×ˢ (t + u) = s ×ˢ t + s ×ˢ u

full_name: Multiset.card_product
code: @[simp]
theorem card_product : card (s ×ˢ t) = card s * card t 
goal: Multiset.card (s ×ˢ t) = Multiset.card s * Multiset.card t

full_name: Multiset.mem_product
code: @[simp] lemma mem_product : ∀ {p : α × β}, p ∈ @product α β s t ↔ p.1 ∈ s ∧ p.2 ∈ t
  
goal: p ∈ s.product t ↔ p.1 ∈ s ∧ p.2 ∈ t

full_name: Multiset.Nodup.product
code: protected theorem Nodup.product : Nodup s → Nodup t → Nodup (s ×ˢ t) 
goal: s.Nodup → t.Nodup → (s ×ˢ t).Nodup

full_name: Multiset.sigma
code: /-- `Multiset.sigma s t` is the dependent version of `Multiset.product`. It is the sum of
  `(a, b)` as `a` ranges over `s` and `b` ranges over `t a`. -/
protected def sigma (s : Multiset α) (t : ∀ a, Multiset (σ a)) : Multiset (Σa, σ a) 
goal: Multiset ((a : α) × σ a)

full_name: Multiset.coe_sigma
code: @[simp]
theorem coe_sigma (l₁ : List α) (l₂ : ∀ a, List (σ a)) :
    (@Multiset.sigma α σ l₁ fun a => l₂ a) = l₁.sigma l₂ 
goal: ((↑l₁).sigma fun a => ↑(l₂ a)) = ↑(l₁.sigma l₂)

full_name: Multiset.zero_sigma
code: @[simp]
theorem zero_sigma : @Multiset.sigma α σ 0 t = 0 
goal: Multiset.sigma 0 t = 0

full_name: Multiset.cons_sigma
code: @[simp]
theorem cons_sigma : (a ::ₘ s).sigma t = (t a).map (Sigma.mk a) + s.sigma t 
goal: (a ::ₘ s).sigma t = Multiset.map (Sigma.mk a) (t a) + s.sigma t

full_name: Multiset.sigma_singleton
code: @[simp]
theorem sigma_singleton (b : α → β) :
    (({a} : Multiset α).sigma fun a => ({b a} : Multiset β)) = {⟨a, b a⟩} 
goal: ({a}.sigma fun a => {b a}) = {⟨a, b a⟩}

full_name: Multiset.add_sigma
code: @[simp]
theorem add_sigma (s t : Multiset α) (u : ∀ a, Multiset (σ a)) :
    (s + t).sigma u = s.sigma u + t.sigma u 
goal: (s + t).sigma u = s.sigma u + t.sigma u

full_name: Multiset.sigma_add
code: @[simp]
theorem sigma_add :
    ∀ t u : ∀ a, Multiset (σ a), (s.sigma fun a => t a + u a) = s.sigma t + s.sigma u 
goal: (s.sigma fun a => t a + u a) = s.sigma t + s.sigma u

full_name: Multiset.card_sigma
code: @[simp]
theorem card_sigma : card (s.sigma t) = sum (map (fun a => card (t a)) s) 
goal: Multiset.card (s.sigma t) = (Multiset.map (fun a => Multiset.card (t a)) s).sum

full_name: Multiset.mem_sigma
code: @[simp] lemma mem_sigma : ∀ {p : Σa, σ a}, p ∈ @Multiset.sigma α σ s t ↔ p.1 ∈ s ∧ p.2 ∈ t p.1
  
goal: p ∈ s.sigma t ↔ p.fst ∈ s ∧ p.snd ∈ t p.fst

full_name: Multiset.Nodup.sigma
code: protected theorem Nodup.sigma {σ : α → Type*} {t : ∀ a, Multiset (σ a)} :
    Nodup s → (∀ a, Nodup (t a)) → Nodup (s.sigma t) 
goal: s.Nodup → (∀ (a : α), (t a).Nodup) → (s.sigma t).Nodup