File: Mathlib/Data/Finset/Prod.lean

full_name: Finset.product
code: /-- `product s t` is the set of pairs `(a, b)` such that `a ∈ s` and `b ∈ t`. -/
protected def product (s : Finset α) (t : Finset β) : Finset (α × β) 
goal: Finset (α × β)

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

full_name: Finset.product_val
code: @[simp]
theorem product_val : (s ×ˢ t).1 = s.1 ×ˢ t.1 
goal: (s ×ˢ t).val = s.val ×ˢ t.val

full_name: Finset.mem_product
code: @[simp]
theorem mem_product {p : α × β} : p ∈ s ×ˢ t ↔ p.1 ∈ s ∧ p.2 ∈ t 
goal: p ∈ s ×ˢ t ↔ p.1 ∈ s ∧ p.2 ∈ t

full_name: Finset.mk_mem_product
code: theorem mk_mem_product (ha : a ∈ s) (hb : b ∈ t) : (a, b) ∈ s ×ˢ t 
goal: (a, b) ∈ s ×ˢ t

full_name: Finset.coe_product
code: @[simp, norm_cast]
theorem coe_product (s : Finset α) (t : Finset β) :
    (↑(s ×ˢ t) : Set (α × β)) = (s : Set α) ×ˢ t 
goal: ↑(s ×ˢ t) = ↑s ×ˢ ↑t

full_name: Finset.subset_product_image_fst
code: theorem subset_product_image_fst [DecidableEq α] : (s ×ˢ t).image Prod.fst ⊆ s 
goal: Finset.image Prod.fst (s ×ˢ t) ⊆ s

full_name: Finset.subset_product_image_snd
code: theorem subset_product_image_snd [DecidableEq β] : (s ×ˢ t).image Prod.snd ⊆ t 
goal: Finset.image Prod.snd (s ×ˢ t) ⊆ t

full_name: Finset.product_image_fst
code: theorem product_image_fst [DecidableEq α] (ht : t.Nonempty) : (s ×ˢ t).image Prod.fst = s 
goal: Finset.image Prod.fst (s ×ˢ t) = s

full_name: Finset.product_image_snd
code: theorem product_image_snd [DecidableEq β] (ht : s.Nonempty) : (s ×ˢ t).image Prod.snd = t 
goal: Finset.image Prod.snd (s ×ˢ t) = t

full_name: Finset.subset_product
code: theorem subset_product [DecidableEq α] [DecidableEq β] {s : Finset (α × β)} :
    s ⊆ s.image Prod.fst ×ˢ s.image Prod.snd 
goal: s ⊆ Finset.image Prod.fst s ×ˢ Finset.image Prod.snd s

full_name: Finset.product_subset_product
code: @[gcongr]
theorem product_subset_product (hs : s ⊆ s') (ht : t ⊆ t') : s ×ˢ t ⊆ s' ×ˢ t' 
goal: s ×ˢ t ⊆ s' ×ˢ t'

full_name: Finset.product_subset_product_left
code: @[gcongr]
theorem product_subset_product_left (hs : s ⊆ s') : s ×ˢ t ⊆ s' ×ˢ t 
goal: s ×ˢ t ⊆ s' ×ˢ t

full_name: Finset.product_subset_product_right
code: @[gcongr]
theorem product_subset_product_right (ht : t ⊆ t') : s ×ˢ t ⊆ s ×ˢ t' 
goal: s ×ˢ t ⊆ s ×ˢ t'

full_name: Finset.map_swap_product
code: theorem map_swap_product (s : Finset α) (t : Finset β) :
    (t ×ˢ s).map ⟨Prod.swap, Prod.swap_injective⟩ = s ×ˢ t 
goal: Finset.map { toFun := Prod.swap, inj' := ⋯ } (t ×ˢ s) = s ×ˢ t

full_name: Finset.image_swap_product
code: @[simp]
theorem image_swap_product [DecidableEq (α × β)] (s : Finset α) (t : Finset β) :
    (t ×ˢ s).image Prod.swap = s ×ˢ t 
goal: Finset.image Prod.swap (t ×ˢ s) = s ×ˢ t

full_name: Finset.product_eq_biUnion
code: theorem product_eq_biUnion [DecidableEq (α × β)] (s : Finset α) (t : Finset β) :
    s ×ˢ t = s.biUnion fun a => t.image fun b => (a, b) 
goal: s ×ˢ t = s.biUnion fun a => Finset.image (fun b => (a, b)) t

full_name: Finset.product_eq_biUnion_right
code: theorem product_eq_biUnion_right [DecidableEq (α × β)] (s : Finset α) (t : Finset β) :
    s ×ˢ t = t.biUnion fun b => s.image fun a => (a, b) 
goal: s ×ˢ t = t.biUnion fun b => Finset.image (fun a => (a, b)) s

full_name: Finset.product_biUnion
code: /-- See also `Finset.sup_product_left`. -/
@[simp]
theorem product_biUnion [DecidableEq γ] (s : Finset α) (t : Finset β) (f : α × β → Finset γ) :
    (s ×ˢ t).biUnion f = s.biUnion fun a => t.biUnion fun b => f (a, b) 
goal: (s ×ˢ t).biUnion f = s.biUnion fun a => t.biUnion fun b => f (a, b)

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

full_name: Finset.nontrivial_prod_iff
code: /-- The product of two Finsets is nontrivial iff both are nonempty
  at least one of them is nontrivial. -/
lemma nontrivial_prod_iff : (s ×ˢ t).Nontrivial ↔
    s.Nonempty ∧ t.Nonempty ∧ (s.Nontrivial ∨ t.Nontrivial) 
goal: (s ×ˢ t).Nontrivial ↔ s.Nonempty ∧ t.Nonempty ∧ (s.Nontrivial ∨ t.Nontrivial)

full_name: Finset.filter_product
code: theorem filter_product (p : α → Prop) (q : β → Prop) [DecidablePred p] [DecidablePred q] :
    ((s ×ˢ t).filter fun x : α × β => p x.1 ∧ q x.2) = s.filter p ×ˢ t.filter q 
goal: Finset.filter (fun x => p x.1 ∧ q x.2) (s ×ˢ t) = Finset.filter p s ×ˢ Finset.filter q t

full_name: Finset.filter_product_left
code: theorem filter_product_left (p : α → Prop) [DecidablePred p] :
    ((s ×ˢ t).filter fun x : α × β => p x.1) = s.filter p ×ˢ t 
goal: Finset.filter (fun x => p x.1) (s ×ˢ t) = Finset.filter p s ×ˢ t

full_name: Finset.filter_product_right
code: theorem filter_product_right (q : β → Prop) [DecidablePred q] :
    ((s ×ˢ t).filter fun x : α × β => q x.2) = s ×ˢ t.filter q 
goal: Finset.filter (fun x => q x.2) (s ×ˢ t) = s ×ˢ Finset.filter q t

full_name: Finset.filter_product_card
code: theorem filter_product_card (s : Finset α) (t : Finset β) (p : α → Prop) (q : β → Prop)
    [DecidablePred p] [DecidablePred q] :
    ((s ×ˢ t).filter fun x : α × β => (p x.1) = (q x.2)).card =
      (s.filter p).card * (t.filter q).card +
        (s.filter (¬ p ·)).card * (t.filter (¬ q ·)).card 
goal: (Finset.filter (fun x => p x.1 = q x.2) (s ×ˢ t)).card =
  (Finset.filter p s).card * (Finset.filter q t).card +
    (Finset.filter (fun x => ¬p x) s).card * (Finset.filter (fun x => ¬q x) t).card

full_name: Finset.empty_product
code: @[simp]
theorem empty_product (t : Finset β) : (∅ : Finset α) ×ˢ t = ∅ 
goal: ∅ ×ˢ t = ∅

full_name: Finset.product_empty
code: @[simp]
theorem product_empty (s : Finset α) : s ×ˢ (∅ : Finset β) = ∅ 
goal: s ×ˢ ∅ = ∅

full_name: Finset.Nonempty.product
code: theorem Nonempty.product (hs : s.Nonempty) (ht : t.Nonempty) : (s ×ˢ t).Nonempty 
goal: (s ×ˢ t).Nonempty

full_name: Finset.Nonempty.fst
code: theorem Nonempty.fst (h : (s ×ˢ t).Nonempty) : s.Nonempty 
goal: s.Nonempty

full_name: Finset.Nonempty.snd
code: theorem Nonempty.snd (h : (s ×ˢ t).Nonempty) : t.Nonempty 
goal: t.Nonempty

full_name: Finset.nonempty_product
code: @[simp, aesop safe apply (rule_sets := [finsetNonempty])]
theorem nonempty_product : (s ×ˢ t).Nonempty ↔ s.Nonempty ∧ t.Nonempty 
goal: (s ×ˢ t).Nonempty ↔ s.Nonempty ∧ t.Nonempty

full_name: Finset.product_eq_empty
code: @[simp]
theorem product_eq_empty {s : Finset α} {t : Finset β} : s ×ˢ t = ∅ ↔ s = ∅ ∨ t = ∅ 
goal: s ×ˢ t = ∅ ↔ s = ∅ ∨ t = ∅

full_name: Finset.singleton_product
code: @[simp]
theorem singleton_product {a : α} :
    ({a} : Finset α) ×ˢ t = t.map ⟨Prod.mk a, Prod.mk.inj_left _⟩ 
goal: {a} ×ˢ t = Finset.map { toFun := Prod.mk a, inj' := ⋯ } t

full_name: Finset.product_singleton
code: @[simp]
theorem product_singleton {b : β} : s ×ˢ {b} = s.map ⟨fun i => (i, b), Prod.mk.inj_right _⟩ 
goal: s ×ˢ {b} = Finset.map { toFun := fun i => (i, b), inj' := ⋯ } s

full_name: Finset.singleton_product_singleton
code: theorem singleton_product_singleton {a : α} {b : β} :
    ({a} ×ˢ {b} : Finset _) = {(a, b)} 
goal: {a} ×ˢ {b} = {(a, b)}

full_name: Finset.union_product
code: @[simp]
theorem union_product [DecidableEq α] [DecidableEq β] : (s ∪ s') ×ˢ t = s ×ˢ t ∪ s' ×ˢ t 
goal: (s ∪ s') ×ˢ t = s ×ˢ t ∪ s' ×ˢ t

full_name: Finset.product_union
code: @[simp]
theorem product_union [DecidableEq α] [DecidableEq β] : s ×ˢ (t ∪ t') = s ×ˢ t ∪ s ×ˢ t' 
goal: s ×ˢ (t ∪ t') = s ×ˢ t ∪ s ×ˢ t'

full_name: Finset.inter_product
code: theorem inter_product [DecidableEq α] [DecidableEq β] : (s ∩ s') ×ˢ t = s ×ˢ t ∩ s' ×ˢ t 
goal: (s ∩ s') ×ˢ t = s ×ˢ t ∩ s' ×ˢ t

full_name: Finset.product_inter
code: theorem product_inter [DecidableEq α] [DecidableEq β] : s ×ˢ (t ∩ t') = s ×ˢ t ∩ s ×ˢ t' 
goal: s ×ˢ (t ∩ t') = s ×ˢ t ∩ s ×ˢ t'

full_name: Finset.product_inter_product
code: theorem product_inter_product [DecidableEq α] [DecidableEq β] :
    s ×ˢ t ∩ s' ×ˢ t' = (s ∩ s') ×ˢ (t ∩ t') 
goal: s ×ˢ t ∩ s' ×ˢ t' = (s ∩ s') ×ˢ (t ∩ t')

full_name: Finset.disjoint_product
code: theorem disjoint_product : Disjoint (s ×ˢ t) (s' ×ˢ t') ↔ Disjoint s s' ∨ Disjoint t t' 
goal: Disjoint (s ×ˢ t) (s' ×ˢ t') ↔ Disjoint s s' ∨ Disjoint t t'

full_name: Finset.disjUnion_product
code: @[simp]
theorem disjUnion_product (hs : Disjoint s s') :
    s.disjUnion s' hs ×ˢ t = (s ×ˢ t).disjUnion (s' ×ˢ t) (disjoint_product.mpr <| Or.inl hs) 
goal: s.disjUnion s' hs ×ˢ t = (s ×ˢ t).disjUnion (s' ×ˢ t) ⋯

full_name: Finset.product_disjUnion
code: @[simp]
theorem product_disjUnion (ht : Disjoint t t') :
    s ×ˢ t.disjUnion t' ht = (s ×ˢ t).disjUnion (s ×ˢ t') (disjoint_product.mpr <| Or.inr ht) 
goal: s ×ˢ t.disjUnion t' ht = (s ×ˢ t).disjUnion (s ×ˢ t') ⋯

full_name: Finset.diag
code: /-- Given a finite set `s`, the diagonal, `s.diag` is the set of pairs of the form `(a, a)` for
`a ∈ s`. -/
def diag 
goal: Finset (α × α)

full_name: Finset.offDiag
code: /-- Given a finite set `s`, the off-diagonal, `s.offDiag` is the set of pairs `(a, b)` with `a ≠ b`
for `a, b ∈ s`. -/
def offDiag 
goal: Finset (α × α)

full_name: Finset.mem_diag
code: @[simp]
theorem mem_diag : x ∈ s.diag ↔ x.1 ∈ s ∧ x.1 = x.2 
goal: x ∈ s.diag ↔ x.1 ∈ s ∧ x.1 = x.2

full_name: Finset.mem_offDiag
code: @[simp]
theorem mem_offDiag : x ∈ s.offDiag ↔ x.1 ∈ s ∧ x.2 ∈ s ∧ x.1 ≠ x.2 
goal: x ∈ s.offDiag ↔ x.1 ∈ s ∧ x.2 ∈ s ∧ x.1 ≠ x.2

full_name: Finset.coe_offDiag
code: @[simp, norm_cast]
theorem coe_offDiag : (s.offDiag : Set (α × α)) = (s : Set α).offDiag 
goal: ↑s.offDiag = (↑s).offDiag

full_name: Finset.diag_card
code: @[simp]
theorem diag_card : (diag s).card = s.card 
goal: s.diag.card = s.card

full_name: Finset.offDiag_card
code: @[simp]
theorem offDiag_card : (offDiag s).card = s.card * s.card - s.card 
goal: s.offDiag.card = s.card * s.card - s.card

full_name: Finset.diag_mono
code: @[mono]
theorem diag_mono : Monotone (diag : Finset α → Finset (α × α)) 
goal: Monotone Finset.diag

full_name: Finset.offDiag_mono
code: @[mono]
theorem offDiag_mono : Monotone (offDiag : Finset α → Finset (α × α)) 
goal: Monotone Finset.offDiag

full_name: Finset.diag_empty
code: @[simp]
theorem diag_empty : (∅ : Finset α).diag = ∅ 
goal: ∅.diag = ∅

full_name: Finset.offDiag_empty
code: @[simp]
theorem offDiag_empty : (∅ : Finset α).offDiag = ∅ 
goal: ∅.offDiag = ∅

full_name: Finset.diag_union_offDiag
code: @[simp]
theorem diag_union_offDiag : s.diag ∪ s.offDiag = s ×ˢ s 
goal: s.diag ∪ s.offDiag = s ×ˢ s

full_name: Finset.disjoint_diag_offDiag
code: @[simp]
theorem disjoint_diag_offDiag : Disjoint s.diag s.offDiag 
goal: Disjoint s.diag s.offDiag

full_name: Finset.product_sdiff_diag
code: theorem product_sdiff_diag : s ×ˢ s \ s.diag = s.offDiag 
goal: s ×ˢ s \ s.diag = s.offDiag

full_name: Finset.product_sdiff_offDiag
code: theorem product_sdiff_offDiag : s ×ˢ s \ s.offDiag = s.diag 
goal: s ×ˢ s \ s.offDiag = s.diag

full_name: Finset.diag_inter
code: theorem diag_inter : (s ∩ t).diag = s.diag ∩ t.diag 
goal: (s ∩ t).diag = s.diag ∩ t.diag

full_name: Finset.offDiag_inter
code: theorem offDiag_inter : (s ∩ t).offDiag = s.offDiag ∩ t.offDiag 
goal: (s ∩ t).offDiag = s.offDiag ∩ t.offDiag

full_name: Finset.diag_union
code: theorem diag_union : (s ∪ t).diag = s.diag ∪ t.diag 
goal: (s ∪ t).diag = s.diag ∪ t.diag

full_name: Finset.offDiag_union
code: theorem offDiag_union (h : Disjoint s t) :
    (s ∪ t).offDiag = s.offDiag ∪ t.offDiag ∪ s ×ˢ t ∪ t ×ˢ s 
goal: (s ∪ t).offDiag = s.offDiag ∪ t.offDiag ∪ s ×ˢ t ∪ t ×ˢ s

full_name: Finset.offDiag_singleton
code: @[simp]
theorem offDiag_singleton : ({a} : Finset α).offDiag = ∅ 
goal: {a}.offDiag = ∅

full_name: Finset.diag_singleton
code: theorem diag_singleton : ({a} : Finset α).diag = {(a, a)} 
goal: {a}.diag = {(a, a)}

full_name: Finset.diag_insert
code: theorem diag_insert : (insert a s).diag = insert (a, a) s.diag 
goal: (insert a s).diag = insert (a, a) s.diag

full_name: Finset.offDiag_insert
code: theorem offDiag_insert (has : a ∉ s) : (insert a s).offDiag = s.offDiag ∪ {a} ×ˢ s ∪ s ×ˢ {a} 
goal: (insert a s).offDiag = s.offDiag ∪ {a} ×ˢ s ∪ s ×ˢ {a}

full_name: Finset.offDiag_filter_lt_eq_filter_le
code: theorem offDiag_filter_lt_eq_filter_le {ι}
    [PartialOrder ι] [DecidableEq ι]
    [DecidableRel (LE.le (α := ι))] [DecidableRel (LT.lt (α := ι))]
    (s : Finset ι) :
    s.offDiag.filter (fun i => i.1 < i.2) = s.offDiag.filter (fun i => i.1 ≤ i.2) 
goal: Finset.filter (fun i => i.1 < i.2) s.offDiag = Finset.filter (fun i => i.1 ≤ i.2) s.offDiag