/-
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, Yury Kudryashov

! This file was ported from Lean 3 source module measure_theory.constructions.borel_space
! leanprover-community/mathlib commit fbde2f60a46865c85f49b4193175c6e339ff9020
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Analysis.Complex.Basic
import Mathbin.Analysis.NormedSpace.FiniteDimension
import Mathbin.MeasureTheory.Function.AeMeasurableSequence
import Mathbin.MeasureTheory.Group.Arithmetic
import Mathbin.MeasureTheory.Lattice
import Mathbin.MeasureTheory.Measure.OpenPos
import Mathbin.Topology.Algebra.Order.LiminfLimsup
import Mathbin.Topology.ContinuousFunction.Basic
import Mathbin.Topology.Instances.AddCircle
import Mathbin.Topology.Instances.Ereal
import Mathbin.Topology.GDelta
import Mathbin.Topology.Order.Lattice
import Mathbin.Topology.Semicontinuous
import Mathbin.Topology.MetricSpace.Metrizable

/-!
# Borel (measurable) space

## Main definitions

* `borel α` : the least `σ`-algebra that contains all open sets;
* `class borel_space` : a space with `topological_space` and `measurable_space` structures
  such that `‹measurable_space α› = borel α`;
* `class opens_measurable_space` : a space with `topological_space` and `measurable_space`
  structures such that all open sets are measurable; equivalently, `borel α ≤ ‹measurable_space α›`.
* `borel_space` instances on `empty`, `unit`, `bool`, `nat`, `int`, `rat`;
* `measurable` and `borel_space` instances on `ℝ`, `ℝ≥0`, `ℝ≥0∞`.

## Main statements

* `is_open.measurable_set`, `is_closed.measurable_set`: open and closed sets are measurable;
* `continuous.measurable` : a continuous function is measurable;
* `continuous.measurable2` : if `f : α → β` and `g : α → γ` are measurable and `op : β × γ → δ`
  is continuous, then `λ x, op (f x, g y)` is measurable;
* `measurable.add` etc : dot notation for arithmetic operations on `measurable` predicates,
  and similarly for `dist` and `edist`;
* `ae_measurable.add` : similar dot notation for almost everywhere measurable functions;
* `measurable.ennreal*` : special cases for arithmetic operations on `ℝ≥0∞`.
-/

noncomputable section

open Classical Set Filter MeasureTheory

open Classical BigOperators Topology NNReal ENNReal MeasureTheory

universe u v w x y

variable {α β γ γ₂ δ : Type _} {ι : Sort y} {s t u : Set α}

open MeasurableSpace TopologicalSpace

/-- `measurable_space` structure generated by `topological_space`. -/
def borel (α : Type u) [TopologicalSpace α] : MeasurableSpace α :=
  generateFrom { s : Set α | IsOpen s }
#align borel borel

theorem borel_eq_top_of_discrete [TopologicalSpace α] [DiscreteTopology α] : borel α = ⊤ :=
  top_le_iff.1 fun s hs => GenerateMeasurable.basic s (isOpen_discrete s)
#align borel_eq_top_of_discrete borel_eq_top_of_discrete

theorem borel_eq_top_of_countable [TopologicalSpace α] [T1Space α] [Countable α] : borel α = ⊤ :=
  by
  refine' top_le_iff.1 fun s hs => bUnion_of_singleton s ▸ _
  apply MeasurableSet.bunionᵢ s.to_countable
  intro x hx
  apply MeasurableSet.of_compl
  apply generate_measurable.basic
  exact is_closed_singleton.is_open_compl
#align borel_eq_top_of_countable borel_eq_top_of_countable

theorem borel_eq_generateFrom_of_subbasis {s : Set (Set α)} [t : TopologicalSpace α]
    [SecondCountableTopology α] (hs : t = generateFrom s) : borel α = generateFrom s :=
  le_antisymm
    (generateFrom_le fun u (hu : t.IsOpen u) =>
      by
      rw [hs] at hu
      induction hu
      case basic u hu => exact generate_measurable.basic u hu
      case univ => exact @MeasurableSet.univ α (generate_from s)
      case inter s₁ s₂ _ _ hs₁ hs₂ => exact @MeasurableSet.inter α (generate_from s) _ _ hs₁ hs₂
      case
        sUnion f hf ih =>
        rcases is_open_sUnion_countable f (by rwa [hs]) with ⟨v, hv, vf, vu⟩
        rw [← vu]
        exact @MeasurableSet.unionₛ α (generate_from s) _ hv fun x xv => ih _ (vf xv))
    (generateFrom_le fun u hu =>
      GenerateMeasurable.basic _ <| show t.IsOpen u by rw [hs] <;> exact generate_open.basic _ hu)
#align borel_eq_generate_from_of_subbasis borel_eq_generateFrom_of_subbasis

theorem TopologicalSpace.IsTopologicalBasis.borel_eq_generateFrom [TopologicalSpace α]
    [SecondCountableTopology α] {s : Set (Set α)} (hs : IsTopologicalBasis s) :
    borel α = generateFrom s :=
  borel_eq_generateFrom_of_subbasis hs.eq_generateFrom
#align topological_space.is_topological_basis.borel_eq_generate_from TopologicalSpace.IsTopologicalBasis.borel_eq_generateFrom

theorem isPiSystem_isOpen [TopologicalSpace α] : IsPiSystem (IsOpen : Set α → Prop) :=
  fun s hs t ht hst => IsOpen.inter hs ht
#align is_pi_system_is_open isPiSystem_isOpen

theorem borel_eq_generateFrom_isClosed [TopologicalSpace α] :
    borel α = generateFrom { s | IsClosed s } :=
  le_antisymm
    (generateFrom_le fun t ht =>
      @MeasurableSet.of_compl α _ (generateFrom { s | IsClosed s })
        (GenerateMeasurable.basic _ <| isClosed_compl_iff.2 ht))
    (generateFrom_le fun t ht =>
      @MeasurableSet.of_compl α _ (borel α) (GenerateMeasurable.basic _ <| isOpen_compl_iff.2 ht))
#align borel_eq_generate_from_is_closed borel_eq_generateFrom_isClosed

section OrderTopology

variable (α)

variable [TopologicalSpace α] [SecondCountableTopology α] [LinearOrder α] [OrderTopology α]

theorem borel_eq_generateFrom_Iio : borel α = generateFrom (range Iio) :=
  by
  refine' le_antisymm _ (generate_from_le _)
  · rw [borel_eq_generateFrom_of_subbasis (@OrderTopology.topology_eq_generate_intervals α _ _ _)]
    letI : MeasurableSpace α := MeasurableSpace.generateFrom (range Iio)
    have H : ∀ a : α, MeasurableSet (Iio a) := fun a => generate_measurable.basic _ ⟨_, rfl⟩
    refine' generate_from_le _
    rintro _ ⟨a, rfl | rfl⟩ <;> [skip, apply H]
    by_cases h : ∃ a', ∀ b, a < b ↔ a' ≤ b
    · rcases h with ⟨a', ha'⟩
      rw [(_ : Ioi a = Iio a'ᶜ)]
      · exact (H _).compl
      simp [Set.ext_iff, ha']
    · rcases is_open_Union_countable (fun a' : { a' : α // a < a' } => { b | a'.1 < b }) fun a' =>
          isOpen_lt' _ with ⟨v, ⟨hv⟩, vu⟩
      simp [Set.ext_iff] at vu
      have : Ioi a = ⋃ x : v, Iio x.1.1ᶜ :=
        by
        simp [Set.ext_iff]
        refine' fun x => ⟨fun ax => _, fun ⟨a', ⟨h, av⟩, ax⟩ => lt_of_lt_of_le h ax⟩
        rcases(vu x).2 _ with ⟨a', h₁, h₂⟩
        · exact ⟨a', h₁, le_of_lt h₂⟩
        refine' not_imp_comm.1 (fun h => _) h
        exact ⟨x, fun b => ⟨fun ab => le_of_not_lt fun h' => h ⟨b, ab, h'⟩, lt_of_lt_of_le ax⟩⟩
      rw [this]
      skip
      apply MeasurableSet.unionᵢ
      exact fun _ => (H _).compl
  · rw [forall_range_iff]
    intro a
    exact generate_measurable.basic _ isOpen_Iio
#align borel_eq_generate_from_Iio borel_eq_generateFrom_Iio

theorem borel_eq_generateFrom_Ioi : borel α = generateFrom (range Ioi) :=
  @borel_eq_generateFrom_Iio αᵒᵈ _ (by infer_instance : SecondCountableTopology α) _ _
#align borel_eq_generate_from_Ioi borel_eq_generateFrom_Ioi

end OrderTopology

theorem borel_comap {f : α → β} {t : TopologicalSpace β} :
    @borel α (t.induced f) = (@borel β t).comap f :=
  comap_generateFrom.symm
#align borel_comap borel_comap

theorem Continuous.borel_measurable [TopologicalSpace α] [TopologicalSpace β] {f : α → β}
    (hf : Continuous f) : @Measurable α β (borel α) (borel β) f :=
  Measurable.of_le_map <|
    generateFrom_le fun s hs => GenerateMeasurable.basic (f ⁻¹' s) (hs.Preimage hf)
#align continuous.borel_measurable Continuous.borel_measurable

/-- A space with `measurable_space` and `topological_space` structures such that
all open sets are measurable. -/
class OpensMeasurableSpace (α : Type _) [TopologicalSpace α] [h : MeasurableSpace α] : Prop where
  borel_le : borel α ≤ h
#align opens_measurable_space OpensMeasurableSpace

/-- A space with `measurable_space` and `topological_space` structures such that
the `σ`-algebra of measurable sets is exactly the `σ`-algebra generated by open sets. -/
class BorelSpace (α : Type _) [TopologicalSpace α] [MeasurableSpace α] : Prop where
  measurable_eq : ‹MeasurableSpace α› = borel α
#align borel_space BorelSpace

namespace Tactic

/-- Add instances `borel α : measurable_space α` and `⟨rfl⟩ : borel_space α`. -/
unsafe def add_borel_instance (α : expr) : tactic Unit := do
  let n1 ← get_unused_name "_inst"
  to_expr ``(borel $(α)) >>= pose n1
  reset_instance_cache
  let n2 ← get_unused_name "_inst"
  let v ← to_expr ``((BorelSpace.mk rfl : BorelSpace $(α)))
  note n2 none v
  reset_instance_cache
#align tactic.add_borel_instance tactic.add_borel_instance

-- failed to format: unknown constant 'term.pseudo.antiquot'
/--
      Given a type `α`, an assumption `i : measurable_space α`, and an instance `[borel_space α]`,
      replace `i` with `borel α`. -/
    unsafe
  def
    borel_to_refl
    ( α i : expr ) : tactic Unit
    :=
      do
        let n ← get_unused_name "h"
          to_expr ` `( $ ( i ) = borel $ ( α ) ) >>= assert n
          applyc `borel_space.measurable_eq
          unfreezing ( tactic.subst i )
          let n1 ← get_unused_name "_inst"
          to_expr ` `( borel $ ( α ) ) >>= pose n1
          reset_instance_cache
#align tactic.borel_to_refl tactic.borel_to_refl

/-- Given a type `α`, if there is an assumption `[i : measurable_space α]`, then try to prove
`[borel_space α]` and replace `i` with `borel α`. Otherwise, add instances
`borel α : measurable_space α` and `⟨rfl⟩ : borel_space α`. -/
unsafe def borelize (α : expr) : tactic Unit := do
  let i ← optional (to_expr ``(MeasurableSpace $(α)) >>= find_assumption)
  i (add_borel_instance α) (borel_to_refl α)
#align tactic.borelize tactic.borelize

namespace Interactive

/- ./././Mathport/Syntax/Translate/Tactic/Mathlib/Core.lean:38:34: unsupported: setup_tactic_parser -/
/-- The behaviour of `borelize α` depends on the existing assumptions on `α`.

- if `α` is a topological space with instances `[measurable_space α] [borel_space α]`, then
  `borelize α` replaces the former instance by `borel α`;
- otherwise, `borelize α` adds instances `borel α : measurable_space α` and `⟨rfl⟩ : borel_space α`.

Finally, `borelize [α, β, γ]` runs `borelize α, borelize β, borelize γ`.
-/
unsafe def borelize (ts : parse pexpr_list_or_texpr) : tactic Unit :=
  mapM' (fun t => to_expr t >>= tactic.borelize) ts
#align tactic.interactive.borelize tactic.interactive.borelize

add_tactic_doc
  { Name := "borelize"
    category := DocCategory.tactic
    declNames := [`tactic.interactive.borelize]
    tags := ["type class"] }

end Interactive

end Tactic

instance (priority := 100) OrderDual.opensMeasurableSpace {α : Type _} [TopologicalSpace α]
    [MeasurableSpace α] [h : OpensMeasurableSpace α] : OpensMeasurableSpace αᵒᵈ
    where borel_le := h.borel_le
#align order_dual.opens_measurable_space OrderDual.opensMeasurableSpace

instance (priority := 100) OrderDual.borelSpace {α : Type _} [TopologicalSpace α]
    [MeasurableSpace α] [h : BorelSpace α] : BorelSpace αᵒᵈ where measurable_eq := h.measurable_eq
#align order_dual.borel_space OrderDual.borelSpace

/-- In a `borel_space` all open sets are measurable. -/
instance (priority := 100) BorelSpace.opens_measurable {α : Type _} [TopologicalSpace α]
    [MeasurableSpace α] [BorelSpace α] : OpensMeasurableSpace α :=
  ⟨ge_of_eq <| BorelSpace.measurable_eq⟩
#align borel_space.opens_measurable BorelSpace.opens_measurable

instance Subtype.borelSpace {α : Type _} [TopologicalSpace α] [MeasurableSpace α]
    [hα : BorelSpace α] (s : Set α) : BorelSpace s :=
  ⟨by
    rw [hα.1, Subtype.measurableSpace, ← borel_comap]
    rfl⟩
#align subtype.borel_space Subtype.borelSpace

instance Subtype.opensMeasurableSpace {α : Type _} [TopologicalSpace α] [MeasurableSpace α]
    [h : OpensMeasurableSpace α] (s : Set α) : OpensMeasurableSpace s :=
  ⟨by
    rw [borel_comap]
    exact comap_mono h.1⟩
#align subtype.opens_measurable_space Subtype.opensMeasurableSpace

theorem MeasurableSet.induction_on_open [TopologicalSpace α] [MeasurableSpace α] [BorelSpace α]
    {C : Set α → Prop} (h_open : ∀ U, IsOpen U → C U)
    (h_compl : ∀ t, MeasurableSet t → C t → C (tᶜ))
    (h_union :
      ∀ f : ℕ → Set α,
        Pairwise (Disjoint on f) → (∀ i, MeasurableSet (f i)) → (∀ i, C (f i)) → C (⋃ i, f i)) :
    ∀ ⦃t⦄, MeasurableSet t → C t :=
  MeasurableSpace.induction_on_inter BorelSpace.measurable_eq isPiSystem_isOpen
    (h_open _ isOpen_empty) h_open h_compl h_union
#align measurable_set.induction_on_open MeasurableSet.induction_on_open

section

variable [TopologicalSpace α] [MeasurableSpace α] [OpensMeasurableSpace α] [TopologicalSpace β]
  [MeasurableSpace β] [OpensMeasurableSpace β] [TopologicalSpace γ] [MeasurableSpace γ]
  [BorelSpace γ] [TopologicalSpace γ₂] [MeasurableSpace γ₂] [BorelSpace γ₂] [MeasurableSpace δ]

theorem IsOpen.measurableSet (h : IsOpen s) : MeasurableSet s :=
  OpensMeasurableSpace.borel_le _ <| GenerateMeasurable.basic _ h
#align is_open.measurable_set IsOpen.measurableSet

@[measurability]
theorem measurableSet_interior : MeasurableSet (interior s) :=
  isOpen_interior.MeasurableSet
#align measurable_set_interior measurableSet_interior

theorem IsGδ.measurableSet (h : IsGδ s) : MeasurableSet s :=
  by
  rcases h with ⟨S, hSo, hSc, rfl⟩
  exact MeasurableSet.interₛ hSc fun t ht => (hSo t ht).MeasurableSet
#align is_Gδ.measurable_set IsGδ.measurableSet

theorem measurableSet_of_continuousAt {β} [EMetricSpace β] (f : α → β) :
    MeasurableSet { x | ContinuousAt f x } :=
  (isGδ_setOf_continuousAt f).MeasurableSet
#align measurable_set_of_continuous_at measurableSet_of_continuousAt

theorem IsClosed.measurableSet (h : IsClosed s) : MeasurableSet s :=
  h.isOpen_compl.MeasurableSet.ofCompl
#align is_closed.measurable_set IsClosed.measurableSet

theorem IsCompact.measurableSet [T2Space α] (h : IsCompact s) : MeasurableSet s :=
  h.IsClosed.MeasurableSet
#align is_compact.measurable_set IsCompact.measurableSet

@[measurability]
theorem measurableSet_closure : MeasurableSet (closure s) :=
  isClosed_closure.MeasurableSet
#align measurable_set_closure measurableSet_closure

theorem measurable_of_isOpen {f : δ → γ} (hf : ∀ s, IsOpen s → MeasurableSet (f ⁻¹' s)) :
    Measurable f := by
  rw [‹BorelSpace γ›.measurable_eq]
  exact measurable_generateFrom hf
#align measurable_of_is_open measurable_of_isOpen

theorem measurable_of_isClosed {f : δ → γ} (hf : ∀ s, IsClosed s → MeasurableSet (f ⁻¹' s)) :
    Measurable f := by
  apply measurable_of_isOpen; intro s hs
  rw [← MeasurableSet.compl_iff, ← preimage_compl]; apply hf; rw [isClosed_compl_iff]; exact hs
#align measurable_of_is_closed measurable_of_isClosed

theorem measurable_of_is_closed' {f : δ → γ}
    (hf : ∀ s, IsClosed s → s.Nonempty → s ≠ univ → MeasurableSet (f ⁻¹' s)) : Measurable f :=
  by
  apply measurable_of_isClosed; intro s hs
  cases' eq_empty_or_nonempty s with h1 h1; · simp [h1]
  by_cases h2 : s = univ; · simp [h2]
  exact hf s hs h1 h2
#align measurable_of_is_closed' measurable_of_is_closed'

instance nhds_isMeasurablyGenerated (a : α) : (𝓝 a).IsMeasurablyGenerated :=
  by
  rw [nhds, infᵢ_subtype']
  refine' @Filter.infᵢ_isMeasurablyGenerated _ _ _ _ fun i => _
  exact i.2.2.MeasurableSet.principal_isMeasurablyGenerated
#align nhds_is_measurably_generated nhds_isMeasurablyGenerated

/-- If `s` is a measurable set, then `𝓝[s] a` is a measurably generated filter for
each `a`. This cannot be an `instance` because it depends on a non-instance `hs : measurable_set s`.
-/
theorem MeasurableSet.nhdsWithin_isMeasurablyGenerated {s : Set α} (hs : MeasurableSet s) (a : α) :
    (𝓝[s] a).IsMeasurablyGenerated :=
  haveI := hs.principal_is_measurably_generated
  Filter.inf_isMeasurablyGenerated _ _
#align measurable_set.nhds_within_is_measurably_generated MeasurableSet.nhdsWithin_isMeasurablyGenerated

-- see Note [lower instance priority]
instance (priority := 100) OpensMeasurableSpace.to_measurableSingletonClass [T1Space α] :
    MeasurableSingletonClass α :=
  ⟨fun x => isClosed_singleton.MeasurableSet⟩
#align opens_measurable_space.to_measurable_singleton_class OpensMeasurableSpace.to_measurableSingletonClass

instance Pi.opensMeasurableSpace {ι : Type _} {π : ι → Type _} [Countable ι]
    [t' : ∀ i, TopologicalSpace (π i)] [∀ i, MeasurableSpace (π i)]
    [∀ i, SecondCountableTopology (π i)] [∀ i, OpensMeasurableSpace (π i)] :
    OpensMeasurableSpace (∀ i, π i) := by
  constructor
  have :
    Pi.topologicalSpace =
      generate_from
        { t |
          ∃ (s : ∀ a, Set (π a))(i : Finset ι),
            (∀ a ∈ i, s a ∈ countable_basis (π a)) ∧ t = pi (↑i) s } :=
    by rw [funext fun a => @eq_generate_from_countable_basis (π a) _ _, pi_generateFrom_eq]
  rw [borel_eq_generateFrom_of_subbasis this]
  apply generate_from_le
  rintro _ ⟨s, i, hi, rfl⟩
  refine' MeasurableSet.pi i.countable_to_set fun a ha => IsOpen.measurableSet _
  rw [eq_generate_from_countable_basis (π a)]
  exact generate_open.basic _ (hi a ha)
#align pi.opens_measurable_space Pi.opensMeasurableSpace

instance Prod.opensMeasurableSpace [SecondCountableTopology α] [SecondCountableTopology β] :
    OpensMeasurableSpace (α × β) := by
  constructor
  rw [((is_basis_countable_basis α).Prod (is_basis_countable_basis β)).borel_eq_generateFrom]
  apply generate_from_le
  rintro _ ⟨u, v, hu, hv, rfl⟩
  exact
    (is_open_of_mem_countable_basis hu).MeasurableSet.Prod
      (is_open_of_mem_countable_basis hv).MeasurableSet
#align prod.opens_measurable_space Prod.opensMeasurableSpace

variable {α' : Type _} [TopologicalSpace α'] [MeasurableSpace α']

theorem interior_ae_eq_of_null_frontier {μ : Measure α'} {s : Set α'} (h : μ (frontier s) = 0) :
    interior s =ᵐ[μ] s :=
  interior_subset.EventuallyLE.antisymm <| subset_closure.EventuallyLE.trans (ae_le_set.2 h)
#align interior_ae_eq_of_null_frontier interior_ae_eq_of_null_frontier

theorem measure_interior_of_null_frontier {μ : Measure α'} {s : Set α'} (h : μ (frontier s) = 0) :
    μ (interior s) = μ s :=
  measure_congr (interior_ae_eq_of_null_frontier h)
#align measure_interior_of_null_frontier measure_interior_of_null_frontier

theorem nullMeasurableSetOfNullFrontier {s : Set α} {μ : Measure α} (h : μ (frontier s) = 0) :
    NullMeasurableSet s μ :=
  ⟨interior s, isOpen_interior.MeasurableSet, (interior_ae_eq_of_null_frontier h).symm⟩
#align null_measurable_set_of_null_frontier nullMeasurableSetOfNullFrontier

theorem closure_ae_eq_of_null_frontier {μ : Measure α'} {s : Set α'} (h : μ (frontier s) = 0) :
    closure s =ᵐ[μ] s :=
  ((ae_le_set.2 h).trans interior_subset.EventuallyLE).antisymm <| subset_closure.EventuallyLE
#align closure_ae_eq_of_null_frontier closure_ae_eq_of_null_frontier

theorem measure_closure_of_null_frontier {μ : Measure α'} {s : Set α'} (h : μ (frontier s) = 0) :
    μ (closure s) = μ s :=
  measure_congr (closure_ae_eq_of_null_frontier h)
#align measure_closure_of_null_frontier measure_closure_of_null_frontier

section Preorder

variable [Preorder α] [OrderClosedTopology α] {a b x : α}

@[simp, measurability]
theorem measurableSet_Ici : MeasurableSet (Ici a) :=
  isClosed_Ici.MeasurableSet
#align measurable_set_Ici measurableSet_Ici

@[simp, measurability]
theorem measurableSet_Iic : MeasurableSet (Iic a) :=
  isClosed_Iic.MeasurableSet
#align measurable_set_Iic measurableSet_Iic

@[simp, measurability]
theorem measurableSet_Icc : MeasurableSet (Icc a b) :=
  isClosed_Icc.MeasurableSet
#align measurable_set_Icc measurableSet_Icc

instance nhdsWithin_Ici_isMeasurablyGenerated : (𝓝[Ici b] a).IsMeasurablyGenerated :=
  measurableSet_Ici.nhdsWithin_isMeasurablyGenerated _
#align nhds_within_Ici_is_measurably_generated nhdsWithin_Ici_isMeasurablyGenerated

instance nhdsWithin_Iic_isMeasurablyGenerated : (𝓝[Iic b] a).IsMeasurablyGenerated :=
  measurableSet_Iic.nhdsWithin_isMeasurablyGenerated _
#align nhds_within_Iic_is_measurably_generated nhdsWithin_Iic_isMeasurablyGenerated

instance nhdsWithin_Icc_isMeasurablyGenerated : IsMeasurablyGenerated (𝓝[Icc a b] x) :=
  by
  rw [← Ici_inter_Iic, nhdsWithin_inter]
  infer_instance
#align nhds_within_Icc_is_measurably_generated nhdsWithin_Icc_isMeasurablyGenerated

instance atTop_isMeasurablyGenerated : (Filter.atTop : Filter α).IsMeasurablyGenerated :=
  @Filter.infᵢ_isMeasurablyGenerated _ _ _ _ fun a =>
    (measurableSet_Ici : MeasurableSet (Ici a)).principal_isMeasurablyGenerated
#align at_top_is_measurably_generated atTop_isMeasurablyGenerated

instance atBot_isMeasurablyGenerated : (Filter.atBot : Filter α).IsMeasurablyGenerated :=
  @Filter.infᵢ_isMeasurablyGenerated _ _ _ _ fun a =>
    (measurableSet_Iic : MeasurableSet (Iic a)).principal_isMeasurablyGenerated
#align at_bot_is_measurably_generated atBot_isMeasurablyGenerated

end Preorder

section PartialOrder

variable [PartialOrder α] [OrderClosedTopology α] [SecondCountableTopology α] {a b : α}

@[measurability]
theorem measurableSet_le' : MeasurableSet { p : α × α | p.1 ≤ p.2 } :=
  OrderClosedTopology.isClosed_le'.MeasurableSet
#align measurable_set_le' measurableSet_le'

@[measurability]
theorem measurableSet_le {f g : δ → α} (hf : Measurable f) (hg : Measurable g) :
    MeasurableSet { a | f a ≤ g a } :=
  hf.prod_mk hg measurableSet_le'
#align measurable_set_le measurableSet_le

end PartialOrder

section LinearOrder

variable [LinearOrder α] [OrderClosedTopology α] {a b x : α}

-- we open this locale only here to avoid issues with list being treated as intervals above
open Interval

@[simp, measurability]
theorem measurableSet_Iio : MeasurableSet (Iio a) :=
  isOpen_Iio.MeasurableSet
#align measurable_set_Iio measurableSet_Iio

@[simp, measurability]
theorem measurableSet_Ioi : MeasurableSet (Ioi a) :=
  isOpen_Ioi.MeasurableSet
#align measurable_set_Ioi measurableSet_Ioi

@[simp, measurability]
theorem measurableSet_Ioo : MeasurableSet (Ioo a b) :=
  isOpen_Ioo.MeasurableSet
#align measurable_set_Ioo measurableSet_Ioo

@[simp, measurability]
theorem measurableSet_Ioc : MeasurableSet (Ioc a b) :=
  measurableSet_Ioi.inter measurableSet_Iic
#align measurable_set_Ioc measurableSet_Ioc

@[simp, measurability]
theorem measurableSet_Ico : MeasurableSet (Ico a b) :=
  measurableSet_Ici.inter measurableSet_Iio
#align measurable_set_Ico measurableSet_Ico

instance nhdsWithin_Ioi_isMeasurablyGenerated : (𝓝[Ioi b] a).IsMeasurablyGenerated :=
  measurableSet_Ioi.nhdsWithin_isMeasurablyGenerated _
#align nhds_within_Ioi_is_measurably_generated nhdsWithin_Ioi_isMeasurablyGenerated

instance nhdsWithin_Iio_isMeasurablyGenerated : (𝓝[Iio b] a).IsMeasurablyGenerated :=
  measurableSet_Iio.nhdsWithin_isMeasurablyGenerated _
#align nhds_within_Iio_is_measurably_generated nhdsWithin_Iio_isMeasurablyGenerated

instance nhdsWithin_uIcc_isMeasurablyGenerated : IsMeasurablyGenerated (𝓝[[a, b]] x) :=
  nhdsWithin_Icc_isMeasurablyGenerated
#align nhds_within_uIcc_is_measurably_generated nhdsWithin_uIcc_isMeasurablyGenerated

@[measurability]
theorem measurableSet_lt' [SecondCountableTopology α] : MeasurableSet { p : α × α | p.1 < p.2 } :=
  (isOpen_lt continuous_fst continuous_snd).MeasurableSet
#align measurable_set_lt' measurableSet_lt'

@[measurability]
theorem measurableSet_lt [SecondCountableTopology α] {f g : δ → α} (hf : Measurable f)
    (hg : Measurable g) : MeasurableSet { a | f a < g a } :=
  hf.prod_mk hg measurableSet_lt'
#align measurable_set_lt measurableSet_lt

theorem nullMeasurableSetLt [SecondCountableTopology α] {μ : Measure δ} {f g : δ → α}
    (hf : AeMeasurable f μ) (hg : AeMeasurable g μ) : NullMeasurableSet { a | f a < g a } μ :=
  (hf.prod_mk hg).NullMeasurable measurableSet_lt'
#align null_measurable_set_lt nullMeasurableSetLt

theorem Set.OrdConnected.measurableSet (h : OrdConnected s) : MeasurableSet s :=
  by
  let u := ⋃ (x ∈ s) (y ∈ s), Ioo x y
  have huopen : IsOpen u := isOpen_bunionᵢ fun x hx => isOpen_bunionᵢ fun y hy => isOpen_Ioo
  have humeas : MeasurableSet u := huopen.measurable_set
  have hfinite : (s \ u).Finite := s.finite_diff_Union_Ioo
  have : u ⊆ s :=
    Union₂_subset fun x hx => Union₂_subset fun y hy => Ioo_subset_Icc_self.trans (h.out hx hy)
  rw [← union_diff_cancel this]
  exact humeas.union hfinite.measurable_set
#align set.ord_connected.measurable_set Set.OrdConnected.measurableSet

theorem IsPreconnected.measurableSet (h : IsPreconnected s) : MeasurableSet s :=
  h.OrdConnected.MeasurableSet
#align is_preconnected.measurable_set IsPreconnected.measurableSet

theorem generateFrom_Ico_mem_le_borel {α : Type _} [TopologicalSpace α] [LinearOrder α]
    [OrderClosedTopology α] (s t : Set α) :
    MeasurableSpace.generateFrom { S | ∃ l ∈ s, ∃ u ∈ t, ∃ h : l < u, Ico l u = S } ≤ borel α :=
  by
  apply generate_from_le
  borelize α
  rintro _ ⟨a, -, b, -, -, rfl⟩
  exact measurableSet_Ico
#align generate_from_Ico_mem_le_borel generateFrom_Ico_mem_le_borel

theorem Dense.borel_eq_generateFrom_Ico_mem_aux {α : Type _} [TopologicalSpace α] [LinearOrder α]
    [OrderTopology α] [SecondCountableTopology α] {s : Set α} (hd : Dense s)
    (hbot : ∀ x, IsBot x → x ∈ s) (hIoo : ∀ x y : α, x < y → Ioo x y = ∅ → y ∈ s) :
    borel α = generateFrom { S : Set α | ∃ l ∈ s, ∃ u ∈ s, ∃ h : l < u, Ico l u = S } :=
  by
  set S : Set (Set α) := { S | ∃ l ∈ s, ∃ u ∈ s, ∃ h : l < u, Ico l u = S }
  refine' le_antisymm _ (generateFrom_Ico_mem_le_borel _ _)
  letI : MeasurableSpace α := generate_from S
  rw [borel_eq_generateFrom_Iio]
  refine' generate_from_le (forall_range_iff.2 fun a => _)
  rcases hd.exists_countable_dense_subset_bot_top with ⟨t, hts, hc, htd, htb, htt⟩
  by_cases ha : ∀ b < a, (Ioo b a).Nonempty
  · convert_to MeasurableSet (⋃ (l ∈ t) (u ∈ t) (hlu : l < u) (hu : u ≤ a), Ico l u)
    · ext y
      simp only [mem_Union, mem_Iio, mem_Ico]
      constructor
      · intro hy
        rcases htd.exists_le' (fun b hb => htb _ hb (hbot b hb)) y with ⟨l, hlt, hly⟩
        rcases htd.exists_mem_open isOpen_Ioo (ha y hy) with ⟨u, hut, hyu, hua⟩
        exact ⟨l, hlt, u, hut, hly.trans_lt hyu, hua.le, hly, hyu⟩
      · rintro ⟨l, -, u, -, -, hua, -, hyu⟩
        exact hyu.trans_le hua
    · refine' MeasurableSet.bunionᵢ hc fun a ha => MeasurableSet.bunionᵢ hc fun b hb => _
      refine' MeasurableSet.unionᵢ fun hab => MeasurableSet.unionᵢ fun hb' => _
      exact generate_measurable.basic _ ⟨a, hts ha, b, hts hb, hab, mem_singleton _⟩
  · simp only [not_forall, not_nonempty_iff_eq_empty] at ha
    replace ha : a ∈ s := hIoo ha.some a ha.some_spec.fst ha.some_spec.snd
    convert_to MeasurableSet (⋃ (l ∈ t) (hl : l < a), Ico l a)
    · symm
      simp only [← Ici_inter_Iio, ← Union_inter, inter_eq_right_iff_subset, subset_def, mem_Union,
        mem_Ici, mem_Iio]
      intro x hx
      rcases htd.exists_le' (fun b hb => htb _ hb (hbot b hb)) x with ⟨z, hzt, hzx⟩
      exact ⟨z, hzt, hzx.trans_lt hx, hzx⟩
    · refine' MeasurableSet.bunionᵢ hc fun x hx => MeasurableSet.unionᵢ fun hlt => _
      exact generate_measurable.basic _ ⟨x, hts hx, a, ha, hlt, mem_singleton _⟩
#align dense.borel_eq_generate_from_Ico_mem_aux Dense.borel_eq_generateFrom_Ico_mem_aux

theorem Dense.borel_eq_generateFrom_Ico_mem {α : Type _} [TopologicalSpace α] [LinearOrder α]
    [OrderTopology α] [SecondCountableTopology α] [DenselyOrdered α] [NoMinOrder α] {s : Set α}
    (hd : Dense s) :
    borel α = generateFrom { S : Set α | ∃ l ∈ s, ∃ u ∈ s, ∃ h : l < u, Ico l u = S } :=
  hd.borel_eq_generateFrom_Ico_mem_aux (by simp) fun x y hxy H =>
    ((nonempty_Ioo.2 hxy).ne_empty H).elim
#align dense.borel_eq_generate_from_Ico_mem Dense.borel_eq_generateFrom_Ico_mem

theorem borel_eq_generateFrom_Ico (α : Type _) [TopologicalSpace α] [SecondCountableTopology α]
    [LinearOrder α] [OrderTopology α] :
    borel α = generateFrom { S : Set α | ∃ (l u : _)(h : l < u), Ico l u = S } := by
  simpa only [exists_prop, mem_univ, true_and_iff] using
    (@dense_univ α _).borel_eq_generateFrom_Ico_mem_aux (fun _ _ => mem_univ _) fun _ _ _ _ =>
      mem_univ _
#align borel_eq_generate_from_Ico borel_eq_generateFrom_Ico

theorem Dense.borel_eq_generateFrom_Ioc_mem_aux {α : Type _} [TopologicalSpace α] [LinearOrder α]
    [OrderTopology α] [SecondCountableTopology α] {s : Set α} (hd : Dense s)
    (hbot : ∀ x, IsTop x → x ∈ s) (hIoo : ∀ x y : α, x < y → Ioo x y = ∅ → x ∈ s) :
    borel α = generateFrom { S : Set α | ∃ l ∈ s, ∃ u ∈ s, ∃ h : l < u, Ioc l u = S } :=
  by
  convert hd.order_dual.borel_eq_generate_from_Ico_mem_aux hbot fun x y hlt he => hIoo y x hlt _
  · ext s
    constructor <;> rintro ⟨l, hl, u, hu, hlt, rfl⟩
    exacts[⟨u, hu, l, hl, hlt, dual_Ico⟩, ⟨u, hu, l, hl, hlt, dual_Ioc⟩]
  · erw [dual_Ioo]
    exact he
#align dense.borel_eq_generate_from_Ioc_mem_aux Dense.borel_eq_generateFrom_Ioc_mem_aux

theorem Dense.borel_eq_generateFrom_Ioc_mem {α : Type _} [TopologicalSpace α] [LinearOrder α]
    [OrderTopology α] [SecondCountableTopology α] [DenselyOrdered α] [NoMaxOrder α] {s : Set α}
    (hd : Dense s) :
    borel α = generateFrom { S : Set α | ∃ l ∈ s, ∃ u ∈ s, ∃ h : l < u, Ioc l u = S } :=
  hd.borel_eq_generateFrom_Ioc_mem_aux (by simp) fun x y hxy H =>
    ((nonempty_Ioo.2 hxy).ne_empty H).elim
#align dense.borel_eq_generate_from_Ioc_mem Dense.borel_eq_generateFrom_Ioc_mem

theorem borel_eq_generateFrom_Ioc (α : Type _) [TopologicalSpace α] [SecondCountableTopology α]
    [LinearOrder α] [OrderTopology α] :
    borel α = generateFrom { S : Set α | ∃ (l u : _)(h : l < u), Ioc l u = S } := by
  simpa only [exists_prop, mem_univ, true_and_iff] using
    (@dense_univ α _).borel_eq_generateFrom_Ioc_mem_aux (fun _ _ => mem_univ _) fun _ _ _ _ =>
      mem_univ _
#align borel_eq_generate_from_Ioc borel_eq_generateFrom_Ioc

namespace MeasureTheory.Measure

/-- Two finite measures on a Borel space are equal if they agree on all closed-open intervals.  If
`α` is a conditionally complete linear order with no top element,
`measure_theory.measure..ext_of_Ico` is an extensionality lemma with weaker assumptions on `μ` and
`ν`. -/
theorem ext_of_Ico_finite {α : Type _} [TopologicalSpace α] {m : MeasurableSpace α}
    [SecondCountableTopology α] [LinearOrder α] [OrderTopology α] [BorelSpace α] (μ ν : Measure α)
    [IsFiniteMeasure μ] (hμν : μ univ = ν univ) (h : ∀ ⦃a b⦄, a < b → μ (Ico a b) = ν (Ico a b)) :
    μ = ν :=
  by
  refine'
    ext_of_generate_finite _ (borel_space.measurable_eq.trans (borel_eq_generateFrom_Ico α))
      (isPiSystem_Ico (id : α → α) id) _ hμν
  · rintro - ⟨a, b, hlt, rfl⟩
    exact h hlt
#align measure_theory.measure.ext_of_Ico_finite MeasureTheory.Measure.ext_of_Ico_finite

/-- Two finite measures on a Borel space are equal if they agree on all open-closed intervals.  If
`α` is a conditionally complete linear order with no top element,
`measure_theory.measure..ext_of_Ioc` is an extensionality lemma with weaker assumptions on `μ` and
`ν`. -/
theorem ext_of_Ioc_finite {α : Type _} [TopologicalSpace α] {m : MeasurableSpace α}
    [SecondCountableTopology α] [LinearOrder α] [OrderTopology α] [BorelSpace α] (μ ν : Measure α)
    [IsFiniteMeasure μ] (hμν : μ univ = ν univ) (h : ∀ ⦃a b⦄, a < b → μ (Ioc a b) = ν (Ioc a b)) :
    μ = ν := by
  refine' @ext_of_Ico_finite αᵒᵈ _ _ _ _ _ ‹_› μ ν _ hμν fun a b hab => _
  erw [dual_Ico]
  exact h hab
#align measure_theory.measure.ext_of_Ioc_finite MeasureTheory.Measure.ext_of_Ioc_finite

/-- Two measures which are finite on closed-open intervals are equal if the agree on all
closed-open intervals. -/
theorem ext_of_Ico' {α : Type _} [TopologicalSpace α] {m : MeasurableSpace α}
    [SecondCountableTopology α] [LinearOrder α] [OrderTopology α] [BorelSpace α] [NoMaxOrder α]
    (μ ν : Measure α) (hμ : ∀ ⦃a b⦄, a < b → μ (Ico a b) ≠ ∞)
    (h : ∀ ⦃a b⦄, a < b → μ (Ico a b) = ν (Ico a b)) : μ = ν :=
  by
  rcases exists_countable_dense_bot_top α with ⟨s, hsc, hsd, hsb, hst⟩
  have : (⋃ (l ∈ s) (u ∈ s) (h : l < u), {Ico l u} : Set (Set α)).Countable :=
    hsc.bUnion fun l hl => hsc.bUnion fun u hu => countable_Union fun _ => countable_singleton _
  simp only [← set_of_eq_eq_singleton, ← set_of_exists] at this
  refine'
    measure.ext_of_generate_from_of_cover_subset
      (borel_space.measurable_eq.trans (borel_eq_generateFrom_Ico α)) (isPiSystem_Ico id id) _ this
      _ _ _
  · rintro _ ⟨l, -, u, -, h, rfl⟩
    exact ⟨l, u, h, rfl⟩
  · refine' sUnion_eq_univ_iff.2 fun x => _
    rcases hsd.exists_le' hsb x with ⟨l, hls, hlx⟩
    rcases hsd.exists_gt x with ⟨u, hus, hxu⟩
    exact ⟨_, ⟨l, hls, u, hus, hlx.trans_lt hxu, rfl⟩, hlx, hxu⟩
  · rintro _ ⟨l, -, u, -, hlt, rfl⟩
    exact hμ hlt
  · rintro _ ⟨l, u, hlt, rfl⟩
    exact h hlt
#align measure_theory.measure.ext_of_Ico' MeasureTheory.Measure.ext_of_Ico'

/-- Two measures which are finite on closed-open intervals are equal if the agree on all
open-closed intervals. -/
theorem ext_of_Ioc' {α : Type _} [TopologicalSpace α] {m : MeasurableSpace α}
    [SecondCountableTopology α] [LinearOrder α] [OrderTopology α] [BorelSpace α] [NoMinOrder α]
    (μ ν : Measure α) (hμ : ∀ ⦃a b⦄, a < b → μ (Ioc a b) ≠ ∞)
    (h : ∀ ⦃a b⦄, a < b → μ (Ioc a b) = ν (Ioc a b)) : μ = ν :=
  by
  refine' @ext_of_Ico' αᵒᵈ _ _ _ _ _ ‹_› _ μ ν _ _ <;> intro a b hab <;> erw [dual_Ico]
  exacts[hμ hab, h hab]
#align measure_theory.measure.ext_of_Ioc' MeasureTheory.Measure.ext_of_Ioc'

/-- Two measures which are finite on closed-open intervals are equal if the agree on all
closed-open intervals. -/
theorem ext_of_Ico {α : Type _} [TopologicalSpace α] {m : MeasurableSpace α}
    [SecondCountableTopology α] [ConditionallyCompleteLinearOrder α] [OrderTopology α]
    [BorelSpace α] [NoMaxOrder α] (μ ν : Measure α) [IsLocallyFiniteMeasure μ]
    (h : ∀ ⦃a b⦄, a < b → μ (Ico a b) = ν (Ico a b)) : μ = ν :=
  μ.ext_of_Ico' ν (fun a b hab => measure_Ico_lt_top.Ne) h
#align measure_theory.measure.ext_of_Ico MeasureTheory.Measure.ext_of_Ico

/-- Two measures which are finite on closed-open intervals are equal if the agree on all
open-closed intervals. -/
theorem ext_of_Ioc {α : Type _} [TopologicalSpace α] {m : MeasurableSpace α}
    [SecondCountableTopology α] [ConditionallyCompleteLinearOrder α] [OrderTopology α]
    [BorelSpace α] [NoMinOrder α] (μ ν : Measure α) [IsLocallyFiniteMeasure μ]
    (h : ∀ ⦃a b⦄, a < b → μ (Ioc a b) = ν (Ioc a b)) : μ = ν :=
  μ.ext_of_Ioc' ν (fun a b hab => measure_Ioc_lt_top.Ne) h
#align measure_theory.measure.ext_of_Ioc MeasureTheory.Measure.ext_of_Ioc

/-- Two finite measures on a Borel space are equal if they agree on all left-infinite right-closed
intervals. -/
theorem ext_of_Iic {α : Type _} [TopologicalSpace α] {m : MeasurableSpace α}
    [SecondCountableTopology α] [LinearOrder α] [OrderTopology α] [BorelSpace α] (μ ν : Measure α)
    [IsFiniteMeasure μ] (h : ∀ a, μ (Iic a) = ν (Iic a)) : μ = ν :=
  by
  refine' ext_of_Ioc_finite μ ν _ fun a b hlt => _
  · rcases exists_countable_dense_bot_top α with ⟨s, hsc, hsd, -, hst⟩
    have : DirectedOn (· ≤ ·) s := directedOn_iff_directed.2 (directed_of_sup fun _ _ => id)
    simp only [← bsupr_measure_Iic hsc (hsd.exists_ge' hst) this, h]
  rw [← Iic_diff_Iic, measure_diff (Iic_subset_Iic.2 hlt.le) measurableSet_Iic,
    measure_diff (Iic_subset_Iic.2 hlt.le) measurableSet_Iic, h a, h b]
  · rw [← h a]
    exact (measure_lt_top μ _).Ne
  · exact (measure_lt_top μ _).Ne
#align measure_theory.measure.ext_of_Iic MeasureTheory.Measure.ext_of_Iic

/-- Two finite measures on a Borel space are equal if they agree on all left-closed right-infinite
intervals. -/
theorem ext_of_Ici {α : Type _} [TopologicalSpace α] {m : MeasurableSpace α}
    [SecondCountableTopology α] [LinearOrder α] [OrderTopology α] [BorelSpace α] (μ ν : Measure α)
    [IsFiniteMeasure μ] (h : ∀ a, μ (Ici a) = ν (Ici a)) : μ = ν :=
  @ext_of_Iic αᵒᵈ _ _ _ _ _ ‹_› _ _ _ h
#align measure_theory.measure.ext_of_Ici MeasureTheory.Measure.ext_of_Ici

end MeasureTheory.Measure

end LinearOrder

section LinearOrder

variable [LinearOrder α] [OrderClosedTopology α] {a b : α}

@[measurability]
theorem measurableSet_uIcc : MeasurableSet (uIcc a b) :=
  measurableSet_Icc
#align measurable_set_uIcc measurableSet_uIcc

@[measurability]
theorem measurableSet_uIoc : MeasurableSet (uIoc a b) :=
  measurableSet_Ioc
#align measurable_set_uIoc measurableSet_uIoc

variable [SecondCountableTopology α]

@[measurability]
theorem Measurable.max {f g : δ → α} (hf : Measurable f) (hg : Measurable g) :
    Measurable fun a => max (f a) (g a) := by
  simpa only [max_def'] using hf.piecewise (measurableSet_le hg hf) hg
#align measurable.max Measurable.max

@[measurability]
theorem AeMeasurable.max {f g : δ → α} {μ : Measure δ} (hf : AeMeasurable f μ)
    (hg : AeMeasurable g μ) : AeMeasurable (fun a => max (f a) (g a)) μ :=
  ⟨fun a => max (hf.mk f a) (hg.mk g a), hf.measurable_mk.max hg.measurable_mk,
    EventuallyEq.comp₂ hf.ae_eq_mk _ hg.ae_eq_mk⟩
#align ae_measurable.max AeMeasurable.max

@[measurability]
theorem Measurable.min {f g : δ → α} (hf : Measurable f) (hg : Measurable g) :
    Measurable fun a => min (f a) (g a) := by
  simpa only [min_def] using hf.piecewise (measurableSet_le hf hg) hg
#align measurable.min Measurable.min

@[measurability]
theorem AeMeasurable.min {f g : δ → α} {μ : Measure δ} (hf : AeMeasurable f μ)
    (hg : AeMeasurable g μ) : AeMeasurable (fun a => min (f a) (g a)) μ :=
  ⟨fun a => min (hf.mk f a) (hg.mk g a), hf.measurable_mk.min hg.measurable_mk,
    EventuallyEq.comp₂ hf.ae_eq_mk _ hg.ae_eq_mk⟩
#align ae_measurable.min AeMeasurable.min

end LinearOrder

/-- A continuous function from an `opens_measurable_space` to a `borel_space`
is measurable. -/
theorem Continuous.measurable {f : α → γ} (hf : Continuous f) : Measurable f :=
  hf.borel_measurable.mono OpensMeasurableSpace.borel_le (le_of_eq <| BorelSpace.measurable_eq)
#align continuous.measurable Continuous.measurable

/-- A continuous function from an `opens_measurable_space` to a `borel_space`
is ae-measurable. -/
theorem Continuous.aeMeasurable {f : α → γ} (h : Continuous f) {μ : Measure α} : AeMeasurable f μ :=
  h.Measurable.AeMeasurable
#align continuous.ae_measurable Continuous.aeMeasurable

theorem ClosedEmbedding.measurable {f : α → γ} (hf : ClosedEmbedding f) : Measurable f :=
  hf.Continuous.Measurable
#align closed_embedding.measurable ClosedEmbedding.measurable

theorem Continuous.isOpenPosMeasureMap {f : β → γ} (hf : Continuous f)
    (hf_surj : Function.Surjective f) {μ : Measure β} [μ.IsOpenPosMeasure] :
    (Measure.map f μ).IsOpenPosMeasure :=
  by
  refine' ⟨fun U hUo hUne => _⟩
  rw [measure.map_apply hf.measurable hUo.measurable_set]
  exact (hUo.preimage hf).measure_ne_zero μ (hf_surj.nonempty_preimage.mpr hUne)
#align continuous.is_open_pos_measure_map Continuous.isOpenPosMeasureMap

/-- If a function is defined piecewise in terms of functions which are continuous on their
respective pieces, then it is measurable. -/
theorem ContinuousOn.measurable_piecewise {f g : α → γ} {s : Set α} [∀ j : α, Decidable (j ∈ s)]
    (hf : ContinuousOn f s) (hg : ContinuousOn g (sᶜ)) (hs : MeasurableSet s) :
    Measurable (s.piecewise f g) :=
  by
  refine' measurable_of_isOpen fun t ht => _
  rw [piecewise_preimage, Set.ite]
  apply MeasurableSet.union
  · rcases _root_.continuous_on_iff'.1 hf t ht with ⟨u, u_open, hu⟩
    rw [hu]
    exact u_open.measurable_set.inter hs
  · rcases _root_.continuous_on_iff'.1 hg t ht with ⟨u, u_open, hu⟩
    rw [diff_eq_compl_inter, inter_comm, hu]
    exact u_open.measurable_set.inter hs.compl
#align continuous_on.measurable_piecewise ContinuousOn.measurable_piecewise

@[to_additive]
instance (priority := 100) ContinuousMul.hasMeasurableMul [Mul γ] [ContinuousMul γ] :
    HasMeasurableMul γ
    where
  measurable_const_mul c := (continuous_const.mul continuous_id).Measurable
  measurable_mul_const c := (continuous_id.mul continuous_const).Measurable
#align has_continuous_mul.has_measurable_mul ContinuousMul.hasMeasurableMul
#align has_continuous_add.has_measurable_add ContinuousAdd.has_measurable_add

instance (priority := 100) ContinuousSub.hasMeasurableSub [Sub γ] [ContinuousSub γ] :
    HasMeasurableSub γ
    where
  measurable_const_sub c := (continuous_const.sub continuous_id).Measurable
  measurable_sub_const c := (continuous_id.sub continuous_const).Measurable
#align has_continuous_sub.has_measurable_sub ContinuousSub.hasMeasurableSub

@[to_additive]
instance (priority := 100) TopologicalGroup.hasMeasurableInv [Group γ] [TopologicalGroup γ] :
    HasMeasurableInv γ :=
  ⟨continuous_inv.Measurable⟩
#align topological_group.has_measurable_inv TopologicalGroup.hasMeasurableInv
#align topological_add_group.has_measurable_neg TopologicalAddGroup.has_measurable_neg

instance (priority := 100) ContinuousSMul.hasMeasurableSmul {M α} [TopologicalSpace M]
    [TopologicalSpace α] [MeasurableSpace M] [MeasurableSpace α] [OpensMeasurableSpace M]
    [BorelSpace α] [SMul M α] [ContinuousSMul M α] : HasMeasurableSmul M α :=
  ⟨fun c => (continuous_const_smul _).Measurable, fun y =>
    (continuous_id.smul continuous_const).Measurable⟩
#align has_continuous_smul.has_measurable_smul ContinuousSMul.hasMeasurableSmul

section Lattice

instance (priority := 100) ContinuousSup.hasMeasurableSup [Sup γ] [ContinuousSup γ] :
    HasMeasurableSup γ
    where
  measurable_const_sup c := (continuous_const.sup continuous_id).Measurable
  measurable_sup_const c := (continuous_id.sup continuous_const).Measurable
#align has_continuous_sup.has_measurable_sup ContinuousSup.hasMeasurableSup

instance (priority := 100) ContinuousSup.hasMeasurableSup₂ [SecondCountableTopology γ] [Sup γ]
    [ContinuousSup γ] : HasMeasurableSup₂ γ :=
  ⟨continuous_sup.Measurable⟩
#align has_continuous_sup.has_measurable_sup₂ ContinuousSup.hasMeasurableSup₂

instance (priority := 100) ContinuousInf.hasMeasurableInf [Inf γ] [ContinuousInf γ] :
    HasMeasurableInf γ
    where
  measurable_const_inf c := (continuous_const.inf continuous_id).Measurable
  measurable_inf_const c := (continuous_id.inf continuous_const).Measurable
#align has_continuous_inf.has_measurable_inf ContinuousInf.hasMeasurableInf

instance (priority := 100) ContinuousInf.hasMeasurableInf₂ [SecondCountableTopology γ] [Inf γ]
    [ContinuousInf γ] : HasMeasurableInf₂ γ :=
  ⟨continuous_inf.Measurable⟩
#align has_continuous_inf.has_measurable_inf₂ ContinuousInf.hasMeasurableInf₂

end Lattice

section Homeomorph

@[measurability]
protected theorem Homeomorph.measurable (h : α ≃ₜ γ) : Measurable h :=
  h.Continuous.Measurable
#align homeomorph.measurable Homeomorph.measurable

/-- A homeomorphism between two Borel spaces is a measurable equivalence.-/
def Homeomorph.toMeasurableEquiv (h : γ ≃ₜ γ₂) : γ ≃ᵐ γ₂
    where
  measurable_to_fun := h.Measurable
  measurable_inv_fun := h.symm.Measurable
  toEquiv := h.toEquiv
#align homeomorph.to_measurable_equiv Homeomorph.toMeasurableEquiv

@[simp]
theorem Homeomorph.toMeasurableEquiv_coe (h : γ ≃ₜ γ₂) : (h.toMeasurableEquiv : γ → γ₂) = h :=
  rfl
#align homeomorph.to_measurable_equiv_coe Homeomorph.toMeasurableEquiv_coe

@[simp]
theorem Homeomorph.toMeasurableEquiv_symm_coe (h : γ ≃ₜ γ₂) :
    (h.toMeasurableEquiv.symm : γ₂ → γ) = h.symm :=
  rfl
#align homeomorph.to_measurable_equiv_symm_coe Homeomorph.toMeasurableEquiv_symm_coe

end Homeomorph

@[measurability]
theorem ContinuousMap.measurable (f : C(α, γ)) : Measurable f :=
  f.Continuous.Measurable
#align continuous_map.measurable ContinuousMap.measurable

theorem measurable_of_continuousOn_compl_singleton [T1Space α] {f : α → γ} (a : α)
    (hf : ContinuousOn f ({a}ᶜ)) : Measurable f :=
  measurable_of_measurable_on_compl_singleton a
    (continuousOn_iff_continuous_restrict.1 hf).Measurable
#align measurable_of_continuous_on_compl_singleton measurable_of_continuousOn_compl_singleton

theorem Continuous.measurable2 [SecondCountableTopology α] [SecondCountableTopology β] {f : δ → α}
    {g : δ → β} {c : α → β → γ} (h : Continuous fun p : α × β => c p.1 p.2) (hf : Measurable f)
    (hg : Measurable g) : Measurable fun a => c (f a) (g a) :=
  h.Measurable.comp (hf.prod_mk hg)
#align continuous.measurable2 Continuous.measurable2

theorem Continuous.aeMeasurable2 [SecondCountableTopology α] [SecondCountableTopology β] {f : δ → α}
    {g : δ → β} {c : α → β → γ} {μ : Measure δ} (h : Continuous fun p : α × β => c p.1 p.2)
    (hf : AeMeasurable f μ) (hg : AeMeasurable g μ) : AeMeasurable (fun a => c (f a) (g a)) μ :=
  h.Measurable.compAeMeasurable (hf.prod_mk hg)
#align continuous.ae_measurable2 Continuous.aeMeasurable2

instance (priority := 100) HasContinuousInv₀.hasMeasurableInv [GroupWithZero γ] [T1Space γ]
    [HasContinuousInv₀ γ] : HasMeasurableInv γ :=
  ⟨measurable_of_continuousOn_compl_singleton 0 continuousOn_inv₀⟩
#align has_continuous_inv₀.has_measurable_inv HasContinuousInv₀.hasMeasurableInv

@[to_additive]
instance (priority := 100) ContinuousMul.hasMeasurableMul₂ [SecondCountableTopology γ] [Mul γ]
    [ContinuousMul γ] : HasMeasurableMul₂ γ :=
  ⟨continuous_mul.Measurable⟩
#align has_continuous_mul.has_measurable_mul₂ ContinuousMul.hasMeasurableMul₂
#align has_continuous_add.has_measurable_mul₂ ContinuousAdd.hasMeasurableMul₂

instance (priority := 100) ContinuousSub.hasMeasurableSub₂ [SecondCountableTopology γ] [Sub γ]
    [ContinuousSub γ] : HasMeasurableSub₂ γ :=
  ⟨continuous_sub.Measurable⟩
#align has_continuous_sub.has_measurable_sub₂ ContinuousSub.hasMeasurableSub₂

instance (priority := 100) ContinuousSMul.hasMeasurableSmul₂ {M α} [TopologicalSpace M]
    [SecondCountableTopology M] [MeasurableSpace M] [OpensMeasurableSpace M] [TopologicalSpace α]
    [SecondCountableTopology α] [MeasurableSpace α] [BorelSpace α] [SMul M α] [ContinuousSMul M α] :
    HasMeasurableSmul₂ M α :=
  ⟨continuous_smul.Measurable⟩
#align has_continuous_smul.has_measurable_smul₂ ContinuousSMul.hasMeasurableSmul₂

end

section BorelSpace

variable [TopologicalSpace α] [MeasurableSpace α] [BorelSpace α] [TopologicalSpace β]
  [MeasurableSpace β] [BorelSpace β] [TopologicalSpace γ] [MeasurableSpace γ] [BorelSpace γ]
  [MeasurableSpace δ]

theorem pi_le_borel_pi {ι : Type _} {π : ι → Type _} [∀ i, TopologicalSpace (π i)]
    [∀ i, MeasurableSpace (π i)] [∀ i, BorelSpace (π i)] : MeasurableSpace.pi ≤ borel (∀ i, π i) :=
  by
  have : ‹∀ i, MeasurableSpace (π i)› = fun i => borel (π i) :=
    funext fun i => BorelSpace.measurable_eq
  rw [this]
  exact supᵢ_le fun i => comap_le_iff_le_map.2 <| (continuous_apply i).borel_measurable
#align pi_le_borel_pi pi_le_borel_pi

theorem prod_le_borel_prod : Prod.measurableSpace ≤ borel (α × β) :=
  by
  rw [‹BorelSpace α›.measurable_eq, ‹BorelSpace β›.measurable_eq]
  refine' sup_le _ _
  · exact comap_le_iff_le_map.mpr continuous_fst.borel_measurable
  · exact comap_le_iff_le_map.mpr continuous_snd.borel_measurable
#align prod_le_borel_prod prod_le_borel_prod

instance Pi.borelSpace {ι : Type _} {π : ι → Type _} [Countable ι] [∀ i, TopologicalSpace (π i)]
    [∀ i, MeasurableSpace (π i)] [∀ i, SecondCountableTopology (π i)] [∀ i, BorelSpace (π i)] :
    BorelSpace (∀ i, π i) :=
  ⟨le_antisymm pi_le_borel_pi OpensMeasurableSpace.borel_le⟩
#align pi.borel_space Pi.borelSpace

instance Prod.borelSpace [SecondCountableTopology α] [SecondCountableTopology β] :
    BorelSpace (α × β) :=
  ⟨le_antisymm prod_le_borel_prod OpensMeasurableSpace.borel_le⟩
#align prod.borel_space Prod.borelSpace

protected theorem Embedding.measurableEmbedding {f : α → β} (h₁ : Embedding f)
    (h₂ : MeasurableSet (range f)) : MeasurableEmbedding f :=
  show MeasurableEmbedding (coe ∘ (Homeomorph.ofEmbedding f h₁).toMeasurableEquiv) from
    (MeasurableEmbedding.subtype_coe h₂).comp (MeasurableEquiv.measurableEmbedding _)
#align embedding.measurable_embedding Embedding.measurableEmbedding

protected theorem ClosedEmbedding.measurableEmbedding {f : α → β} (h : ClosedEmbedding f) :
    MeasurableEmbedding f :=
  h.toEmbedding.MeasurableEmbedding h.closed_range.MeasurableSet
#align closed_embedding.measurable_embedding ClosedEmbedding.measurableEmbedding

protected theorem OpenEmbedding.measurableEmbedding {f : α → β} (h : OpenEmbedding f) :
    MeasurableEmbedding f :=
  h.toEmbedding.MeasurableEmbedding h.open_range.MeasurableSet
#align open_embedding.measurable_embedding OpenEmbedding.measurableEmbedding

section LinearOrder

variable [LinearOrder α] [OrderTopology α] [SecondCountableTopology α]

theorem measurable_of_Iio {f : δ → α} (hf : ∀ x, MeasurableSet (f ⁻¹' Iio x)) : Measurable f :=
  by
  convert measurable_generateFrom _
  exact borel_space.measurable_eq.trans (borel_eq_generateFrom_Iio _)
  rintro _ ⟨x, rfl⟩; exact hf x
#align measurable_of_Iio measurable_of_Iio

theorem UpperSemicontinuous.measurable [TopologicalSpace δ] [OpensMeasurableSpace δ] {f : δ → α}
    (hf : UpperSemicontinuous f) : Measurable f :=
  measurable_of_Iio fun y => (hf.isOpen_preimage y).MeasurableSet
#align upper_semicontinuous.measurable UpperSemicontinuous.measurable

theorem measurable_of_Ioi {f : δ → α} (hf : ∀ x, MeasurableSet (f ⁻¹' Ioi x)) : Measurable f :=
  by
  convert measurable_generateFrom _
  exact borel_space.measurable_eq.trans (borel_eq_generateFrom_Ioi _)
  rintro _ ⟨x, rfl⟩; exact hf x
#align measurable_of_Ioi measurable_of_Ioi

theorem LowerSemicontinuous.measurable [TopologicalSpace δ] [OpensMeasurableSpace δ] {f : δ → α}
    (hf : LowerSemicontinuous f) : Measurable f :=
  measurable_of_Ioi fun y => (hf.isOpen_preimage y).MeasurableSet
#align lower_semicontinuous.measurable LowerSemicontinuous.measurable

theorem measurable_of_Iic {f : δ → α} (hf : ∀ x, MeasurableSet (f ⁻¹' Iic x)) : Measurable f :=
  by
  apply measurable_of_Ioi
  simp_rw [← compl_Iic, preimage_compl, MeasurableSet.compl_iff]
  assumption
#align measurable_of_Iic measurable_of_Iic

theorem measurable_of_Ici {f : δ → α} (hf : ∀ x, MeasurableSet (f ⁻¹' Ici x)) : Measurable f :=
  by
  apply measurable_of_Iio
  simp_rw [← compl_Ici, preimage_compl, MeasurableSet.compl_iff]
  assumption
#align measurable_of_Ici measurable_of_Ici

theorem Measurable.isLUB {ι} [Countable ι] {f : ι → δ → α} {g : δ → α} (hf : ∀ i, Measurable (f i))
    (hg : ∀ b, IsLUB { a | ∃ i, f i b = a } (g b)) : Measurable g :=
  by
  change ∀ b, IsLUB (range fun i => f i b) (g b) at hg
  rw [‹BorelSpace α›.measurable_eq, borel_eq_generateFrom_Ioi α]
  apply measurable_generateFrom
  rintro _ ⟨a, rfl⟩
  simp_rw [Set.preimage, mem_Ioi, lt_isLUB_iff (hg _), exists_range_iff, set_of_exists]
  exact MeasurableSet.unionᵢ fun i => hf i (isOpen_lt' _).MeasurableSet
#align measurable.is_lub Measurable.isLUB

private theorem ae_measurable.is_lub_of_nonempty {ι} (hι : Nonempty ι) {μ : Measure δ} [Countable ι]
    {f : ι → δ → α} {g : δ → α} (hf : ∀ i, AeMeasurable (f i) μ)
    (hg : ∀ᵐ b ∂μ, IsLUB { a | ∃ i, f i b = a } (g b)) : AeMeasurable g μ :=
  by
  let p : δ → (ι → α) → Prop := fun x f' => IsLUB { a | ∃ i, f' i = a } (g x)
  let g_seq x := ite (x ∈ aeSeqSet hf p) (g x) (⟨g x⟩ : Nonempty α).some
  have hg_seq : ∀ b, IsLUB { a | ∃ i, aeSeq hf p i b = a } (g_seq b) :=
    by
    intro b
    haveI hα : Nonempty α := Nonempty.map g ⟨b⟩
    simp only [aeSeq, g_seq]
    split_ifs
    · have h_set_eq : { a : α | ∃ i : ι, (hf i).mk (f i) b = a } = { a : α | ∃ i : ι, f i b = a } :=
        by
        ext x
        simp_rw [Set.mem_setOf_eq, aeSeq.mk_eq_fun_of_mem_aeSeqSet hf h]
      rw [h_set_eq]
      exact aeSeq.funPropOfMemAeSeqSet hf h
    · have h_singleton : { a : α | ∃ i : ι, hα.some = a } = {hα.some} :=
        by
        ext1 x
        exact ⟨fun hx => hx.some_spec.symm, fun hx => ⟨hι.some, hx.symm⟩⟩
      rw [h_singleton]
      exact isLUB_singleton
  refine' ⟨g_seq, Measurable.isLUB (aeSeq.measurable hf p) hg_seq, _⟩
  exact
    (ite_ae_eq_of_measure_compl_zero g (fun x => (⟨g x⟩ : Nonempty α).some) (aeSeqSet hf p)
        (aeSeq.measure_compl_aeSeqSet_eq_zero hf hg)).symm
#align ae_measurable.is_lub_of_nonempty ae_measurable.is_lub_of_nonempty

theorem AeMeasurable.isLub {ι} {μ : Measure δ} [Countable ι] {f : ι → δ → α} {g : δ → α}
    (hf : ∀ i, AeMeasurable (f i) μ) (hg : ∀ᵐ b ∂μ, IsLUB { a | ∃ i, f i b = a } (g b)) :
    AeMeasurable g μ := by
  by_cases hμ : μ = 0
  · rw [hμ]
    exact aeMeasurableZeroMeasure
  have : μ.ae.ne_bot := by simpa [ne_bot_iff]
  by_cases hι : Nonempty ι
  · exact ae_measurable.is_lub_of_nonempty hι hf hg
  suffices ∃ x, g =ᵐ[μ] fun y => g x by
    exact ⟨fun y => g this.some, measurable_const, this.some_spec⟩
  have h_empty : ∀ x, { a : α | ∃ i : ι, f i x = a } = ∅ :=
    by
    intro x
    ext1 y
    rw [Set.mem_setOf_eq, Set.mem_empty_iff_false, iff_false_iff]
    exact fun hi => hι (nonempty_of_exists hi)
  simp_rw [h_empty] at hg
  exact ⟨hg.exists.some, hg.mono fun y hy => IsLUB.unique hy hg.exists.some_spec⟩
#align ae_measurable.is_lub AeMeasurable.isLub

theorem Measurable.isGLB {ι} [Countable ι] {f : ι → δ → α} {g : δ → α} (hf : ∀ i, Measurable (f i))
    (hg : ∀ b, IsGLB { a | ∃ i, f i b = a } (g b)) : Measurable g :=
  by
  change ∀ b, IsGLB (range fun i => f i b) (g b) at hg
  rw [‹BorelSpace α›.measurable_eq, borel_eq_generateFrom_Iio α]
  apply measurable_generateFrom
  rintro _ ⟨a, rfl⟩
  simp_rw [Set.preimage, mem_Iio, isGLB_lt_iff (hg _), exists_range_iff, set_of_exists]
  exact MeasurableSet.unionᵢ fun i => hf i (isOpen_gt' _).MeasurableSet
#align measurable.is_glb Measurable.isGLB

theorem AeMeasurable.isGlb {ι} {μ : Measure δ} [Countable ι] {f : ι → δ → α} {g : δ → α}
    (hf : ∀ i, AeMeasurable (f i) μ) (hg : ∀ᵐ b ∂μ, IsGLB { a | ∃ i, f i b = a } (g b)) :
    AeMeasurable g μ := by
  nontriviality α
  haveI hα : Nonempty α := inferInstance
  cases' isEmpty_or_nonempty ι with hι hι
  · simp only [IsEmpty.exists_iff, set_of_false, isGLB_empty_iff] at hg
    exact aeMeasurableConst' (hg.mono fun a ha => hg.mono fun b hb => (hb _).antisymm (ha _))
  let p : δ → (ι → α) → Prop := fun x f' => IsGLB { a | ∃ i, f' i = a } (g x)
  let g_seq := (aeSeqSet hf p).piecewise g fun _ => hα.some
  have hg_seq : ∀ b, IsGLB { a | ∃ i, aeSeq hf p i b = a } (g_seq b) :=
    by
    intro b
    simp only [aeSeq, g_seq, Set.piecewise]
    split_ifs
    · have h_set_eq : { a : α | ∃ i : ι, (hf i).mk (f i) b = a } = { a : α | ∃ i : ι, f i b = a } :=
        by
        ext x
        simp_rw [Set.mem_setOf_eq, aeSeq.mk_eq_fun_of_mem_aeSeqSet hf h]
      rw [h_set_eq]
      exact aeSeq.funPropOfMemAeSeqSet hf h
    · exact IsLeast.isGLB ⟨(@exists_const (hα.some = hα.some) ι _).2 rfl, fun x ⟨i, hi⟩ => hi.le⟩
  refine' ⟨g_seq, Measurable.isGLB (aeSeq.measurable hf p) hg_seq, _⟩
  exact
    (ite_ae_eq_of_measure_compl_zero g (fun x => hα.some) (aeSeqSet hf p)
        (aeSeq.measure_compl_aeSeqSet_eq_zero hf hg)).symm
#align ae_measurable.is_glb AeMeasurable.isGlb

protected theorem Monotone.measurable [LinearOrder β] [OrderClosedTopology β] {f : β → α}
    (hf : Monotone f) : Measurable f :=
  suffices h : ∀ x, OrdConnected (f ⁻¹' Ioi x) from measurable_of_Ioi fun x => (h x).MeasurableSet
  fun x => ordConnected_def.mpr fun a ha b hb c hc => lt_of_lt_of_le ha (hf hc.1)
#align monotone.measurable Monotone.measurable

theorem aeMeasurableRestrictOfMonotoneOn [LinearOrder β] [OrderClosedTopology β] {μ : Measure β}
    {s : Set β} (hs : MeasurableSet s) {f : β → α} (hf : MonotoneOn f s) :
    AeMeasurable f (μ.restrict s) :=
  have this : Monotone (f ∘ coe : s → α) := fun ⟨x, hx⟩ ⟨y, hy⟩ (hxy : x ≤ y) => hf hx hy hxy
  aeMeasurableRestrictOfMeasurableSubtype hs this.Measurable
#align ae_measurable_restrict_of_monotone_on aeMeasurableRestrictOfMonotoneOn

protected theorem Antitone.measurable [LinearOrder β] [OrderClosedTopology β] {f : β → α}
    (hf : Antitone f) : Measurable f :=
  @Monotone.measurable αᵒᵈ β _ _ ‹_› _ _ _ _ _ ‹_› _ _ _ hf
#align antitone.measurable Antitone.measurable

theorem aeMeasurableRestrictOfAntitoneOn [LinearOrder β] [OrderClosedTopology β] {μ : Measure β}
    {s : Set β} (hs : MeasurableSet s) {f : β → α} (hf : AntitoneOn f s) :
    AeMeasurable f (μ.restrict s) :=
  @aeMeasurableRestrictOfMonotoneOn αᵒᵈ β _ _ ‹_› _ _ _ _ _ ‹_› _ _ _ _ hs _ hf
#align ae_measurable_restrict_of_antitone_on aeMeasurableRestrictOfAntitoneOn

theorem measurableSet_of_mem_nhdsWithin_Ioi_aux {s : Set α} (h : ∀ x ∈ s, s ∈ 𝓝[>] x)
    (h' : ∀ x ∈ s, ∃ y, x < y) : MeasurableSet s :=
  by
  choose! M hM using h'
  suffices H : (s \ interior s).Countable
  · have : s = interior s ∪ s \ interior s := by rw [union_diff_cancel interior_subset]
    rw [this]
    exact is_open_interior.measurable_set.union H.measurable_set
  have A : ∀ x ∈ s, ∃ y ∈ Ioi x, Ioo x y ⊆ s := fun x hx =>
    (mem_nhdsWithin_Ioi_iff_exists_Ioo_subset' (hM x hx)).1 (h x hx)
  choose! y hy h'y using A
  have B : Set.PairwiseDisjoint (s \ interior s) fun x => Ioo x (y x) :=
    by
    intro x hx x' hx' hxx'
    rcases lt_or_gt_of_ne hxx' with (h' | h')
    · apply disjoint_left.2 fun z hz h'z => _
      have : x' ∈ interior s :=
        mem_interior.2 ⟨Ioo x (y x), h'y _ hx.1, isOpen_Ioo, ⟨h', h'z.1.trans hz.2⟩⟩
      exact False.elim (hx'.2 this)
    · apply disjoint_left.2 fun z hz h'z => _
      have : x ∈ interior s :=
        mem_interior.2 ⟨Ioo x' (y x'), h'y _ hx'.1, isOpen_Ioo, ⟨h', hz.1.trans h'z.2⟩⟩
      exact False.elim (hx.2 this)
  exact B.countable_of_Ioo fun x hx => hy x hx.1
#align measurable_set_of_mem_nhds_within_Ioi_aux measurableSet_of_mem_nhdsWithin_Ioi_aux

/-- If a set is a right-neighborhood of all of its points, then it is measurable. -/
theorem measurableSet_of_mem_nhdsWithin_Ioi {s : Set α} (h : ∀ x ∈ s, s ∈ 𝓝[>] x) :
    MeasurableSet s := by
  by_cases H : ∃ x ∈ s, IsTop x
  · rcases H with ⟨x₀, x₀s, h₀⟩
    have : s = {x₀} ∪ s \ {x₀} := by rw [union_diff_cancel (singleton_subset_iff.2 x₀s)]
    rw [this]
    refine' (measurable_set_singleton _).union _
    have A : ∀ x ∈ s \ {x₀}, x < x₀ := fun x hx => lt_of_le_of_ne (h₀ _) (by simpa using hx.2)
    refine' measurableSet_of_mem_nhdsWithin_Ioi_aux (fun x hx => _) fun x hx => ⟨x₀, A x hx⟩
    obtain ⟨u, hu, us⟩ : ∃ (u : α)(H : u ∈ Ioi x), Ioo x u ⊆ s :=
      (mem_nhdsWithin_Ioi_iff_exists_Ioo_subset' (A x hx)).1 (h x hx.1)
    refine' (mem_nhdsWithin_Ioi_iff_exists_Ioo_subset' (A x hx)).2 ⟨u, hu, fun y hy => ⟨us hy, _⟩⟩
    exact ne_of_lt (hy.2.trans_le (h₀ _))
  · apply measurableSet_of_mem_nhdsWithin_Ioi_aux h
    simp only [IsTop] at H
    push_neg  at H
    exact H
#align measurable_set_of_mem_nhds_within_Ioi measurableSet_of_mem_nhdsWithin_Ioi

end LinearOrder

@[measurability]
theorem Measurable.supᵢ_Prop {α} [MeasurableSpace α] [CompleteLattice α] (p : Prop) {f : δ → α}
    (hf : Measurable f) : Measurable fun b => ⨆ h : p, f b :=
  by_cases (fun h : p => by convert hf; funext; exact supᵢ_pos h) fun h : ¬p => by
    convert measurable_const; funext; exact supᵢ_neg h
#align measurable.supr_Prop Measurable.supᵢ_Prop

@[measurability]
theorem Measurable.infᵢ_Prop {α} [MeasurableSpace α] [CompleteLattice α] (p : Prop) {f : δ → α}
    (hf : Measurable f) : Measurable fun b => ⨅ h : p, f b :=
  by_cases (fun h : p => by convert hf; funext; exact infᵢ_pos h) fun h : ¬p => by
    convert measurable_const; funext; exact infᵢ_neg h
#align measurable.infi_Prop Measurable.infᵢ_Prop

section CompleteLinearOrder

variable [CompleteLinearOrder α] [OrderTopology α] [SecondCountableTopology α]

@[measurability]
theorem measurable_supᵢ {ι} [Countable ι] {f : ι → δ → α} (hf : ∀ i, Measurable (f i)) :
    Measurable fun b => ⨆ i, f i b :=
  Measurable.isLUB hf fun b => isLUB_supᵢ
#align measurable_supr measurable_supᵢ

@[measurability]
theorem aeMeasurableSupr {ι} {μ : Measure δ} [Countable ι] {f : ι → δ → α}
    (hf : ∀ i, AeMeasurable (f i) μ) : AeMeasurable (fun b => ⨆ i, f i b) μ :=
  AeMeasurable.isLub hf <| ae_of_all μ fun b => isLUB_supᵢ
#align ae_measurable_supr aeMeasurableSupr

@[measurability]
theorem measurable_infᵢ {ι} [Countable ι] {f : ι → δ → α} (hf : ∀ i, Measurable (f i)) :
    Measurable fun b => ⨅ i, f i b :=
  Measurable.isGLB hf fun b => isGLB_infᵢ
#align measurable_infi measurable_infᵢ

@[measurability]
theorem aeMeasurableInfi {ι} {μ : Measure δ} [Countable ι] {f : ι → δ → α}
    (hf : ∀ i, AeMeasurable (f i) μ) : AeMeasurable (fun b => ⨅ i, f i b) μ :=
  AeMeasurable.isGlb hf <| ae_of_all μ fun b => isGLB_infᵢ
#align ae_measurable_infi aeMeasurableInfi

theorem measurable_bsupr {ι} (s : Set ι) {f : ι → δ → α} (hs : s.Countable)
    (hf : ∀ i, Measurable (f i)) : Measurable fun b => ⨆ i ∈ s, f i b :=
  by
  haveI : Encodable s := hs.to_encodable
  simp only [supᵢ_subtype']
  exact measurable_supᵢ fun i => hf i
#align measurable_bsupr measurable_bsupr

theorem aeMeasurableBsupr {ι} {μ : Measure δ} (s : Set ι) {f : ι → δ → α} (hs : s.Countable)
    (hf : ∀ i, AeMeasurable (f i) μ) : AeMeasurable (fun b => ⨆ i ∈ s, f i b) μ :=
  by
  haveI : Encodable s := hs.to_encodable
  simp only [supᵢ_subtype']
  exact aeMeasurableSupr fun i => hf i
#align ae_measurable_bsupr aeMeasurableBsupr

theorem measurable_binfi {ι} (s : Set ι) {f : ι → δ → α} (hs : s.Countable)
    (hf : ∀ i, Measurable (f i)) : Measurable fun b => ⨅ i ∈ s, f i b :=
  by
  haveI : Encodable s := hs.to_encodable
  simp only [infᵢ_subtype']
  exact measurable_infᵢ fun i => hf i
#align measurable_binfi measurable_binfi

theorem aeMeasurableBinfi {ι} {μ : Measure δ} (s : Set ι) {f : ι → δ → α} (hs : s.Countable)
    (hf : ∀ i, AeMeasurable (f i) μ) : AeMeasurable (fun b => ⨅ i ∈ s, f i b) μ :=
  by
  haveI : Encodable s := hs.to_encodable
  simp only [infᵢ_subtype']
  exact aeMeasurableInfi fun i => hf i
#align ae_measurable_binfi aeMeasurableBinfi

/-- `liminf` over a general filter is measurable. See `measurable_liminf` for the version over `ℕ`.
-/
theorem measurable_liminf' {ι ι'} {f : ι → δ → α} {u : Filter ι} (hf : ∀ i, Measurable (f i))
    {p : ι' → Prop} {s : ι' → Set ι} (hu : u.HasCountableBasis p s) (hs : ∀ i, (s i).Countable) :
    Measurable fun x => liminf (fun i => f i x) u :=
  by
  simp_rw [hu.to_has_basis.liminf_eq_supr_infi]
  refine' measurable_bsupr _ hu.countable _
  exact fun i => measurable_binfi _ (hs i) hf
#align measurable_liminf' measurable_liminf'

/-- `limsup` over a general filter is measurable. See `measurable_limsup` for the version over `ℕ`.
-/
theorem measurable_limsup' {ι ι'} {f : ι → δ → α} {u : Filter ι} (hf : ∀ i, Measurable (f i))
    {p : ι' → Prop} {s : ι' → Set ι} (hu : u.HasCountableBasis p s) (hs : ∀ i, (s i).Countable) :
    Measurable fun x => limsup (fun i => f i x) u :=
  by
  simp_rw [hu.to_has_basis.limsup_eq_infi_supr]
  refine' measurable_binfi _ hu.countable _
  exact fun i => measurable_bsupr _ (hs i) hf
#align measurable_limsup' measurable_limsup'

/-- `liminf` over `ℕ` is measurable. See `measurable_liminf'` for a version with a general filter.
-/
@[measurability]
theorem measurable_liminf {f : ℕ → δ → α} (hf : ∀ i, Measurable (f i)) :
    Measurable fun x => liminf (fun i => f i x) atTop :=
  measurable_liminf' hf atTop_countable_basis fun i => to_countable _
#align measurable_liminf measurable_liminf

/-- `limsup` over `ℕ` is measurable. See `measurable_limsup'` for a version with a general filter.
-/
@[measurability]
theorem measurable_limsup {f : ℕ → δ → α} (hf : ∀ i, Measurable (f i)) :
    Measurable fun x => limsup (fun i => f i x) atTop :=
  measurable_limsup' hf atTop_countable_basis fun i => to_countable _
#align measurable_limsup measurable_limsup

end CompleteLinearOrder

section ConditionallyCompleteLinearOrder

variable [ConditionallyCompleteLinearOrder α] [OrderTopology α] [SecondCountableTopology α]

theorem measurable_cSup {ι} {f : ι → δ → α} {s : Set ι} (hs : s.Countable)
    (hf : ∀ i, Measurable (f i)) (bdd : ∀ x, BddAbove ((fun i => f i x) '' s)) :
    Measurable fun x => supₛ ((fun i => f i x) '' s) :=
  by
  cases' eq_empty_or_nonempty s with h2s h2s
  · simp [h2s, measurable_const]
  · apply measurable_of_Iic
    intro y
    simp_rw [preimage, mem_Iic, csupₛ_le_iff (bdd _) (h2s.image _), ball_image_iff, set_of_forall]
    exact MeasurableSet.binterᵢ hs fun i hi => measurableSet_le (hf i) measurable_const
#align measurable_cSup measurable_cSup

end ConditionallyCompleteLinearOrder

/-- Convert a `homeomorph` to a `measurable_equiv`. -/
def Homemorph.toMeasurableEquiv (h : α ≃ₜ β) : α ≃ᵐ β
    where
  toEquiv := h.toEquiv
  measurable_to_fun := h.continuous_toFun.Measurable
  measurable_inv_fun := h.continuous_invFun.Measurable
#align homemorph.to_measurable_equiv Homemorph.toMeasurableEquiv

protected theorem IsFiniteMeasureOnCompacts.map {α : Type _} {m0 : MeasurableSpace α}
    [TopologicalSpace α] [OpensMeasurableSpace α] {β : Type _} [MeasurableSpace β]
    [TopologicalSpace β] [BorelSpace β] [T2Space β] (μ : Measure α) [IsFiniteMeasureOnCompacts μ]
    (f : α ≃ₜ β) : IsFiniteMeasureOnCompacts (Measure.map f μ) :=
  ⟨by
    intro K hK
    rw [measure.map_apply f.measurable hK.measurable_set]
    apply IsCompact.measure_lt_top
    rwa [f.is_compact_preimage]⟩
#align is_finite_measure_on_compacts.map IsFiniteMeasureOnCompacts.map

end BorelSpace

instance Empty.borelSpace : BorelSpace Empty :=
  ⟨borel_eq_top_of_discrete.symm⟩
#align empty.borel_space Empty.borelSpace

instance Unit.borelSpace : BorelSpace Unit :=
  ⟨borel_eq_top_of_discrete.symm⟩
#align unit.borel_space Unit.borelSpace

instance Bool.borelSpace : BorelSpace Bool :=
  ⟨borel_eq_top_of_discrete.symm⟩
#align bool.borel_space Bool.borelSpace

instance Nat.borelSpace : BorelSpace ℕ :=
  ⟨borel_eq_top_of_discrete.symm⟩
#align nat.borel_space Nat.borelSpace

instance Int.borelSpace : BorelSpace ℤ :=
  ⟨borel_eq_top_of_discrete.symm⟩
#align int.borel_space Int.borelSpace

instance Rat.borelSpace : BorelSpace ℚ :=
  ⟨borel_eq_top_of_countable.symm⟩
#align rat.borel_space Rat.borelSpace

instance (priority := 900) IsROrC.measurableSpace {𝕜 : Type _} [IsROrC 𝕜] : MeasurableSpace 𝕜 :=
  borel 𝕜
#align is_R_or_C.measurable_space IsROrC.measurableSpace

instance (priority := 900) IsROrC.borelSpace {𝕜 : Type _} [IsROrC 𝕜] : BorelSpace 𝕜 :=
  ⟨rfl⟩
#align is_R_or_C.borel_space IsROrC.borelSpace

/- Instances on `real` and `complex` are special cases of `is_R_or_C` but without these instances,
Lean fails to prove `borel_space (ι → ℝ)`, so we leave them here. -/
instance Real.measurableSpace : MeasurableSpace ℝ :=
  borel ℝ
#align real.measurable_space Real.measurableSpace

instance Real.borelSpace : BorelSpace ℝ :=
  ⟨rfl⟩
#align real.borel_space Real.borelSpace

instance NNReal.measurableSpace : MeasurableSpace ℝ≥0 :=
  Subtype.measurableSpace
#align nnreal.measurable_space NNReal.measurableSpace

instance NNReal.borelSpace : BorelSpace ℝ≥0 :=
  Subtype.borelSpace _
#align nnreal.borel_space NNReal.borelSpace

instance ENNReal.measurableSpace : MeasurableSpace ℝ≥0∞ :=
  borel ℝ≥0∞
#align ennreal.measurable_space ENNReal.measurableSpace

instance ENNReal.borelSpace : BorelSpace ℝ≥0∞ :=
  ⟨rfl⟩
#align ennreal.borel_space ENNReal.borelSpace

instance EReal.measurableSpace : MeasurableSpace EReal :=
  borel EReal
#align ereal.measurable_space EReal.measurableSpace

instance EReal.borelSpace : BorelSpace EReal :=
  ⟨rfl⟩
#align ereal.borel_space EReal.borelSpace

instance Complex.measurableSpace : MeasurableSpace ℂ :=
  borel ℂ
#align complex.measurable_space Complex.measurableSpace

instance Complex.borelSpace : BorelSpace ℂ :=
  ⟨rfl⟩
#align complex.borel_space Complex.borelSpace

instance AddCircle.measurableSpace {a : ℝ} : MeasurableSpace (AddCircle a) :=
  borel (AddCircle a)
#align add_circle.measurable_space AddCircle.measurableSpace

instance AddCircle.borelSpace {a : ℝ} : BorelSpace (AddCircle a) :=
  ⟨rfl⟩
#align add_circle.borel_space AddCircle.borelSpace

@[measurability]
protected theorem AddCircle.measurable_mk' {a : ℝ} : Measurable (coe : ℝ → AddCircle a) :=
  Continuous.measurable <| AddCircle.continuous_mk' a
#align add_circle.measurable_mk' AddCircle.measurable_mk'

/-- One can cut out `ℝ≥0∞` into the sets `{0}`, `Ico (t^n) (t^(n+1))` for `n : ℤ` and `{∞}`. This
gives a way to compute the measure of a set in terms of sets on which a given function `f` does not
fluctuate by more than `t`. -/
theorem measure_eq_measure_preimage_add_measure_tsum_Ico_zpow [MeasurableSpace α] (μ : Measure α)
    {f : α → ℝ≥0∞} (hf : Measurable f) {s : Set α} (hs : MeasurableSet s) {t : ℝ≥0} (ht : 1 < t) :
    μ s =
      μ (s ∩ f ⁻¹' {0}) + μ (s ∩ f ⁻¹' {∞}) + ∑' n : ℤ, μ (s ∩ f ⁻¹' Ico (t ^ n) (t ^ (n + 1))) :=
  by
  have A : μ s = μ (s ∩ f ⁻¹' {0}) + μ (s ∩ f ⁻¹' Ioi 0) :=
    by
    rw [← measure_union]
    · congr 1
      ext x
      have : 0 = f x ∨ 0 < f x := eq_or_lt_of_le bot_le
      rw [eq_comm] at this
      simp only [← and_or_left, this, mem_singleton_iff, mem_inter_iff, and_true_iff, mem_union,
        mem_Ioi, mem_preimage]
    · apply disjoint_left.2 fun x hx h'x => _
      have : 0 < f x := h'x.2
      exact lt_irrefl 0 (this.trans_le hx.2.le)
    · exact hs.inter (hf measurableSet_Ioi)
  have B : μ (s ∩ f ⁻¹' Ioi 0) = μ (s ∩ f ⁻¹' {∞}) + μ (s ∩ f ⁻¹' Ioo 0 ∞) :=
    by
    rw [← measure_union]
    · rw [← inter_union_distrib_left]
      congr
      ext x
      simp only [mem_singleton_iff, mem_union, mem_Ioo, mem_Ioi, mem_preimage]
      have H : f x = ∞ ∨ f x < ∞ := eq_or_lt_of_le le_top
      cases H
      ·
        simp only [H, eq_self_iff_true, or_false_iff, WithTop.zero_lt_top, not_top_lt,
          and_false_iff]
      · simp only [H, H.ne, and_true_iff, false_or_iff]
    · apply disjoint_left.2 fun x hx h'x => _
      have : f x < ∞ := h'x.2.2
      exact lt_irrefl _ (this.trans_le (le_of_eq hx.2.symm))
    · exact hs.inter (hf measurableSet_Ioo)
  have C : μ (s ∩ f ⁻¹' Ioo 0 ∞) = ∑' n : ℤ, μ (s ∩ f ⁻¹' Ico (t ^ n) (t ^ (n + 1))) :=
    by
    rw [← measure_Union,
      ENNReal.Ioo_zero_top_eq_unionᵢ_Ico_zpow (ENNReal.one_lt_coe_iff.2 ht) ENNReal.coe_ne_top,
      preimage_Union, inter_Union]
    · intro i j
      simp only [Function.onFun]
      intro hij
      wlog h : i < j generalizing i j
      · exact (this hij.symm (hij.lt_or_lt.resolve_left h)).symm
      apply disjoint_left.2 fun x hx h'x => lt_irrefl (f x) _
      calc
        f x < t ^ (i + 1) := hx.2.2
        _ ≤ t ^ j := (ENNReal.zpow_le_of_le (ENNReal.one_le_coe_iff.2 ht.le) h)
        _ ≤ f x := h'x.2.1

    · intro n
      exact hs.inter (hf measurableSet_Ico)
  rw [A, B, C, add_assoc]
#align measure_eq_measure_preimage_add_measure_tsum_Ico_zpow measure_eq_measure_preimage_add_measure_tsum_Ico_zpow

section PseudoMetricSpace

variable [PseudoMetricSpace α] [MeasurableSpace α] [OpensMeasurableSpace α]

variable [MeasurableSpace β] {x : α} {ε : ℝ}

open Metric

@[measurability]
theorem measurableSet_ball : MeasurableSet (Metric.ball x ε) :=
  Metric.isOpen_ball.MeasurableSet
#align measurable_set_ball measurableSet_ball

@[measurability]
theorem measurableSet_closedBall : MeasurableSet (Metric.closedBall x ε) :=
  Metric.isClosed_ball.MeasurableSet
#align measurable_set_closed_ball measurableSet_closedBall

@[measurability]
theorem measurable_infDist {s : Set α} : Measurable fun x => infDist x s :=
  (continuous_infDist_pt s).Measurable
#align measurable_inf_dist measurable_infDist

@[measurability]
theorem Measurable.infDist {f : β → α} (hf : Measurable f) {s : Set α} :
    Measurable fun x => infDist (f x) s :=
  measurable_infDist.comp hf
#align measurable.inf_dist Measurable.infDist

@[measurability]
theorem measurable_infNndist {s : Set α} : Measurable fun x => infNndist x s :=
  (continuous_infNndist_pt s).Measurable
#align measurable_inf_nndist measurable_infNndist

@[measurability]
theorem Measurable.infNndist {f : β → α} (hf : Measurable f) {s : Set α} :
    Measurable fun x => infNndist (f x) s :=
  measurable_infNndist.comp hf
#align measurable.inf_nndist Measurable.infNndist

section

variable [SecondCountableTopology α]

@[measurability]
theorem measurable_dist : Measurable fun p : α × α => dist p.1 p.2 :=
  continuous_dist.Measurable
#align measurable_dist measurable_dist

@[measurability]
theorem Measurable.dist {f g : β → α} (hf : Measurable f) (hg : Measurable g) :
    Measurable fun b => dist (f b) (g b) :=
  (@continuous_dist α _).measurable2 hf hg
#align measurable.dist Measurable.dist

@[measurability]
theorem measurable_nndist : Measurable fun p : α × α => nndist p.1 p.2 :=
  continuous_nndist.Measurable
#align measurable_nndist measurable_nndist

@[measurability]
theorem Measurable.nndist {f g : β → α} (hf : Measurable f) (hg : Measurable g) :
    Measurable fun b => nndist (f b) (g b) :=
  (@continuous_nndist α _).measurable2 hf hg
#align measurable.nndist Measurable.nndist

end

/-- If a set has a closed thickening with finite measure, then the measure of its `r`-closed
thickenings converges to the measure of its closure as `r` tends to `0`. -/
theorem tendsto_measure_cthickening {μ : Measure α} {s : Set α}
    (hs : ∃ R > 0, μ (cthickening R s) ≠ ∞) :
    Tendsto (fun r => μ (cthickening r s)) (𝓝 0) (𝓝 (μ (closure s))) :=
  by
  have A : tendsto (fun r => μ (cthickening r s)) (𝓝[Ioi 0] 0) (𝓝 (μ (closure s))) :=
    by
    rw [closure_eq_Inter_cthickening]
    exact
      tendsto_measure_bInter_gt (fun r hr => is_closed_cthickening.measurable_set)
        (fun i j ipos ij => cthickening_mono ij _) hs
  have B : tendsto (fun r => μ (cthickening r s)) (𝓝[Iic 0] 0) (𝓝 (μ (closure s))) :=
    by
    apply tendsto.congr' _ tendsto_const_nhds
    filter_upwards [self_mem_nhdsWithin]with _ hr
    rw [cthickening_of_nonpos hr]
  convert B.sup A
  exact (nhds_left_sup_nhds_right' 0).symm
#align tendsto_measure_cthickening tendsto_measure_cthickening

/-- If a closed set has a closed thickening with finite measure, then the measure of its `r`-closed
thickenings converges to its measure as `r` tends to `0`. -/
theorem tendsto_measure_cthickening_of_isClosed {μ : Measure α} {s : Set α}
    (hs : ∃ R > 0, μ (cthickening R s) ≠ ∞) (h's : IsClosed s) :
    Tendsto (fun r => μ (cthickening r s)) (𝓝 0) (𝓝 (μ s)) :=
  by
  convert tendsto_measure_cthickening hs
  exact h's.closure_eq.symm
#align tendsto_measure_cthickening_of_is_closed tendsto_measure_cthickening_of_isClosed

end PseudoMetricSpace

/-- Given a compact set in a proper space, the measure of its `r`-closed thickenings converges to
its measure as `r` tends to `0`. -/
theorem tendsto_measure_cthickening_of_isCompact [MetricSpace α] [MeasurableSpace α]
    [OpensMeasurableSpace α] [ProperSpace α] {μ : Measure α} [IsFiniteMeasureOnCompacts μ]
    {s : Set α} (hs : IsCompact s) :
    Tendsto (fun r => μ (Metric.cthickening r s)) (𝓝 0) (𝓝 (μ s)) :=
  tendsto_measure_cthickening_of_isClosed ⟨1, zero_lt_one, hs.Bounded.cthickening.measure_lt_top.Ne⟩
    hs.IsClosed
#align tendsto_measure_cthickening_of_is_compact tendsto_measure_cthickening_of_isCompact

section PseudoEMetricSpace

variable [PseudoEMetricSpace α] [MeasurableSpace α] [OpensMeasurableSpace α]

variable [MeasurableSpace β] {x : α} {ε : ℝ≥0∞}

open Emetric

@[measurability]
theorem measurableSet_eball : MeasurableSet (EMetric.ball x ε) :=
  EMetric.isOpen_ball.MeasurableSet
#align measurable_set_eball measurableSet_eball

@[measurability]
theorem measurable_edist_right : Measurable (edist x) :=
  (continuous_const.edist continuous_id).Measurable
#align measurable_edist_right measurable_edist_right

@[measurability]
theorem measurable_edist_left : Measurable fun y => edist y x :=
  (continuous_id.edist continuous_const).Measurable
#align measurable_edist_left measurable_edist_left

@[measurability]
theorem measurable_infEdist {s : Set α} : Measurable fun x => infEdist x s :=
  continuous_infEdist.Measurable
#align measurable_inf_edist measurable_infEdist

@[measurability]
theorem Measurable.infEdist {f : β → α} (hf : Measurable f) {s : Set α} :
    Measurable fun x => infEdist (f x) s :=
  measurable_infEdist.comp hf
#align measurable.inf_edist Measurable.infEdist

variable [SecondCountableTopology α]

@[measurability]
theorem measurable_edist : Measurable fun p : α × α => edist p.1 p.2 :=
  continuous_edist.Measurable
#align measurable_edist measurable_edist

@[measurability]
theorem Measurable.edist {f g : β → α} (hf : Measurable f) (hg : Measurable g) :
    Measurable fun b => edist (f b) (g b) :=
  (@continuous_edist α _).measurable2 hf hg
#align measurable.edist Measurable.edist

@[measurability]
theorem AeMeasurable.edist {f g : β → α} {μ : Measure β} (hf : AeMeasurable f μ)
    (hg : AeMeasurable g μ) : AeMeasurable (fun a => edist (f a) (g a)) μ :=
  (@continuous_edist α _).aeMeasurable2 hf hg
#align ae_measurable.edist AeMeasurable.edist

end PseudoEMetricSpace

namespace Real

open MeasurableSpace MeasureTheory

/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (a b) -/
theorem borel_eq_generateFrom_Ioo_rat :
    borel ℝ = generateFrom (⋃ (a : ℚ) (b : ℚ) (h : a < b), {Ioo a b}) :=
  isTopologicalBasis_Ioo_rat.borel_eq_generateFrom
#align real.borel_eq_generate_from_Ioo_rat Real.borel_eq_generateFrom_Ioo_rat

/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (a b) -/
theorem isPiSystem_Ioo_rat : @IsPiSystem ℝ (⋃ (a : ℚ) (b : ℚ) (h : a < b), {Ioo a b}) :=
  by
  convert isPiSystem_Ioo (coe : ℚ → ℝ) (coe : ℚ → ℝ)
  ext x
  simp [eq_comm]
#align real.is_pi_system_Ioo_rat Real.isPiSystem_Ioo_rat

/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (a b) -/
/-- The intervals `(-(n + 1), (n + 1))` form a finite spanning sets in the set of open intervals
with rational endpoints for a locally finite measure `μ` on `ℝ`. -/
def finiteSpanningSetsInIooRat (μ : Measure ℝ) [IsLocallyFiniteMeasure μ] :
    μ.FiniteSpanningSetsIn (⋃ (a : ℚ) (b : ℚ) (h : a < b), {Ioo a b})
    where
  Set n := Ioo (-(n + 1)) (n + 1)
  set_mem n := by
    simp only [mem_Union, mem_singleton_iff]
    refine' ⟨-(n + 1 : ℕ), n + 1, _, by simp⟩
    -- TODO: norm_cast fails here?
    exact (neg_nonpos.2 (@Nat.cast_nonneg ℚ _ (n + 1))).trans_lt n.cast_add_one_pos
  Finite n := measure_Ioo_lt_top
  spanning :=
    unionᵢ_eq_univ_iff.2 fun x =>
      ⟨⌊|x|⌋₊, neg_lt.1 ((neg_le_abs_self x).trans_lt (Nat.lt_floor_add_one _)),
        (le_abs_self x).trans_lt (Nat.lt_floor_add_one _)⟩
#align real.finite_spanning_sets_in_Ioo_rat Real.finiteSpanningSetsInIooRat

theorem measure_ext_Ioo_rat {μ ν : Measure ℝ} [IsLocallyFiniteMeasure μ]
    (h : ∀ a b : ℚ, μ (Ioo a b) = ν (Ioo a b)) : μ = ν :=
  (finiteSpanningSetsInIooRat μ).ext borel_eq_generateFrom_Ioo_rat isPiSystem_Ioo_rat <|
    by
    simp only [mem_Union, mem_singleton_iff]
    rintro _ ⟨a, b, -, rfl⟩
    apply h
#align real.measure_ext_Ioo_rat Real.measure_ext_Ioo_rat

theorem borel_eq_generateFrom_Iio_rat : borel ℝ = generateFrom (⋃ a : ℚ, {Iio a}) :=
  by
  let g : MeasurableSpace ℝ := generate_from (⋃ a : ℚ, {Iio a})
  refine' le_antisymm _ _
  · rw [borel_eq_generate_from_Ioo_rat]
    refine' generate_from_le fun t => _
    simp only [mem_Union, mem_singleton_iff]
    rintro ⟨a, b, h, rfl⟩
    rw [(Set.ext fun x => _ : Ioo (a : ℝ) b = (⋃ c > a, Iio cᶜ) ∩ Iio b)]
    · have hg : ∀ q : ℚ, measurable_set[g] (Iio q) := fun q =>
        generate_measurable.basic (Iio q) (by simp)
      refine' @MeasurableSet.inter _ g _ _ _ (hg _)
      refine' @MeasurableSet.bunionᵢ _ _ g _ _ (to_countable _) fun c h => _
      exact @MeasurableSet.compl _ _ g (hg _)
    · suffices x < ↑b → (↑a < x ↔ ∃ i : ℚ, a < i ∧ ↑i ≤ x) by simpa
      refine' fun _ => ⟨fun h => _, fun ⟨i, hai, hix⟩ => (Rat.cast_lt.2 hai).trans_le hix⟩
      rcases exists_rat_btwn h with ⟨c, ac, cx⟩
      exact ⟨c, Rat.cast_lt.1 ac, cx.le⟩
  · refine' MeasurableSpace.generateFrom_le fun _ => _
    simp only [mem_Union, mem_singleton_iff]
    rintro ⟨r, rfl⟩
    exact measurableSet_Iio
#align real.borel_eq_generate_from_Iio_rat Real.borel_eq_generateFrom_Iio_rat

end Real

variable [MeasurableSpace α]

@[measurability]
theorem measurable_real_toNNReal : Measurable Real.toNNReal :=
  continuous_real_toNNReal.Measurable
#align measurable_real_to_nnreal measurable_real_toNNReal

@[measurability]
theorem Measurable.real_toNNReal {f : α → ℝ} (hf : Measurable f) :
    Measurable fun x => Real.toNNReal (f x) :=
  measurable_real_toNNReal.comp hf
#align measurable.real_to_nnreal Measurable.real_toNNReal

@[measurability]
theorem AeMeasurable.realToNnreal {f : α → ℝ} {μ : Measure α} (hf : AeMeasurable f μ) :
    AeMeasurable (fun x => Real.toNNReal (f x)) μ :=
  measurable_real_toNNReal.compAeMeasurable hf
#align ae_measurable.real_to_nnreal AeMeasurable.realToNnreal

@[measurability]
theorem measurable_coe_nNReal_real : Measurable (coe : ℝ≥0 → ℝ) :=
  NNReal.continuous_coe.Measurable
#align measurable_coe_nnreal_real measurable_coe_nNReal_real

@[measurability]
theorem Measurable.coe_nNReal_real {f : α → ℝ≥0} (hf : Measurable f) :
    Measurable fun x => (f x : ℝ) :=
  measurable_coe_nNReal_real.comp hf
#align measurable.coe_nnreal_real Measurable.coe_nNReal_real

@[measurability]
theorem AeMeasurable.coeNnrealReal {f : α → ℝ≥0} {μ : Measure α} (hf : AeMeasurable f μ) :
    AeMeasurable (fun x => (f x : ℝ)) μ :=
  measurable_coe_nNReal_real.compAeMeasurable hf
#align ae_measurable.coe_nnreal_real AeMeasurable.coeNnrealReal

@[measurability]
theorem measurable_coe_nNReal_eNNReal : Measurable (coe : ℝ≥0 → ℝ≥0∞) :=
  ENNReal.continuous_coe.Measurable
#align measurable_coe_nnreal_ennreal measurable_coe_nNReal_eNNReal

@[measurability]
theorem Measurable.coe_nNReal_eNNReal {f : α → ℝ≥0} (hf : Measurable f) :
    Measurable fun x => (f x : ℝ≥0∞) :=
  ENNReal.continuous_coe.Measurable.comp hf
#align measurable.coe_nnreal_ennreal Measurable.coe_nNReal_eNNReal

@[measurability]
theorem AeMeasurable.coeNnrealEnnreal {f : α → ℝ≥0} {μ : Measure α} (hf : AeMeasurable f μ) :
    AeMeasurable (fun x => (f x : ℝ≥0∞)) μ :=
  ENNReal.continuous_coe.Measurable.compAeMeasurable hf
#align ae_measurable.coe_nnreal_ennreal AeMeasurable.coeNnrealEnnreal

@[measurability]
theorem Measurable.eNNReal_ofReal {f : α → ℝ} (hf : Measurable f) :
    Measurable fun x => ENNReal.ofReal (f x) :=
  ENNReal.continuous_ofReal.Measurable.comp hf
#align measurable.ennreal_of_real Measurable.eNNReal_ofReal

@[simp, norm_cast]
theorem measurable_coe_nNReal_real_iff {f : α → ℝ≥0} :
    Measurable (fun x => f x : α → ℝ) ↔ Measurable f :=
  ⟨fun h => by simpa only [Real.toNNReal_coe] using h.real_to_nnreal, Measurable.coe_nNReal_real⟩
#align measurable_coe_nnreal_real_iff measurable_coe_nNReal_real_iff

@[simp, norm_cast]
theorem aeMeasurable_coe_nNReal_real_iff {f : α → ℝ≥0} {μ : Measure α} :
    AeMeasurable (fun x => f x : α → ℝ) μ ↔ AeMeasurable f μ :=
  ⟨fun h => by simpa only [Real.toNNReal_coe] using h.real_to_nnreal, AeMeasurable.coeNnrealReal⟩
#align ae_measurable_coe_nnreal_real_iff aeMeasurable_coe_nNReal_real_iff

/-- The set of finite `ℝ≥0∞` numbers is `measurable_equiv` to `ℝ≥0`. -/
def MeasurableEquiv.ennrealEquivNnreal : { r : ℝ≥0∞ | r ≠ ∞ } ≃ᵐ ℝ≥0 :=
  ENNReal.neTopHomeomorphNNReal.toMeasurableEquiv
#align measurable_equiv.ennreal_equiv_nnreal MeasurableEquiv.ennrealEquivNnreal

namespace ENNReal

theorem measurable_of_measurable_nNReal {f : ℝ≥0∞ → α} (h : Measurable fun p : ℝ≥0 => f p) :
    Measurable f :=
  measurable_of_measurable_on_compl_singleton ∞
    (MeasurableEquiv.ennrealEquivNnreal.symm.measurable_comp_iff.1 h)
#align ennreal.measurable_of_measurable_nnreal ENNReal.measurable_of_measurable_nNReal

/-- `ℝ≥0∞` is `measurable_equiv` to `ℝ≥0 ⊕ unit`. -/
def ennrealEquivSum : ℝ≥0∞ ≃ᵐ Sum ℝ≥0 Unit :=
  {
    Equiv.optionEquivSumPUnit
      ℝ≥0 with
    measurable_to_fun := measurable_of_measurable_nNReal measurable_inl
    measurable_inv_fun :=
      measurable_sum measurable_coe_nNReal_eNNReal (@measurable_const ℝ≥0∞ Unit _ _ ∞) }
#align ennreal.ennreal_equiv_sum ENNReal.ennrealEquivSum

open Function (uncurry)

theorem measurable_of_measurable_nNReal_prod [MeasurableSpace β] [MeasurableSpace γ]
    {f : ℝ≥0∞ × β → γ} (H₁ : Measurable fun p : ℝ≥0 × β => f (p.1, p.2))
    (H₂ : Measurable fun x => f (∞, x)) : Measurable f :=
  let e : ℝ≥0∞ × β ≃ᵐ Sum (ℝ≥0 × β) (Unit × β) :=
    (ennrealEquivSum.prodCongr (MeasurableEquiv.refl β)).trans
      (MeasurableEquiv.sumProdDistrib _ _ _)
  e.symm.measurable_comp_iff.1 <| measurable_sum H₁ (H₂.comp measurable_id.snd)
#align ennreal.measurable_of_measurable_nnreal_prod ENNReal.measurable_of_measurable_nNReal_prod

theorem measurable_of_measurable_nNReal_nNReal [MeasurableSpace β] {f : ℝ≥0∞ × ℝ≥0∞ → β}
    (h₁ : Measurable fun p : ℝ≥0 × ℝ≥0 => f (p.1, p.2)) (h₂ : Measurable fun r : ℝ≥0 => f (∞, r))
    (h₃ : Measurable fun r : ℝ≥0 => f (r, ∞)) : Measurable f :=
  measurable_of_measurable_nNReal_prod
    (measurable_swap_iff.1 <| measurable_of_measurable_nNReal_prod (h₁.comp measurable_swap) h₃)
    (measurable_of_measurable_nNReal h₂)
#align ennreal.measurable_of_measurable_nnreal_nnreal ENNReal.measurable_of_measurable_nNReal_nNReal

@[measurability]
theorem measurable_ofReal : Measurable ENNReal.ofReal :=
  ENNReal.continuous_ofReal.Measurable
#align ennreal.measurable_of_real ENNReal.measurable_ofReal

@[measurability]
theorem measurable_toReal : Measurable ENNReal.toReal :=
  ENNReal.measurable_of_measurable_nNReal measurable_coe_nNReal_real
#align ennreal.measurable_to_real ENNReal.measurable_toReal

@[measurability]
theorem measurable_toNNReal : Measurable ENNReal.toNNReal :=
  ENNReal.measurable_of_measurable_nNReal measurable_id
#align ennreal.measurable_to_nnreal ENNReal.measurable_toNNReal

instance : HasMeasurableMul₂ ℝ≥0∞ :=
  by
  refine' ⟨measurable_of_measurable_nnreal_nnreal _ _ _⟩
  · simp only [← ENNReal.coe_mul, measurable_mul.coe_nnreal_ennreal]
  · simp only [ENNReal.top_mul', ENNReal.coe_eq_zero]
    exact measurable_const.piecewise (measurable_set_singleton _) measurable_const
  · simp only [ENNReal.mul_top', ENNReal.coe_eq_zero]
    exact measurable_const.piecewise (measurable_set_singleton _) measurable_const

instance : HasMeasurableSub₂ ℝ≥0∞ :=
  ⟨by
    apply measurable_of_measurable_nnreal_nnreal <;>
      simp [← WithTop.coe_sub, continuous_sub.measurable.coe_nnreal_ennreal]⟩

instance : HasMeasurableInv ℝ≥0∞ :=
  ⟨continuous_inv.Measurable⟩

end ENNReal

@[measurability]
theorem Measurable.eNNReal_toNNReal {f : α → ℝ≥0∞} (hf : Measurable f) :
    Measurable fun x => (f x).toNNReal :=
  ENNReal.measurable_toNNReal.comp hf
#align measurable.ennreal_to_nnreal Measurable.eNNReal_toNNReal

@[measurability]
theorem AeMeasurable.ennrealToNnreal {f : α → ℝ≥0∞} {μ : Measure α} (hf : AeMeasurable f μ) :
    AeMeasurable (fun x => (f x).toNNReal) μ :=
  ENNReal.measurable_toNNReal.compAeMeasurable hf
#align ae_measurable.ennreal_to_nnreal AeMeasurable.ennrealToNnreal

@[simp, norm_cast]
theorem measurable_coe_nNReal_eNNReal_iff {f : α → ℝ≥0} :
    (Measurable fun x => (f x : ℝ≥0∞)) ↔ Measurable f :=
  ⟨fun h => h.eNNReal_toNNReal, fun h => h.coe_nNReal_eNNReal⟩
#align measurable_coe_nnreal_ennreal_iff measurable_coe_nNReal_eNNReal_iff

@[simp, norm_cast]
theorem aeMeasurable_coe_nNReal_eNNReal_iff {f : α → ℝ≥0} {μ : Measure α} :
    AeMeasurable (fun x => (f x : ℝ≥0∞)) μ ↔ AeMeasurable f μ :=
  ⟨fun h => h.eNNReal_toNNReal, fun h => h.coe_nNReal_eNNReal⟩
#align ae_measurable_coe_nnreal_ennreal_iff aeMeasurable_coe_nNReal_eNNReal_iff

@[measurability]
theorem Measurable.eNNReal_toReal {f : α → ℝ≥0∞} (hf : Measurable f) :
    Measurable fun x => ENNReal.toReal (f x) :=
  ENNReal.measurable_toReal.comp hf
#align measurable.ennreal_to_real Measurable.eNNReal_toReal

@[measurability]
theorem AeMeasurable.ennrealToReal {f : α → ℝ≥0∞} {μ : Measure α} (hf : AeMeasurable f μ) :
    AeMeasurable (fun x => ENNReal.toReal (f x)) μ :=
  ENNReal.measurable_toReal.compAeMeasurable hf
#align ae_measurable.ennreal_to_real AeMeasurable.ennrealToReal

/-- note: `ℝ≥0∞` can probably be generalized in a future version of this lemma. -/
@[measurability]
theorem Measurable.eNNReal_tsum {ι} [Countable ι] {f : ι → α → ℝ≥0∞} (h : ∀ i, Measurable (f i)) :
    Measurable fun x => ∑' i, f i x :=
  by
  simp_rw [ENNReal.tsum_eq_supᵢ_sum]
  apply measurable_supᵢ
  exact fun s => s.measurable_sum fun i _ => h i
#align measurable.ennreal_tsum Measurable.eNNReal_tsum

@[measurability]
theorem Measurable.eNNReal_tsum' {ι} [Countable ι] {f : ι → α → ℝ≥0∞} (h : ∀ i, Measurable (f i)) :
    Measurable (∑' i, f i) := by
  convert Measurable.eNNReal_tsum h
  ext1 x
  exact tsum_apply (Pi.summable.2 fun _ => ENNReal.summable)
#align measurable.ennreal_tsum' Measurable.eNNReal_tsum'

@[measurability]
theorem Measurable.nNReal_tsum {ι} [Countable ι] {f : ι → α → ℝ≥0} (h : ∀ i, Measurable (f i)) :
    Measurable fun x => ∑' i, f i x :=
  by
  simp_rw [NNReal.tsum_eq_toNNReal_tsum]
  exact (Measurable.eNNReal_tsum fun i => (h i).coe_nNReal_eNNReal).eNNReal_toNNReal
#align measurable.nnreal_tsum Measurable.nNReal_tsum

@[measurability]
theorem AeMeasurable.ennrealTsum {ι} [Countable ι] {f : ι → α → ℝ≥0∞} {μ : Measure α}
    (h : ∀ i, AeMeasurable (f i) μ) : AeMeasurable (fun x => ∑' i, f i x) μ :=
  by
  simp_rw [ENNReal.tsum_eq_supᵢ_sum]
  apply aeMeasurableSupr
  exact fun s => Finset.ae_measurable_sum s fun i _ => h i
#align ae_measurable.ennreal_tsum AeMeasurable.ennrealTsum

@[measurability]
theorem AeMeasurable.nnrealTsum {α : Type _} [MeasurableSpace α] {ι : Type _} [Countable ι]
    {f : ι → α → NNReal} {μ : MeasureTheory.Measure α} (h : ∀ i : ι, AeMeasurable (f i) μ) :
    AeMeasurable (fun x : α => ∑' i : ι, f i x) μ :=
  by
  simp_rw [NNReal.tsum_eq_toNNReal_tsum]
  exact (AeMeasurable.ennrealTsum fun i => (h i).coe_nNReal_eNNReal).eNNReal_toNNReal
#align ae_measurable.nnreal_tsum AeMeasurable.nnrealTsum

@[measurability]
theorem measurable_coe_real_eReal : Measurable (coe : ℝ → EReal) :=
  continuous_coe_real_ereal.Measurable
#align measurable_coe_real_ereal measurable_coe_real_eReal

@[measurability]
theorem Measurable.coe_real_eReal {f : α → ℝ} (hf : Measurable f) :
    Measurable fun x => (f x : EReal) :=
  measurable_coe_real_eReal.comp hf
#align measurable.coe_real_ereal Measurable.coe_real_eReal

@[measurability]
theorem AeMeasurable.coeRealEreal {f : α → ℝ} {μ : Measure α} (hf : AeMeasurable f μ) :
    AeMeasurable (fun x => (f x : EReal)) μ :=
  measurable_coe_real_eReal.compAeMeasurable hf
#align ae_measurable.coe_real_ereal AeMeasurable.coeRealEreal

/-- The set of finite `ereal` numbers is `measurable_equiv` to `ℝ`. -/
def MeasurableEquiv.erealEquivReal : ({⊥, ⊤}ᶜ : Set EReal) ≃ᵐ ℝ :=
  EReal.neBotTopHomeomorphReal.toMeasurableEquiv
#align measurable_equiv.ereal_equiv_real MeasurableEquiv.erealEquivReal

theorem EReal.measurable_of_measurable_real {f : EReal → α} (h : Measurable fun p : ℝ => f p) :
    Measurable f :=
  measurable_of_measurable_on_compl_finite {⊥, ⊤} (by simp)
    (MeasurableEquiv.erealEquivReal.symm.measurable_comp_iff.1 h)
#align ereal.measurable_of_measurable_real EReal.measurable_of_measurable_real

@[measurability]
theorem measurable_eReal_toReal : Measurable EReal.toReal :=
  EReal.measurable_of_measurable_real (by simpa using measurable_id)
#align measurable_ereal_to_real measurable_eReal_toReal

@[measurability]
theorem Measurable.eReal_toReal {f : α → EReal} (hf : Measurable f) :
    Measurable fun x => (f x).toReal :=
  measurable_eReal_toReal.comp hf
#align measurable.ereal_to_real Measurable.eReal_toReal

@[measurability]
theorem AeMeasurable.erealToReal {f : α → EReal} {μ : Measure α} (hf : AeMeasurable f μ) :
    AeMeasurable (fun x => (f x).toReal) μ :=
  measurable_eReal_toReal.compAeMeasurable hf
#align ae_measurable.ereal_to_real AeMeasurable.erealToReal

@[measurability]
theorem measurable_coe_eNNReal_eReal : Measurable (coe : ℝ≥0∞ → EReal) :=
  continuous_coe_ennreal_ereal.Measurable
#align measurable_coe_ennreal_ereal measurable_coe_eNNReal_eReal

@[measurability]
theorem Measurable.coe_eReal_eNNReal {f : α → ℝ≥0∞} (hf : Measurable f) :
    Measurable fun x => (f x : EReal) :=
  measurable_coe_eNNReal_eReal.comp hf
#align measurable.coe_ereal_ennreal Measurable.coe_eReal_eNNReal

@[measurability]
theorem AeMeasurable.coeErealEnnreal {f : α → ℝ≥0∞} {μ : Measure α} (hf : AeMeasurable f μ) :
    AeMeasurable (fun x => (f x : EReal)) μ :=
  measurable_coe_eNNReal_eReal.compAeMeasurable hf
#align ae_measurable.coe_ereal_ennreal AeMeasurable.coeErealEnnreal

section NormedAddCommGroup

variable [NormedAddCommGroup α] [OpensMeasurableSpace α] [MeasurableSpace β]

@[measurability]
theorem measurable_norm : Measurable (norm : α → ℝ) :=
  continuous_norm.Measurable
#align measurable_norm measurable_norm

@[measurability]
theorem Measurable.norm {f : β → α} (hf : Measurable f) : Measurable fun a => norm (f a) :=
  measurable_norm.comp hf
#align measurable.norm Measurable.norm

@[measurability]
theorem AeMeasurable.norm {f : β → α} {μ : Measure β} (hf : AeMeasurable f μ) :
    AeMeasurable (fun a => norm (f a)) μ :=
  measurable_norm.compAeMeasurable hf
#align ae_measurable.norm AeMeasurable.norm

@[measurability]
theorem measurable_nnnorm : Measurable (nnnorm : α → ℝ≥0) :=
  continuous_nnnorm.Measurable
#align measurable_nnnorm measurable_nnnorm

@[measurability]
theorem Measurable.nnnorm {f : β → α} (hf : Measurable f) : Measurable fun a => ‖f a‖₊ :=
  measurable_nnnorm.comp hf
#align measurable.nnnorm Measurable.nnnorm

@[measurability]
theorem AeMeasurable.nnnorm {f : β → α} {μ : Measure β} (hf : AeMeasurable f μ) :
    AeMeasurable (fun a => ‖f a‖₊) μ :=
  measurable_nnnorm.compAeMeasurable hf
#align ae_measurable.nnnorm AeMeasurable.nnnorm

@[measurability]
theorem measurable_ennnorm : Measurable fun x : α => (‖x‖₊ : ℝ≥0∞) :=
  measurable_nnnorm.coe_nNReal_eNNReal
#align measurable_ennnorm measurable_ennnorm

@[measurability]
theorem Measurable.ennnorm {f : β → α} (hf : Measurable f) : Measurable fun a => (‖f a‖₊ : ℝ≥0∞) :=
  hf.nnnorm.coe_nNReal_eNNReal
#align measurable.ennnorm Measurable.ennnorm

@[measurability]
theorem AeMeasurable.ennnorm {f : β → α} {μ : Measure β} (hf : AeMeasurable f μ) :
    AeMeasurable (fun a => (‖f a‖₊ : ℝ≥0∞)) μ :=
  measurable_ennnorm.compAeMeasurable hf
#align ae_measurable.ennnorm AeMeasurable.ennnorm

end NormedAddCommGroup

section Limits

variable [TopologicalSpace β] [PseudoMetrizableSpace β] [MeasurableSpace β] [BorelSpace β]

open Metric

/-- A limit (over a general filter) of measurable `ℝ≥0∞` valued functions is measurable. -/
theorem measurable_of_tendsto_ennreal' {ι} {f : ι → α → ℝ≥0∞} {g : α → ℝ≥0∞} (u : Filter ι)
    [NeBot u] [IsCountablyGenerated u] (hf : ∀ i, Measurable (f i)) (lim : Tendsto f u (𝓝 g)) :
    Measurable g := by
  rcases u.exists_seq_tendsto with ⟨x, hx⟩
  rw [tendsto_pi_nhds] at lim
  have : (fun y => liminf (fun n => (f (x n) y : ℝ≥0∞)) at_top) = g :=
    by
    ext1 y
    exact ((limUnder y).comp hx).liminf_eq
  rw [← this]
  show Measurable fun y => liminf (fun n => (f (x n) y : ℝ≥0∞)) at_top
  exact measurable_liminf fun n => hf (x n)
#align measurable_of_tendsto_ennreal' measurable_of_tendsto_ennreal'

/-- A sequential limit of measurable `ℝ≥0∞` valued functions is measurable. -/
theorem measurable_of_tendsto_eNNReal {f : ℕ → α → ℝ≥0∞} {g : α → ℝ≥0∞} (hf : ∀ i, Measurable (f i))
    (lim : Tendsto f atTop (𝓝 g)) : Measurable g :=
  measurable_of_tendsto_ennreal' atTop hf limUnder
#align measurable_of_tendsto_ennreal measurable_of_tendsto_eNNReal

/-- A limit (over a general filter) of measurable `ℝ≥0` valued functions is measurable. -/
theorem measurable_of_tendsto_nnreal' {ι} {f : ι → α → ℝ≥0} {g : α → ℝ≥0} (u : Filter ι) [NeBot u]
    [IsCountablyGenerated u] (hf : ∀ i, Measurable (f i)) (lim : Tendsto f u (𝓝 g)) :
    Measurable g := by
  simp_rw [← measurable_coe_nNReal_eNNReal_iff] at hf⊢
  refine' measurable_of_tendsto_ennreal' u hf _
  rw [tendsto_pi_nhds] at lim⊢
  exact fun x => (ennreal.continuous_coe.tendsto (g x)).comp (limUnder x)
#align measurable_of_tendsto_nnreal' measurable_of_tendsto_nnreal'

/-- A sequential limit of measurable `ℝ≥0` valued functions is measurable. -/
theorem measurable_of_tendsto_nNReal {f : ℕ → α → ℝ≥0} {g : α → ℝ≥0} (hf : ∀ i, Measurable (f i))
    (lim : Tendsto f atTop (𝓝 g)) : Measurable g :=
  measurable_of_tendsto_nnreal' atTop hf limUnder
#align measurable_of_tendsto_nnreal measurable_of_tendsto_nNReal

/-- A limit (over a general filter) of measurable functions valued in a (pseudo) metrizable space is
measurable. -/
theorem measurable_of_tendsto_metrizable' {ι} {f : ι → α → β} {g : α → β} (u : Filter ι) [NeBot u]
    [IsCountablyGenerated u] (hf : ∀ i, Measurable (f i)) (lim : Tendsto f u (𝓝 g)) :
    Measurable g :=
  by
  letI : PseudoMetricSpace β := pseudo_metrizable_space_pseudo_metric β
  apply measurable_of_is_closed'
  intro s h1s h2s h3s
  have : Measurable fun x => inf_nndist (g x) s :=
    by
    suffices : tendsto (fun i x => inf_nndist (f i x) s) u (𝓝 fun x => inf_nndist (g x) s)
    exact measurable_of_tendsto_nnreal' u (fun i => (hf i).infNndist) this
    rw [tendsto_pi_nhds] at lim⊢
    intro x
    exact ((continuous_inf_nndist_pt s).Tendsto (g x)).comp (limUnder x)
  have h4s : g ⁻¹' s = (fun x => inf_nndist (g x) s) ⁻¹' {0} :=
    by
    ext x
    simp [h1s, ← h1s.mem_iff_inf_dist_zero h2s, ← NNReal.coe_eq_zero]
  rw [h4s]
  exact this (measurable_set_singleton 0)
#align measurable_of_tendsto_metrizable' measurable_of_tendsto_metrizable'

/-- A sequential limit of measurable functions valued in a (pseudo) metrizable space is
measurable. -/
theorem measurable_of_tendsto_metrizable {f : ℕ → α → β} {g : α → β} (hf : ∀ i, Measurable (f i))
    (lim : Tendsto f atTop (𝓝 g)) : Measurable g :=
  measurable_of_tendsto_metrizable' atTop hf limUnder
#align measurable_of_tendsto_metrizable measurable_of_tendsto_metrizable

theorem aeMeasurableOfTendstoMetrizableAe {ι} {μ : Measure α} {f : ι → α → β} {g : α → β}
    (u : Filter ι) [hu : NeBot u] [IsCountablyGenerated u] (hf : ∀ n, AeMeasurable (f n) μ)
    (h_tendsto : ∀ᵐ x ∂μ, Tendsto (fun n => f n x) u (𝓝 (g x))) : AeMeasurable g μ :=
  by
  rcases u.exists_seq_tendsto with ⟨v, hv⟩
  have h'f : ∀ n, AeMeasurable (f (v n)) μ := fun n => hf (v n)
  set p : α → (ℕ → β) → Prop := fun x f' => tendsto (fun n => f' n) at_top (𝓝 (g x))
  have hp : ∀ᵐ x ∂μ, p x fun n => f (v n) x := by
    filter_upwards [h_tendsto]with x hx using hx.comp hv
  set ae_seq_lim := fun x => ite (x ∈ aeSeqSet h'f p) (g x) (⟨f (v 0) x⟩ : Nonempty β).some with hs
  refine'
    ⟨ae_seq_lim,
      measurable_of_tendsto_metrizable' at_top (aeSeq.measurable h'f p)
        (tendsto_pi_nhds.mpr fun x => _),
      _⟩
  · simp_rw [aeSeq, ae_seq_lim]
    split_ifs with hx
    · simp_rw [aeSeq.mk_eq_fun_of_mem_aeSeqSet h'f hx]
      exact @aeSeq.funPropOfMemAeSeqSet _ α β _ _ _ _ _ h'f x hx
    · exact tendsto_const_nhds
  ·
    exact
      (ite_ae_eq_of_measure_compl_zero g (fun x => (⟨f (v 0) x⟩ : Nonempty β).some) (aeSeqSet h'f p)
          (aeSeq.measure_compl_aeSeqSet_eq_zero h'f hp)).symm
#align ae_measurable_of_tendsto_metrizable_ae aeMeasurableOfTendstoMetrizableAe

theorem aeMeasurableOfTendstoMetrizableAe' {μ : Measure α} {f : ℕ → α → β} {g : α → β}
    (hf : ∀ n, AeMeasurable (f n) μ)
    (h_ae_tendsto : ∀ᵐ x ∂μ, Tendsto (fun n => f n x) atTop (𝓝 (g x))) : AeMeasurable g μ :=
  aeMeasurableOfTendstoMetrizableAe atTop hf h_ae_tendsto
#align ae_measurable_of_tendsto_metrizable_ae' aeMeasurableOfTendstoMetrizableAe'

theorem aeMeasurableOfUnifApprox {β} [MeasurableSpace β] [PseudoMetricSpace β] [BorelSpace β]
    {μ : Measure α} {g : α → β}
    (hf : ∀ ε > (0 : ℝ), ∃ f : α → β, AeMeasurable f μ ∧ ∀ᵐ x ∂μ, dist (f x) (g x) ≤ ε) :
    AeMeasurable g μ :=
  by
  obtain ⟨u, u_anti, u_pos, u_lim⟩ :
    ∃ u : ℕ → ℝ, StrictAnti u ∧ (∀ n : ℕ, 0 < u n) ∧ tendsto u at_top (𝓝 0) :=
    exists_seq_strictAnti_tendsto (0 : ℝ)
  choose f Hf using fun n : ℕ => hf (u n) (u_pos n)
  have : ∀ᵐ x ∂μ, tendsto (fun n => f n x) at_top (𝓝 (g x)) :=
    by
    have : ∀ᵐ x ∂μ, ∀ n, dist (f n x) (g x) ≤ u n := ae_all_iff.2 fun n => (Hf n).2
    filter_upwards [this]
    intro x hx
    rw [tendsto_iff_dist_tendsto_zero]
    exact squeeze_zero (fun n => dist_nonneg) hx u_lim
  exact aeMeasurableOfTendstoMetrizableAe' (fun n => (Hf n).1) this
#align ae_measurable_of_unif_approx aeMeasurableOfUnifApprox

theorem measurable_of_tendsto_metrizable_ae {μ : Measure α} [μ.IsComplete] {f : ℕ → α → β}
    {g : α → β} (hf : ∀ n, Measurable (f n))
    (h_ae_tendsto : ∀ᵐ x ∂μ, Tendsto (fun n => f n x) atTop (𝓝 (g x))) : Measurable g :=
  aeMeasurable_iff_measurable.mp
    (aeMeasurableOfTendstoMetrizableAe' (fun i => (hf i).AeMeasurable) h_ae_tendsto)
#align measurable_of_tendsto_metrizable_ae measurable_of_tendsto_metrizable_ae

theorem measurable_limit_of_tendsto_metrizable_ae {ι} [Countable ι] [Nonempty ι] {μ : Measure α}
    {f : ι → α → β} {L : Filter ι} [L.IsCountablyGenerated] (hf : ∀ n, AeMeasurable (f n) μ)
    (h_ae_tendsto : ∀ᵐ x ∂μ, ∃ l : β, Tendsto (fun n => f n x) L (𝓝 l)) :
    ∃ (f_lim : α → β)(hf_lim_meas : Measurable f_lim),
      ∀ᵐ x ∂μ, Tendsto (fun n => f n x) L (𝓝 (f_lim x)) :=
  by
  inhabit ι
  rcases eq_or_ne L ⊥ with (rfl | hL)
  · exact ⟨(hf default).mk _, (hf default).measurable_mk, eventually_of_forall fun x => tendsto_bot⟩
  haveI : ne_bot L := ⟨hL⟩
  let p : α → (ι → β) → Prop := fun x f' => ∃ l : β, tendsto (fun n => f' n) L (𝓝 l)
  have hp_mem : ∀ x ∈ aeSeqSet hf p, p x fun n => f n x := fun x hx =>
    aeSeq.funPropOfMemAeSeqSet hf hx
  have h_ae_eq : ∀ᵐ x ∂μ, ∀ n, aeSeq hf p n x = f n x := aeSeq.aeSeq_eq_fun_ae hf h_ae_tendsto
  let f_lim : α → β := fun x =>
    dite (x ∈ aeSeqSet hf p) (fun h => (hp_mem x h).some) fun h => (⟨f default x⟩ : Nonempty β).some
  have hf_lim : ∀ x, tendsto (fun n => aeSeq hf p n x) L (𝓝 (f_lim x)) :=
    by
    intro x
    simp only [f_lim, aeSeq]
    split_ifs
    · refine' (hp_mem x h).choose_spec.congr fun n => _
      exact (aeSeq.mk_eq_fun_of_mem_aeSeqSet hf h n).symm
    · exact tendsto_const_nhds
  have h_ae_tendsto_f_lim : ∀ᵐ x ∂μ, tendsto (fun n => f n x) L (𝓝 (f_lim x)) :=
    h_ae_eq.mono fun x hx => (hf_lim x).congr hx
  have h_f_lim_meas : Measurable f_lim :=
    measurable_of_tendsto_metrizable' L (aeSeq.measurable hf p)
      (tendsto_pi_nhds.mpr fun x => hf_lim x)
  exact ⟨f_lim, h_f_lim_meas, h_ae_tendsto_f_lim⟩
#align measurable_limit_of_tendsto_metrizable_ae measurable_limit_of_tendsto_metrizable_ae

end Limits

namespace ContinuousLinearMap

variable {𝕜 : Type _} [NormedField 𝕜]

variable {E : Type _} [NormedAddCommGroup E] [NormedSpace 𝕜 E] [MeasurableSpace E]
  [OpensMeasurableSpace E] {F : Type _} [NormedAddCommGroup F] [NormedSpace 𝕜 F] [MeasurableSpace F]
  [BorelSpace F]

@[measurability]
protected theorem measurable (L : E →L[𝕜] F) : Measurable L :=
  L.Continuous.Measurable
#align continuous_linear_map.measurable ContinuousLinearMap.measurable

theorem measurable_comp (L : E →L[𝕜] F) {φ : α → E} (φ_meas : Measurable φ) :
    Measurable fun a : α => L (φ a) :=
  L.Measurable.comp φ_meas
#align continuous_linear_map.measurable_comp ContinuousLinearMap.measurable_comp

end ContinuousLinearMap

namespace ContinuousLinearMap

variable {𝕜 : Type _} [NontriviallyNormedField 𝕜]

variable {E : Type _} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {F : Type _} [NormedAddCommGroup F]
  [NormedSpace 𝕜 F]

instance : MeasurableSpace (E →L[𝕜] F) :=
  borel _

instance : BorelSpace (E →L[𝕜] F) :=
  ⟨rfl⟩

@[measurability]
theorem measurable_apply [MeasurableSpace F] [BorelSpace F] (x : E) :
    Measurable fun f : E →L[𝕜] F => f x :=
  (apply 𝕜 F x).Continuous.Measurable
#align continuous_linear_map.measurable_apply ContinuousLinearMap.measurable_apply

@[measurability]
theorem measurable_apply' [MeasurableSpace E] [OpensMeasurableSpace E] [MeasurableSpace F]
    [BorelSpace F] : Measurable fun (x : E) (f : E →L[𝕜] F) => f x :=
  measurable_pi_lambda _ fun f => f.Measurable
#align continuous_linear_map.measurable_apply' ContinuousLinearMap.measurable_apply'

@[measurability]
theorem measurable_coe [MeasurableSpace F] [BorelSpace F] :
    Measurable fun (f : E →L[𝕜] F) (x : E) => f x :=
  measurable_pi_lambda _ measurable_apply
#align continuous_linear_map.measurable_coe ContinuousLinearMap.measurable_coe

end ContinuousLinearMap

section ContinuousLinearMapNontriviallyNormedField

variable {𝕜 : Type _} [NontriviallyNormedField 𝕜]

variable {E : Type _} [NormedAddCommGroup E] [NormedSpace 𝕜 E] [MeasurableSpace E] [BorelSpace E]
  {F : Type _} [NormedAddCommGroup F] [NormedSpace 𝕜 F]

@[measurability]
theorem Measurable.apply_continuousLinearMap {φ : α → F →L[𝕜] E} (hφ : Measurable φ) (v : F) :
    Measurable fun a => φ a v :=
  (ContinuousLinearMap.apply 𝕜 E v).Measurable.comp hφ
#align measurable.apply_continuous_linear_map Measurable.apply_continuousLinearMap

@[measurability]
theorem AeMeasurable.applyContinuousLinearMap {φ : α → F →L[𝕜] E} {μ : Measure α}
    (hφ : AeMeasurable φ μ) (v : F) : AeMeasurable (fun a => φ a v) μ :=
  (ContinuousLinearMap.apply 𝕜 E v).Measurable.compAeMeasurable hφ
#align ae_measurable.apply_continuous_linear_map AeMeasurable.applyContinuousLinearMap

end ContinuousLinearMapNontriviallyNormedField

section NormedSpace

variable {𝕜 : Type _} [NontriviallyNormedField 𝕜] [CompleteSpace 𝕜] [MeasurableSpace 𝕜]

variable [BorelSpace 𝕜] {E : Type _} [NormedAddCommGroup E] [NormedSpace 𝕜 E] [MeasurableSpace E]
  [BorelSpace E]

theorem measurable_smul_const {f : α → 𝕜} {c : E} (hc : c ≠ 0) :
    (Measurable fun x => f x • c) ↔ Measurable f :=
  (closedEmbedding_smul_left hc).MeasurableEmbedding.measurable_comp_iff
#align measurable_smul_const measurable_smul_const

theorem aeMeasurable_smul_const {f : α → 𝕜} {μ : Measure α} {c : E} (hc : c ≠ 0) :
    AeMeasurable (fun x => f x • c) μ ↔ AeMeasurable f μ :=
  (closedEmbedding_smul_left hc).MeasurableEmbedding.aeMeasurable_comp_iff
#align ae_measurable_smul_const aeMeasurable_smul_const

end NormedSpace