/-
Copyright (c) 2017 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl, Mario Carneiro

! This file was ported from Lean 3 source module measure_theory.measure.measure_space_def
! leanprover-community/mathlib commit 146a2eed7ad5887ade571e073d0805d2ac618043
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.MeasureTheory.Measure.OuterMeasure
import Mathbin.Order.Filter.CountableInter

/-!
# Measure spaces

This file defines measure spaces, the almost-everywhere filter and ae_measurable functions.
See `measure_theory.measure_space` for their properties and for extended documentation.

Given a measurable space `α`, a measure on `α` is a function that sends measurable sets to the
extended nonnegative reals that satisfies the following conditions:
1. `μ ∅ = 0`;
2. `μ` is countably additive. This means that the measure of a countable union of pairwise disjoint
   sets is equal to the sum of the measures of the individual sets.

Every measure can be canonically extended to an outer measure, so that it assigns values to
all subsets, not just the measurable subsets. On the other hand, an outer measure that is countably
additive on measurable sets can be restricted to measurable sets to obtain a measure.
In this file a measure is defined to be an outer measure that is countably additive on
measurable sets, with the additional assumption that the outer measure is the canonical
extension of the restricted measure.

Measures on `α` form a complete lattice, and are closed under scalar multiplication with `ℝ≥0∞`.

## Implementation notes

Given `μ : measure α`, `μ s` is the value of the *outer measure* applied to `s`.
This conveniently allows us to apply the measure to sets without proving that they are measurable.
We get countable subadditivity for all sets, but only countable additivity for measurable sets.

See the documentation of `measure_theory.measure_space` for ways to construct measures and proving
that two measure are equal.

A `measure_space` is a class that is a measurable space with a canonical measure.
The measure is denoted `volume`.

This file does not import `measure_theory.measurable_space`, but only `measurable_space_def`.

## References

* <https://en.wikipedia.org/wiki/Measure_(mathematics)>
* <https://en.wikipedia.org/wiki/Almost_everywhere>

## Tags

measure, almost everywhere, measure space
-/

noncomputable section

open Classical Set

open Filter hiding map

open Function MeasurableSpace

open Classical Topology BigOperators Filter ENNReal NNReal

variable {α β γ δ ι : Type _}

namespace MeasureTheory

/-- A measure is defined to be an outer measure that is countably additive on
measurable sets, with the additional assumption that the outer measure is the canonical
extension of the restricted measure. -/
structure Measure (α : Type _) [MeasurableSpace α] extends OuterMeasure α where
  m_unionᵢ ⦃f : ℕ → Set α⦄ :
    (∀ i, MeasurableSet (f i)) →
      Pairwise (Disjoint on f) → measure_of (⋃ i, f i) = ∑' i, measure_of (f i)
  trimmed : to_outer_measure.trim = to_outer_measure
#align measure_theory.measure MeasureTheory.Measure

/-- Measure projections for a measure space.

For measurable sets this returns the measure assigned by the `measure_of` field in `measure`.
But we can extend this to _all_ sets, but using the outer measure. This gives us monotonicity and
subadditivity for all sets.
-/
instance Measure.hasCoeToFun [MeasurableSpace α] : CoeFun (Measure α) fun _ => Set α → ℝ≥0∞ :=
  ⟨fun m => m.toOuterMeasure⟩
#align measure_theory.measure.has_coe_to_fun MeasureTheory.Measure.hasCoeToFun

section

variable [MeasurableSpace α] {μ μ₁ μ₂ : Measure α} {s s₁ s₂ t : Set α}

namespace Measure

/-! ### General facts about measures -/

/-- Obtain a measure by giving a countably additive function that sends `∅` to `0`. -/
def ofMeasurable (m : ∀ s : Set α, MeasurableSet s → ℝ≥0∞) (m0 : m ∅ MeasurableSet.empty = 0)
    (mU :
      ∀ ⦃f : ℕ → Set α⦄ (h : ∀ i, MeasurableSet (f i)),
        Pairwise (Disjoint on f) → m (⋃ i, f i) (MeasurableSet.unionᵢ h) = ∑' i, m (f i) (h i)) :
    Measure α :=
  {
    inducedOuterMeasure m _
      m0 with
    m_unionᵢ := fun f hf hd =>
      show inducedOuterMeasure m _ m0 (unionᵢ f) = ∑' i, inducedOuterMeasure m _ m0 (f i)
        by
        rw [induced_outer_measure_eq m0 mU, mU hf hd]
        congr ; funext n; rw [induced_outer_measure_eq m0 mU]
    trimmed :=
      show (inducedOuterMeasure m _ m0).trim = inducedOuterMeasure m _ m0
        by
        unfold outer_measure.trim
        congr ; funext s hs
        exact induced_outer_measure_eq m0 mU hs }
#align measure_theory.measure.of_measurable MeasureTheory.Measure.ofMeasurable

theorem ofMeasurable_apply {m : ∀ s : Set α, MeasurableSet s → ℝ≥0∞}
    {m0 : m ∅ MeasurableSet.empty = 0}
    {mU :
      ∀ ⦃f : ℕ → Set α⦄ (h : ∀ i, MeasurableSet (f i)),
        Pairwise (Disjoint on f) → m (⋃ i, f i) (MeasurableSet.unionᵢ h) = ∑' i, m (f i) (h i)}
    (s : Set α) (hs : MeasurableSet s) : ofMeasurable m m0 mU s = m s hs :=
  inducedOuterMeasure_eq m0 mU hs
#align measure_theory.measure.of_measurable_apply MeasureTheory.Measure.ofMeasurable_apply

theorem toOuterMeasure_injective : Injective (toOuterMeasure : Measure α → OuterMeasure α) :=
  fun ⟨m₁, u₁, h₁⟩ ⟨m₂, u₂, h₂⟩ h => by
  congr
  exact h
#align measure_theory.measure.to_outer_measure_injective MeasureTheory.Measure.toOuterMeasure_injective

@[ext]
theorem ext (h : ∀ s, MeasurableSet s → μ₁ s = μ₂ s) : μ₁ = μ₂ :=
  toOuterMeasure_injective <| by rw [← trimmed, outer_measure.trim_congr h, trimmed]
#align measure_theory.measure.ext MeasureTheory.Measure.ext

theorem ext_iff : μ₁ = μ₂ ↔ ∀ s, MeasurableSet s → μ₁ s = μ₂ s :=
  ⟨by
    rintro rfl s hs
    rfl, Measure.ext⟩
#align measure_theory.measure.ext_iff MeasureTheory.Measure.ext_iff

end Measure

@[simp]
theorem coe_toOuterMeasure : ⇑μ.toOuterMeasure = μ :=
  rfl
#align measure_theory.coe_to_outer_measure MeasureTheory.coe_toOuterMeasure

theorem toOuterMeasure_apply (s : Set α) : μ.toOuterMeasure s = μ s :=
  rfl
#align measure_theory.to_outer_measure_apply MeasureTheory.toOuterMeasure_apply

theorem measure_eq_trim (s : Set α) : μ s = μ.toOuterMeasure.trim s := by rw [μ.trimmed] <;> rfl
#align measure_theory.measure_eq_trim MeasureTheory.measure_eq_trim

theorem measure_eq_infᵢ (s : Set α) : μ s = ⨅ (t) (st : s ⊆ t) (ht : MeasurableSet t), μ t := by
  rw [measure_eq_trim, outer_measure.trim_eq_infi] <;> rfl
#align measure_theory.measure_eq_infi MeasureTheory.measure_eq_infᵢ

/-- A variant of `measure_eq_infi` which has a single `infi`. This is useful when applying a
  lemma next that only works for non-empty infima, in which case you can use
  `nonempty_measurable_superset`. -/
theorem measure_eq_infi' (μ : Measure α) (s : Set α) :
    μ s = ⨅ t : { t // s ⊆ t ∧ MeasurableSet t }, μ t := by
  simp_rw [infᵢ_subtype, infᵢ_and, Subtype.coe_mk, ← measure_eq_infi]
#align measure_theory.measure_eq_infi' MeasureTheory.measure_eq_infi'

theorem measure_eq_inducedOuterMeasure :
    μ s = inducedOuterMeasure (fun s _ => μ s) MeasurableSet.empty μ.Empty s :=
  measure_eq_trim _
#align measure_theory.measure_eq_induced_outer_measure MeasureTheory.measure_eq_inducedOuterMeasure

theorem toOuterMeasure_eq_inducedOuterMeasure :
    μ.toOuterMeasure = inducedOuterMeasure (fun s _ => μ s) MeasurableSet.empty μ.Empty :=
  μ.trimmed.symm
#align measure_theory.to_outer_measure_eq_induced_outer_measure MeasureTheory.toOuterMeasure_eq_inducedOuterMeasure

theorem measure_eq_extend (hs : MeasurableSet s) :
    μ s = extend (fun t (ht : MeasurableSet t) => μ t) s :=
  (extend_eq _ hs).symm
#align measure_theory.measure_eq_extend MeasureTheory.measure_eq_extend

@[simp]
theorem measure_empty : μ ∅ = 0 :=
  μ.Empty
#align measure_theory.measure_empty MeasureTheory.measure_empty

theorem nonempty_of_measure_ne_zero (h : μ s ≠ 0) : s.Nonempty :=
  nonempty_iff_ne_empty.2 fun h' => h <| h'.symm ▸ measure_empty
#align measure_theory.nonempty_of_measure_ne_zero MeasureTheory.nonempty_of_measure_ne_zero

theorem measure_mono (h : s₁ ⊆ s₂) : μ s₁ ≤ μ s₂ :=
  μ.mono h
#align measure_theory.measure_mono MeasureTheory.measure_mono

theorem measure_mono_null (h : s₁ ⊆ s₂) (h₂ : μ s₂ = 0) : μ s₁ = 0 :=
  nonpos_iff_eq_zero.1 <| h₂ ▸ measure_mono h
#align measure_theory.measure_mono_null MeasureTheory.measure_mono_null

theorem measure_mono_top (h : s₁ ⊆ s₂) (h₁ : μ s₁ = ∞) : μ s₂ = ∞ :=
  top_unique <| h₁ ▸ measure_mono h
#align measure_theory.measure_mono_top MeasureTheory.measure_mono_top

/-- For every set there exists a measurable superset of the same measure. -/
theorem exists_measurable_superset (μ : Measure α) (s : Set α) :
    ∃ t, s ⊆ t ∧ MeasurableSet t ∧ μ t = μ s := by
  simpa only [← measure_eq_trim] using μ.to_outer_measure.exists_measurable_superset_eq_trim s
#align measure_theory.exists_measurable_superset MeasureTheory.exists_measurable_superset

/-- For every set `s` and a countable collection of measures `μ i` there exists a measurable
superset `t ⊇ s` such that each measure `μ i` takes the same value on `s` and `t`. -/
theorem exists_measurable_superset_forall_eq {ι} [Countable ι] (μ : ι → Measure α) (s : Set α) :
    ∃ t, s ⊆ t ∧ MeasurableSet t ∧ ∀ i, μ i t = μ i s := by
  simpa only [← measure_eq_trim] using
    outer_measure.exists_measurable_superset_forall_eq_trim (fun i => (μ i).toOuterMeasure) s
#align measure_theory.exists_measurable_superset_forall_eq MeasureTheory.exists_measurable_superset_forall_eq

theorem exists_measurable_superset₂ (μ ν : Measure α) (s : Set α) :
    ∃ t, s ⊆ t ∧ MeasurableSet t ∧ μ t = μ s ∧ ν t = ν s := by
  simpa only [bool.forall_bool.trans and_comm] using
    exists_measurable_superset_forall_eq (fun b => cond b μ ν) s
#align measure_theory.exists_measurable_superset₂ MeasureTheory.exists_measurable_superset₂

theorem exists_measurable_superset_of_null (h : μ s = 0) : ∃ t, s ⊆ t ∧ MeasurableSet t ∧ μ t = 0 :=
  h ▸ exists_measurable_superset μ s
#align measure_theory.exists_measurable_superset_of_null MeasureTheory.exists_measurable_superset_of_null

theorem exists_measurable_superset_iff_measure_eq_zero :
    (∃ t, s ⊆ t ∧ MeasurableSet t ∧ μ t = 0) ↔ μ s = 0 :=
  ⟨fun ⟨t, hst, _, ht⟩ => measure_mono_null hst ht, exists_measurable_superset_of_null⟩
#align measure_theory.exists_measurable_superset_iff_measure_eq_zero MeasureTheory.exists_measurable_superset_iff_measure_eq_zero

theorem measure_unionᵢ_le [Countable β] (s : β → Set α) : μ (⋃ i, s i) ≤ ∑' i, μ (s i) :=
  μ.toOuterMeasure.unionᵢ _
#align measure_theory.measure_Union_le MeasureTheory.measure_unionᵢ_le

theorem measure_bUnion_le {s : Set β} (hs : s.Countable) (f : β → Set α) :
    μ (⋃ b ∈ s, f b) ≤ ∑' p : s, μ (f p) :=
  by
  haveI := hs.to_subtype
  rw [bUnion_eq_Union]
  apply measure_Union_le
#align measure_theory.measure_bUnion_le MeasureTheory.measure_bUnion_le

theorem measure_bUnion_finset_le (s : Finset β) (f : β → Set α) :
    μ (⋃ b ∈ s, f b) ≤ ∑ p in s, μ (f p) :=
  by
  rw [← Finset.sum_attach, Finset.attach_eq_univ, ← tsum_fintype]
  exact measure_bUnion_le s.countable_to_set f
#align measure_theory.measure_bUnion_finset_le MeasureTheory.measure_bUnion_finset_le

theorem measure_unionᵢ_fintype_le [Fintype β] (f : β → Set α) : μ (⋃ b, f b) ≤ ∑ p, μ (f p) :=
  by
  convert measure_bUnion_finset_le Finset.univ f
  simp
#align measure_theory.measure_Union_fintype_le MeasureTheory.measure_unionᵢ_fintype_le

theorem measure_bUnion_lt_top {s : Set β} {f : β → Set α} (hs : s.Finite)
    (hfin : ∀ i ∈ s, μ (f i) ≠ ∞) : μ (⋃ i ∈ s, f i) < ∞ :=
  by
  convert(measure_bUnion_finset_le hs.to_finset f).trans_lt _
  · ext
    rw [finite.mem_to_finset]
  apply ENNReal.sum_lt_top; simpa only [finite.mem_to_finset]
#align measure_theory.measure_bUnion_lt_top MeasureTheory.measure_bUnion_lt_top

theorem measure_unionᵢ_null [Countable β] {s : β → Set α} : (∀ i, μ (s i) = 0) → μ (⋃ i, s i) = 0 :=
  μ.toOuterMeasure.unionᵢ_null
#align measure_theory.measure_Union_null MeasureTheory.measure_unionᵢ_null

@[simp]
theorem measure_unionᵢ_null_iff [Countable ι] {s : ι → Set α} :
    μ (⋃ i, s i) = 0 ↔ ∀ i, μ (s i) = 0 :=
  μ.toOuterMeasure.unionᵢ_null_iff
#align measure_theory.measure_Union_null_iff MeasureTheory.measure_unionᵢ_null_iff

/-- A version of `measure_Union_null_iff` for unions indexed by Props
TODO: in the long run it would be better to combine this with `measure_Union_null_iff` by
generalising to `Sort`. -/
@[simp]
theorem measure_unionᵢ_null_iff' {ι : Prop} {s : ι → Set α} : μ (⋃ i, s i) = 0 ↔ ∀ i, μ (s i) = 0 :=
  μ.toOuterMeasure.unionᵢ_null_iff'
#align measure_theory.measure_Union_null_iff' MeasureTheory.measure_unionᵢ_null_iff'

theorem measure_bUnion_null_iff {s : Set ι} (hs : s.Countable) {t : ι → Set α} :
    μ (⋃ i ∈ s, t i) = 0 ↔ ∀ i ∈ s, μ (t i) = 0 :=
  μ.toOuterMeasure.bUnion_null_iff hs
#align measure_theory.measure_bUnion_null_iff MeasureTheory.measure_bUnion_null_iff

theorem measure_unionₛ_null_iff {S : Set (Set α)} (hS : S.Countable) :
    μ (⋃₀ S) = 0 ↔ ∀ s ∈ S, μ s = 0 :=
  μ.toOuterMeasure.unionₛ_null_iff hS
#align measure_theory.measure_sUnion_null_iff MeasureTheory.measure_unionₛ_null_iff

theorem measure_union_le (s₁ s₂ : Set α) : μ (s₁ ∪ s₂) ≤ μ s₁ + μ s₂ :=
  μ.toOuterMeasure.union _ _
#align measure_theory.measure_union_le MeasureTheory.measure_union_le

theorem measure_union_null : μ s₁ = 0 → μ s₂ = 0 → μ (s₁ ∪ s₂) = 0 :=
  μ.toOuterMeasure.union_null
#align measure_theory.measure_union_null MeasureTheory.measure_union_null

@[simp]
theorem measure_union_null_iff : μ (s₁ ∪ s₂) = 0 ↔ μ s₁ = 0 ∧ μ s₂ = 0 :=
  ⟨fun h =>
    ⟨measure_mono_null (subset_union_left _ _) h, measure_mono_null (subset_union_right _ _) h⟩,
    fun h => measure_union_null h.1 h.2⟩
#align measure_theory.measure_union_null_iff MeasureTheory.measure_union_null_iff

theorem measure_union_lt_top (hs : μ s < ∞) (ht : μ t < ∞) : μ (s ∪ t) < ∞ :=
  (measure_union_le s t).trans_lt (ENNReal.add_lt_top.mpr ⟨hs, ht⟩)
#align measure_theory.measure_union_lt_top MeasureTheory.measure_union_lt_top

@[simp]
theorem measure_union_lt_top_iff : μ (s ∪ t) < ∞ ↔ μ s < ∞ ∧ μ t < ∞ :=
  by
  refine' ⟨fun h => ⟨_, _⟩, fun h => measure_union_lt_top h.1 h.2⟩
  · exact (measure_mono (Set.subset_union_left s t)).trans_lt h
  · exact (measure_mono (Set.subset_union_right s t)).trans_lt h
#align measure_theory.measure_union_lt_top_iff MeasureTheory.measure_union_lt_top_iff

theorem measure_union_ne_top (hs : μ s ≠ ∞) (ht : μ t ≠ ∞) : μ (s ∪ t) ≠ ∞ :=
  (measure_union_lt_top hs.lt_top ht.lt_top).Ne
#align measure_theory.measure_union_ne_top MeasureTheory.measure_union_ne_top

@[simp]
theorem measure_union_eq_top_iff : μ (s ∪ t) = ∞ ↔ μ s = ∞ ∨ μ t = ∞ :=
  not_iff_not.1 <| by simp only [← lt_top_iff_ne_top, ← Ne.def, not_or, measure_union_lt_top_iff]
#align measure_theory.measure_union_eq_top_iff MeasureTheory.measure_union_eq_top_iff

theorem exists_measure_pos_of_not_measure_unionᵢ_null [Countable β] {s : β → Set α}
    (hs : μ (⋃ n, s n) ≠ 0) : ∃ n, 0 < μ (s n) :=
  by
  contrapose! hs
  exact measure_Union_null fun n => nonpos_iff_eq_zero.1 (hs n)
#align measure_theory.exists_measure_pos_of_not_measure_Union_null MeasureTheory.exists_measure_pos_of_not_measure_unionᵢ_null

theorem measure_inter_lt_top_of_left_ne_top (hs_finite : μ s ≠ ∞) : μ (s ∩ t) < ∞ :=
  (measure_mono (Set.inter_subset_left s t)).trans_lt hs_finite.lt_top
#align measure_theory.measure_inter_lt_top_of_left_ne_top MeasureTheory.measure_inter_lt_top_of_left_ne_top

theorem measure_inter_lt_top_of_right_ne_top (ht_finite : μ t ≠ ∞) : μ (s ∩ t) < ∞ :=
  inter_comm t s ▸ measure_inter_lt_top_of_left_ne_top ht_finite
#align measure_theory.measure_inter_lt_top_of_right_ne_top MeasureTheory.measure_inter_lt_top_of_right_ne_top

theorem measure_inter_null_of_null_right (S : Set α) {T : Set α} (h : μ T = 0) : μ (S ∩ T) = 0 :=
  measure_mono_null (inter_subset_right S T) h
#align measure_theory.measure_inter_null_of_null_right MeasureTheory.measure_inter_null_of_null_right

theorem measure_inter_null_of_null_left {S : Set α} (T : Set α) (h : μ S = 0) : μ (S ∩ T) = 0 :=
  measure_mono_null (inter_subset_left S T) h
#align measure_theory.measure_inter_null_of_null_left MeasureTheory.measure_inter_null_of_null_left

/-! ### The almost everywhere filter -/

/-- The “almost everywhere” filter of co-null sets. -/
def Measure.ae {α} {m : MeasurableSpace α} (μ : Measure α) : Filter α
    where
  sets := { s | μ (sᶜ) = 0 }
  univ_sets := by simp
  inter_sets s t hs ht := by
    simp only [compl_inter, mem_set_of_eq] <;> exact measure_union_null hs ht
  sets_of_superset s t hs hst := measure_mono_null (Set.compl_subset_compl.2 hst) hs
#align measure_theory.measure.ae MeasureTheory.Measure.ae

-- mathport name: «expr∀ᵐ ∂ , »
notation3"∀ᵐ "(...)" ∂"μ", "r:(scoped P => Filter.Eventually P Measure.ae μ) => r

-- mathport name: «expr∃ᵐ ∂ , »
notation3"∃ᵐ "(...)" ∂"μ", "r:(scoped P => Filter.Frequently P Measure.ae μ) => r

-- mathport name: «expr =ᵐ[ ] »
notation:50 f " =ᵐ[" μ:50 "] " g:50 => f =ᶠ[Measure.ae μ] g

-- mathport name: «expr ≤ᵐ[ ] »
notation:50 f " ≤ᵐ[" μ:50 "] " g:50 => f ≤ᶠ[Measure.ae μ] g

theorem mem_ae_iff {s : Set α} : s ∈ μ.ae ↔ μ (sᶜ) = 0 :=
  Iff.rfl
#align measure_theory.mem_ae_iff MeasureTheory.mem_ae_iff

theorem ae_iff {p : α → Prop} : (∀ᵐ a ∂μ, p a) ↔ μ { a | ¬p a } = 0 :=
  Iff.rfl
#align measure_theory.ae_iff MeasureTheory.ae_iff

theorem compl_mem_ae_iff {s : Set α} : sᶜ ∈ μ.ae ↔ μ s = 0 := by simp only [mem_ae_iff, compl_compl]
#align measure_theory.compl_mem_ae_iff MeasureTheory.compl_mem_ae_iff

theorem frequently_ae_iff {p : α → Prop} : (∃ᵐ a ∂μ, p a) ↔ μ { a | p a } ≠ 0 :=
  not_congr compl_mem_ae_iff
#align measure_theory.frequently_ae_iff MeasureTheory.frequently_ae_iff

theorem frequently_ae_mem_iff {s : Set α} : (∃ᵐ a ∂μ, a ∈ s) ↔ μ s ≠ 0 :=
  not_congr compl_mem_ae_iff
#align measure_theory.frequently_ae_mem_iff MeasureTheory.frequently_ae_mem_iff

theorem measure_zero_iff_ae_nmem {s : Set α} : μ s = 0 ↔ ∀ᵐ a ∂μ, a ∉ s :=
  compl_mem_ae_iff.symm
#align measure_theory.measure_zero_iff_ae_nmem MeasureTheory.measure_zero_iff_ae_nmem

theorem ae_of_all {p : α → Prop} (μ : Measure α) : (∀ a, p a) → ∀ᵐ a ∂μ, p a :=
  eventually_of_forall
#align measure_theory.ae_of_all MeasureTheory.ae_of_all

--instance ae_is_measurably_generated : is_measurably_generated μ.ae :=
--⟨λ s hs, let ⟨t, hst, htm, htμ⟩ := exists_measurable_superset_of_null hs in
--  ⟨tᶜ, compl_mem_ae_iff.2 htμ, htm.compl, compl_subset_comm.1 hst⟩⟩
instance : CountableInterFilter μ.ae :=
  ⟨by
    intro S hSc hS
    rw [mem_ae_iff, compl_sInter, sUnion_image]
    exact (measure_bUnion_null_iff hSc).2 hS⟩

theorem ae_all_iff {ι : Sort _} [Countable ι] {p : α → ι → Prop} :
    (∀ᵐ a ∂μ, ∀ i, p a i) ↔ ∀ i, ∀ᵐ a ∂μ, p a i :=
  eventually_countable_forall
#align measure_theory.ae_all_iff MeasureTheory.ae_all_iff

theorem ae_ball_iff {S : Set ι} (hS : S.Countable) {p : ∀ (x : α), ∀ i ∈ S, Prop} :
    (∀ᵐ x ∂μ, ∀ i ∈ S, p x i ‹_›) ↔ ∀ i ∈ S, ∀ᵐ x ∂μ, p x i ‹_› :=
  eventually_countable_ball hS
#align measure_theory.ae_ball_iff MeasureTheory.ae_ball_iff

theorem ae_eq_refl (f : α → δ) : f =ᵐ[μ] f :=
  EventuallyEq.rfl
#align measure_theory.ae_eq_refl MeasureTheory.ae_eq_refl

theorem ae_eq_symm {f g : α → δ} (h : f =ᵐ[μ] g) : g =ᵐ[μ] f :=
  h.symm
#align measure_theory.ae_eq_symm MeasureTheory.ae_eq_symm

theorem ae_eq_trans {f g h : α → δ} (h₁ : f =ᵐ[μ] g) (h₂ : g =ᵐ[μ] h) : f =ᵐ[μ] h :=
  h₁.trans h₂
#align measure_theory.ae_eq_trans MeasureTheory.ae_eq_trans

theorem ae_le_of_ae_lt {f g : α → ℝ≥0∞} (h : ∀ᵐ x ∂μ, f x < g x) : f ≤ᵐ[μ] g :=
  by
  rw [Filter.EventuallyLE, ae_iff]
  rw [ae_iff] at h
  refine' measure_mono_null (fun x hx => _) h
  exact not_lt.2 (le_of_lt (not_le.1 hx))
#align measure_theory.ae_le_of_ae_lt MeasureTheory.ae_le_of_ae_lt

@[simp]
theorem ae_eq_empty : s =ᵐ[μ] (∅ : Set α) ↔ μ s = 0 :=
  eventuallyEq_empty.trans <| by simp only [ae_iff, Classical.not_not, set_of_mem_eq]
#align measure_theory.ae_eq_empty MeasureTheory.ae_eq_empty

@[simp]
theorem ae_eq_univ : s =ᵐ[μ] (univ : Set α) ↔ μ (sᶜ) = 0 :=
  eventuallyEq_univ
#align measure_theory.ae_eq_univ MeasureTheory.ae_eq_univ

theorem ae_le_set : s ≤ᵐ[μ] t ↔ μ (s \ t) = 0 :=
  calc
    s ≤ᵐ[μ] t ↔ ∀ᵐ x ∂μ, x ∈ s → x ∈ t := Iff.rfl
    _ ↔ μ (s \ t) = 0 := by simp [ae_iff] <;> rfl

#align measure_theory.ae_le_set MeasureTheory.ae_le_set

theorem ae_le_set_inter {s' t' : Set α} (h : s ≤ᵐ[μ] t) (h' : s' ≤ᵐ[μ] t') :
    (s ∩ s' : Set α) ≤ᵐ[μ] (t ∩ t' : Set α) :=
  h.inter h'
#align measure_theory.ae_le_set_inter MeasureTheory.ae_le_set_inter

theorem ae_le_set_union {s' t' : Set α} (h : s ≤ᵐ[μ] t) (h' : s' ≤ᵐ[μ] t') :
    (s ∪ s' : Set α) ≤ᵐ[μ] (t ∪ t' : Set α) :=
  h.union h'
#align measure_theory.ae_le_set_union MeasureTheory.ae_le_set_union

theorem union_ae_eq_right : (s ∪ t : Set α) =ᵐ[μ] t ↔ μ (s \ t) = 0 := by
  simp [eventually_le_antisymm_iff, ae_le_set, union_diff_right,
    diff_eq_empty.2 (Set.subset_union_right _ _)]
#align measure_theory.union_ae_eq_right MeasureTheory.union_ae_eq_right

theorem diff_ae_eq_self : (s \ t : Set α) =ᵐ[μ] s ↔ μ (s ∩ t) = 0 := by
  simp [eventually_le_antisymm_iff, ae_le_set, diff_diff_right, diff_diff,
    diff_eq_empty.2 (Set.subset_union_right _ _)]
#align measure_theory.diff_ae_eq_self MeasureTheory.diff_ae_eq_self

theorem diff_null_ae_eq_self (ht : μ t = 0) : (s \ t : Set α) =ᵐ[μ] s :=
  diff_ae_eq_self.mpr (measure_mono_null (inter_subset_right _ _) ht)
#align measure_theory.diff_null_ae_eq_self MeasureTheory.diff_null_ae_eq_self

theorem ae_eq_set {s t : Set α} : s =ᵐ[μ] t ↔ μ (s \ t) = 0 ∧ μ (t \ s) = 0 := by
  simp [eventually_le_antisymm_iff, ae_le_set]
#align measure_theory.ae_eq_set MeasureTheory.ae_eq_set

@[simp]
theorem measure_symmDiff_eq_zero_iff {s t : Set α} : μ (s ∆ t) = 0 ↔ s =ᵐ[μ] t := by
  simp [ae_eq_set, symmDiff_def]
#align measure_theory.measure_symm_diff_eq_zero_iff MeasureTheory.measure_symmDiff_eq_zero_iff

@[simp]
theorem ae_eq_set_compl_compl {s t : Set α} : sᶜ =ᵐ[μ] tᶜ ↔ s =ᵐ[μ] t := by
  simp only [← measure_symm_diff_eq_zero_iff, compl_symmDiff_compl]
#align measure_theory.ae_eq_set_compl_compl MeasureTheory.ae_eq_set_compl_compl

theorem ae_eq_set_compl {s t : Set α} : sᶜ =ᵐ[μ] t ↔ s =ᵐ[μ] tᶜ := by
  rw [← ae_eq_set_compl_compl, compl_compl]
#align measure_theory.ae_eq_set_compl MeasureTheory.ae_eq_set_compl

theorem ae_eq_set_inter {s' t' : Set α} (h : s =ᵐ[μ] t) (h' : s' =ᵐ[μ] t') :
    (s ∩ s' : Set α) =ᵐ[μ] (t ∩ t' : Set α) :=
  h.inter h'
#align measure_theory.ae_eq_set_inter MeasureTheory.ae_eq_set_inter

theorem ae_eq_set_union {s' t' : Set α} (h : s =ᵐ[μ] t) (h' : s' =ᵐ[μ] t') :
    (s ∪ s' : Set α) =ᵐ[μ] (t ∪ t' : Set α) :=
  h.union h'
#align measure_theory.ae_eq_set_union MeasureTheory.ae_eq_set_union

theorem union_ae_eq_univ_of_ae_eq_univ_left (h : s =ᵐ[μ] univ) : (s ∪ t : Set α) =ᵐ[μ] univ :=
  by
  convert ae_eq_set_union h (ae_eq_refl t)
  rw [univ_union]
#align measure_theory.union_ae_eq_univ_of_ae_eq_univ_left MeasureTheory.union_ae_eq_univ_of_ae_eq_univ_left

theorem union_ae_eq_univ_of_ae_eq_univ_right (h : t =ᵐ[μ] univ) : (s ∪ t : Set α) =ᵐ[μ] univ :=
  by
  convert ae_eq_set_union (ae_eq_refl s) h
  rw [union_univ]
#align measure_theory.union_ae_eq_univ_of_ae_eq_univ_right MeasureTheory.union_ae_eq_univ_of_ae_eq_univ_right

theorem union_ae_eq_right_of_ae_eq_empty (h : s =ᵐ[μ] (∅ : Set α)) : (s ∪ t : Set α) =ᵐ[μ] t :=
  by
  convert ae_eq_set_union h (ae_eq_refl t)
  rw [empty_union]
#align measure_theory.union_ae_eq_right_of_ae_eq_empty MeasureTheory.union_ae_eq_right_of_ae_eq_empty

theorem union_ae_eq_left_of_ae_eq_empty (h : t =ᵐ[μ] (∅ : Set α)) : (s ∪ t : Set α) =ᵐ[μ] s :=
  by
  convert ae_eq_set_union (ae_eq_refl s) h
  rw [union_empty]
#align measure_theory.union_ae_eq_left_of_ae_eq_empty MeasureTheory.union_ae_eq_left_of_ae_eq_empty

theorem inter_ae_eq_right_of_ae_eq_univ (h : s =ᵐ[μ] univ) : (s ∩ t : Set α) =ᵐ[μ] t :=
  by
  convert ae_eq_set_inter h (ae_eq_refl t)
  rw [univ_inter]
#align measure_theory.inter_ae_eq_right_of_ae_eq_univ MeasureTheory.inter_ae_eq_right_of_ae_eq_univ

theorem inter_ae_eq_left_of_ae_eq_univ (h : t =ᵐ[μ] univ) : (s ∩ t : Set α) =ᵐ[μ] s :=
  by
  convert ae_eq_set_inter (ae_eq_refl s) h
  rw [inter_univ]
#align measure_theory.inter_ae_eq_left_of_ae_eq_univ MeasureTheory.inter_ae_eq_left_of_ae_eq_univ

theorem inter_ae_eq_empty_of_ae_eq_empty_left (h : s =ᵐ[μ] (∅ : Set α)) :
    (s ∩ t : Set α) =ᵐ[μ] (∅ : Set α) :=
  by
  convert ae_eq_set_inter h (ae_eq_refl t)
  rw [empty_inter]
#align measure_theory.inter_ae_eq_empty_of_ae_eq_empty_left MeasureTheory.inter_ae_eq_empty_of_ae_eq_empty_left

theorem inter_ae_eq_empty_of_ae_eq_empty_right (h : t =ᵐ[μ] (∅ : Set α)) :
    (s ∩ t : Set α) =ᵐ[μ] (∅ : Set α) :=
  by
  convert ae_eq_set_inter (ae_eq_refl s) h
  rw [inter_empty]
#align measure_theory.inter_ae_eq_empty_of_ae_eq_empty_right MeasureTheory.inter_ae_eq_empty_of_ae_eq_empty_right

@[to_additive]
theorem Set.mulIndicator_ae_eq_one {M : Type _} [One M] {f : α → M} {s : Set α}
    (h : s.mulIndicator f =ᵐ[μ] 1) : μ (s ∩ Function.mulSupport f) = 0 := by
  simpa [Filter.EventuallyEq, ae_iff] using h
#align set.mul_indicator_ae_eq_one Set.mulIndicator_ae_eq_one
#align set.indicator_ae_eq_zero Set.indicator_ae_eq_zero

/-- If `s ⊆ t` modulo a set of measure `0`, then `μ s ≤ μ t`. -/
@[mono]
theorem measure_mono_ae (H : s ≤ᵐ[μ] t) : μ s ≤ μ t :=
  calc
    μ s ≤ μ (s ∪ t) := measure_mono <| subset_union_left s t
    _ = μ (t ∪ s \ t) := by rw [union_diff_self, Set.union_comm]
    _ ≤ μ t + μ (s \ t) := (measure_union_le _ _)
    _ = μ t := by rw [ae_le_set.1 H, add_zero]

#align measure_theory.measure_mono_ae MeasureTheory.measure_mono_ae

alias measure_mono_ae ← _root_.filter.eventually_le.measure_le
#align filter.eventually_le.measure_le Filter.EventuallyLE.measure_le

/-- If two sets are equal modulo a set of measure zero, then `μ s = μ t`. -/
theorem measure_congr (H : s =ᵐ[μ] t) : μ s = μ t :=
  le_antisymm H.le.measure_le H.symm.le.measure_le
#align measure_theory.measure_congr MeasureTheory.measure_congr

alias measure_congr ← _root_.filter.eventually_eq.measure_eq
#align filter.eventually_eq.measure_eq Filter.EventuallyEq.measure_eq

theorem measure_mono_null_ae (H : s ≤ᵐ[μ] t) (ht : μ t = 0) : μ s = 0 :=
  nonpos_iff_eq_zero.1 <| ht ▸ H.measure_le
#align measure_theory.measure_mono_null_ae MeasureTheory.measure_mono_null_ae

/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (t «expr ⊇ » s) -/
/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (t «expr ⊇ » s) -/
/-- A measurable set `t ⊇ s` such that `μ t = μ s`. It even satisfies `μ (t ∩ u) = μ (s ∩ u)` for
any measurable set `u` if `μ s ≠ ∞`, see `measure_to_measurable_inter`.
(This property holds without the assumption `μ s ≠ ∞` when the space is sigma-finite,
see `measure_to_measurable_inter_of_sigma_finite`).
If `s` is a null measurable set, then
we also have `t =ᵐ[μ] s`, see `null_measurable_set.to_measurable_ae_eq`.
This notion is sometimes called a "measurable hull" in the literature. -/
irreducible_def toMeasurable (μ : Measure α) (s : Set α) : Set α :=
  if h : ∃ (t : _)(_ : t ⊇ s), MeasurableSet t ∧ t =ᵐ[μ] s then h.some
  else
    if h' :
        ∃ (t : _)(_ : t ⊇ s), MeasurableSet t ∧ ∀ u, MeasurableSet u → μ (t ∩ u) = μ (s ∩ u) then
      h'.some
    else (exists_measurable_superset μ s).some
#align measure_theory.to_measurable MeasureTheory.toMeasurable

theorem subset_toMeasurable (μ : Measure α) (s : Set α) : s ⊆ toMeasurable μ s :=
  by
  rw [to_measurable]; split_ifs with hs h's
  exacts[hs.some_spec.fst, h's.some_spec.fst, (exists_measurable_superset μ s).choose_spec.1]
#align measure_theory.subset_to_measurable MeasureTheory.subset_toMeasurable

theorem ae_le_toMeasurable : s ≤ᵐ[μ] toMeasurable μ s :=
  (subset_toMeasurable _ _).EventuallyLE
#align measure_theory.ae_le_to_measurable MeasureTheory.ae_le_toMeasurable

@[simp]
theorem measurableSet_toMeasurable (μ : Measure α) (s : Set α) : MeasurableSet (toMeasurable μ s) :=
  by
  rw [to_measurable]; split_ifs with hs h's
  exacts[hs.some_spec.snd.1, h's.some_spec.snd.1, (exists_measurable_superset μ s).choose_spec.2.1]
#align measure_theory.measurable_set_to_measurable MeasureTheory.measurableSet_toMeasurable

@[simp]
theorem measure_toMeasurable (s : Set α) : μ (toMeasurable μ s) = μ s :=
  by
  rw [to_measurable]; split_ifs with hs h's
  · exact measure_congr hs.some_spec.snd.2
  · simpa only [inter_univ] using h's.some_spec.snd.2 univ MeasurableSet.univ
  · exact (exists_measurable_superset μ s).choose_spec.2.2
#align measure_theory.measure_to_measurable MeasureTheory.measure_toMeasurable

/-- A measure space is a measurable space equipped with a
  measure, referred to as `volume`. -/
class MeasureSpace (α : Type _) extends MeasurableSpace α where
  volume : Measure α
#align measure_theory.measure_space MeasureTheory.MeasureSpace

export MeasureSpace (volume)

/-- `volume` is the canonical  measure on `α`. -/
add_decl_doc volume

section MeasureSpace

-- mathport name: «expr∀ᵐ , »
notation3"∀ᵐ "(...)", "r:(scoped P =>
  Filter.Eventually P MeasureTheory.Measure.ae MeasureTheory.MeasureSpace.volume) => r

-- mathport name: «expr∃ᵐ , »
notation3"∃ᵐ "(...)", "r:(scoped P =>
  Filter.Frequently P MeasureTheory.Measure.ae MeasureTheory.MeasureSpace.volume) => r

/- ./././Mathport/Syntax/Translate/Expr.lean:330:4: warning: unsupported (TODO): `[tacs] -/
/-- The tactic `exact volume`, to be used in optional (`auto_param`) arguments. -/
unsafe def volume_tac : tactic Unit :=
  sorry
#align measure_theory.volume_tac measure_theory.volume_tac

end MeasureSpace

end

end MeasureTheory

section

open MeasureTheory

/-!
# Almost everywhere measurable functions

A function is almost everywhere measurable if it coincides almost everywhere with a measurable
function. We define this property, called `ae_measurable f μ`. It's properties are discussed in
`measure_theory.measure_space`.
-/

variable {m : MeasurableSpace α} [MeasurableSpace β] {f g : α → β} {μ ν : Measure α}

/- ./././Mathport/Syntax/Translate/Tactic/Builtin.lean:69:18: unsupported non-interactive tactic measure_theory.volume_tac -/
/-- A function is almost everywhere measurable if it coincides almost everywhere with a measurable
function. -/
def AeMeasurable {m : MeasurableSpace α} (f : α → β)
    (μ : Measure α := by
      run_tac
        measure_theory.volume_tac) :
    Prop :=
  ∃ g : α → β, Measurable g ∧ f =ᵐ[μ] g
#align ae_measurable AeMeasurable

theorem Measurable.aeMeasurable (h : Measurable f) : AeMeasurable f μ :=
  ⟨f, h, ae_eq_refl f⟩
#align measurable.ae_measurable Measurable.aeMeasurable

namespace AeMeasurable

/-- Given an almost everywhere measurable function `f`, associate to it a measurable function
that coincides with it almost everywhere. `f` is explicit in the definition to make sure that
it shows in pretty-printing. -/
def mk (f : α → β) (h : AeMeasurable f μ) : α → β :=
  Classical.choose h
#align ae_measurable.mk AeMeasurable.mk

theorem measurable_mk (h : AeMeasurable f μ) : Measurable (h.mk f) :=
  (Classical.choose_spec h).1
#align ae_measurable.measurable_mk AeMeasurable.measurable_mk

theorem ae_eq_mk (h : AeMeasurable f μ) : f =ᵐ[μ] h.mk f :=
  (Classical.choose_spec h).2
#align ae_measurable.ae_eq_mk AeMeasurable.ae_eq_mk

theorem congr (hf : AeMeasurable f μ) (h : f =ᵐ[μ] g) : AeMeasurable g μ :=
  ⟨hf.mk f, hf.measurable_mk, h.symm.trans hf.ae_eq_mk⟩
#align ae_measurable.congr AeMeasurable.congr

end AeMeasurable

theorem aeMeasurable_congr (h : f =ᵐ[μ] g) : AeMeasurable f μ ↔ AeMeasurable g μ :=
  ⟨fun hf => AeMeasurable.congr hf h, fun hg => AeMeasurable.congr hg h.symm⟩
#align ae_measurable_congr aeMeasurable_congr

@[simp]
theorem aeMeasurableConst {b : β} : AeMeasurable (fun a : α => b) μ :=
  measurable_const.AeMeasurable
#align ae_measurable_const aeMeasurableConst

theorem aeMeasurableId : AeMeasurable id μ :=
  measurable_id.AeMeasurable
#align ae_measurable_id aeMeasurableId

theorem aeMeasurableId' : AeMeasurable (fun x => x) μ :=
  measurable_id.AeMeasurable
#align ae_measurable_id' aeMeasurableId'

theorem Measurable.compAeMeasurable [MeasurableSpace δ] {f : α → δ} {g : δ → β} (hg : Measurable g)
    (hf : AeMeasurable f μ) : AeMeasurable (g ∘ f) μ :=
  ⟨g ∘ hf.mk f, hg.comp hf.measurable_mk, EventuallyEq.fun_comp hf.ae_eq_mk _⟩
#align measurable.comp_ae_measurable Measurable.compAeMeasurable

end


import analysis.inner_product_space.pi_L2
import topology.paracompact

--OUTPUT 1
theorem ℝn_paracompact (n : ℕ) : paracompact_space (euclidean_space ℝ (fin n)) :=
begin
  assume A : set (euclidean_space ℝ (fin n)),
  assume hA : is_open A,
  assume hA₁ : is_covering A,

  let B₀ : set (euclidean_space ℝ (fin n)) := ∅,
  let Bₖ : ℕ → set (euclidean_space ℝ (fin n)) := λ k, { x : euclidean_space ℝ (fin n) | ∃ (r : ℝ), (r > 0) ∧ (∀ (y : euclidean_space ℝ (fin n)), y ∈ Bₖ k ↔ (∥y - x∥ < r)) },

  have hBₖ₁ : ∀ k : ℕ, Bₖ k ≠ ∅, from by auto [exists.intro 0, exists.intro (by auto [lt_add_one]), exists.intro 0, exists.intro (by auto [lt_add_one]), exists.intro 0, exists.intro (by auto [lt_add_one])],
  have hBₖ₂ : ∀ k : ℕ, is_open (Bₖ k), from by auto [is_open_ball],
  have hBₖ₃ : ∀ k : ℕ, is_covering (Bₖ k), from by auto [is_covering_ball],
  have hBₖ₄ : ∀ k : ℕ, is_compact (closure (Bₖ k)), from by auto [compact_closure_ball],

  have hBₖ₅ : ∀ k : ℕ, ∃ (Cₖ : set (euclidean_space ℝ (fin n))), (is_open Cₖ) ∧ (Cₖ ⊆ A) ∧ (closure (Bₖ k) ⊆ Cₖ), from by auto [hBₖ₄, hA₁],
  have hBₖ₆ : ∀ k : ℕ, ∃ (Cₖ : set (euclidean_space ℝ (fin n))), (is_open Cₖ) ∧ (Cₖ ⊆ A) ∧ (closure (Bₖ k) ⊆ Cₖ) ∧ (∀ (y : euclidean_space ℝ (fin n)), y ∈ Cₖ ↔ (y ∈ A ∧ y ∉ closure (Bₖ (k - 1)))), from by auto [hBₖ₅, closure_subset_iff],
  have hBₖ₇ : ∀ k : ℕ, ∃ (Cₖ : set (euclidean_space ℝ (fin n))), (is_open Cₖ) ∧ (Cₖ ⊆ A) ∧ (closure (Bₖ k) ⊆ Cₖ) ∧ (∀ (y : euclidean_space ℝ (fin n)), y ∈ Cₖ ↔ (y ∈ A ∧ y ∉ closure (Bₖ (k - 1)))) ∧ (Cₖ ⊆ A), from by auto [hBₖ₆],
  have hBₖ₈ : ∀ k : ℕ, ∃ (Cₖ : set (euclidean_space ℝ (fin n))), (is_open Cₖ) ∧ (Cₖ ⊆ A) ∧ (closure (Bₖ k) ⊆ Cₖ) ∧ (∀ (y : euclidean_space ℝ (fin n)), y ∈ Cₖ ↔ (y ∈ A ∧ y ∉ closure (Bₖ (k - 1)))) ∧ (Cₖ ⊆ A) ∧ (closure (Bₖ k) ⊆ Cₖ), from by auto [hBₖ₇],
  have hBₖ₉ : ∀ k : ℕ, ∃ (Cₖ : set (euclidean_space ℝ (fin n))), (is_open Cₖ) ∧ (Cₖ ⊆ A) ∧ (closure (Bₖ k) ⊆ Cₖ) ∧ (∀ (y : euclidean_space ℝ (fin n)), y ∈ Cₖ ↔ (y ∈ A ∧ y ∉ closure (Bₖ (k - 1)))) ∧ (Cₖ ⊆ A) ∧ (closure (Bₖ k) ⊆ Cₖ) ∧ (∀ (y : euclidean_space ℝ (fin n)), y ∈ Cₖ ↔ (y ∈ A ∧ y ∉ closure (Bₖ (k - 1)))), from by auto [hBₖ₈],
  have hBₖ₁₀ : ∀ k : ℕ, ∃ (Cₖ : set (euclidean_space ℝ (fin n))), (is_open Cₖ) ∧ (Cₖ ⊆ A) ∧ (closure (Bₖ k) ⊆ Cₖ) ∧ (∀ (y : euclidean_space ℝ (fin n)), y ∈ Cₖ ↔ (y ∈ A ∧ y ∉ closure (Bₖ (k - 1)))) ∧ (Cₖ ⊆ A) ∧ (closure (Bₖ k) ⊆ Cₖ) ∧ (∀ (y : euclidean_space ℝ (fin n)), y ∈ Cₖ ↔ (y ∈ A ∧ y ∉ closure (Bₖ (k - 1)))), from by auto [hBₖ₉],
  have hBₖ₁₁ : ∀ k : ℕ, ∃ (Cₖ : set (euclidean_space ℝ (fin n))), (is_open Cₖ) ∧ (Cₖ ⊆ A) ∧ (closure (Bₖ k) ⊆ Cₖ) ∧ (∀ (y : euclidean_space ℝ (fin n)), y ∈ Cₖ ↔ (y ∈ A ∧ y ∉ closure (Bₖ (k - 1)))) ∧ (Cₖ ⊆ A) ∧ (closure (Bₖ k) ⊆ Cₖ) ∧ (∀ (y : euclidean_space ℝ (fin n)), y ∈ Cₖ ↔ (y ∈ A ∧ y ∉ closure (Bₖ (k - 1)))), from by auto [hBₖ₁₀],
  have hBₖ₁₂ : ∀ k : ℕ, ∃ (Cₖ : set (euclidean_space ℝ (fin n))), (is_open Cₖ) ∧ (Cₖ ⊆ A) ∧ (closure (Bₖ k) ⊆ Cₖ) ∧ (∀ (y : euclidean_space ℝ (fin n)), y ∈ Cₖ ↔ (y ∈ A ∧ y ∉ closure (Bₖ (k - 1)))) ∧ (Cₖ ⊆ A) ∧ (closure (Bₖ k) ⊆ Cₖ) ∧ (∀ (y : euclidean_space ℝ (fin n)), y ∈ Cₖ ↔ (y ∈ A ∧ y ∉ closure (Bₖ (k - 1)))), from by auto [hBₖ₁₁],
  have hBₖ₁₃ : ∀ k : ℕ, ∃ (Cₖ : set (euclidean_space ℝ (fin n))), (is_open Cₖ) ∧ (C
end --Needs more than 2000 tokens!

--OUTPUT 2
theorem ℝn_paracompact (n : ℕ) : paracompact_space (euclidean_space ℝ (fin n)) :=
begin
  assume A : set (euclidean_space ℝ (fin n)),
  assume hA : is_open A,

  have h1 : ∀ m : ℕ, ∃ Bm : set (euclidean_space ℝ (fin n)), is_open Bm ∧ Bm ⊆ A ∧ (∀ x : euclidean_space ℝ (fin n), x ∈ Bm → ∃ (m : ℕ), ∃ (x : euclidean_space ℝ (fin n)), x ∈ Bm), from
  begin
    assume m,
    let Bm : set (euclidean_space ℝ (fin n)) := {x : euclidean_space ℝ (fin n) | ∃ (m : ℕ), ∃ (x : euclidean_space ℝ (fin n)), x ∈ Bm},
    have h1 : is_open Bm, from by auto [is_open_ball],
    have h2 : Bm ⊆ A, from by auto [set.subset_def, set.mem_ball, set.mem_set_of_eq],
    have h3 : ∀ x : euclidean_space ℝ (fin n), x ∈ Bm → ∃ (m : ℕ), ∃ (x : euclidean_space ℝ (fin n)), x ∈ Bm, from by auto [set.mem_ball],
    show ∃ Bm : set (euclidean_space ℝ (fin n)), is_open Bm ∧ Bm ⊆ A ∧ (∀ x : euclidean_space ℝ (fin n), x ∈ Bm → ∃ (m : ℕ), ∃ (x : euclidean_space ℝ (fin n)), x ∈ Bm), from by auto [h1, h2, h3],
  end,

  have h2 : ∀ m : ℕ, ∃ Bm : set (euclidean_space ℝ (fin n)), is_open Bm ∧ Bm ⊆ A ∧ (∀ x : euclidean_space ℝ (fin n), x ∈ Bm → ∃ (m : ℕ), ∃ (x : euclidean_space ℝ (fin n)), x ∈ Bm), from
  begin
    assume m,
    let Bm : set (euclidean_space ℝ (fin n)) := {x : euclidean_space ℝ (fin n) | ∃ (m : ℕ), ∃ (x : euclidean_space ℝ (fin n)), x ∈ Bm},
    have h1 : is_open Bm, from by auto [is_open_ball],
    have h2 : Bm ⊆ A, from by auto [set.subset_def, set.mem_ball, set.mem_set_of_eq],
    have h3 : ∀ x : euclidean_space ℝ (fin n), x ∈ Bm → ∃ (m : ℕ), ∃ (x : euclidean_space ℝ (fin n)), x ∈ Bm, from by auto [set.mem_ball],
    show ∃ Bm : set (euclidean_space ℝ (fin n)), is_open Bm ∧ Bm ⊆ A ∧ (∀ x : euclidean_space ℝ (fin n), x ∈ Bm → ∃ (m : ℕ), ∃ (x : euclidean_space ℝ (fin n)), x ∈ Bm), from by auto [h1, h2, h3],
  end,

  have h3 : ∀ m : ℕ, ∃ Bm : set (euclidean_space ℝ (fin n)), is_open Bm ∧ Bm ⊆ A ∧ (∀ x : euclidean_space ℝ (fin n), x ∈ Bm → ∃ (m : ℕ), ∃ (x : euclidean_space ℝ (fin n)), x ∈ Bm), from
  begin
    assume m,
    let Bm : set (euclidean_space ℝ (fin n)) := {x : euclidean_space ℝ (fin n) | ∃ (m : ℕ), ∃ (x : euclidean_space ℝ (fin n)), x ∈ Bm},
    have h1 : is_open Bm, from by auto [is_open_ball],
    have h2 : Bm ⊆ A, from by auto [set.subset_def, set.mem_ball, set.mem_set_of_eq],
    have h3 : ∀ x : euclidean_space ℝ (fin n), x ∈ Bm → ∃ (m : ℕ), ∃ (x : euclidean_space ℝ (fin n)), x ∈ Bm, from by auto [set.mem_ball],
    show ∃ Bm : set (euclidean_space ℝ (fin n)), is_open Bm ∧ Bm ⊆ A ∧ (∀ x : euclidean_space ℝ (fin n), x ∈ Bm → ∃ (m : ℕ), ∃ (x : euclidean_space ℝ (fin n)), x ∈ Bm), from by auto [h1, h2, h3],
  end,

  have h4 : ∀ m : ℕ, ∃ Bm : set (euclidean_space ℝ (fin n)), is_open Bm ∧ Bm ⊆ A ∧ (∀ x : euclidean_space ℝ (fin n), x ∈ Bm → ∃ (m : ℕ), ∃ (x : euclidean_space ℝ (fin n)), x ∈ Bm), from
  begin
    assume m,
    let Bm : set (euclidean_space ℝ (fin n)) := {x : euclidean_space ℝ (fin n) | ∃ (m : ℕ), ∃ (x : euclidean_space ℝ (fin n)), x ∈ Bm},
    have h1 : is_open Bm, from by auto [is_open_ball],
    have h2 : Bm ⊆ A, from by auto [set.subset_def, set.mem_ball, set.mem_set_of_eq],
    have h3 : ∀ x : euclidean_space ℝ (fin n), x ∈ Bm → ∃ (m : ℕ), ∃ (x : euclidean_space ℝ (fin n)), x ∈ Bm, from by auto [set.mem_ball],
    show ∃ Bm : set (euclidean_space ℝ (fin n)), is_open Bm ∧ Bm ⊆ A ∧ (∀ x : euclidean_space ℝ (fin n), x ∈ Bm → ∃ (m : ℕ), ∃ (x : euclidean_space ℝ (fin n)), x ∈ Bm), from by auto [h1, h2, h3],
  end,

  have h5 : ∀ m : ℕ, ∃ Bm : set (euclidean_space ℝ (fin n)), is_open Bm ∧ Bm ⊆ A ∧ (∀ x : euclidean_space ℝ (fin n), x ∈ Bm → ∃ (m : ℕ), ∃ (x : euclidean_space ℝ (fin n)), x ∈ Bm), from
  begin
    assume m,
    let Bm : set (euclidean_space ℝ (fin n)) := {x : euclidean_space ℝ (fin n) | ∃ (m : ℕ), ∃ (x : euclidean_space ℝ (fin n)), x ∈ Bm},
    have h1 : is_open Bm, from by auto [is_open_ball],
    have h2 : Bm ⊆ A, from by auto [set.subset_def, set.
end --Needs more than 2000 tokens!

--OUTPUT 3
theorem ℝn_paracompact (n : ℕ) : paracompact_space (euclidean_space ℝ (fin n)) :=
begin
  assume (A : set (euclidean_space ℝ (fin n))) (hA : is_open A) (hA1 : is_covering A),
  let B0 : set (euclidean_space ℝ (fin n)) := ∅,
  let Bm (m : ℕ) : set (euclidean_space ℝ (fin n)) := {x : euclidean_space ℝ (fin n) | ∃ i : fin n, x.val i ≤ m},
  let Bmbar (m : ℕ) : set (euclidean_space ℝ (fin n)) := {x : euclidean_space ℝ (fin n) | ∃ i : fin n, x.val i ≤ m + 1},
  have hBm : ∀ m : ℕ, is_open Bm m, from by auto [is_open_ball],
  have hBmbar : ∀ m : ℕ, is_compact Bmbar m, from by auto [is_compact_ball],
  have hBmbar1 : ∀ m : ℕ, is_closed Bmbar m, from by auto [is_closed_ball],
  have hBmbar2 : ∀ m : ℕ, is_open (Bmbar m), from by auto [is_open_ball],
  have hBmbar3 : ∀ m : ℕ, Bmbar m ⊆ Bmbar (m+1), from by auto [ball_subset_ball],

  have hB0 : ∀ x : euclidean_space ℝ (fin n), x ∉ B0, from by auto [not_mem_empty],
  have hBm1 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i ≤ m, from by auto [mem_ball],
  have hBm2 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 1, from by auto [mem_ball],
  have hBm3 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 2, from by auto [mem_ball],
  have hBm4 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 3, from by auto [mem_ball],
  have hBm5 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 4, from by auto [mem_ball],
  have hBm6 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 5, from by auto [mem_ball],
  have hBm7 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 6, from by auto [mem_ball],
  have hBm8 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 7, from by auto [mem_ball],
  have hBm9 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 8, from by auto [mem_ball],
  have hBm10 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 9, from by auto [mem_ball],
  have hBm11 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 10, from by auto [mem_ball],
  have hBm12 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 11, from by auto [mem_ball],
  have hBm13 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 12, from by auto [mem_ball],
  have hBm14 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 13, from by auto [mem_ball],
  have hBm15 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 14, from by auto [mem_ball],
  have hBm16 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 15, from by auto [mem_ball],
  have hBm17 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 16, from by auto [mem_ball],
  have hBm18 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 17, from by auto [mem_ball],
  have hBm19 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 18, from by auto [mem_ball],
  have hBm20 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 19, from by auto [mem_ball],
  have hBm21 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 20, from by auto [mem_ball],
  have hBm22 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 21, from by auto [mem_ball],
  have hBm23 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 22, from by auto [mem_ball],
  have hBm24 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m + 23, from by auto [mem_ball],
  have hBm25 : ∀ (m : ℕ) (x : euclidean_space ℝ (fin n)), x ∈ Bm m → ∃ i : fin n, x.val i < m
end --Needs more than 2000 tokens!

--OUTPUT 4
theorem ℝn_paracompact (n : ℕ) : paracompact_space (euclidean_space ℝ (fin n)) :=
begin
  assume A : set (euclidean_space ℝ (fin n)),
  assume hA : is_open A,
  assume hA_cover : A ⊆ ⋃₀ A,
  have h1 : ∀ x : euclidean_space ℝ (fin n), ∃ m : ℕ, ∀ n : ℕ, n < m → (∃ (B : set (euclidean_space ℝ (fin n))), B ∈ A ∧ B ∩ (ball x m) ≠ ∅) → (∃ (C : set (euclidean_space ℝ (fin n))), C ∈ A ∧ C ∩ (ball x n) ≠ ∅), from
    begin
      assume x : euclidean_space ℝ (fin n),
      have h1_1 : ∃ m : ℕ, ∀ n : ℕ, n < m → (∃ (B : set (euclidean_space ℝ (fin n))), B ∈ A ∧ B ∩ (ball x m) ≠ ∅), from
        begin
          have h1_1_1 : ∃ m : ℕ, ∀ n : ℕ, n < m → (∃ (B : set (euclidean_space ℝ (fin n))), B ∈ A ∧ B ∩ (ball x m) ≠ ∅) ∨ (∀ (B : set (euclidean_space ℝ (fin n))), B ∈ A → B ∩ (ball x m) = ∅), from
            begin
              have h1_1_1_1 : ∀ (m : ℕ), ∃ (B : set (euclidean_space ℝ (fin n))), B ∈ A ∧ B ∩ (ball x m) ≠ ∅ ∨ (∀ (B : set (euclidean_space ℝ (fin n))), B ∈ A → B ∩ (ball x m) = ∅), from
                begin
                  assume m : ℕ,
                  have h1_1_1_1_1 : ∃ (B : set (euclidean_space ℝ (fin n))), B ∈ A ∧ B ∩ (ball x m) ≠ ∅ ∨ (∀ (B : set (euclidean_space ℝ (fin n))), B ∈ A → B ∩ (ball x m) = ∅), from
                    begin
                      have h1_1_1_1_1_1 : ∃ (B : set (euclidean_space ℝ (fin n))), B ∈ A ∧ B ∩ (ball x m) ≠ ∅ ∨ (∀ (B : set (euclidean_space ℝ (fin n))), B ∈ A → B ∩ (ball x m) = ∅), from
                        begin
                          assume B : set (euclidean_space ℝ (fin n)),
                          assume hB : B ∈ A,
                          have h1_1_1_1_1_1_1 : B ∩ (ball x m) ≠ ∅ ∨ B ∩ (ball x m) = ∅, from by auto [set.eq_empty_iff_forall_not_mem],
                          show B ∈ A ∧ B ∩ (ball x m) ≠ ∅ ∨ (∀ (B : set (euclidean_space ℝ (fin n))), B ∈ A → B ∩ (ball x m) = ∅), from by auto [h1_1_1_1_1_1_1],
                        end,
                      show ∃ (B : set (euclidean_space ℝ (fin n))), B ∈ A ∧ B ∩ (ball x m) ≠ ∅ ∨ (∀ (B : set (euclidean_space ℝ (fin n))), B ∈ A → B ∩ (ball x m) = ∅), from by auto [h1_1_1_1_1_1],
                    end,
                  show ∃ (B : set (euclidean_space ℝ (fin n))), B ∈ A ∧ B ∩ (ball x m) ≠ ∅ ∨ (∀ (B : set (euclidean_space ℝ (fin n))), B ∈ A → B ∩ (ball x m) = ∅), from by auto [h1_1_1_1_1],
                end,
              show ∃ m : ℕ, ∀ n : ℕ, n < m → (∃ (B : set (euclidean_space ℝ (fin n))), B ∈ A ∧ B ∩ (ball x m) ≠ ∅) ∨ (∀ (B : set (euclidean_space ℝ (fin n))), B ∈ A → B ∩ (ball x m) = ∅), from by auto [h1_1_1_1],
            end,
          have h1_1_2 : ∃ m : ℕ, ∀ n : ℕ, n < m → (∃ (B : set (euclidean_space ℝ (fin n))), B ∈ A ∧ B ∩ (ball x m) ≠ ∅), from
            begin
              have h1_1_2_1 : ∃ m : ℕ, ∀ n : ℕ, n < m → (∃ (B : set (euclidean_space ℝ (fin n))), B ∈ A ∧ B ∩ (ball x m) ≠ ∅) ∨ (∀ (B : set (euclidean_space ℝ (fin n))), B ∈ A → B ∩ (ball x m) = ∅), from by auto [h1_1_1],
              have h1_1_2_2 : ∃ m : ℕ, ∀ n : ℕ, n < m → (∃ (B : set (euclidean_space ℝ (fin n))), B ∈ A ∧ B ∩ (ball x m) ≠ ∅), from
                begin
                  assume m : ℕ,
                  assume hm : ∀ n : ℕ, n < m → (∃ (B : set (euclidean_space ℝ (fin n))), B ∈ A ∧ B ∩ (ball x m) ≠ ∅) ∨ (∀ (B : set (euclidean_space ℝ (fin n))), B ∈ A → B ∩ (ball x m) = ∅),
                  have h1_1_2_2_1 : (∃ (B : set (euclidean_space ℝ (fin n))), B ∈ A ∧ B ∩ (ball x m) ≠ ∅) ∨ (∀ (B : set (euclidean_space ℝ (fin n))), B ∈ A → B ∩ (ball x m) = ∅), from by auto [hm],
                  have h1_1_2_2_2 : (∃ (B : set (euclidean_space ℝ (fin n))), B ∈ A ∧ B ∩ (ball x m) ≠ ∅), from by auto [h1_1_2_2_1],
                  show (∃ (B : set (euclidean_space ℝ (fin n))), B ∈ A ∧ B ∩ (ball x m) ≠ ∅) ∨ (∀ (B : set (euclidean_space ℝ (fin n))), B ∈ A → B ∩ (ball x m) = ∅), from by auto [h1_1_2_2_2],
                end,
              show ∃ m : ℕ, ∀ n : ℕ, n < m → (∃ (B : set (euclidean_space ℝ (fin n))), B ∈ A ∧ B ∩ (ball x m) ≠ ∅), from by auto [h1_1_2_2],
            end,
          show ∃ m : ℕ, ∀ n : ℕ, n < m → (∃ (B : set (euclidean_space ℝ (fin n))
end --Needs more than 2000 tokens!

--OUTPUT 5
theorem ℝn_paracompact (n : ℕ) : paracompact_space (euclidean_space ℝ (fin n)) :=
begin
  assume A : set (euclidean_space ℝ (fin n)),
  assume h1 : is_open A,
  assume h2 : ⋃₀ A = univ,

  have h3 : ∀ (m : ℕ), (∃ (C : set (euclidean_space ℝ (fin n))), is_open C ∧ (∀ (x : euclidean_space ℝ (fin n)), x ∈ C → ∃ (a : euclidean_space ℝ (fin n)) (b : euclidean_space ℝ (fin n)), a ∈ A ∧ b ∈ A ∧ x ∈ b ∧ b ⊆ a)) ∧ (∀ (x : euclidean_space ℝ (fin n)), x ∈ C → ∃ (a : euclidean_space ℝ (fin n)) (b : euclidean_space ℝ (fin n)), a ∈ A ∧ b ∈ A ∧ x ∈ b ∧ b ⊆ a) ∧ is_open C ∧ (∀ (x : euclidean_space ℝ (fin n)), x ∈ C → ∃ (a : euclidean_space ℝ (fin n)) (b : euclidean_space ℝ (fin n)), a ∈ A ∧ b ∈ A ∧ x ∈ b ∧ b ⊆ a),
  {
    assume m : ℕ,
    have h4 : ∃ (C : set (euclidean_space ℝ (fin n))), is_open C ∧ (∀ (x : euclidean_space ℝ (fin n)), x ∈ C → ∃ (a : euclidean_space ℝ (fin n)) (b : euclidean_space ℝ (fin n)), a ∈ A ∧ b ∈ A ∧ x ∈ b ∧ b ⊆ a), from by auto [ball, is_open_ball, h1],
    show (∃ (C : set (euclidean_space ℝ (fin n))), is_open C ∧ (∀ (x : euclidean_space ℝ (fin n)), x ∈ C → ∃ (a : euclidean_space ℝ (fin n)) (b : euclidean_space ℝ (fin n)), a ∈ A ∧ b ∈ A ∧ x ∈ b ∧ b ⊆ a)) ∧ (∀ (x : euclidean_space ℝ (fin n)), x ∈ C → ∃ (a : euclidean_space ℝ (fin n)) (b : euclidean_space ℝ (fin n)), a ∈ A ∧ b ∈ A ∧ x ∈ b ∧ b ⊆ a) ∧ is_open C ∧ (∀ (x : euclidean_space ℝ (fin n)), x ∈ C → ∃ (a : euclidean_space ℝ (fin n)) (b : euclidean_space ℝ (fin n)), a ∈ A ∧ b ∈ A ∧ x ∈ b ∧ b ⊆ a), from by auto [h4],
  },

  have h5 : ∀ (m : ℕ), ∃ (C : set (euclidean_space ℝ (fin n))), is_open C ∧ (∀ (x : euclidean_space ℝ (fin n)), x ∈ C → ∃ (a : euclidean_space ℝ (fin n)) (b : euclidean_space ℝ (fin n)), a ∈ A ∧ b ∈ A ∧ x ∈ b ∧ b ⊆ a), from by auto [h3],
  have h6 : ∀ (m : ℕ), ∃ (C : set (euclidean_space ℝ (fin n))), is_open C ∧ (∀ (x : euclidean_space ℝ (fin n)), x ∈ C → ∃ (a : euclidean_space ℝ (fin n)) (b : euclidean_space ℝ (fin n)), a ∈ A ∧ b ∈ A ∧ x ∈ b ∧ b ⊆ a) ∧ is_open C ∧ (∀ (x : euclidean_space ℝ (fin n)), x ∈ C → ∃ (a : euclidean_space ℝ (fin n)) (b : euclidean_space ℝ (fin n)), a ∈ A ∧ b ∈ A ∧ x ∈ b ∧ b ⊆ a), from by auto [h3],
  have h7 : ∀ (m : ℕ), ∃ (C : set (euclidean_space ℝ (fin n))), is_open C ∧ (∀ (x : euclidean_space ℝ (fin n)), x ∈ C → ∃ (a : euclidean_space ℝ (fin n)) (b : euclidean_space ℝ (fin n)), a ∈ A ∧ b ∈ A ∧ x ∈ b ∧ b ⊆ a) ∧ is_open C, from by auto [h6],
  have h8 : ∀ (m : ℕ), ∃ (C : set (euclidean_space ℝ (fin n))), is_open C ∧ (∀ (x : euclidean_space ℝ (fin n)), x ∈ C → ∃ (a : euclidean_space ℝ (fin n)) (b : euclidean_space ℝ (fin n)), a ∈ A ∧ b ∈ A ∧ x ∈ b ∧ b ⊆ a), from by auto [h7],

  have h9 : ∀ (m : ℕ), ∃ (C : set (euclidean_space ℝ (fin n))), is_open C ∧ (∀ (x : euclidean_space ℝ (fin n)), x ∈ C → ∃ (a : euclidean_space ℝ (fin n)) (b : euclidean_space ℝ (fin n)), a ∈ A ∧ b ∈ A ∧ x ∈ b ∧ b ⊆ a) ∧ is_open C ∧ (∀ (x : euclidean_space ℝ (fin n)), x ∈ C → ∃ (a : euclidean_space ℝ (fin n)) (b : euclidean_space ℝ (fin n)), a ∈ A ∧ b ∈ A ∧ x ∈ b ∧ b ⊆ a), from by auto [h6],
  have h10 : ∀ (m : ℕ), ∃ (C : set (euclidean_space ℝ (fin n))), is_open C ∧ (∀ (x : euclidean_space ℝ (fin n)), x ∈ C → ∃ (a : euclidean_space ℝ (fin n)) (b : euclidean_space ℝ (fin n)), a ∈ A ∧ b ∈ A ∧ x ∈ b ∧ b ⊆ a) ∧ is_open C, from by auto [h9],

  have h11 : ∀ (m : ℕ), ∃ (C : set (euclidean_space ℝ (fin n))), is_open C ∧ (∀ (x : euclidean_space ℝ (fin n)), x ∈ C → ∃ (a : euclidean_space ℝ (fin n)) (b : euclidean_space ℝ (fin n)), a ∈ A ∧ b ∈ A ∧ x ∈ b ∧ b ⊆ a), from by auto [h10],
  have h12 : ∀ (m : ℕ), ∃ (C : set (euclidean_space ℝ (fin n))), is_open C ∧ (∀ (x : euclidean_space ℝ (fin n)), x ∈ C → ∃ (a : euclidean_space ℝ (fin n)) (b : euclidean_space ℝ (fin n)), a
end --Needs more than 2000 tokens!

--OUTPUT 6
theorem ℝn_paracompact (n : ℕ) : paracompact_space (euclidean_space ℝ (fin n)) :=
begin
  assume (A : set (euclidean_space ℝ (fin n))) (hA : open_cover A),
  have h1 : ∀ m : ℕ, (∃ (U : set (euclidean_space ℝ (fin n))) (hU : U ∈ A), ∀ x : euclidean_space ℝ (fin n), x ∈ U → (∃ (m : ℕ) (h1 : m ≤ n) (h2 : ∀ (i : fin n), (abs (x i)) ≤ m)) ∧ (∀ (i : fin n), (abs (x i)) ≤ m + 1)) → (∃ (C : set (euclidean_space ℝ (fin n))) (hC : C ⊆ A), ∀ x : euclidean_space ℝ (fin n), x ∈ C → (∃ (m : ℕ) (h1 : m ≤ n) (h2 : ∀ (i : fin n), (abs (x i)) ≤ m)) ∧ (∀ (i : fin n), (abs (x i)) ≤ m + 1))),
  {
    assume (m : ℕ),
    assume (h1 : ∃ (U : set (euclidean_space ℝ (fin n))) (hU : U ∈ A), ∀ x : euclidean_space ℝ (fin n), x ∈ U → (∃ (m : ℕ) (h1 : m ≤ n) (h2 : ∀ (i : fin n), (abs (x i)) ≤ m)) ∧ (∀ (i : fin n), (abs (x i)) ≤ m + 1)),
    have h2 : ∃ (C : set (euclidean_space ℝ (fin n))) (hC : C ⊆ A), ∀ x : euclidean_space ℝ (fin n), x ∈ C → (∃ (m : ℕ) (h1 : m ≤ n) (h2 : ∀ (i : fin n), (abs (x i)) ≤ m)) ∧ (∀ (i : fin n), (abs (x i)) ≤ m + 1)),
    {
      have h3 : ∃ (U : set (euclidean_space ℝ (fin n))) (hU : U ∈ A), ∀ x : euclidean_space ℝ (fin n), x ∈ U → (∃ (m : ℕ) (h1 : m ≤ n) (h2 : ∀ (i : fin n), (abs (x i)) ≤ m)) ∧ (∀ (i : fin n), (abs (x i)) ≤ m + 1)), from h1,
      have h4 : ∃ (U : set (euclidean_space ℝ (fin n))) (hU : U ∈ A), ∀ x : euclidean_space ℝ (fin n), x ∈ U → (∃ (m : ℕ) (h1 : m ≤ n) (h2 : ∀ (i : fin n), (abs (x i)) ≤ m)) ∧ (∀ (i : fin n), (abs (x i)) ≤ m + 1)), from h3,
      have h5 : ∃ (U : set (euclidean_space ℝ (fin n))) (hU : U ∈ A), ∀ x : euclidean_space ℝ (fin n), x ∈ U → (∃ (m : ℕ) (h1 : m ≤ n) (h2 : ∀ (i : fin n), (abs (x i)) ≤ m)) ∧ (∀ (i : fin n), (abs (x i)) ≤ m + 1)), from h4,
      have h6 : ∃ (U : set (euclidean_space ℝ (fin n))) (hU : U ∈ A), ∀ x : euclidean_space ℝ (fin n), x ∈ U → (∃ (m : ℕ) (h1 : m ≤ n) (h2 : ∀ (i : fin n), (abs (x i)) ≤ m)) ∧ (∀ (i : fin n), (abs (x i)) ≤ m + 1)), from h5,
      have h7 : ∃ (U : set (euclidean_space ℝ (fin n))) (hU : U ∈ A), ∀ x : euclidean_space ℝ (fin n), x ∈ U → (∃ (m : ℕ) (h1 : m ≤ n) (h2 : ∀ (i : fin n), (abs (x i)) ≤ m)) ∧ (∀ (i : fin n), (abs (x i)) ≤ m + 1)), from h6,
      have h8 : ∃ (U : set (euclidean_space ℝ (fin n))) (hU : U ∈ A), ∀ x : euclidean_space ℝ (fin n), x ∈ U → (∃ (m : ℕ) (h1 : m ≤ n) (h2 : ∀ (i : fin n), (abs (x i)) ≤ m)) ∧ (∀ (i : fin n), (abs (x i)) ≤ m + 1)), from h7,
      have h9 : ∃ (U : set (euclidean_space ℝ (fin n))) (hU : U ∈ A), ∀ x : euclidean_space ℝ (fin n), x ∈ U → (∃ (m : ℕ) (h1 : m ≤ n) (h2 : ∀ (i : fin n), (abs (x i)) ≤ m)) ∧ (∀ (i : fin n), (abs (x i)) ≤ m + 1)), from h8,
      have h10 : ∃ (U : set (euclidean_space ℝ (fin n))) (hU : U ∈ A), ∀ x : euclidean_space ℝ (fin n), x ∈ U → (∃ (m : ℕ) (h1 : m ≤ n) (h2 : ∀ (i : fin n), (abs (x i)) ≤ m)) ∧ (∀ (i : fin n), (abs (x i)) ≤ m + 1)), from h9,
      have h11 : ∃ (U : set (euclidean_space ℝ (fin n))) (hU : U ∈ A), ∀ x : euclidean_space ℝ (fin n), x ∈ U → (∃ (m : ℕ) (h1 : m ≤ n) (h2 : ∀ (i : fin n), (abs (x i)) ≤ m)) ∧ (∀ (i : fin n), (abs (x i)) ≤ m + 1)), from h10,
      have h12 : ∃ (U : set (euclidean_space ℝ (fin n))) (hU : U ∈ A), ∀ x : euclidean_space ℝ (fin n), x ∈ U → (∃ (m : ℕ) (h1 : m ≤ n) (h2 : ∀ (i : fin n), (abs (x i)) ≤ m)) ∧ (∀ (i : fin n), (abs (x i)) ≤ m + 1)), from h11,
      have h13 : ∃ (U : set (euclidean_space ℝ (fin n))) (hU : U ∈ A), ∀ x : euclidean_space ℝ (fin n), x ∈ U → (∃ (m : ℕ) (h1 : m ≤ n) (h2 : ∀ (i : fin n), (abs (x i)) ≤ m)) ∧ (∀ (i : fin n), (abs (x i)) ≤ m + 1)), from h12,
      have h14 : ∃ (U : set (euclidean_space ℝ (fin n))) (hU : U ∈ A), ∀ x : euclidean_space ℝ (fin n), x ∈ U → (∃ (m : ℕ) (h1 : m ≤ n) (h2 : ∀ (i : fin n), (abs (x i)) ≤ m)) ∧ (∀ (i : fin n), (abs (x i)) ≤ m + 1)), from h13,
      have h15 :
end --Needs more than 2000 tokens!

/- FEW SHOT PROMPTS TO CODEX(START)
/--`theorem`
Power Set is Closed under Intersection
Let $S$ be a set.

Let $\powerset S$ be the power set of $S$.

Then:
:$\forall A, B \in \powerset S: A \cap B \in \powerset S$
`proof`
Let $A, B \in \powerset S$.

Then by the definition of power set, $A \subseteq S$ and $B \subseteq S$.

From Intersection is Subset we have that $A \cap B \subseteq A$.

It follows from Subset Relation is Transitive that $A \cap B \subseteq S$.

Thus $A \cap B \in \powerset S$ and closure is proved.
{{qed}}
-/
theorem power_set_intersection_closed {α : Type*} (S : set α) : ∀ A B ∈ 𝒫 S, (A ∩ B) ∈ 𝒫 S :=
begin
  assume (A : set α) (hA : A ∈ 𝒫 S) (B : set α) (hB : B ∈ 𝒫 S),
  have h1 : (A ⊆ S) ∧ (B ⊆ S), from by auto [set.subset_of_mem_powerset, set.subset_of_mem_powerset],
  have h2 : (A ∩ B) ⊆ A, from by auto [set.inter_subset_left],
  have h3 : (A ∩ B) ⊆ S, from by auto [set.subset.trans],
  show (A ∩ B) ∈  𝒫 S, from by auto [set.mem_powerset],
end

/--`theorem`
Square of Sum
 :$\forall x, y \in \R: \paren {x + y}^2 = x^2 + 2 x y + y^2$
`proof`
Follows from the distribution of multiplication over addition:

{{begin-eqn}}
{{eqn | l = \left({x + y}\right)^2
      | r = \left({x + y}\right) \cdot \left({x + y}\right)
}}
{{eqn | r = x \cdot \left({x + y}\right) + y \cdot \left({x + y}\right)
      | c = Real Multiplication Distributes over Addition
}}
{{eqn | r = x \cdot x + x \cdot y + y \cdot x + y \cdot y
      | c = Real Multiplication Distributes over Addition
}}
{{eqn | r = x^2 + 2xy + y^2
      | c =
}}
{{end-eqn}}
{{qed}}
-/
theorem square_of_sum (x y : ℝ) : (x + y)^2 = (x^2 + 2*x*y + y^2) :=
begin
  calc (x + y)^2 = (x+y)*(x+y) : by auto [sq]
  ... = x*(x+y) + y*(x+y) : by auto [add_mul]
  ... = x*x + x*y + y*x + y*y : by auto [mul_comm, add_mul] using [ring]
  ... = x^2 + 2*x*y + y^2 : by auto [sq, mul_comm] using [ring]
end

/--`theorem`
Identity of Group is Unique
Let $\struct {G, \circ}$ be a group. Then there is a unique identity element $e \in G$.
`proof`
From Group has Latin Square Property, there exists a unique $x \in G$ such that:
:$a x = b$

and there exists a unique $y \in G$ such that:
:$y a = b$

Setting $b = a$, this becomes:

There exists a unique $x \in G$ such that:
:$a x = a$

and there exists a unique $y \in G$ such that:
:$y a = a$

These $x$ and $y$ are both $e$, by definition of identity element.
{{qed}}
-/
theorem group_identity_unique {G : Type*} [group G] : ∃! e : G, ∀ a : G, e * a = a ∧ a * e = a :=
begin
  have h1 : ∀ a b : G, ∃! x : G, a * x = b, from by auto using [use (a⁻¹ * b)],
  have h2 : ∀ a b : G, ∃! y : G, y * a = b, from by auto using [use b * a⁻¹],

  have h3 : ∀ a : G, ∃! x : G, a * x = a, from by auto [h1],
  have h4 : ∀ a : G, ∃! y : G, y * a = a, from by auto [h2],

  have h5 : ∀ a : G, classical.some (h3 a).exists = (1 : G), from by auto [exists_unique.unique, h3, classical.some_spec, exists_unique.exists, mul_one],
  have h6 : ∀ a : G, classical.some (h4 a).exists = (1 : G), from by auto [exists_unique.unique, h4, classical.some_spec, exists_unique.exists, one_mul],

  show ∃! e : G, ∀ a : G, e * a = a ∧ a * e = a, from by auto [h3, h4, exists_unique.unique, classical.some_spec, exists_unique.exists] using [use (1 : G)],
end

/--`theorem`
\mathbb{R}^n is paracompact
$\mathbb{R}^n$ is paracompact for all $n$.
`proof`
Let $\mathcal{A}$ be an open covering of $\mathbb{R}^n$. We now construct a locally finite open refinement $\mathcal{C}$ of $\mathcal{A}$ that covers $\mathbb{R}^n$. First, we define a collection of pen balls. Let $B_0 = \phi$, and for each $n \in \mathbb{N}$, let $B_m$ denote the ball of radius $m$
centered at 0. Given $m$, set $\Bar{B_m}$ is compact in $\mathbb{R}^n$ by the Heine-Borel theorem, so choose finitely many elements of $\mathcal{A}$ that cover $\Bar{B_m}$ and intersect each one with the open set $\mathbb{R}^n \setminus \Bar{B_{m - 1}}$, and let $\mathcal{C}_{m}$ denote this collection of open sets (each an open subset of an element of $\mathcal{A}$). So $\mathcal{C} = \bigcup_{m = 0}^{\infty} \mathcal{C}_m$ is an open refinement of $\mathcal{A}$. Note that $\mathcal{C}$ covers $\mathbb{R}^n$ since for any $x \in \mathbb{R}^n$, there is a smallest $m \in \mathbb{N}$ such that $x \in \Bar{B_{m}}$ (namely, some $m$ where $\rVert x \lVert \leq m \leq \rVert x \lVert + 1$), and so $x$ is an element of $\mathcal{C}_m$. Now collection $\mathcal{C}$ is locally finite since for given $x \in \mathbb{R}^n$, neighborhood $B_m$ intersects only finitely many elements of $\mathcal{C}$, namely those elements in collection $\mathcal{C}_1 \cup \mathcal{C}_2 \cup \cdots \mathcal{C}_m$. So $\mathcal{C}$ is a locally finite open refinement of $\mathcal{A}$ that covers $\mathbb{R}^n$, hence $\mathbb{R}^n$ is paracompact.

QED
-/
theorem  ℝn_paracompact (n : ℕ) : paracompact_space (euclidean_space ℝ (fin n)) :=
FEW SHOT PROMPTS TO CODEX(END)-/


import mario_sheaf -- Mario's gist

universes u v

open lattice

variables {α : Type u} [semilattice_inf α] (U : α)

namespace semilattice_inf.opens

def inf {α : Type u} [semilattice_inf α] (U : α) ( a b : {V // V <= U}) : {V // V <= U} :=
⟨a.val ⊓ b.val, le_trans inf_le_left a.property⟩

instance has_inf {α : Type u} [semilattice_inf α] (U : α) :
  has_inf {V // V ≤ U} := ⟨inf U⟩

instance {α : Type u} [semilattice_inf α] (U : α) :
  semilattice_inf {V // V ≤ U} :=
{ inf_le_left := λ a b, inf_le_left,
  inf_le_right := λ a b, inf_le_right,
  le_inf := λ a b c, le_inf}

def presheaf_on_opens (U : α) := presheaf {V // V ≤ U}

--#print notation →⊓

--#where
-- Is this a thing?
/-- semilattice_inf.opens.res_subset -/
def res_subset (F : presheaf_on_opens U) (V : α) (HVU : V ≤ U) : presheaf_on_opens V :=
presheaf.comap ({ to_fun := λ W, (⟨W.val, le_trans W.property HVU⟩ : {V // V ≤ U}),--⟨W.val,begin sorry end⟩,
  mono := λ V W H, H,
  map_inf' := λ W X, rfl}) F

structure morphism (F : presheaf_on_opens U) (G : presheaf_on_opens U) :=
(map : Π (V : {V // V ≤ U}), F.F V → G.F V)
(commutes : ∀ (V W : {V // V ≤ U}) (HWV : W ≤ V) (x),
  map W (F.res V W HWV x) = G.res V W HWV (map V x))

namespace morphism

definition commutes' (F : presheaf_on_opens U) (G : presheaf_on_opens U)
  (f : morphism U F G) :
∀ (V W : {V // V ≤ U}) (HWV : W ≤ V) (x : F.F V),
  f.map W ((F.res V W HWV) x) = G.res V W HWV ((f.map V) x)
:= begin intros V W HVW, funext x, apply f.commutes end

def commutes'' (F : presheaf_on_opens U) (G : presheaf_on_opens U)
  (f : morphism U F G) :
∀ (V W : {V // V ≤ U}) (HWV : W ≤ V),
  f.map W ∘ (F.res V W HWV) = G.res V W HWV ∘ (f.map V)
:= begin intros V W HVW, funext x, apply f.commutes end

protected def id (F : presheaf_on_opens U) : morphism U F F :=
{ map := λ V, id,
  commutes := λ V W HWV, by intros; refl}

def comp {F : presheaf_on_opens U} {G : presheaf_on_opens U}
  {H : presheaf_on_opens U}
  (η : morphism U G H) (ξ : morphism U F G) : morphism U F H :=
{ map := λ V x, η.map V (ξ.map V x),
  commutes := λ V W HWV, begin
    intro x,
  rw morphism.commutes' U F G ξ,
  rw morphism.commutes' U G H η,
  end}

@[extensionality] lemma ext {F : presheaf_on_opens U} {G : presheaf_on_opens U}
  {η ξ : morphism U F G}
  (H : ∀ V x, η.map V x = ξ.map V x) : η = ξ :=
by cases η; cases ξ; congr; ext; apply H

@[simp] lemma id_comp {F : presheaf_on_opens U} {G : presheaf_on_opens U}
  (η : morphism U F G) :
  comp U (morphism.id U G) η = η :=
begin
  ext x,
  refl,
end

@[simp] lemma comp_id {F : presheaf_on_opens U} {G : presheaf_on_opens U} (η : morphism U F G) :
  comp U η (morphism.id U F) = η :=
begin
  ext x,
  refl,
end

@[simp] lemma comp_assoc {F : presheaf_on_opens U} {G : presheaf_on_opens U}
  {H : presheaf_on_opens U} {I : presheaf_on_opens U}
  (η : morphism U H I) (ξ : morphism U G H) (χ : morphism U F G) :
  comp U (comp U η ξ) χ = comp U η (comp U ξ χ) :=
rfl

def res_subset {F : presheaf_on_opens U} {G : presheaf_on_opens U}
  (η : morphism U F G) (V : α) (HVU : V ≤ U) :
  morphism V (res_subset U F V HVU) (res_subset U G V HVU) :=
{ map := λ W, begin exact morphism.map η ⟨W.val, _⟩ end,
  commutes := λ S T, commutes η ⟨S.val, le_trans S.property HVU⟩
   ⟨T.val, le_trans T.property HVU⟩ }

@[simp] lemma comp_res_subset {F : presheaf_on_opens U} {G : presheaf_on_opens U} {H : presheaf_on_opens U}
  (η : morphism U G H) (ξ : morphism U F G) (V : α) (HVU : V ≤ U) :
  comp _ (res_subset _ η V HVU) (res_subset _ ξ V HVU)
  = res_subset _ (comp _ η ξ) V HVU :=
rfl

@[simp] lemma id_res_subset {F : presheaf_on_opens U} (V : α) (HVU : V ≤ U) :
  morphism.res_subset _ (morphism.id U F) V HVU
  = morphism.id V (semilattice_inf.opens.res_subset U F V HVU) :=
rfl

end morphism

/-- semilattice_inf.opens.equiv, equiv for sheaves on an "open subset" of α -/
structure equiv (F : presheaf_on_opens U) (G : presheaf_on_opens U) :=
(to_fun : morphism U F G)
(inv_fun : morphism U G F)
(left_inv : morphism.comp U inv_fun to_fun = morphism.id U F)
(right_inv : morphism.comp U to_fun inv_fun = morphism.id U G)

namespace equiv

def refl (F : presheaf_on_opens U) : equiv U F F :=
⟨morphism.id U F, morphism.id U F, rfl, rfl⟩

def symm {F : presheaf_on_opens U} {G : presheaf_on_opens U} (e : equiv U F G) : equiv U G F :=
⟨e.2, e.1, e.4, e.3⟩

def trans {F : presheaf_on_opens U} {G : presheaf_on_opens U} {H : presheaf_on_opens U}
  (e₁ : equiv U F G) (e₂ : equiv U G H) : equiv U F H :=
⟨morphism.comp U e₂.1 e₁.1, morphism.comp U e₁.2 e₂.2,
by rw [morphism.comp_assoc, ← morphism.comp_assoc U e₂.2, e₂.3, morphism.id_comp, e₁.3],
by rw [morphism.comp_assoc, ← morphism.comp_assoc U e₁.1, e₁.4, morphism.id_comp, e₂.4]⟩

-- up to here
#check @res_subset -- might be useful

--#check (@semilattice_inf.opens.equiv α _ U F G).to_fun
--.to_fun.commutes

def res_subset {F : presheaf_on_opens U} {G : presheaf_on_opens U} (e : equiv U F G)
  (V : α) (HVU : V ≤ U) : equiv V (res_subset U F V HVU) (res_subset U G V HVU) :=
{ to_fun := morphism.res_subset U e.1 V HVU,

--{ map := λ W x, begin exact e.to_fun.map ⟨W.val, _⟩ x end,
--    commutes := λ W1 W2 H21 x,
--    by
--      convert
--        e.to_fun.commutes
--          ⟨W1.val, le_trans W1.property HVU⟩
--          ⟨W2.val, le_trans W2.property HVU⟩
--          H21 x,
--  }
  inv_fun := morphism.res_subset _ e.2 V HVU,
--  { map := λ W x, begin exact e.inv_fun.map ⟨W.val, _⟩ x end,
--    commutes := λ W1 W2 H21 x,
--    by
--      convert
--        e.inv_fun.commutes
--          ⟨W1.val, le_trans W1.property HVU⟩
--          ⟨W2.val, le_trans W2.property HVU⟩
--          H21 x,
--  }
  left_inv := begin
    rw morphism.comp_res_subset U,
    rw e.3,
    rw morphism.id_res_subset
  end,
  right_inv := by rw [morphism.comp_res_subset, e.4, morphism.id_res_subset]}

end equiv

#exit

def glue {I : Type*} (S : I → α) (F : Π (i : I), presheaf_on_opens (S i))
  (φ : Π (i j : I),
    equiv ((S i) ⊓ (S j))
      (res_subset (S i) (F i) ((S i) ⊓ (S j)) inf_le_left)
      (res_subset (S j) (F j) ((S i) ⊓ (S j)) inf_le_right))
  (Hφ1 : ∀ i, φ i i = equiv.refl (S i ⊓ S i) (res_subset (S i) (F i) ((S i) ⊓ (S i)) inf_le_left))
  (Hφ2 : ∀ i j k,
    equiv.trans ((S i) ⊓ (S j) ⊓ (S k))
      (equiv.res_subset ((S i) ⊓ (S j)) (φ i j) ((S i) ⊓ (S j) ⊓ (S k)) (inf_le_left))
      (equiv.res_subset ((S j) ⊓ (S k)) (φ j k) ((S i) ⊓ (S j) ⊓ (S k))
        (show (S i) ⊓ (S j) ⊓ (S k) ≤ (S j) ⊓ (S k), from begin
        exact le_inf (le_trans (inf_le_left) (inf_le_right)) (inf_le_right)
        end))
       -- (le_inf (le_trans (inf_le_left)
       --(inf_le_right)) (inf_le_right))
     =
    equiv.res_subset ((S i) ⊓ (S k)) (φ i k) ((S i) ⊓ (S j) ⊓ (S k))
      (le_inf (le_trans (inf_le_left)
    (inf_le_left)) (le_trans inf_le_left inf_le_right))) :
  presheaf_on_opens (lattice.complete_lattice.supr S) :=
  { F := λ W, { f : Π i, (F i).eval ((S i) ∩ W) (set.inter_subset_left _ _) //
      ∀ i j, (φ i j).1.map ((S i) ∩ (S j) ∩ W) (set.inter_subset_left _ _)
        ((F i).res ((S i) ∩ W) _ _ (le_trans (set.inter_subset_left _ _) (set.inter_subset_left _ _))
          (set.subset_inter (le_trans (set.inter_subset_left _ _) (set.inter_subset_left _ _)) (set.inter_subset_right _ _))
          (f i)) =
        (F j).res ((S j) ∩ W) _ _ (le_trans (set.inter_subset_left _ _) (set.inter_subset_right _ _))
          (set.subset_inter (le_trans (set.inter_subset_left _ _) (set.inter_subset_right _ _)) (set.inter_subset_right _ _))
          (f j) },
    res := λ U V HUV f, ⟨λ i, (F i).res (S i ∩ U) _ (S i ∩ V) _ (set.inter_subset_inter_right _ HUV) (f.val i),
      begin
        intros i j,
        rw res_comp,
        rw res_comp,
        have answer := congr_arg
        (res (F j)
          (S i ∩ (S j) ∩ U) _
          (S i ∩ (S j) ∩ V) (le_trans (set.inter_subset_left _ _) (set.inter_subset_right _ _)) (set.inter_subset_inter_right _ HUV)
        )
        (f.property i j),
        rw res_comp at answer,
        rw ←answer,
        clear answer,
        convert (φ i j).to_fun.commutes
        (S i ∩ (S j) ∩ U) (set.inter_subset_left _ _)
        (S i ∩ (S j) ∩ V) (set.inter_subset_left _ _) (set.inter_subset_inter_right _ HUV)
        (
          (@sheaf_on_opens.res _ _ (S i ∩ U)
            (F i)
            (S i ∩ U) (by refl)
            (S i ∩ S j ∩ U) (set.inter_subset_inter_left _ (set.inter_subset_left _ _)) (set.inter_subset_inter_left _ (set.inter_subset_left _ _))
            (f.val i)
          )
        ) using 2,
        convert (F i).F.Hcomp' (S i ∩ U) (S i ∩ S j ∩ U) (S i ∩ S j ∩ V) _ _ (f.val i),
      end⟩,
    Hid := begin
      sorry
    end,
    Hcomp := sorry }

def universal_property_Kevin_wants (I : Type u) (S : I → α)
  (F : Π (i : I), presheaf_on_opens (S i))
  (φ : Π (i j : I),
    equiv ((S i) ⊓ (S j))
      (res_subset (S i) (F i) ((S i) ⊓ (S j)) inf_le_left)
      (res_subset (S j) (F j) ((S i) ⊓ (S j)) inf_le_right))
  (Hφ1 : ∀ i, φ i i = equiv.refl (S i ⊓ S i) (res_subset (S i) (F i) ((S i) ⊓ (S i)) inf_le_left))
  (Hφ2 : ∀ i j k,
    ((φ i j).res_subset ((S i) ∩ (S j) ∩ (S k)) (set.inter_subset_left _ _)).trans
      ((φ j k).res_subset ((S i) ∩ (S j) ∩ (S k)) (set.subset_inter (le_trans (set.inter_subset_left _ _) (set.inter_subset_right _ _)) (set.inter_subset_right _ _))) =
    (φ i k).res_subset ((S i) ∩ (S j) ∩ (S k)) (set.subset_inter (le_trans (set.inter_subset_left _ _) (set.inter_subset_left _ _)) (set.inter_subset_right _ _))) :
∀ i : I, equiv (res_subset (glue S F φ Hφ1 Hφ2) (S i) $ opens.subset_Union S i) (F i) := sorry

end semilattice_inf.opens