l3lab/ntp-mathlib huggingface dataset:
/-- Given a prepartition `π` of a box `I` and a collection of prepartitions `πi J` of all boxes
`J ∈ π`, returns the prepartition of `I` into the union of the boxes of all `πi J`.

Though we only use the values of `πi` on the boxes of `π`, we require `πi` to be a globally defined
function. -/
@[simps]
def biUnion (πi : ∀ J : Box ι, Prepartition J) : Prepartition I where
  boxes := π.boxes.biUnion fun J => (πi J).boxes
  le_of_mem' J hJ := by
    simp only [Finset.mem_biUnion, exists_prop, mem_boxes] at hJ
    rcases hJ with ⟨J', hJ', hJ⟩
    exact ((πi J').le_of_mem hJ).trans (π.le_of_mem hJ')
  pairwiseDisjoint := by
    simp only [Set.Pairwise, Finset.mem_coe, Finset.mem_biUnion]
    rintro J₁' ⟨J₁, hJ₁, hJ₁'⟩ J₂' ⟨J₂, hJ₂, hJ₂'⟩ Hne
    

Proof state:
case intro.intro.intro.intro
ι : Type u_1
I J J₁✝ J₂✝ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi : (J : Box ι) → Prepartition J
J₁' J₁ : Box ι
hJ₁ : J₁ ∈ π.boxes
hJ₁' : J₁' ∈ (πi J₁).boxes
J₂' J₂ : Box ι
hJ₂ : J₂ ∈ π.boxes
hJ₂' : J₂' ∈ (πi J₂).boxes
Hne : J₁' ≠ J₂'
⊢ (Disjoint on Box.toSet) J₁' J₂'

Next tactic:
rw [Function.onFun, Set.disjoint_left]
/-- Given a prepartition `π` of a box `I` and a collection of prepartitions `πi J` of all boxes
`J ∈ π`, returns the prepartition of `I` into the union of the boxes of all `πi J`.

Though we only use the values of `πi` on the boxes of `π`, we require `πi` to be a globally defined
function. -/
@[simps]
def biUnion (πi : ∀ J : Box ι, Prepartition J) : Prepartition I where
  boxes := π.boxes.biUnion fun J => (πi J).boxes
  le_of_mem' J hJ := by
    simp only [Finset.mem_biUnion, exists_prop, mem_boxes] at hJ
    rcases hJ with ⟨J', hJ', hJ⟩
    exact ((πi J').le_of_mem hJ).trans (π.le_of_mem hJ')
  pairwiseDisjoint := by
    simp only [Set.Pairwise, Finset.mem_coe, Finset.mem_biUnion]
    rintro J₁' ⟨J₁, hJ₁, hJ₁'⟩ J₂' ⟨J₂, hJ₂, hJ₂'⟩ Hne
    rw [Function.onFun, Set.disjoint_left]
    

Proof state:
case intro.intro.intro.intro
ι : Type u_1
I J J₁✝ J₂✝ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi : (J : Box ι) → Prepartition J
J₁' J₁ : Box ι
hJ₁ : J₁ ∈ π.boxes
hJ₁' : J₁' ∈ (πi J₁).boxes
J₂' J₂ : Box ι
hJ₂ : J₂ ∈ π.boxes
hJ₂' : J₂' ∈ (πi J₂).boxes
Hne : J₁' ≠ J₂'
⊢ ∀ ⦃a : ι → ℝ⦄, a ∈ ↑J₁' → a ∉ ↑J₂'

Next tactic:
rintro x hx₁ hx₂
/-- Given a prepartition `π` of a box `I` and a collection of prepartitions `πi J` of all boxes
`J ∈ π`, returns the prepartition of `I` into the union of the boxes of all `πi J`.

Though we only use the values of `πi` on the boxes of `π`, we require `πi` to be a globally defined
function. -/
@[simps]
def biUnion (πi : ∀ J : Box ι, Prepartition J) : Prepartition I where
  boxes := π.boxes.biUnion fun J => (πi J).boxes
  le_of_mem' J hJ := by
    simp only [Finset.mem_biUnion, exists_prop, mem_boxes] at hJ
    rcases hJ with ⟨J', hJ', hJ⟩
    exact ((πi J').le_of_mem hJ).trans (π.le_of_mem hJ')
  pairwiseDisjoint := by
    simp only [Set.Pairwise, Finset.mem_coe, Finset.mem_biUnion]
    rintro J₁' ⟨J₁, hJ₁, hJ₁'⟩ J₂' ⟨J₂, hJ₂, hJ₂'⟩ Hne
    rw [Function.onFun, Set.disjoint_left]
    rintro x hx₁ hx₂; 

Proof state:
case intro.intro.intro.intro
ι : Type u_1
I J J₁✝ J₂✝ : Box ι
π π₁ π₂ : Prepartition I
x✝ : ι → ℝ
πi : (J : Box ι) → Prepartition J
J₁' J₁ : Box ι
hJ₁ : J₁ ∈ π.boxes
hJ₁' : J₁' ∈ (πi J₁).boxes
J₂' J₂ : Box ι
hJ₂ : J₂ ∈ π.boxes
hJ₂' : J₂' ∈ (πi J₂).boxes
Hne : J₁' ≠ J₂'
x : ι → ℝ
hx₁ : x ∈ ↑J₁'
hx₂ : x ∈ ↑J₂'
⊢ False

Next tactic:
apply Hne
/-- Given a prepartition `π` of a box `I` and a collection of prepartitions `πi J` of all boxes
`J ∈ π`, returns the prepartition of `I` into the union of the boxes of all `πi J`.

Though we only use the values of `πi` on the boxes of `π`, we require `πi` to be a globally defined
function. -/
@[simps]
def biUnion (πi : ∀ J : Box ι, Prepartition J) : Prepartition I where
  boxes := π.boxes.biUnion fun J => (πi J).boxes
  le_of_mem' J hJ := by
    simp only [Finset.mem_biUnion, exists_prop, mem_boxes] at hJ
    rcases hJ with ⟨J', hJ', hJ⟩
    exact ((πi J').le_of_mem hJ).trans (π.le_of_mem hJ')
  pairwiseDisjoint := by
    simp only [Set.Pairwise, Finset.mem_coe, Finset.mem_biUnion]
    rintro J₁' ⟨J₁, hJ₁, hJ₁'⟩ J₂' ⟨J₂, hJ₂, hJ₂'⟩ Hne
    rw [Function.onFun, Set.disjoint_left]
    rintro x hx₁ hx₂; apply Hne
    

Proof state:
case intro.intro.intro.intro
ι : Type u_1
I J J₁✝ J₂✝ : Box ι
π π₁ π₂ : Prepartition I
x✝ : ι → ℝ
πi : (J : Box ι) → Prepartition J
J₁' J₁ : Box ι
hJ₁ : J₁ ∈ π.boxes
hJ₁' : J₁' ∈ (πi J₁).boxes
J₂' J₂ : Box ι
hJ₂ : J₂ ∈ π.boxes
hJ₂' : J₂' ∈ (πi J₂).boxes
Hne : J₁' ≠ J₂'
x : ι → ℝ
hx₁ : x ∈ ↑J₁'
hx₂ : x ∈ ↑J₂'
⊢ J₁' = J₂'

Next tactic:
obtain rfl : J₁ = J₂
/-- Given a prepartition `π` of a box `I` and a collection of prepartitions `πi J` of all boxes
`J ∈ π`, returns the prepartition of `I` into the union of the boxes of all `πi J`.

Though we only use the values of `πi` on the boxes of `π`, we require `πi` to be a globally defined
function. -/
@[simps]
def biUnion (πi : ∀ J : Box ι, Prepartition J) : Prepartition I where
  boxes := π.boxes.biUnion fun J => (πi J).boxes
  le_of_mem' J hJ := by
    simp only [Finset.mem_biUnion, exists_prop, mem_boxes] at hJ
    rcases hJ with ⟨J', hJ', hJ⟩
    exact ((πi J').le_of_mem hJ).trans (π.le_of_mem hJ')
  pairwiseDisjoint := by
    simp only [Set.Pairwise, Finset.mem_coe, Finset.mem_biUnion]
    rintro J₁' ⟨J₁, hJ₁, hJ₁'⟩ J₂' ⟨J₂, hJ₂, hJ₂'⟩ Hne
    rw [Function.onFun, Set.disjoint_left]
    rintro x hx₁ hx₂; apply Hne
    obtain rfl : J₁ = J₂
    

Proof state:
ι : Type u_1
I J J₁✝ J₂✝ : Box ι
π π₁ π₂ : Prepartition I
x✝ : ι → ℝ
πi : (J : Box ι) → Prepartition J
J₁' J₁ : Box ι
hJ₁ : J₁ ∈ π.boxes
hJ₁' : J₁' ∈ (πi J₁).boxes
J₂' J₂ : Box ι
hJ₂ : J₂ ∈ π.boxes
hJ₂' : J₂' ∈ (πi J₂).boxes
Hne : J₁' ≠ J₂'
x : ι → ℝ
hx₁ : x ∈ ↑J₁'
hx₂ : x ∈ ↑J₂'
⊢ J₁ = J₂
case intro.intro.intro.intro
ι : Type u_1
I J J₁✝ J₂ : Box ι
π π₁ π₂ : Prepartition I
x✝ : ι → ℝ
πi : (J : Box ι) → Prepartition J
J₁' J₁ : Box ι
hJ₁ : J₁ ∈ π.boxes
hJ₁' : J₁' ∈ (πi J₁).boxes
J₂' : Box ι
Hne : J₁' ≠ J₂'
x : ι → ℝ
hx₁ : x ∈ ↑J₁'
hx₂ : x ∈ ↑J₂'
hJ₂ : J₁ ∈ π.boxes
hJ₂' : J₂' ∈ (πi J₁).boxes
⊢ J₁' = J₂'

Next tactic:
exact π.eq_of_mem_of_mem hJ₁ hJ₂ ((πi J₁).le_of_mem hJ₁' hx₁) ((πi J₂).le_of_mem hJ₂' hx₂)
/-- Given a prepartition `π` of a box `I` and a collection of prepartitions `πi J` of all boxes
`J ∈ π`, returns the prepartition of `I` into the union of the boxes of all `πi J`.

Though we only use the values of `πi` on the boxes of `π`, we require `πi` to be a globally defined
function. -/
@[simps]
def biUnion (πi : ∀ J : Box ι, Prepartition J) : Prepartition I where
  boxes := π.boxes.biUnion fun J => (πi J).boxes
  le_of_mem' J hJ := by
    simp only [Finset.mem_biUnion, exists_prop, mem_boxes] at hJ
    rcases hJ with ⟨J', hJ', hJ⟩
    exact ((πi J').le_of_mem hJ).trans (π.le_of_mem hJ')
  pairwiseDisjoint := by
    simp only [Set.Pairwise, Finset.mem_coe, Finset.mem_biUnion]
    rintro J₁' ⟨J₁, hJ₁, hJ₁'⟩ J₂' ⟨J₂, hJ₂, hJ₂'⟩ Hne
    rw [Function.onFun, Set.disjoint_left]
    rintro x hx₁ hx₂; apply Hne
    obtain rfl : J₁ = J₂
    exact π.eq_of_mem_of_mem hJ₁ hJ₂ ((πi J₁).le_of_mem hJ₁' hx₁) ((πi J₂).le_of_mem hJ₂' hx₂)
    

Proof state:
case intro.intro.intro.intro
ι : Type u_1
I J J₁✝ J₂ : Box ι
π π₁ π₂ : Prepartition I
x✝ : ι → ℝ
πi : (J : Box ι) → Prepartition J
J₁' J₁ : Box ι
hJ₁ : J₁ ∈ π.boxes
hJ₁' : J₁' ∈ (πi J₁).boxes
J₂' : Box ι
Hne : J₁' ≠ J₂'
x : ι → ℝ
hx₁ : x ∈ ↑J₁'
hx₂ : x ∈ ↑J₂'
hJ₂ : J₁ ∈ π.boxes
hJ₂' : J₂' ∈ (πi J₁).boxes
⊢ J₁' = J₂'

Next tactic:
exact (πi J₁).eq_of_mem_of_mem hJ₁' hJ₂' hx₁ hx₂
@[simp]
theorem mem_biUnion : J ∈ π.biUnion πi ↔ ∃ J' ∈ π, J ∈ πi J' := by 

Proof state:
ι : Type u_1
I J J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi πi₁ πi₂ : (J : Box ι) → Prepartition J
⊢ J ∈ biUnion π πi ↔ ∃ J' ∈ π, J ∈ πi J'

Next tactic:
simp [biUnion]
@[simp]
theorem biUnion_top : (π.biUnion fun _ => ⊤) = π := by
  

Proof state:
ι : Type u_1
I J J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi πi₁ πi₂ : (J : Box ι) → Prepartition J
⊢ (biUnion π fun x => ⊤) = π

Next tactic:
ext
@[simp]
theorem biUnion_top : (π.biUnion fun _ => ⊤) = π := by
  ext
  

Proof state:
case h
ι : Type u_1
I J J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi πi₁ πi₂ : (J : Box ι) → Prepartition J
J✝ : Box ι
⊢ (J✝ ∈ biUnion π fun x => ⊤) ↔ J✝ ∈ π

Next tactic:
simp
@[congr]
theorem biUnion_congr (h : π₁ = π₂) (hi : ∀ J ∈ π₁, πi₁ J = πi₂ J) :
    π₁.biUnion πi₁ = π₂.biUnion πi₂ := by
  

Proof state:
ι : Type u_1
I J J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi πi₁ πi₂ : (J : Box ι) → Prepartition J
h : π₁ = π₂
hi : ∀ J ∈ π₁, πi₁ J = πi₂ J
⊢ biUnion π₁ πi₁ = biUnion π₂ πi₂

Next tactic:
subst π₂
@[congr]
theorem biUnion_congr (h : π₁ = π₂) (hi : ∀ J ∈ π₁, πi₁ J = πi₂ J) :
    π₁.biUnion πi₁ = π₂.biUnion πi₂ := by
  subst π₂
  

Proof state:
ι : Type u_1
I J J₁ J₂ : Box ι
π π₁ : Prepartition I
x : ι → ℝ
πi πi₁ πi₂ : (J : Box ι) → Prepartition J
hi : ∀ J ∈ π₁, πi₁ J = πi₂ J
⊢ biUnion π₁ πi₁ = biUnion π₁ πi₂

Next tactic:
ext J
@[congr]
theorem biUnion_congr (h : π₁ = π₂) (hi : ∀ J ∈ π₁, πi₁ J = πi₂ J) :
    π₁.biUnion πi₁ = π₂.biUnion πi₂ := by
  subst π₂
  ext J
  

Proof state:
case h
ι : Type u_1
I J✝ J₁ J₂ : Box ι
π π₁ : Prepartition I
x : ι → ℝ
πi πi₁ πi₂ : (J : Box ι) → Prepartition J
hi : ∀ J ∈ π₁, πi₁ J = πi₂ J
J : Box ι
⊢ J ∈ biUnion π₁ πi₁ ↔ J ∈ biUnion π₁ πi₂

Next tactic:
simp only [mem_biUnion]
@[congr]
theorem biUnion_congr (h : π₁ = π₂) (hi : ∀ J ∈ π₁, πi₁ J = πi₂ J) :
    π₁.biUnion πi₁ = π₂.biUnion πi₂ := by
  subst π₂
  ext J
  simp only [mem_biUnion]
  

Proof state:
case h
ι : Type u_1
I J✝ J₁ J₂ : Box ι
π π₁ : Prepartition I
x : ι → ℝ
πi πi₁ πi₂ : (J : Box ι) → Prepartition J
hi : ∀ J ∈ π₁, πi₁ J = πi₂ J
J : Box ι
⊢ (∃ J' ∈ π₁, J ∈ πi₁ J') ↔ ∃ J' ∈ π₁, J ∈ πi₂ J'

Next tactic:
constructor
@[congr]
theorem biUnion_congr (h : π₁ = π₂) (hi : ∀ J ∈ π₁, πi₁ J = πi₂ J) :
    π₁.biUnion πi₁ = π₂.biUnion πi₂ := by
  subst π₂
  ext J
  simp only [mem_biUnion]
  constructor <;> 

Proof state:
case h.mp
ι : Type u_1
I J✝ J₁ J₂ : Box ι
π π₁ : Prepartition I
x : ι → ℝ
πi πi₁ πi₂ : (J : Box ι) → Prepartition J
hi : ∀ J ∈ π₁, πi₁ J = πi₂ J
J : Box ι
⊢ (∃ J' ∈ π₁, J ∈ πi₁ J') → ∃ J' ∈ π₁, J ∈ πi₂ J'

Next tactic:
exact fun ⟨J', h₁, h₂⟩ => ⟨J', h₁, hi J' h₁ ▸ h₂⟩
@[congr]
theorem biUnion_congr (h : π₁ = π₂) (hi : ∀ J ∈ π₁, πi₁ J = πi₂ J) :
    π₁.biUnion πi₁ = π₂.biUnion πi₂ := by
  subst π₂
  ext J
  simp only [mem_biUnion]
  constructor <;> 

Proof state:
case h.mpr
ι : Type u_1
I J✝ J₁ J₂ : Box ι
π π₁ : Prepartition I
x : ι → ℝ
πi πi₁ πi₂ : (J : Box ι) → Prepartition J
hi : ∀ J ∈ π₁, πi₁ J = πi₂ J
J : Box ι
⊢ (∃ J' ∈ π₁, J ∈ πi₂ J') → ∃ J' ∈ π₁, J ∈ πi₁ J'

Next tactic:
exact fun ⟨J', h₁, h₂⟩ => ⟨J', h₁, hi J' h₁ ▸ h₂⟩
@[simp]
theorem iUnion_biUnion (πi : ∀ J : Box ι, Prepartition J) :
    (π.biUnion πi).iUnion = ⋃ J ∈ π, (πi J).iUnion := by 

Proof state:
ι : Type u_1
I J J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi✝ πi₁ πi₂ πi : (J : Box ι) → Prepartition J
⊢ Prepartition.iUnion (biUnion π πi) = ⋃ J ∈ π, Prepartition.iUnion (πi J)

Next tactic:
simp [Prepartition.iUnion]
@[simp]
theorem sum_biUnion_boxes {M : Type*} [AddCommMonoid M] (π : Prepartition I)
    (πi : ∀ J, Prepartition J) (f : Box ι → M) :
    (∑ J in π.boxes.biUnion fun J => (πi J).boxes, f J) =
      ∑ J in π.boxes, ∑ J' in (πi J).boxes, f J' := by
  

Proof state:
ι : Type u_1
I J J₁ J₂ : Box ι
π✝ π₁ π₂ : Prepartition I
x : ι → ℝ
πi✝ πi₁ πi₂ : (J : Box ι) → Prepartition J
M : Type u_2
inst✝ : AddCommMonoid M
π : Prepartition I
πi : (J : Box ι) → Prepartition J
f : Box ι → M
⊢ ∑ J in Finset.biUnion π.boxes fun J => (πi J).boxes, f J = ∑ J in π.boxes, ∑ J' in (πi J).boxes, f J'

Next tactic:
refine' Finset.sum_biUnion fun J₁ h₁ J₂ h₂ hne => Finset.disjoint_left.2 fun J' h₁' h₂' => _
@[simp]
theorem sum_biUnion_boxes {M : Type*} [AddCommMonoid M] (π : Prepartition I)
    (πi : ∀ J, Prepartition J) (f : Box ι → M) :
    (∑ J in π.boxes.biUnion fun J => (πi J).boxes, f J) =
      ∑ J in π.boxes, ∑ J' in (πi J).boxes, f J' := by
  refine' Finset.sum_biUnion fun J₁ h₁ J₂ h₂ hne => Finset.disjoint_left.2 fun J' h₁' h₂' => _
  

Proof state:
ι : Type u_1
I J J₁✝ J₂✝ : Box ι
π✝ π₁ π₂ : Prepartition I
x : ι → ℝ
πi✝ πi₁ πi₂ : (J : Box ι) → Prepartition J
M : Type u_2
inst✝ : AddCommMonoid M
π : Prepartition I
πi : (J : Box ι) → Prepartition J
f : Box ι → M
J₁ : Box ι
h₁ : J₁ ∈ ↑π.boxes
J₂ : Box ι
h₂ : J₂ ∈ ↑π.boxes
hne : J₁ ≠ J₂
J' : Box ι
h₁' : J' ∈ (fun J => (πi J).boxes) J₁
h₂' : J' ∈ (fun J => (πi J).boxes) J₂
⊢ False

Next tactic:
exact hne (π.eq_of_le_of_le h₁ h₂ ((πi J₁).le_of_mem h₁') ((πi J₂).le_of_mem h₂'))
theorem biUnionIndex_mem (hJ : J ∈ π.biUnion πi) : π.biUnionIndex πi J ∈ π := by
  

Proof state:
ι : Type u_1
I J J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi πi₁ πi₂ : (J : Box ι) → Prepartition J
hJ : J ∈ biUnion π πi
⊢ biUnionIndex π πi J ∈ π

Next tactic:
rw [biUnionIndex, dif_pos hJ]
theorem biUnionIndex_mem (hJ : J ∈ π.biUnion πi) : π.biUnionIndex πi J ∈ π := by
  rw [biUnionIndex, dif_pos hJ]
  

Proof state:
ι : Type u_1
I J J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi πi₁ πi₂ : (J : Box ι) → Prepartition J
hJ : J ∈ biUnion π πi
⊢ Exists.choose (_ : ∃ J' ∈ π, J ∈ πi J') ∈ π

Next tactic:
exact (π.mem_biUnion.1 hJ).choose_spec.1
theorem biUnionIndex_le (πi : ∀ J, Prepartition J) (J : Box ι) : π.biUnionIndex πi J ≤ I := by
  

Proof state:
ι : Type u_1
I J✝ J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi✝ πi₁ πi₂ πi : (J : Box ι) → Prepartition J
J : Box ι
⊢ biUnionIndex π πi J ≤ I

Next tactic:
by_cases hJ : J ∈ π.biUnion πi
theorem biUnionIndex_le (πi : ∀ J, Prepartition J) (J : Box ι) : π.biUnionIndex πi J ≤ I := by
  by_cases hJ : J ∈ π.biUnion πi
  · 

Proof state:
case pos
ι : Type u_1
I J✝ J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi✝ πi₁ πi₂ πi : (J : Box ι) → Prepartition J
J : Box ι
hJ : J ∈ biUnion π πi
⊢ biUnionIndex π πi J ≤ I

Next tactic:
exact π.le_of_mem (π.biUnionIndex_mem hJ)
theorem biUnionIndex_le (πi : ∀ J, Prepartition J) (J : Box ι) : π.biUnionIndex πi J ≤ I := by
  by_cases hJ : J ∈ π.biUnion πi
  · exact π.le_of_mem (π.biUnionIndex_mem hJ)
  · 

Proof state:
case neg
ι : Type u_1
I J✝ J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi✝ πi₁ πi₂ πi : (J : Box ι) → Prepartition J
J : Box ι
hJ : J ∉ biUnion π πi
⊢ biUnionIndex π πi J ≤ I

Next tactic:
rw [biUnionIndex, dif_neg hJ]
theorem mem_biUnionIndex (hJ : J ∈ π.biUnion πi) : J ∈ πi (π.biUnionIndex πi J) := by
  

Proof state:
ι : Type u_1
I J J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi πi₁ πi₂ : (J : Box ι) → Prepartition J
hJ : J ∈ biUnion π πi
⊢ J ∈ πi (biUnionIndex π πi J)

Next tactic:
convert (π.mem_biUnion.1 hJ).choose_spec.2
theorem mem_biUnionIndex (hJ : J ∈ π.biUnion πi) : J ∈ πi (π.biUnionIndex πi J) := by
  convert (π.mem_biUnion.1 hJ).choose_spec.2 <;> 

Proof state:
case h.e'_2.h.e'_2
ι : Type u_1
I J J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi πi₁ πi₂ : (J : Box ι) → Prepartition J
hJ : J ∈ biUnion π πi
⊢ biUnionIndex π πi J = Exists.choose (_ : ∃ J' ∈ π, J ∈ πi J')

Next tactic:
exact dif_pos hJ
theorem mem_biUnionIndex (hJ : J ∈ π.biUnion πi) : J ∈ πi (π.biUnionIndex πi J) := by
  convert (π.mem_biUnion.1 hJ).choose_spec.2 <;> 

Proof state:
case h.e'_3.e'_2
ι : Type u_1
I J J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi πi₁ πi₂ : (J : Box ι) → Prepartition J
hJ : J ∈ biUnion π πi
e_2✝ : Prepartition (biUnionIndex π πi J) = Prepartition (Exists.choose (_ : ∃ J' ∈ π, J ∈ πi J'))
⊢ biUnionIndex π πi J = Exists.choose (_ : ∃ J' ∈ π, J ∈ πi J')

Next tactic:
exact dif_pos hJ
theorem mem_biUnionIndex (hJ : J ∈ π.biUnion πi) : J ∈ πi (π.biUnionIndex πi J) := by
  convert (π.mem_biUnion.1 hJ).choose_spec.2 <;> 

Proof state:
case h.e'_5.e'_1
ι : Type u_1
I J J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi πi₁ πi₂ : (J : Box ι) → Prepartition J
hJ : J ∈ biUnion π πi
e_2✝ : Prepartition (biUnionIndex π πi J) = Prepartition (Exists.choose (_ : ∃ J' ∈ π, J ∈ πi J'))
⊢ biUnionIndex π πi J = Exists.choose (_ : ∃ J' ∈ π, J ∈ πi J')

Next tactic:
exact dif_pos hJ
theorem biUnion_assoc (πi : ∀ J, Prepartition J) (πi' : Box ι → ∀ J : Box ι, Prepartition J) :
    (π.biUnion fun J => (πi J).biUnion (πi' J)) =
      (π.biUnion πi).biUnion fun J => πi' (π.biUnionIndex πi J) J := by
  

Proof state:
ι : Type u_1
I J J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi✝ πi₁ πi₂ πi : (J : Box ι) → Prepartition J
πi' : Box ι → (J : Box ι) → Prepartition J
⊢ (biUnion π fun J => biUnion (πi J) (πi' J)) = biUnion (biUnion π πi) fun J => πi' (biUnionIndex π πi J) J

Next tactic:
ext J
theorem biUnion_assoc (πi : ∀ J, Prepartition J) (πi' : Box ι → ∀ J : Box ι, Prepartition J) :
    (π.biUnion fun J => (πi J).biUnion (πi' J)) =
      (π.biUnion πi).biUnion fun J => πi' (π.biUnionIndex πi J) J := by
  ext J
  

Proof state:
case h
ι : Type u_1
I J✝ J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi✝ πi₁ πi₂ πi : (J : Box ι) → Prepartition J
πi' : Box ι → (J : Box ι) → Prepartition J
J : Box ι
⊢ (J ∈ biUnion π fun J => biUnion (πi J) (πi' J)) ↔ J ∈ biUnion (biUnion π πi) fun J => πi' (biUnionIndex π πi J) J

Next tactic:
simp only [mem_biUnion, exists_prop]
theorem biUnion_assoc (πi : ∀ J, Prepartition J) (πi' : Box ι → ∀ J : Box ι, Prepartition J) :
    (π.biUnion fun J => (πi J).biUnion (πi' J)) =
      (π.biUnion πi).biUnion fun J => πi' (π.biUnionIndex πi J) J := by
  ext J
  simp only [mem_biUnion, exists_prop]
  

Proof state:
case h
ι : Type u_1
I J✝ J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi✝ πi₁ πi₂ πi : (J : Box ι) → Prepartition J
πi' : Box ι → (J : Box ι) → Prepartition J
J : Box ι
⊢ (∃ J' ∈ π, ∃ J'_1 ∈ πi J', J ∈ πi' J' J'_1) ↔ ∃ J', (∃ J'_1 ∈ π, J' ∈ πi J'_1) ∧ J ∈ πi' (biUnionIndex π πi J') J'

Next tactic:
constructor
theorem biUnion_assoc (πi : ∀ J, Prepartition J) (πi' : Box ι → ∀ J : Box ι, Prepartition J) :
    (π.biUnion fun J => (πi J).biUnion (πi' J)) =
      (π.biUnion πi).biUnion fun J => πi' (π.biUnionIndex πi J) J := by
  ext J
  simp only [mem_biUnion, exists_prop]
  constructor
  · 

Proof state:
case h.mp
ι : Type u_1
I J✝ J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi✝ πi₁ πi₂ πi : (J : Box ι) → Prepartition J
πi' : Box ι → (J : Box ι) → Prepartition J
J : Box ι
⊢ (∃ J' ∈ π, ∃ J'_1 ∈ πi J', J ∈ πi' J' J'_1) → ∃ J', (∃ J'_1 ∈ π, J' ∈ πi J'_1) ∧ J ∈ πi' (biUnionIndex π πi J') J'

Next tactic:
rintro ⟨J₁, hJ₁, J₂, hJ₂, hJ⟩
theorem biUnion_assoc (πi : ∀ J, Prepartition J) (πi' : Box ι → ∀ J : Box ι, Prepartition J) :
    (π.biUnion fun J => (πi J).biUnion (πi' J)) =
      (π.biUnion πi).biUnion fun J => πi' (π.biUnionIndex πi J) J := by
  ext J
  simp only [mem_biUnion, exists_prop]
  constructor
  · rintro ⟨J₁, hJ₁, J₂, hJ₂, hJ⟩
    

Proof state:
case h.mp.intro.intro.intro.intro
ι : Type u_1
I J✝ J₁✝ J₂✝ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi✝ πi₁ πi₂ πi : (J : Box ι) → Prepartition J
πi' : Box ι → (J : Box ι) → Prepartition J
J J₁ : Box ι
hJ₁ : J₁ ∈ π
J₂ : Box ι
hJ₂ : J₂ ∈ πi J₁
hJ : J ∈ πi' J₁ J₂
⊢ ∃ J', (∃ J'_1 ∈ π, J' ∈ πi J'_1) ∧ J ∈ πi' (biUnionIndex π πi J') J'

Next tactic:
refine' ⟨J₂, ⟨J₁, hJ₁, hJ₂⟩, _⟩
theorem biUnion_assoc (πi : ∀ J, Prepartition J) (πi' : Box ι → ∀ J : Box ι, Prepartition J) :
    (π.biUnion fun J => (πi J).biUnion (πi' J)) =
      (π.biUnion πi).biUnion fun J => πi' (π.biUnionIndex πi J) J := by
  ext J
  simp only [mem_biUnion, exists_prop]
  constructor
  · rintro ⟨J₁, hJ₁, J₂, hJ₂, hJ⟩
    refine' ⟨J₂, ⟨J₁, hJ₁, hJ₂⟩, _⟩
    

Proof state:
case h.mp.intro.intro.intro.intro
ι : Type u_1
I J✝ J₁✝ J₂✝ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi✝ πi₁ πi₂ πi : (J : Box ι) → Prepartition J
πi' : Box ι → (J : Box ι) → Prepartition J
J J₁ : Box ι
hJ₁ : J₁ ∈ π
J₂ : Box ι
hJ₂ : J₂ ∈ πi J₁
hJ : J ∈ πi' J₁ J₂
⊢ J ∈ πi' (biUnionIndex π πi J₂) J₂

Next tactic:
rwa [π.biUnionIndex_of_mem hJ₁ hJ₂]
theorem biUnion_assoc (πi : ∀ J, Prepartition J) (πi' : Box ι → ∀ J : Box ι, Prepartition J) :
    (π.biUnion fun J => (πi J).biUnion (πi' J)) =
      (π.biUnion πi).biUnion fun J => πi' (π.biUnionIndex πi J) J := by
  ext J
  simp only [mem_biUnion, exists_prop]
  constructor
  · rintro ⟨J₁, hJ₁, J₂, hJ₂, hJ⟩
    refine' ⟨J₂, ⟨J₁, hJ₁, hJ₂⟩, _⟩
    rwa [π.biUnionIndex_of_mem hJ₁ hJ₂]
  · 

Proof state:
case h.mpr
ι : Type u_1
I J✝ J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi✝ πi₁ πi₂ πi : (J : Box ι) → Prepartition J
πi' : Box ι → (J : Box ι) → Prepartition J
J : Box ι
⊢ (∃ J', (∃ J'_1 ∈ π, J' ∈ πi J'_1) ∧ J ∈ πi' (biUnionIndex π πi J') J') → ∃ J' ∈ π, ∃ J'_1 ∈ πi J', J ∈ πi' J' J'_1

Next tactic:
rintro ⟨J₁, ⟨J₂, hJ₂, hJ₁⟩, hJ⟩
theorem biUnion_assoc (πi : ∀ J, Prepartition J) (πi' : Box ι → ∀ J : Box ι, Prepartition J) :
    (π.biUnion fun J => (πi J).biUnion (πi' J)) =
      (π.biUnion πi).biUnion fun J => πi' (π.biUnionIndex πi J) J := by
  ext J
  simp only [mem_biUnion, exists_prop]
  constructor
  · rintro ⟨J₁, hJ₁, J₂, hJ₂, hJ⟩
    refine' ⟨J₂, ⟨J₁, hJ₁, hJ₂⟩, _⟩
    rwa [π.biUnionIndex_of_mem hJ₁ hJ₂]
  · rintro ⟨J₁, ⟨J₂, hJ₂, hJ₁⟩, hJ⟩
    

Proof state:
case h.mpr.intro.intro.intro.intro
ι : Type u_1
I J✝ J₁✝ J₂✝ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi✝ πi₁ πi₂ πi : (J : Box ι) → Prepartition J
πi' : Box ι → (J : Box ι) → Prepartition J
J J₁ : Box ι
hJ : J ∈ πi' (biUnionIndex π πi J₁) J₁
J₂ : Box ι
hJ₂ : J₂ ∈ π
hJ₁ : J₁ ∈ πi J₂
⊢ ∃ J' ∈ π, ∃ J'_1 ∈ πi J', J ∈ πi' J' J'_1

Next tactic:
refine' ⟨J₂, hJ₂, J₁, hJ₁, _⟩
theorem biUnion_assoc (πi : ∀ J, Prepartition J) (πi' : Box ι → ∀ J : Box ι, Prepartition J) :
    (π.biUnion fun J => (πi J).biUnion (πi' J)) =
      (π.biUnion πi).biUnion fun J => πi' (π.biUnionIndex πi J) J := by
  ext J
  simp only [mem_biUnion, exists_prop]
  constructor
  · rintro ⟨J₁, hJ₁, J₂, hJ₂, hJ⟩
    refine' ⟨J₂, ⟨J₁, hJ₁, hJ₂⟩, _⟩
    rwa [π.biUnionIndex_of_mem hJ₁ hJ₂]
  · rintro ⟨J₁, ⟨J₂, hJ₂, hJ₁⟩, hJ⟩
    refine' ⟨J₂, hJ₂, J₁, hJ₁, _⟩
    

Proof state:
case h.mpr.intro.intro.intro.intro
ι : Type u_1
I J✝ J₁✝ J₂✝ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi✝ πi₁ πi₂ πi : (J : Box ι) → Prepartition J
πi' : Box ι → (J : Box ι) → Prepartition J
J J₁ : Box ι
hJ : J ∈ πi' (biUnionIndex π πi J₁) J₁
J₂ : Box ι
hJ₂ : J₂ ∈ π
hJ₁ : J₁ ∈ πi J₂
⊢ J ∈ πi' J₂ J₁

Next tactic:
rwa [π.biUnionIndex_of_mem hJ₂ hJ₁] at hJ
/-- Create a `BoxIntegral.Prepartition` from a collection of possibly empty boxes by filtering out
the empty one if it exists. -/
def ofWithBot (boxes : Finset (WithBot (Box ι)))
    (le_of_mem : ∀ J ∈ boxes, (J : WithBot (Box ι)) ≤ I)
    (pairwise_disjoint : Set.Pairwise (boxes : Set (WithBot (Box ι))) Disjoint) :
    Prepartition I where
  boxes := Finset.eraseNone boxes
  le_of_mem' J hJ := by
    

Proof state:
ι : Type u_1
I J✝ J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi πi₁ πi₂ : (J : Box ι) → Prepartition J
boxes : Finset (WithBot (Box ι))
le_of_mem : ∀ J ∈ boxes, J ≤ ↑I
pairwise_disjoint : Set.Pairwise (↑boxes) Disjoint
J : Box ι
hJ : J ∈ eraseNone boxes
⊢ J ≤ I

Next tactic:
rw [mem_eraseNone] at hJ
/-- Create a `BoxIntegral.Prepartition` from a collection of possibly empty boxes by filtering out
the empty one if it exists. -/
def ofWithBot (boxes : Finset (WithBot (Box ι)))
    (le_of_mem : ∀ J ∈ boxes, (J : WithBot (Box ι)) ≤ I)
    (pairwise_disjoint : Set.Pairwise (boxes : Set (WithBot (Box ι))) Disjoint) :
    Prepartition I where
  boxes := Finset.eraseNone boxes
  le_of_mem' J hJ := by
    rw [mem_eraseNone] at hJ
    

Proof state:
ι : Type u_1
I J✝ J₁ J₂ : Box ι
π π₁ π₂ : Prepartition I
x : ι → ℝ
πi πi₁ πi₂ : (J : Box ι) → Prepartition J
boxes : Finset (WithBot (Box ι))
le_of_mem : ∀ J ∈ boxes, J ≤ ↑I
pairwise_disjoint : Set.Pairwise (↑boxes) Disjoint
J : Box ι
hJ : some J ∈ boxes
⊢ J ≤ I

Next tactic:
simpa only [WithBot.some_eq_coe, WithBot.coe_le_coe] using le_of_mem _ hJ