-- Mathlib/MeasureTheory/MeasurableSpace/Prod.lean
theorem generateFrom_prod_eq {α β} {C : Set (Set α)} {D : Set (Set β)} (hC : IsCountablySpanning C)
    (hD : IsCountablySpanning D) :
    @Prod.instMeasurableSpace _ _ (generateFrom C) (generateFrom D) =
      generateFrom (image2 (· ×ˢ ·) C D)

Proof state:
case a.refine_1.h.intro.intro.intro.intro
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
s : Set α
hs : s ∈ C
t : ℕ → Set β
h1t : ∀ (n : ℕ), t n ∈ D
h2t : ⋃ n, t n = univ
⊢ MeasurableSet (⋃ i, s ×ˢ t i)

Tactic:
apply MeasurableSet.iUnion

Result:
case a.refine_1.h.intro.intro.intro.intro.h
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
s : Set α
hs : s ∈ C
t : ℕ → Set β
h1t : ∀ (n : ℕ), t n ∈ D
h2t : ⋃ n, t n = univ
⊢ ∀ (b : ℕ), MeasurableSet (s ×ˢ t b)

Proof state:
case a.h.intro.intro.intro.intro
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
hD : IsCountablySpanning D
s : Set α
hs : s ∈ C
t : Set β
ht : t ∈ D
⊢ MeasurableSet ((fun x1 x2 => x1 ×ˢ x2) s t)

Tactic:
dsimp only

Result:
case a.h.intro.intro.intro.intro
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
hD : IsCountablySpanning D
s : Set α
hs : s ∈ C
t : Set β
ht : t ∈ D
⊢ MeasurableSet (s ×ˢ t)

Proof state:
case a.refine_2.h.intro.intro.intro.intro.h
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hD : IsCountablySpanning D
s : Set β
hs : s ∈ D
t : ℕ → Set α
h1t : ∀ (n : ℕ), t n ∈ C
h2t : ⋃ n, t n = univ
⊢ ∀ (b : ℕ), MeasurableSet (t b ×ˢ s)

Tactic:
rintro n

Result:
case a.refine_2.h.intro.intro.intro.intro.h
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hD : IsCountablySpanning D
s : Set β
hs : s ∈ D
t : ℕ → Set α
h1t : ∀ (n : ℕ), t n ∈ C
h2t : ⋃ n, t n = univ
n : ℕ
⊢ MeasurableSet (t n ×ˢ s)

Proof state:
case a.refine_2.h.intro.intro.intro.intro.h
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hD : IsCountablySpanning D
s : Set β
hs : s ∈ D
t : ℕ → Set α
h1t : ∀ (n : ℕ), t n ∈ C
h2t : ⋃ n, t n = univ
n : ℕ
⊢ MeasurableSet (t n ×ˢ s)

Tactic:
apply measurableSet_generateFrom

Result:
case a.refine_2.h.intro.intro.intro.intro.h.ht
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hD : IsCountablySpanning D
s : Set β
hs : s ∈ D
t : ℕ → Set α
h1t : ∀ (n : ℕ), t n ∈ C
h2t : ⋃ n, t n = univ
n : ℕ
⊢ t n ×ˢ s ∈ image2 (fun x1 x2 => x1 ×ˢ x2) C D

Proof state:
case a.refine_1.h.intro.intro.intro.intro.h.ht
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
s : Set α
hs : s ∈ C
t : ℕ → Set β
h1t : ∀ (n : ℕ), t n ∈ D
h2t : ⋃ n, t n = univ
n : ℕ
⊢ s ×ˢ t n ∈ image2 (fun x1 x2 => x1 ×ˢ x2) C D

Tactic:
exact ⟨s, hs, t n, h1t n, rfl⟩

Result:
no goals

Proof state:
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
hD : IsCountablySpanning D
s : Set α
hs : s ∈ C
t : Set β
ht : t ∈ D
⊢ MeasurableSet s

Tactic:
exact measurableSet_generateFrom hs

Result:
no goals

Proof state:
case a.refine_2.h.intro.intro.intro.intro
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hD : IsCountablySpanning D
s : Set β
hs : s ∈ D
t : ℕ → Set α
h1t : ∀ (n : ℕ), t n ∈ C
h2t : ⋃ n, t n = univ
⊢ MeasurableSet (⋃ i, t i ×ˢ s)

Tactic:
apply MeasurableSet.iUnion

Result:
case a.refine_2.h.intro.intro.intro.intro.h
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hD : IsCountablySpanning D
s : Set β
hs : s ∈ D
t : ℕ → Set α
h1t : ∀ (n : ℕ), t n ∈ C
h2t : ⋃ n, t n = univ
⊢ ∀ (b : ℕ), MeasurableSet (t b ×ˢ s)

Proof state:
case a.h.intro.intro.intro.intro
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
hD : IsCountablySpanning D
s : Set α
hs : s ∈ C
t : Set β
ht : t ∈ D
⊢ MeasurableSet (s ×ˢ t)

Tactic:
rw [prod_eq]

Result:
case a.h.intro.intro.intro.intro
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
hD : IsCountablySpanning D
s : Set α
hs : s ∈ C
t : Set β
ht : t ∈ D
⊢ MeasurableSet (Prod.fst ⁻¹' s ∩ Prod.snd ⁻¹' t)

Proof state:
case a.refine_1.h.intro.intro.intro.intro
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
s : Set α
hs : s ∈ C
t : ℕ → Set β
h1t : ∀ (n : ℕ), t n ∈ D
h2t : ⋃ n, t n = univ
⊢ MeasurableSet (Prod.fst ⁻¹' s)

Tactic:
rw [← prod_univ, ← h2t, prod_iUnion]

Result:
case a.refine_1.h.intro.intro.intro.intro
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
s : Set α
hs : s ∈ C
t : ℕ → Set β
h1t : ∀ (n : ℕ), t n ∈ D
h2t : ⋃ n, t n = univ
⊢ MeasurableSet (⋃ i, s ×ˢ t i)

Proof state:
case a.refine_1.h.intro.intro
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
hD : IsCountablySpanning D
s : Set α
hs : s ∈ C
⊢ MeasurableSet (Prod.fst ⁻¹' s)

Tactic:
rcases hD with ⟨t, h1t, h2t⟩

Result:
case a.refine_1.h.intro.intro.intro.intro
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
s : Set α
hs : s ∈ C
t : ℕ → Set β
h1t : ∀ (n : ℕ), t n ∈ D
h2t : ⋃ n, t n = univ
⊢ MeasurableSet (Prod.fst ⁻¹' s)

Proof state:
case a
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
hD : IsCountablySpanning D
⊢ Prod.instMeasurableSpace ≤ generateFrom (image2 (fun x1 x2 => x1 ×ˢ x2) C D)

Tactic:
refine sup_le ?_ ?_ <;> rw [comap_generateFrom] <;> apply generateFrom_le <;>
  rintro _ ⟨s, hs, rfl⟩

Result:
case a.refine_1.h.intro.intro
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
hD : IsCountablySpanning D
s : Set α
hs : s ∈ C
⊢ MeasurableSet (Prod.fst ⁻¹' s)

case a.refine_2.h.intro.intro
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
hD : IsCountablySpanning D
s : Set β
hs : s ∈ D
⊢ MeasurableSet (Prod.snd ⁻¹' s)

Proof state:
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
hD : IsCountablySpanning D
⊢ Prod.instMeasurableSpace = generateFrom (image2 (fun x1 x2 => x1 ×ˢ x2) C D)

Tactic:
apply le_antisymm

Result:
case a
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
hD : IsCountablySpanning D
⊢ Prod.instMeasurableSpace ≤ generateFrom (image2 (fun x1 x2 => x1 ×ˢ x2) C D)

case a
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
hD : IsCountablySpanning D
⊢ generateFrom (image2 (fun x1 x2 => x1 ×ˢ x2) C D) ≤ Prod.instMeasurableSpace

Proof state:
case a.h.intro.intro.intro.intro
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
hD : IsCountablySpanning D
s : Set α
hs : s ∈ C
t : Set β
ht : t ∈ D
⊢ MeasurableSet (Prod.fst ⁻¹' s ∩ Prod.snd ⁻¹' t)

Tactic:
apply (measurable_fst _).inter (measurable_snd _)

Result:
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
hD : IsCountablySpanning D
s : Set α
hs : s ∈ C
t : Set β
ht : t ∈ D
⊢ MeasurableSet s

α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
hD : IsCountablySpanning D
s : Set α
hs : s ∈ C
t : Set β
ht : t ∈ D
⊢ MeasurableSet t

Proof state:
case a.refine_2.h.intro.intro
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hC : IsCountablySpanning C
hD : IsCountablySpanning D
s : Set β
hs : s ∈ D
⊢ MeasurableSet (Prod.snd ⁻¹' s)

Tactic:
rcases hC with ⟨t, h1t, h2t⟩

Result:
case a.refine_2.h.intro.intro.intro.intro
α : Type u_3
β : Type u_4
C : Set (Set α)
D : Set (Set β)
hD : IsCountablySpanning D
s : Set β
hs : s ∈ D
t : ℕ → Set α
h1t : ∀ (n : ℕ), t n ∈ C
h2t : ⋃ n, t n = univ
⊢ MeasurableSet (Prod.snd ⁻¹' s)