l3lab/ntp-mathlib huggingface dataset:
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 := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
s✝ s' : Finset α
t✝ t' : Finset β
a : α
b : β
s : Finset α
t : Finset β
p : α → Prop
q : β → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
⊢ card (filter (fun x => p x.1 = q x.2) (s ×ˢ t)) =
    card (filter p s) * card (filter q t) + card (filter (fun x => ¬p x) s) * card (filter (fun x => ¬q x) t)

Next tactic:
classical
    rw [← card_product, ← card_product, ← filter_product, ← filter_product, ← card_union_eq]
    · apply congr_arg
      ext ⟨a, b⟩
      simp only [filter_union_right, mem_filter, mem_product]
      constructor <;> intro h <;> use h.1
      · simp only [h.2, Function.comp_apply, Decidable.em, and_self]
      · revert h
        simp only [Function.comp_apply, and_imp]
        rintro _ _ (_|_) <;> simp [*]
    · apply Finset.disjoint_filter_filter'
      exact (disjoint_compl_right.inf_left _).inf_right _
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 := by
  classical
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
s✝ s' : Finset α
t✝ t' : Finset β
a : α
b : β
s : Finset α
t : Finset β
p : α → Prop
q : β → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
⊢ card (filter (fun x => p x.1 = q x.2) (s ×ˢ t)) =
    card (filter p s) * card (filter q t) + card (filter (fun x => ¬p x) s) * card (filter (fun x => ¬q x) t)

Next tactic:
rw [← card_product, ← card_product, ← filter_product, ← filter_product, ← card_union_eq]
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 := by
  classical
    rw [← card_product, ← card_product, ← filter_product, ← filter_product, ← card_union_eq]
    · 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
s✝ s' : Finset α
t✝ t' : Finset β
a : α
b : β
s : Finset α
t : Finset β
p : α → Prop
q : β → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
⊢ card (filter (fun x => p x.1 = q x.2) (s ×ˢ t)) =
    card (filter (fun x => p x.1 ∧ q x.2) (s ×ˢ t) ∪ filter (fun x => ¬p x.1 ∧ ¬q x.2) (s ×ˢ t))

Next tactic:
apply congr_arg
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 := by
  classical
    rw [← card_product, ← card_product, ← filter_product, ← filter_product, ← card_union_eq]
    · apply congr_arg
      

Proof state:
case h
α : Type u_1
β : Type u_2
γ : Type u_3
s✝ s' : Finset α
t✝ t' : Finset β
a : α
b : β
s : Finset α
t : Finset β
p : α → Prop
q : β → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
⊢ filter (fun x => p x.1 = q x.2) (s ×ˢ t) =
    filter (fun x => p x.1 ∧ q x.2) (s ×ˢ t) ∪ filter (fun x => ¬p x.1 ∧ ¬q x.2) (s ×ˢ t)

Next tactic:
ext ⟨a, b⟩
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 := by
  classical
    rw [← card_product, ← card_product, ← filter_product, ← filter_product, ← card_union_eq]
    · apply congr_arg
      ext ⟨a, b⟩
      

Proof state:
case h.a.mk
α : Type u_1
β : Type u_2
γ : Type u_3
s✝ s' : Finset α
t✝ t' : Finset β
a✝ : α
b✝ : β
s : Finset α
t : Finset β
p : α → Prop
q : β → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
a : α
b : β
⊢ (a, b) ∈ filter (fun x => p x.1 = q x.2) (s ×ˢ t) ↔
    (a, b) ∈ filter (fun x => p x.1 ∧ q x.2) (s ×ˢ t) ∪ filter (fun x => ¬p x.1 ∧ ¬q x.2) (s ×ˢ t)

Next tactic:
simp only [filter_union_right, mem_filter, mem_product]
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 := by
  classical
    rw [← card_product, ← card_product, ← filter_product, ← filter_product, ← card_union_eq]
    · apply congr_arg
      ext ⟨a, b⟩
      simp only [filter_union_right, mem_filter, mem_product]
      

Proof state:
case h.a.mk
α : Type u_1
β : Type u_2
γ : Type u_3
s✝ s' : Finset α
t✝ t' : Finset β
a✝ : α
b✝ : β
s : Finset α
t : Finset β
p : α → Prop
q : β → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
a : α
b : β
⊢ (a ∈ s ∧ b ∈ t) ∧ p a = q b ↔ (a ∈ s ∧ b ∈ t) ∧ (p a ∧ q b ∨ ¬p a ∧ ¬q b)

Next tactic:
constructor
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 := by
  classical
    rw [← card_product, ← card_product, ← filter_product, ← filter_product, ← card_union_eq]
    · apply congr_arg
      ext ⟨a, b⟩
      simp only [filter_union_right, mem_filter, mem_product]
      constructor <;> 

Proof state:
case h.a.mk.mp
α : Type u_1
β : Type u_2
γ : Type u_3
s✝ s' : Finset α
t✝ t' : Finset β
a✝ : α
b✝ : β
s : Finset α
t : Finset β
p : α → Prop
q : β → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
a : α
b : β
⊢ (a ∈ s ∧ b ∈ t) ∧ p a = q b → (a ∈ s ∧ b ∈ t) ∧ (p a ∧ q b ∨ ¬p a ∧ ¬q b)

Next tactic:
intro h
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 := by
  classical
    rw [← card_product, ← card_product, ← filter_product, ← filter_product, ← card_union_eq]
    · apply congr_arg
      ext ⟨a, b⟩
      simp only [filter_union_right, mem_filter, mem_product]
      constructor <;> 

Proof state:
case h.a.mk.mpr
α : Type u_1
β : Type u_2
γ : Type u_3
s✝ s' : Finset α
t✝ t' : Finset β
a✝ : α
b✝ : β
s : Finset α
t : Finset β
p : α → Prop
q : β → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
a : α
b : β
⊢ (a ∈ s ∧ b ∈ t) ∧ (p a ∧ q b ∨ ¬p a ∧ ¬q b) → (a ∈ s ∧ b ∈ t) ∧ p a = q b

Next tactic:
intro h
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 := by
  classical
    rw [← card_product, ← card_product, ← filter_product, ← filter_product, ← card_union_eq]
    · apply congr_arg
      ext ⟨a, b⟩
      simp only [filter_union_right, mem_filter, mem_product]
      constructor <;> intro h <;> 

Proof state:
case h.a.mk.mp
α : Type u_1
β : Type u_2
γ : Type u_3
s✝ s' : Finset α
t✝ t' : Finset β
a✝ : α
b✝ : β
s : Finset α
t : Finset β
p : α → Prop
q : β → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
a : α
b : β
h : (a ∈ s ∧ b ∈ t) ∧ p a = q b
⊢ (a ∈ s ∧ b ∈ t) ∧ (p a ∧ q b ∨ ¬p a ∧ ¬q b)

Next tactic:
use h.1
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 := by
  classical
    rw [← card_product, ← card_product, ← filter_product, ← filter_product, ← card_union_eq]
    · apply congr_arg
      ext ⟨a, b⟩
      simp only [filter_union_right, mem_filter, mem_product]
      constructor <;> intro h <;> 

Proof state:
case h.a.mk.mpr
α : Type u_1
β : Type u_2
γ : Type u_3
s✝ s' : Finset α
t✝ t' : Finset β
a✝ : α
b✝ : β
s : Finset α
t : Finset β
p : α → Prop
q : β → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
a : α
b : β
h : (a ∈ s ∧ b ∈ t) ∧ (p a ∧ q b ∨ ¬p a ∧ ¬q b)
⊢ (a ∈ s ∧ b ∈ t) ∧ p a = q b

Next tactic:
use h.1
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 := by
  classical
    rw [← card_product, ← card_product, ← filter_product, ← filter_product, ← card_union_eq]
    · apply congr_arg
      ext ⟨a, b⟩
      simp only [filter_union_right, mem_filter, mem_product]
      constructor <;> intro h <;> use h.1
      · 

Proof state:
case right
α : Type u_1
β : Type u_2
γ : Type u_3
s✝ s' : Finset α
t✝ t' : Finset β
a✝ : α
b✝ : β
s : Finset α
t : Finset β
p : α → Prop
q : β → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
a : α
b : β
h : (a ∈ s ∧ b ∈ t) ∧ p a = q b
⊢ p a ∧ q b ∨ ¬p a ∧ ¬q b

Next tactic:
simp only [h.2, Function.comp_apply, Decidable.em, and_self]
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 := by
  classical
    rw [← card_product, ← card_product, ← filter_product, ← filter_product, ← card_union_eq]
    · apply congr_arg
      ext ⟨a, b⟩
      simp only [filter_union_right, mem_filter, mem_product]
      constructor <;> intro h <;> use h.1
      · simp only [h.2, Function.comp_apply, Decidable.em, and_self]
      · 

Proof state:
case right
α : Type u_1
β : Type u_2
γ : Type u_3
s✝ s' : Finset α
t✝ t' : Finset β
a✝ : α
b✝ : β
s : Finset α
t : Finset β
p : α → Prop
q : β → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
a : α
b : β
h : (a ∈ s ∧ b ∈ t) ∧ (p a ∧ q b ∨ ¬p a ∧ ¬q b)
⊢ p a = q b

Next tactic:
revert h
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 := by
  classical
    rw [← card_product, ← card_product, ← filter_product, ← filter_product, ← card_union_eq]
    · apply congr_arg
      ext ⟨a, b⟩
      simp only [filter_union_right, mem_filter, mem_product]
      constructor <;> intro h <;> use h.1
      · simp only [h.2, Function.comp_apply, Decidable.em, and_self]
      · revert h
        

Proof state:
case right
α : Type u_1
β : Type u_2
γ : Type u_3
s✝ s' : Finset α
t✝ t' : Finset β
a✝ : α
b✝ : β
s : Finset α
t : Finset β
p : α → Prop
q : β → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
a : α
b : β
⊢ (a ∈ s ∧ b ∈ t) ∧ (p a ∧ q b ∨ ¬p a ∧ ¬q b) → p a = q b

Next tactic:
simp only [Function.comp_apply, and_imp]
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 := by
  classical
    rw [← card_product, ← card_product, ← filter_product, ← filter_product, ← card_union_eq]
    · apply congr_arg
      ext ⟨a, b⟩
      simp only [filter_union_right, mem_filter, mem_product]
      constructor <;> intro h <;> use h.1
      · simp only [h.2, Function.comp_apply, Decidable.em, and_self]
      · revert h
        simp only [Function.comp_apply, and_imp]
        

Proof state:
case right
α : Type u_1
β : Type u_2
γ : Type u_3
s✝ s' : Finset α
t✝ t' : Finset β
a✝ : α
b✝ : β
s : Finset α
t : Finset β
p : α → Prop
q : β → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
a : α
b : β
⊢ a ∈ s → b ∈ t → p a ∧ q b ∨ ¬p a ∧ ¬q b → p a = q b

Next tactic:
rintro _ _ (_|_)
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 := by
  classical
    rw [← card_product, ← card_product, ← filter_product, ← filter_product, ← card_union_eq]
    · apply congr_arg
      ext ⟨a, b⟩
      simp only [filter_union_right, mem_filter, mem_product]
      constructor <;> intro h <;> use h.1
      · simp only [h.2, Function.comp_apply, Decidable.em, and_self]
      · revert h
        simp only [Function.comp_apply, and_imp]
        rintro _ _ (_|_) <;> 

Proof state:
case right.inl
α : Type u_1
β : Type u_2
γ : Type u_3
s✝ s' : Finset α
t✝ t' : Finset β
a✝² : α
b✝ : β
s : Finset α
t : Finset β
p : α → Prop
q : β → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
a : α
b : β
a✝¹ : a ∈ s
a✝ : b ∈ t
h✝ : p a ∧ q b
⊢ p a = q b

Next tactic:
simp [*]
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 := by
  classical
    rw [← card_product, ← card_product, ← filter_product, ← filter_product, ← card_union_eq]
    · apply congr_arg
      ext ⟨a, b⟩
      simp only [filter_union_right, mem_filter, mem_product]
      constructor <;> intro h <;> use h.1
      · simp only [h.2, Function.comp_apply, Decidable.em, and_self]
      · revert h
        simp only [Function.comp_apply, and_imp]
        rintro _ _ (_|_) <;> 

Proof state:
case right.inr
α : Type u_1
β : Type u_2
γ : Type u_3
s✝ s' : Finset α
t✝ t' : Finset β
a✝² : α
b✝ : β
s : Finset α
t : Finset β
p : α → Prop
q : β → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
a : α
b : β
a✝¹ : a ∈ s
a✝ : b ∈ t
h✝ : ¬p a ∧ ¬q b
⊢ p a = q b

Next tactic:
simp [*]
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 := by
  classical
    rw [← card_product, ← card_product, ← filter_product, ← filter_product, ← card_union_eq]
    · apply congr_arg
      ext ⟨a, b⟩
      simp only [filter_union_right, mem_filter, mem_product]
      constructor <;> intro h <;> use h.1
      · simp only [h.2, Function.comp_apply, Decidable.em, and_self]
      · revert h
        simp only [Function.comp_apply, and_imp]
        rintro _ _ (_|_) <;> simp [*]
    · 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
s✝ s' : Finset α
t✝ t' : Finset β
a : α
b : β
s : Finset α
t : Finset β
p : α → Prop
q : β → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
⊢ _root_.Disjoint (filter (fun x => p x.1 ∧ q x.2) (s ×ˢ t)) (filter (fun x => ¬p x.1 ∧ ¬q x.2) (s ×ˢ t))

Next tactic:
apply Finset.disjoint_filter_filter'
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 := by
  classical
    rw [← card_product, ← card_product, ← filter_product, ← filter_product, ← card_union_eq]
    · apply congr_arg
      ext ⟨a, b⟩
      simp only [filter_union_right, mem_filter, mem_product]
      constructor <;> intro h <;> use h.1
      · simp only [h.2, Function.comp_apply, Decidable.em, and_self]
      · revert h
        simp only [Function.comp_apply, and_imp]
        rintro _ _ (_|_) <;> simp [*]
    · apply Finset.disjoint_filter_filter'
      

Proof state:
case h
α : Type u_1
β : Type u_2
γ : Type u_3
s✝ s' : Finset α
t✝ t' : Finset β
a : α
b : β
s : Finset α
t : Finset β
p : α → Prop
q : β → Prop
inst✝¹ : DecidablePred p
inst✝ : DecidablePred q
⊢ _root_.Disjoint (fun x => p x.1 ∧ q x.2) fun x => ¬p x.1 ∧ ¬q x.2

Next tactic:
exact (disjoint_compl_right.inf_left _).inf_right _
@[simp]
theorem product_eq_empty {s : Finset α} {t : Finset β} : s ×ˢ t = ∅ ↔ s = ∅ ∨ t = ∅ := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
s✝ s' : Finset α
t✝ t' : Finset β
a : α
b : β
s : Finset α
t : Finset β
⊢ s ×ˢ t = ∅ ↔ s = ∅ ∨ t = ∅

Next tactic:
rw [← not_nonempty_iff_eq_empty, nonempty_product, not_and_or, not_nonempty_iff_eq_empty,
    not_nonempty_iff_eq_empty]
@[simp]
theorem singleton_product {a : α} :
    ({a} : Finset α) ×ˢ t = t.map ⟨Prod.mk a, Prod.mk.inj_left _⟩ := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
s s' : Finset α
t t' : Finset β
a✝ : α
b : β
a : α
⊢ {a} ×ˢ t = map { toFun := Prod.mk a, inj' := (_ : Function.Injective (Prod.mk a)) } t

Next tactic:
ext ⟨x, y⟩
@[simp]
theorem singleton_product {a : α} :
    ({a} : Finset α) ×ˢ t = t.map ⟨Prod.mk a, Prod.mk.inj_left _⟩ := by
  ext ⟨x, y⟩
  

Proof state:
case a.mk
α : Type u_1
β : Type u_2
γ : Type u_3
s s' : Finset α
t t' : Finset β
a✝ : α
b : β
a x : α
y : β
⊢ (x, y) ∈ {a} ×ˢ t ↔ (x, y) ∈ map { toFun := Prod.mk a, inj' := (_ : Function.Injective (Prod.mk a)) } t

Next tactic:
simp [and_left_comm, eq_comm]
@[simp]
theorem product_singleton {b : β} : s ×ˢ {b} = s.map ⟨fun i => (i, b), Prod.mk.inj_right _⟩ := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
s s' : Finset α
t t' : Finset β
a : α
b✝ b : β
⊢ s ×ˢ {b} = map { toFun := fun i => (i, b), inj' := (_ : Function.Injective fun a => (a, b)) } s

Next tactic:
ext ⟨x, y⟩
@[simp]
theorem product_singleton {b : β} : s ×ˢ {b} = s.map ⟨fun i => (i, b), Prod.mk.inj_right _⟩ := by
  ext ⟨x, y⟩
  

Proof state:
case a.mk
α : Type u_1
β : Type u_2
γ : Type u_3
s s' : Finset α
t t' : Finset β
a : α
b✝ b : β
x : α
y : β
⊢ (x, y) ∈ s ×ˢ {b} ↔ (x, y) ∈ map { toFun := fun i => (i, b), inj' := (_ : Function.Injective fun a => (a, b)) } s

Next tactic:
simp [and_left_comm, eq_comm]
theorem singleton_product_singleton {a : α} {b : β} :
    ({a} ×ˢ {b} : Finset _) = {(a, b)} := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
s s' : Finset α
t t' : Finset β
a✝ : α
b✝ : β
a : α
b : β
⊢ {a} ×ˢ {b} = {(a, b)}

Next tactic:
simp only [product_singleton, Function.Embedding.coeFn_mk, map_singleton]
@[simp]
theorem union_product [DecidableEq α] [DecidableEq β] : (s ∪ s') ×ˢ t = s ×ˢ t ∪ s' ×ˢ t := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
s s' : Finset α
t t' : Finset β
a : α
b : β
inst✝¹ : DecidableEq α
inst✝ : DecidableEq β
⊢ (s ∪ s') ×ˢ t = s ×ˢ t ∪ s' ×ˢ t

Next tactic:
ext ⟨x, y⟩
@[simp]
theorem union_product [DecidableEq α] [DecidableEq β] : (s ∪ s') ×ˢ t = s ×ˢ t ∪ s' ×ˢ t := by
  ext ⟨x, y⟩
  

Proof state:
case a.mk
α : Type u_1
β : Type u_2
γ : Type u_3
s s' : Finset α
t t' : Finset β
a : α
b : β
inst✝¹ : DecidableEq α
inst✝ : DecidableEq β
x : α
y : β
⊢ (x, y) ∈ (s ∪ s') ×ˢ t ↔ (x, y) ∈ s ×ˢ t ∪ s' ×ˢ t

Next tactic:
simp only [or_and_right, mem_union, mem_product]
@[simp]
theorem product_union [DecidableEq α] [DecidableEq β] : s ×ˢ (t ∪ t') = s ×ˢ t ∪ s ×ˢ t' := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
s s' : Finset α
t t' : Finset β
a : α
b : β
inst✝¹ : DecidableEq α
inst✝ : DecidableEq β
⊢ s ×ˢ (t ∪ t') = s ×ˢ t ∪ s ×ˢ t'

Next tactic:
ext ⟨x, y⟩
@[simp]
theorem product_union [DecidableEq α] [DecidableEq β] : s ×ˢ (t ∪ t') = s ×ˢ t ∪ s ×ˢ t' := by
  ext ⟨x, y⟩
  

Proof state:
case a.mk
α : Type u_1
β : Type u_2
γ : Type u_3
s s' : Finset α
t t' : Finset β
a : α
b : β
inst✝¹ : DecidableEq α
inst✝ : DecidableEq β
x : α
y : β
⊢ (x, y) ∈ s ×ˢ (t ∪ t') ↔ (x, y) ∈ s ×ˢ t ∪ s ×ˢ t'

Next tactic:
simp only [and_or_left, mem_union, mem_product]
theorem inter_product [DecidableEq α] [DecidableEq β] : (s ∩ s') ×ˢ t = s ×ˢ t ∩ s' ×ˢ t := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
s s' : Finset α
t t' : Finset β
a : α
b : β
inst✝¹ : DecidableEq α
inst✝ : DecidableEq β
⊢ (s ∩ s') ×ˢ t = s ×ˢ t ∩ s' ×ˢ t

Next tactic:
ext ⟨x, y⟩
theorem inter_product [DecidableEq α] [DecidableEq β] : (s ∩ s') ×ˢ t = s ×ˢ t ∩ s' ×ˢ t := by
  ext ⟨x, y⟩
  

Proof state:
case a.mk
α : Type u_1
β : Type u_2
γ : Type u_3
s s' : Finset α
t t' : Finset β
a : α
b : β
inst✝¹ : DecidableEq α
inst✝ : DecidableEq β
x : α
y : β
⊢ (x, y) ∈ (s ∩ s') ×ˢ t ↔ (x, y) ∈ s ×ˢ t ∩ s' ×ˢ t

Next tactic:
simp only [← and_and_right, mem_inter, mem_product]
theorem product_inter [DecidableEq α] [DecidableEq β] : s ×ˢ (t ∩ t') = s ×ˢ t ∩ s ×ˢ t' := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
s s' : Finset α
t t' : Finset β
a : α
b : β
inst✝¹ : DecidableEq α
inst✝ : DecidableEq β
⊢ s ×ˢ (t ∩ t') = s ×ˢ t ∩ s ×ˢ t'

Next tactic:
ext ⟨x, y⟩
theorem product_inter [DecidableEq α] [DecidableEq β] : s ×ˢ (t ∩ t') = s ×ˢ t ∩ s ×ˢ t' := by
  ext ⟨x, y⟩
  

Proof state:
case a.mk
α : Type u_1
β : Type u_2
γ : Type u_3
s s' : Finset α
t t' : Finset β
a : α
b : β
inst✝¹ : DecidableEq α
inst✝ : DecidableEq β
x : α
y : β
⊢ (x, y) ∈ s ×ˢ (t ∩ t') ↔ (x, y) ∈ s ×ˢ t ∩ s ×ˢ t'

Next tactic:
simp only [← and_and_left, mem_inter, mem_product]
theorem product_inter_product [DecidableEq α] [DecidableEq β] :
    s ×ˢ t ∩ s' ×ˢ t' = (s ∩ s') ×ˢ (t ∩ t') := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
s s' : Finset α
t t' : Finset β
a : α
b : β
inst✝¹ : DecidableEq α
inst✝ : DecidableEq β
⊢ s ×ˢ t ∩ s' ×ˢ t' = (s ∩ s') ×ˢ (t ∩ t')

Next tactic:
ext ⟨x, y⟩
theorem product_inter_product [DecidableEq α] [DecidableEq β] :
    s ×ˢ t ∩ s' ×ˢ t' = (s ∩ s') ×ˢ (t ∩ t') := by
  ext ⟨x, y⟩
  

Proof state:
case a.mk
α : Type u_1
β : Type u_2
γ : Type u_3
s s' : Finset α
t t' : Finset β
a : α
b : β
inst✝¹ : DecidableEq α
inst✝ : DecidableEq β
x : α
y : β
⊢ (x, y) ∈ s ×ˢ t ∩ s' ×ˢ t' ↔ (x, y) ∈ (s ∩ s') ×ˢ (t ∩ t')

Next tactic:
simp only [and_assoc, and_left_comm, mem_inter, mem_product]
theorem disjoint_product : Disjoint (s ×ˢ t) (s' ×ˢ t') ↔ Disjoint s s' ∨ Disjoint t t' := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
s s' : Finset α
t t' : Finset β
a : α
b : β
⊢ _root_.Disjoint (s ×ˢ t) (s' ×ˢ t') ↔ _root_.Disjoint s s' ∨ _root_.Disjoint t t'

Next tactic:
simp_rw [← disjoint_coe, coe_product, Set.disjoint_prod]
@[simp]
theorem mem_diag : x ∈ s.diag ↔ x.1 ∈ s ∧ x.1 = x.2 := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq α
s t : Finset α
x : α × α
⊢ x ∈ diag s ↔ x.1 ∈ s ∧ x.1 = x.2

Next tactic:
simp (config := { contextual := true }) [diag]
@[simp]
theorem mem_offDiag : x ∈ s.offDiag ↔ x.1 ∈ s ∧ x.2 ∈ s ∧ x.1 ≠ x.2 := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq α
s t : Finset α
x : α × α
⊢ x ∈ offDiag s ↔ x.1 ∈ s ∧ x.2 ∈ s ∧ x.1 ≠ x.2

Next tactic:
simp [offDiag, and_assoc]
@[simp]
theorem diag_card : (diag s).card = s.card := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq α
s t : Finset α
x : α × α
⊢ card (diag s) = card s

Next tactic:
suffices diag s = s.image fun a => (a, a) by
    rw [this]
    apply card_image_of_injOn
    exact fun x1 _ x2 _ h3 => (Prod.mk.inj h3).1
@[simp]
theorem diag_card : (diag s).card = s.card := by
  suffices diag s = s.image fun a => (a, a) by
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq α
s t : Finset α
x : α × α
this : diag s = image (fun a => (a, a)) s
⊢ card (diag s) = card s

Next tactic:
rw [this]