/-
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
-/
import measure_theory.function.ae_measurable_sequence
import analysis.complex.basic
import analysis.normed_space.finite_dimension
import measure_theory.group.arithmetic
import topology.algebra.ordered.liminf_limsup
import topology.continuous_function.basic
import topology.instances.ereal
import topology.G_delta
import topology.semicontinuous

/-!
# 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 theory

open classical set filter measure_theory
open_locale classical big_operators topological_space nnreal ennreal interval

universes u v w x y
variables {α β γ γ₂ δ : Type*} {ι : Sort y} {s t u : set α}

open measurable_space topological_space

/-- `measurable_space` structure generated by `topological_space`. -/
def borel (α : Type u) [topological_space α] : measurable_space α :=
generate_from {s : set α | is_open s}

lemma borel_eq_top_of_discrete [topological_space α] [discrete_topology α] :
  borel α = ⊤ :=
top_le_iff.1 $ λ s hs, generate_measurable.basic s (is_open_discrete s)

lemma borel_eq_top_of_encodable [topological_space α] [t1_space α] [encodable α] :
  borel α = ⊤ :=
begin
  refine (top_le_iff.1 $ λ s hs, bUnion_of_singleton s ▸ _),
  apply measurable_set.bUnion s.countable_encodable,
  intros x hx,
  apply measurable_set.of_compl,
  apply generate_measurable.basic,
  exact is_closed_singleton.is_open_compl
end

lemma borel_eq_generate_from_of_subbasis {s : set (set α)}
  [t : topological_space α] [second_countable_topology α] (hs : t = generate_from s) :
  borel α = generate_from s :=
le_antisymm
  (generate_from_le $ assume u (hu : t.is_open u),
    begin
      rw [hs] at hu,
      induction hu,
      case generate_open.basic : u hu
      { exact generate_measurable.basic u hu },
      case generate_open.univ
      { exact @measurable_set.univ α (generate_from s) },
      case generate_open.inter : s₁ s₂ _ _ hs₁ hs₂
      { exact @measurable_set.inter α (generate_from s) _ _ hs₁ hs₂ },
      case generate_open.sUnion : f hf ih
      { rcases is_open_sUnion_countable f (by rwa hs) with ⟨v, hv, vf, vu⟩,
        rw ← vu,
        exact @measurable_set.sUnion α (generate_from s) _ hv
          (λ x xv, ih _ (vf xv)) }
    end)
  (generate_from_le $ assume u hu, generate_measurable.basic _ $
    show t.is_open u, by rw [hs]; exact generate_open.basic _ hu)

lemma topological_space.is_topological_basis.borel_eq_generate_from [topological_space α]
  [second_countable_topology α] {s : set (set α)} (hs : is_topological_basis s) :
  borel α = generate_from s :=
borel_eq_generate_from_of_subbasis hs.eq_generate_from

lemma is_pi_system_is_open [topological_space α] : is_pi_system (is_open : set α → Prop) :=
λ s t hs ht hst, is_open.inter hs ht

lemma borel_eq_generate_from_is_closed [topological_space α] :
  borel α = generate_from {s | is_closed s} :=
le_antisymm
  (generate_from_le $ λ t ht, @measurable_set.of_compl α _ (generate_from {s | is_closed s})
    (generate_measurable.basic _ $ is_closed_compl_iff.2 ht))
  (generate_from_le $ λ t ht, @measurable_set.of_compl α _ (borel α)
    (generate_measurable.basic _ $ is_open_compl_iff.2 ht))

section order_topology

variable (α)
variables [topological_space α] [second_countable_topology α] [linear_order α] [order_topology α]

lemma borel_eq_generate_from_Iio : borel α = generate_from (range Iio) :=
begin
  refine le_antisymm _ (generate_from_le _),
  { rw borel_eq_generate_from_of_subbasis (@order_topology.topology_eq_generate_intervals α _ _ _),
    letI : measurable_space α := measurable_space.generate_from (range Iio),
    have H : ∀ a : α, measurable_set (Iio a) := λ 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
        (λ a' : {a' : α // a < a'}, {b | a'.1 < b})
        (λ a', is_open_lt' _) with ⟨v, ⟨hv⟩, vu⟩,
      simp [set.ext_iff] at vu,
      have : Ioi a = ⋃ x : v, (Iio x.1.1)ᶜ,
      { simp [set.ext_iff],
        refine λ x, ⟨λ ax, _, λ ⟨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 (λ h, _) h,
        exact ⟨x, λ b, ⟨λ ab, le_of_not_lt (λ h', h ⟨b, ab, h'⟩),
          lt_of_lt_of_le ax⟩⟩ },
      rw this, resetI,
      apply measurable_set.Union,
      exact λ _, (H _).compl } },
  { rw forall_range_iff,
    intro a,
    exact generate_measurable.basic _ is_open_Iio }
end

lemma borel_eq_generate_from_Ioi : borel α = generate_from (range Ioi) :=
@borel_eq_generate_from_Iio (order_dual α) _ (by apply_instance : second_countable_topology α) _ _

end order_topology

lemma borel_comap {f : α → β} {t : topological_space β} :
  @borel α (t.induced f) = (@borel β t).comap f :=
comap_generate_from.symm

lemma continuous.borel_measurable [topological_space α] [topological_space β]
  {f : α → β} (hf : continuous f) :
  @measurable α β (borel α) (borel β) f :=
measurable.of_le_map $ generate_from_le $
  λ s hs, generate_measurable.basic (f ⁻¹' s) (hs.preimage hf)

/-- A space with `measurable_space` and `topological_space` structures such that
all open sets are measurable. -/
class opens_measurable_space (α : Type*) [topological_space α] [h : measurable_space α] : Prop :=
(borel_le : borel α ≤ h)

/-- 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 borel_space (α : Type*) [topological_space α] [measurable_space α] : Prop :=
(measurable_eq : ‹measurable_space α› = borel α)

/-- In a `borel_space` all open sets are measurable. -/
@[priority 100]
instance borel_space.opens_measurable {α : Type*} [topological_space α] [measurable_space α]
  [borel_space α] : opens_measurable_space α :=
⟨ge_of_eq $ borel_space.measurable_eq⟩

instance subtype.borel_space {α : Type*} [topological_space α] [measurable_space α]
  [hα : borel_space α] (s : set α) :
  borel_space s :=
⟨by { rw [hα.1, subtype.measurable_space, ← borel_comap], refl }⟩

instance subtype.opens_measurable_space {α : Type*} [topological_space α] [measurable_space α]
  [h : opens_measurable_space α] (s : set α) :
  opens_measurable_space s :=
⟨by { rw [borel_comap], exact comap_mono h.1 }⟩

theorem _root_.measurable_set.induction_on_open [topological_space α] [measurable_space α]
  [borel_space α] {C : set α → Prop} (h_open : ∀ U, is_open U → C U)
  (h_compl : ∀ t, measurable_set t → C t → C tᶜ)
  (h_union : ∀ f : ℕ → set α, pairwise (disjoint on f) →
    (∀ i, measurable_set (f i)) → (∀ i, C (f i)) → C (⋃ i, f i)) :
  ∀ ⦃t⦄, measurable_set t → C t :=
measurable_space.induction_on_inter borel_space.measurable_eq is_pi_system_is_open
  (h_open _ is_open_empty) h_open h_compl h_union

section
variables [topological_space α] [measurable_space α] [opens_measurable_space α]
   [topological_space β] [measurable_space β] [opens_measurable_space β]
   [topological_space γ] [measurable_space γ] [borel_space γ]
   [topological_space γ₂] [measurable_space γ₂] [borel_space γ₂]
   [measurable_space δ]

lemma is_open.measurable_set (h : is_open s) : measurable_set s :=
opens_measurable_space.borel_le _ $ generate_measurable.basic _ h

@[measurability]
lemma measurable_set_interior : measurable_set (interior s) := is_open_interior.measurable_set

lemma is_Gδ.measurable_set (h : is_Gδ s) : measurable_set s :=
begin
  rcases h with ⟨S, hSo, hSc, rfl⟩,
  exact measurable_set.sInter hSc (λ t ht, (hSo t ht).measurable_set)
end

lemma measurable_set_of_continuous_at {β} [emetric_space β] (f : α → β) :
  measurable_set {x | continuous_at f x} :=
(is_Gδ_set_of_continuous_at f).measurable_set

lemma is_closed.measurable_set (h : is_closed s) : measurable_set s :=
h.is_open_compl.measurable_set.of_compl

lemma is_compact.measurable_set [t2_space α] (h : is_compact s) : measurable_set s :=
h.is_closed.measurable_set

@[measurability]
lemma measurable_set_closure : measurable_set (closure s) :=
is_closed_closure.measurable_set

lemma measurable_of_is_open {f : δ → γ} (hf : ∀ s, is_open s → measurable_set (f ⁻¹' s)) :
  measurable f :=
by { rw [‹borel_space γ›.measurable_eq], exact measurable_generate_from hf }

lemma measurable_of_is_closed {f : δ → γ} (hf : ∀ s, is_closed s → measurable_set (f ⁻¹' s)) :
  measurable f :=
begin
  apply measurable_of_is_open, intros s hs,
  rw [← measurable_set.compl_iff, ← preimage_compl], apply hf, rw [is_closed_compl_iff], exact hs
end

lemma measurable_of_is_closed' {f : δ → γ}
  (hf : ∀ s, is_closed s → s.nonempty → s ≠ univ → measurable_set (f ⁻¹' s)) : measurable f :=
begin
  apply measurable_of_is_closed, intros 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
end

instance nhds_is_measurably_generated (a : α) : (𝓝 a).is_measurably_generated :=
begin
  rw [nhds, infi_subtype'],
  refine @filter.infi_is_measurably_generated _ _ _ _ (λ i, _),
  exact i.2.2.measurable_set.principal_is_measurably_generated
end

/-- 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`.
-/
lemma measurable_set.nhds_within_is_measurably_generated {s : set α} (hs : measurable_set s)
  (a : α) :
  (𝓝[s] a).is_measurably_generated :=
by haveI := hs.principal_is_measurably_generated; exact filter.inf_is_measurably_generated _ _

@[priority 100] -- see Note [lower instance priority]
instance opens_measurable_space.to_measurable_singleton_class [t1_space α] :
  measurable_singleton_class α :=
⟨λ x, is_closed_singleton.measurable_set⟩

instance pi.opens_measurable_space_encodable {ι : Type*} {π : ι → Type*} [encodable ι]
  [t' : Π i, topological_space (π i)]
  [Π i, measurable_space (π i)] [∀ i, second_countable_topology (π i)]
  [∀ i, opens_measurable_space (π i)] :
  opens_measurable_space (Π i, π i) :=
begin
  constructor,
  have : Pi.topological_space =
    generate_from {t | ∃(s:Πa, set (π a)) (i : finset ι), (∀a∈i, s a ∈ countable_basis (π a)) ∧
      t = pi ↑i s},
  { rw [funext (λ a, @eq_generate_from_countable_basis (π a) _ _), pi_generate_from_eq] },
  rw [borel_eq_generate_from_of_subbasis this],
  apply generate_from_le,
  rintros _ ⟨s, i, hi, rfl⟩,
  refine measurable_set.pi i.countable_to_set (λ a ha, is_open.measurable_set _),
  rw [eq_generate_from_countable_basis (π a)],
  exact generate_open.basic _ (hi a ha)
end

instance pi.opens_measurable_space_fintype {ι : Type*} {π : ι → Type*} [fintype ι]
  [t' : Π i, topological_space (π i)]
  [Π i, measurable_space (π i)] [∀ i, second_countable_topology (π i)]
  [∀ i, opens_measurable_space (π i)] :
  opens_measurable_space (Π i, π i) :=
by { letI := fintype.encodable ι, apply_instance }

instance prod.opens_measurable_space [second_countable_topology α] [second_countable_topology β] :
  opens_measurable_space (α × β) :=
begin
  constructor,
  rw [((is_basis_countable_basis α).prod (is_basis_countable_basis β)).borel_eq_generate_from],
  apply generate_from_le,
  rintros _ ⟨u, v, hu, hv, rfl⟩,
  exact (is_open_of_mem_countable_basis hu).measurable_set.prod
    (is_open_of_mem_countable_basis hv).measurable_set
end

variables {α' : Type*} [topological_space α'] [measurable_space α']

lemma measure_interior_of_null_bdry {μ : measure α'} {s : set α'}
  (h_nullbdry : μ (frontier s) = 0) : μ (interior s) = μ s :=
measure_eq_measure_smaller_of_between_null_diff
  interior_subset subset_closure h_nullbdry

lemma measure_closure_of_null_bdry {μ : measure α'} {s : set α'}
  (h_nullbdry : μ (frontier s) = 0) : μ (closure s) = μ s :=
(measure_eq_measure_larger_of_between_null_diff
  interior_subset subset_closure h_nullbdry).symm

section preorder
variables [preorder α] [order_closed_topology α] {a b x : α}

@[simp, measurability]
lemma measurable_set_Ici : measurable_set (Ici a) := is_closed_Ici.measurable_set
@[simp, measurability]
lemma measurable_set_Iic : measurable_set (Iic a) := is_closed_Iic.measurable_set
@[simp, measurability]
lemma measurable_set_Icc : measurable_set (Icc a b) := is_closed_Icc.measurable_set

instance nhds_within_Ici_is_measurably_generated :
  (𝓝[Ici b] a).is_measurably_generated :=
measurable_set_Ici.nhds_within_is_measurably_generated _

instance nhds_within_Iic_is_measurably_generated :
  (𝓝[Iic b] a).is_measurably_generated :=
measurable_set_Iic.nhds_within_is_measurably_generated _

instance nhds_within_Icc_is_measurably_generated :
  is_measurably_generated (𝓝[Icc a b] x) :=
by { rw [← Ici_inter_Iic, nhds_within_inter], apply_instance }

instance at_top_is_measurably_generated : (filter.at_top : filter α).is_measurably_generated :=
@filter.infi_is_measurably_generated _ _ _ _ $
  λ a, (measurable_set_Ici : measurable_set (Ici a)).principal_is_measurably_generated

instance at_bot_is_measurably_generated : (filter.at_bot : filter α).is_measurably_generated :=
@filter.infi_is_measurably_generated _ _ _ _ $
  λ a, (measurable_set_Iic : measurable_set (Iic a)).principal_is_measurably_generated

lemma bsupr_measure_Iic {μ : measure α} {s : set α} (hsc : countable s)
  (hst : ∀ x : α, ∃ y ∈ s, x ≤ y) (hdir : directed_on (≤) s) :
  (⨆ x ∈ s, μ (Iic x)) = μ univ :=
begin
  rw ← measure_bUnion_eq_supr hsc,
  { congr, exact bUnion_eq_univ_iff.2 hst },
  { exact λ _ _, measurable_set_Iic },
  { exact directed_on_iff_directed.2 (hdir.directed_coe.mono_comp _ $ λ x y, Iic_subset_Iic.2) }
end

end preorder

section partial_order
variables [partial_order α] [order_closed_topology α] [second_countable_topology α]
  {a b : α}

@[measurability]
lemma measurable_set_le' : measurable_set {p : α × α | p.1 ≤ p.2} :=
order_closed_topology.is_closed_le'.measurable_set

@[measurability]
lemma measurable_set_le {f g : δ → α} (hf : measurable f) (hg : measurable g) :
  measurable_set {a | f a ≤ g a} :=
hf.prod_mk hg measurable_set_le'

end partial_order

section linear_order
variables [linear_order α] [order_closed_topology α] {a b x : α}

@[simp, measurability]
lemma measurable_set_Iio : measurable_set (Iio a) := is_open_Iio.measurable_set
@[simp, measurability]
lemma measurable_set_Ioi : measurable_set (Ioi a) := is_open_Ioi.measurable_set
@[simp, measurability]
lemma measurable_set_Ioo : measurable_set (Ioo a b) := is_open_Ioo.measurable_set

@[simp, measurability] lemma measurable_set_Ioc : measurable_set (Ioc a b) :=
measurable_set_Ioi.inter measurable_set_Iic

@[simp, measurability] lemma measurable_set_Ico : measurable_set (Ico a b) :=
measurable_set_Ici.inter measurable_set_Iio

instance nhds_within_Ioi_is_measurably_generated :
  (𝓝[Ioi b] a).is_measurably_generated :=
measurable_set_Ioi.nhds_within_is_measurably_generated _

instance nhds_within_Iio_is_measurably_generated :
  (𝓝[Iio b] a).is_measurably_generated :=
measurable_set_Iio.nhds_within_is_measurably_generated _

instance nhds_within_interval_is_measurably_generated :
  is_measurably_generated (𝓝[[a, b]] x) :=
nhds_within_Icc_is_measurably_generated

@[measurability]
lemma measurable_set_lt' [second_countable_topology α] : measurable_set {p : α × α | p.1 < p.2} :=
(is_open_lt continuous_fst continuous_snd).measurable_set

@[measurability]
lemma measurable_set_lt [second_countable_topology α] {f g : δ → α} (hf : measurable f)
  (hg : measurable g) : measurable_set {a | f a < g a} :=
hf.prod_mk hg measurable_set_lt'

lemma set.ord_connected.measurable_set (h : ord_connected s) : measurable_set s :=
begin
  let u := ⋃ (x ∈ s) (y ∈ s), Ioo x y,
  have huopen : is_open u := is_open_bUnion (λ x hx, is_open_bUnion (λ y hy, is_open_Ioo)),
  have humeas : measurable_set u := huopen.measurable_set,
  have hfinite : (s \ u).finite,
  { refine set.finite_of_forall_between_eq_endpoints (s \ u) (λ x hx y hy z hz hxy hyz, _),
    by_contra h,
    push_neg at h,
    exact hy.2 (mem_bUnion_iff.mpr ⟨x, hx.1,
      mem_bUnion_iff.mpr ⟨z, hz.1, lt_of_le_of_ne hxy h.1, lt_of_le_of_ne hyz h.2⟩⟩) },
  have : u ⊆ s :=
    bUnion_subset (λ x hx, bUnion_subset (λ y hy, Ioo_subset_Icc_self.trans (h.out hx hy))),
  rw ← union_diff_cancel this,
  exact humeas.union hfinite.measurable_set
end

lemma is_preconnected.measurable_set
  (h : is_preconnected s) : measurable_set s :=
h.ord_connected.measurable_set

lemma generate_from_Ico_mem_le_borel {α : Type*} [topological_space α] [linear_order α]
  [order_closed_topology α] (s t : set α) :
  measurable_space.generate_from {S | ∃ (l ∈ s) (u ∈ t) (h : l < u), Ico l u = S} ≤ borel α :=
begin
  apply generate_from_le,
  letI : measurable_space α := borel α, haveI : borel_space α := ⟨rfl⟩,
  rintro _ ⟨a, -, b, -, -, rfl⟩,
  exact measurable_set_Ico
end

lemma dense.borel_eq_generate_from_Ico_mem_aux {α : Type*} [topological_space α] [linear_order α]
  [order_topology α] [second_countable_topology α] {s : set α} (hd : dense s)
  (hbot : ∀ x, is_bot x → x ∈ s) (hIoo : ∀ x y : α, x < y → Ioo x y = ∅ → y ∈ s) :
  borel α = generate_from {S : set α | ∃ (l ∈ s) (u ∈ s) (h : l < u), Ico l u = S} :=
begin
  set S : set (set α) := {S | ∃ (l ∈ s) (u ∈ s) (h : l < u), Ico l u = S},
  refine le_antisymm _ (generate_from_Ico_mem_le_borel _ _),
  letI : measurable_space α := generate_from S,
  rw borel_eq_generate_from_Iio,
  refine generate_from_le (forall_range_iff.2 $ λ 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 measurable_set (⋃ (l ∈ t) (u ∈ t) (hlu : l < u) (hu : u ≤ a), Ico l u),
    { ext y, simp only [mem_Union, mem_Iio, mem_Ico], split,
      { intro hy,
        rcases htd.exists_le' (λ b hb, htb _ hb (hbot b hb)) y with ⟨l, hlt, hly⟩,
        rcases htd.exists_mem_open is_open_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 measurable_set.bUnion hc (λ a ha, measurable_set.bUnion hc $ λ b hb, _),
      refine measurable_set.Union_Prop (λ hab, measurable_set.Union_Prop $ λ 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 measurable_set (⋃ (l ∈ t) (hl : l < a), Ico l a),
    { symmetry,
      simp only [← Ici_inter_Iio, ← Union_inter, inter_eq_right_iff_subset, subset_def, mem_Union,
        mem_Ici, mem_Iio],
      intros x hx, rcases htd.exists_le' (λ b hb, htb _ hb (hbot b hb)) x with ⟨z, hzt, hzx⟩,
      exact ⟨z, hzt, hzx.trans_lt hx, hzx⟩ },
    { refine measurable_set.bUnion hc (λ x hx, measurable_set.Union_Prop $ λ hlt, _),
      exact generate_measurable.basic _ ⟨x, hts hx, a, ha, hlt, mem_singleton _⟩ } }
end

lemma dense.borel_eq_generate_from_Ico_mem {α : Type*} [topological_space α] [linear_order α]
  [order_topology α] [second_countable_topology α] [densely_ordered α] [no_bot_order α]
  {s : set α} (hd : dense s) :
  borel α = generate_from {S : set α | ∃ (l ∈ s) (u ∈ s) (h : l < u), Ico l u = S} :=
hd.borel_eq_generate_from_Ico_mem_aux (by simp) $
  λ x y hxy H, ((nonempty_Ioo.2 hxy).ne_empty H).elim

lemma borel_eq_generate_from_Ico (α : Type*) [topological_space α]
  [second_countable_topology α] [linear_order α] [order_topology α] :
  borel α = generate_from {S : set α | ∃ l u (h : l < u), Ico l u = S} :=
by simpa only [exists_prop, mem_univ, true_and]
  using (@dense_univ α _).borel_eq_generate_from_Ico_mem_aux (λ _ _, mem_univ _)
      (λ _ _ _ _, mem_univ _)

lemma dense.borel_eq_generate_from_Ioc_mem_aux {α : Type*} [topological_space α] [linear_order α]
  [order_topology α] [second_countable_topology α] {s : set α} (hd : dense s)
  (hbot : ∀ x, is_top x → x ∈ s) (hIoo : ∀ x y : α, x < y → Ioo x y = ∅ → x ∈ s) :
  borel α = generate_from {S : set α | ∃ (l ∈ s) (u ∈ s) (h : l < u), Ioc l u = S} :=
begin
  convert hd.order_dual.borel_eq_generate_from_Ico_mem_aux hbot (λ x y hlt he, hIoo y x hlt _),
  { ext s,
    split; 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 }
end

lemma dense.borel_eq_generate_from_Ioc_mem {α : Type*} [topological_space α] [linear_order α]
  [order_topology α] [second_countable_topology α] [densely_ordered α] [no_top_order α]
  {s : set α} (hd : dense s) :
  borel α = generate_from {S : set α | ∃ (l ∈ s) (u ∈ s) (h : l < u), Ioc l u = S} :=
hd.borel_eq_generate_from_Ioc_mem_aux (by simp) $
  λ x y hxy H, ((nonempty_Ioo.2 hxy).ne_empty H).elim

lemma borel_eq_generate_from_Ioc (α : Type*) [topological_space α]
  [second_countable_topology α] [linear_order α] [order_topology α] :
  borel α = generate_from {S : set α | ∃ l u (h : l < u), Ioc l u = S} :=
by simpa only [exists_prop, mem_univ, true_and]
  using (@dense_univ α _).borel_eq_generate_from_Ioc_mem_aux (λ _ _, mem_univ _)
      (λ _ _ _ _, mem_univ _)

namespace measure_theory.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
`ν`. -/
lemma ext_of_Ico_finite {α : Type*} [topological_space α] {m : measurable_space α}
  [second_countable_topology α] [linear_order α] [order_topology α]
  [borel_space α] (μ ν : measure α) [is_finite_measure μ] (hμν : μ univ = ν univ)
  (h : ∀ ⦃a b⦄, a < b → μ (Ico a b) = ν (Ico a b)) : μ = ν :=
begin
  refine ext_of_generate_finite _
    (borel_space.measurable_eq.trans (borel_eq_generate_from_Ico α))
    (is_pi_system_Ico (id : α → α) id) _ hμν,
  { rintro - ⟨a, b, hlt, rfl⟩,
    exact h hlt }
end

/-- 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
`ν`. -/
lemma ext_of_Ioc_finite {α : Type*} [topological_space α] {m : measurable_space α}
  [second_countable_topology α] [linear_order α] [order_topology α]
  [borel_space α] (μ ν : measure α) [is_finite_measure μ] (hμν : μ univ = ν univ)
  (h : ∀ ⦃a b⦄, a < b → μ (Ioc a b) = ν (Ioc a b)) : μ = ν :=
begin
  refine @ext_of_Ico_finite (order_dual α) _ _ _ _ _ ‹_› μ ν _ hμν (λ a b hab, _),
  erw dual_Ico,
  exact h hab
end

/-- Two measures which are finite on closed-open intervals are equal if the agree on all
closed-open intervals. -/
lemma ext_of_Ico' {α : Type*} [topological_space α] {m : measurable_space α}
  [second_countable_topology α] [linear_order α] [order_topology α] [borel_space α]
  [no_top_order α] (μ ν : measure α) (hμ : ∀ ⦃a b⦄, a < b → μ (Ico a b) ≠ ∞)
  (h : ∀ ⦃a b⦄, a < b → μ (Ico a b) = ν (Ico a b)) : μ = ν :=
begin
  rcases exists_countable_dense_bot_top α with ⟨s, hsc, hsd, hsb, hst⟩,
  have : countable (⋃ (l ∈ s) (u ∈ s) (h : l < u), {Ico l u} : set (set α)),
    from hsc.bUnion (λ l hl, hsc.bUnion
      (λ u hu, countable_Union_Prop $ λ _, 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_generate_from_Ico α))
    (is_pi_system_Ico id id) _ this _ _ _,
  { rintro _ ⟨l, -, u, -, h, rfl⟩, exact ⟨l, u, h, rfl⟩ },
  { refine sUnion_eq_univ_iff.2 (λ 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 }
end

/-- Two measures which are finite on closed-open intervals are equal if the agree on all
open-closed intervals. -/
lemma ext_of_Ioc' {α : Type*} [topological_space α] {m : measurable_space α}
  [second_countable_topology α] [linear_order α] [order_topology α] [borel_space α]
  [no_bot_order α] (μ ν : measure α) (hμ : ∀ ⦃a b⦄, a < b → μ (Ioc a b) ≠ ∞)
  (h : ∀ ⦃a b⦄, a < b → μ (Ioc a b) = ν (Ioc a b)) : μ = ν :=
begin
  refine @ext_of_Ico' (order_dual α) _ _ _ _ _ ‹_› _ μ ν _ _;
    intros a b hab; erw dual_Ico,
  exacts [hμ hab, h hab]
end

/-- Two measures which are finite on closed-open intervals are equal if the agree on all
closed-open intervals. -/
lemma ext_of_Ico {α : Type*} [topological_space α] {m : measurable_space α}
  [second_countable_topology α] [conditionally_complete_linear_order α] [order_topology α]
  [borel_space α] [no_top_order α] (μ ν : measure α) [is_locally_finite_measure μ]
  (h : ∀ ⦃a b⦄, a < b → μ (Ico a b) = ν (Ico a b)) : μ = ν :=
μ.ext_of_Ico' ν (λ a b hab, measure_Ico_lt_top.ne) h

/-- Two measures which are finite on closed-open intervals are equal if the agree on all
open-closed intervals. -/
lemma ext_of_Ioc {α : Type*} [topological_space α] {m : measurable_space α}
  [second_countable_topology α] [conditionally_complete_linear_order α] [order_topology α]
  [borel_space α] [no_bot_order α] (μ ν : measure α) [is_locally_finite_measure μ]
  (h : ∀ ⦃a b⦄, a < b → μ (Ioc a b) = ν (Ioc a b)) : μ = ν :=
μ.ext_of_Ioc' ν (λ a b hab, measure_Ioc_lt_top.ne) h

/-- Two finite measures on a Borel space are equal if they agree on all left-infinite right-closed
intervals. -/
lemma ext_of_Iic {α : Type*} [topological_space α] {m : measurable_space α}
  [second_countable_topology α] [linear_order α] [order_topology α] [borel_space α]
  (μ ν : measure α) [is_finite_measure μ] (h : ∀ a, μ (Iic a) = ν (Iic a)) : μ = ν :=
begin
  refine ext_of_Ioc_finite μ ν _ (λ a b hlt, _),
  { rcases exists_countable_dense_bot_top α with ⟨s, hsc, hsd, -, hst⟩,
    have : directed_on (≤) s, from directed_on_iff_directed.2 (directed_of_sup $ λ _ _, 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) measurable_set_Iic measurable_set_Iic,
      measure_diff (Iic_subset_Iic.2 hlt.le) measurable_set_Iic measurable_set_Iic, h a, h b],
  { rw ← h a, exact (measure_lt_top μ _).ne },
  { exact (measure_lt_top μ _).ne }
end

/-- Two finite measures on a Borel space are equal if they agree on all left-closed right-infinite
intervals. -/
lemma ext_of_Ici {α : Type*} [topological_space α] {m : measurable_space α}
  [second_countable_topology α] [linear_order α] [order_topology α] [borel_space α]
  (μ ν : measure α) [is_finite_measure μ] (h : ∀ a, μ (Ici a) = ν (Ici a)) : μ = ν :=
@ext_of_Iic (order_dual α) _ _ _ _ _ ‹_› _ _ _ h

end measure_theory.measure

end linear_order

section linear_order

variables [linear_order α] [order_closed_topology α]

@[measurability]
lemma measurable_set_interval {a b : α} : measurable_set (interval a b) :=
measurable_set_Icc

@[measurability]
lemma measurable_set_interval_oc {a b : α} : measurable_set (interval_oc a b) :=
measurable_set_Ioc

variables [second_countable_topology α]

@[measurability]
lemma measurable.max {f g : δ → α} (hf : measurable f) (hg : measurable g) :
  measurable (λ a, max (f a) (g a)) :=
by simpa only [max_def] using hf.piecewise (measurable_set_le hg hf) hg

@[measurability]
lemma ae_measurable.max {f g : δ → α} {μ : measure δ}
  (hf : ae_measurable f μ) (hg : ae_measurable g μ) : ae_measurable (λ a, max (f a) (g a)) μ :=
⟨λ a, max (hf.mk f a) (hg.mk g a), hf.measurable_mk.max hg.measurable_mk,
  eventually_eq.comp₂ hf.ae_eq_mk _ hg.ae_eq_mk⟩

@[measurability]
lemma measurable.min {f g : δ → α} (hf : measurable f) (hg : measurable g) :
  measurable (λ a, min (f a) (g a)) :=
by simpa only [min_def] using hf.piecewise (measurable_set_le hf hg) hg

@[measurability]
lemma ae_measurable.min {f g : δ → α} {μ : measure δ}
  (hf : ae_measurable f μ) (hg : ae_measurable g μ) : ae_measurable (λ a, min (f a) (g a)) μ :=
⟨λ a, min (hf.mk f a) (hg.mk g a), hf.measurable_mk.min hg.measurable_mk,
  eventually_eq.comp₂ hf.ae_eq_mk _ hg.ae_eq_mk⟩

end linear_order

/-- A continuous function from an `opens_measurable_space` to a `borel_space`
is measurable. -/
lemma continuous.measurable {f : α → γ} (hf : continuous f) :
  measurable f :=
hf.borel_measurable.mono opens_measurable_space.borel_le
  (le_of_eq $ borel_space.measurable_eq)

/-- A continuous function from an `opens_measurable_space` to a `borel_space`
is ae-measurable. -/
lemma continuous.ae_measurable {f : α → γ} (h : continuous f) (μ : measure α) : ae_measurable f μ :=
h.measurable.ae_measurable

lemma closed_embedding.measurable {f : α → γ} (hf : closed_embedding f) :
  measurable f :=
hf.continuous.measurable

@[priority 100, to_additive]
instance has_continuous_mul.has_measurable_mul [has_mul γ] [has_continuous_mul γ] :
  has_measurable_mul γ :=
{ measurable_const_mul := λ c, (continuous_const.mul continuous_id).measurable,
  measurable_mul_const := λ c, (continuous_id.mul continuous_const).measurable }

@[priority 100]
instance has_continuous_sub.has_measurable_sub [has_sub γ] [has_continuous_sub γ] :
  has_measurable_sub γ :=
{ measurable_const_sub := λ c, (continuous_const.sub continuous_id).measurable,
  measurable_sub_const := λ c, (continuous_id.sub continuous_const).measurable }

@[priority 100, to_additive]
instance topological_group.has_measurable_inv [group γ] [topological_group γ] :
  has_measurable_inv γ :=
⟨continuous_inv.measurable⟩

@[priority 100]
instance has_continuous_smul.has_measurable_smul {M α} [topological_space M]
  [topological_space α] [measurable_space M] [measurable_space α]
  [opens_measurable_space M] [borel_space α] [has_scalar M α] [has_continuous_smul M α] :
  has_measurable_smul M α :=
⟨λ c, (continuous_const.smul continuous_id).measurable,
  λ y, (continuous_id.smul continuous_const).measurable⟩

section homeomorph

@[measurability] protected lemma homeomorph.measurable (h : α ≃ₜ γ) : measurable h :=
h.continuous.measurable

/-- A homeomorphism between two Borel spaces is a measurable equivalence.-/
def homeomorph.to_measurable_equiv (h : γ ≃ₜ γ₂) : γ ≃ᵐ γ₂ :=
{ measurable_to_fun := h.measurable,
  measurable_inv_fun := h.symm.measurable,
  to_equiv := h.to_equiv }

@[simp]
lemma homeomorph.to_measurable_equiv_coe (h : γ ≃ₜ γ₂) : (h.to_measurable_equiv : γ → γ₂) = h :=
rfl

@[simp] lemma homeomorph.to_measurable_equiv_symm_coe (h : γ ≃ₜ γ₂) :
  (h.to_measurable_equiv.symm : γ₂ → γ) = h.symm :=
rfl

end homeomorph

@[measurability] lemma continuous_map.measurable (f : C(α, γ)) : measurable f :=
f.continuous.measurable

lemma measurable_of_continuous_on_compl_singleton [t1_space α] {f : α → γ} (a : α)
  (hf : continuous_on f {a}ᶜ) :
  measurable f :=
measurable_of_measurable_on_compl_singleton a
  (continuous_on_iff_continuous_restrict.1 hf).measurable

lemma continuous.measurable2 [second_countable_topology α] [second_countable_topology β]
  {f : δ → α} {g : δ → β} {c : α → β → γ}
  (h : continuous (λ p : α × β, c p.1 p.2)) (hf : measurable f) (hg : measurable g) :
  measurable (λ a, c (f a) (g a)) :=
h.measurable.comp (hf.prod_mk hg)

lemma continuous.ae_measurable2 [second_countable_topology α] [second_countable_topology β]
  {f : δ → α} {g : δ → β} {c : α → β → γ} {μ : measure δ}
  (h : continuous (λ p : α × β, c p.1 p.2)) (hf : ae_measurable f μ) (hg : ae_measurable g μ) :
  ae_measurable (λ a, c (f a) (g a)) μ :=
h.measurable.comp_ae_measurable (hf.prod_mk hg)

@[priority 100]
instance has_continuous_inv₀.has_measurable_inv [group_with_zero γ] [t1_space γ]
  [has_continuous_inv₀ γ] :
  has_measurable_inv γ :=
⟨measurable_of_continuous_on_compl_singleton 0 continuous_on_inv₀⟩

@[priority 100, to_additive]
instance has_continuous_mul.has_measurable_mul₂ [second_countable_topology γ] [has_mul γ]
  [has_continuous_mul γ] : has_measurable_mul₂ γ :=
⟨continuous_mul.measurable⟩

@[priority 100]
instance has_continuous_sub.has_measurable_sub₂ [second_countable_topology γ] [has_sub γ]
  [has_continuous_sub γ] : has_measurable_sub₂ γ :=
⟨continuous_sub.measurable⟩

@[priority 100]
instance has_continuous_smul.has_measurable_smul₂ {M α} [topological_space M]
  [second_countable_topology M] [measurable_space M] [opens_measurable_space M]
  [topological_space α] [second_countable_topology α] [measurable_space α]
  [borel_space α] [has_scalar M α] [has_continuous_smul M α] :
  has_measurable_smul₂ M α :=
⟨continuous_smul.measurable⟩

end

section borel_space
variables [topological_space α] [measurable_space α] [borel_space α]
  [topological_space β] [measurable_space β] [borel_space β]
  [topological_space γ] [measurable_space γ] [borel_space γ]
  [measurable_space δ]

lemma pi_le_borel_pi {ι : Type*} {π : ι → Type*} [Π i, topological_space (π i)]
  [Π i, measurable_space (π i)] [∀ i, borel_space (π i)] :
  measurable_space.pi ≤ borel (Π i, π i) :=
begin
  have : ‹Π i, measurable_space (π i)› = λ i, borel (π i) :=
    funext (λ i, borel_space.measurable_eq),
  rw [this],
  exact supr_le (λ i, comap_le_iff_le_map.2 $ (continuous_apply i).borel_measurable)
end

lemma prod_le_borel_prod : prod.measurable_space ≤ borel (α × β) :=
begin
  rw [‹borel_space α›.measurable_eq, ‹borel_space β›.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 }
end

instance pi.borel_space_fintype_encodable {ι : Type*} {π : ι → Type*} [encodable ι]
  [t' : Π i, topological_space (π i)]
  [Π i, measurable_space (π i)] [∀ i, second_countable_topology (π i)]
  [∀ i, borel_space (π i)] :
  borel_space (Π i, π i) :=
⟨le_antisymm pi_le_borel_pi opens_measurable_space.borel_le⟩

instance pi.borel_space_fintype {ι : Type*} {π : ι → Type*} [fintype ι]
  [t' : Π i, topological_space (π i)]
  [Π i, measurable_space (π i)] [∀ i, second_countable_topology (π i)]
  [∀ i, borel_space (π i)] :
  borel_space (Π i, π i) :=
⟨le_antisymm pi_le_borel_pi opens_measurable_space.borel_le⟩

instance prod.borel_space [second_countable_topology α] [second_countable_topology β] :
  borel_space (α × β) :=
⟨le_antisymm prod_le_borel_prod opens_measurable_space.borel_le⟩

protected lemma embedding.measurable_embedding {f : α → β} (h₁ : embedding f)
  (h₂ : measurable_set (range f)) : measurable_embedding f :=
show measurable_embedding (coe ∘ (homeomorph.of_embedding f h₁).to_measurable_equiv),
from (measurable_embedding.subtype_coe h₂).comp (measurable_equiv.measurable_embedding _)

protected lemma closed_embedding.measurable_embedding {f : α → β} (h : closed_embedding f) :
  measurable_embedding f :=
h.to_embedding.measurable_embedding h.closed_range.measurable_set

protected lemma open_embedding.measurable_embedding {f : α → β} (h : open_embedding f) :
  measurable_embedding f :=
h.to_embedding.measurable_embedding h.open_range.measurable_set

section linear_order

variables [linear_order α] [order_topology α] [second_countable_topology α]

lemma measurable_of_Iio {f : δ → α} (hf : ∀ x, measurable_set (f ⁻¹' Iio x)) : measurable f :=
begin
  convert measurable_generate_from _,
  exact borel_space.measurable_eq.trans (borel_eq_generate_from_Iio _),
  rintro _ ⟨x, rfl⟩, exact hf x
end

lemma upper_semicontinuous.measurable [topological_space δ] [opens_measurable_space δ]
  {f : δ → α} (hf : upper_semicontinuous f) : measurable f :=
measurable_of_Iio (λ y, (hf.is_open_preimage y).measurable_set)

lemma measurable_of_Ioi {f : δ → α} (hf : ∀ x, measurable_set (f ⁻¹' Ioi x)) : measurable f :=
begin
  convert measurable_generate_from _,
  exact borel_space.measurable_eq.trans (borel_eq_generate_from_Ioi _),
  rintro _ ⟨x, rfl⟩, exact hf x
end

lemma lower_semicontinuous.measurable [topological_space δ] [opens_measurable_space δ]
  {f : δ → α} (hf : lower_semicontinuous f) : measurable f :=
measurable_of_Ioi (λ y, (hf.is_open_preimage y).measurable_set)

lemma measurable_of_Iic {f : δ → α} (hf : ∀ x, measurable_set (f ⁻¹' Iic x)) : measurable f :=
begin
  apply measurable_of_Ioi,
  simp_rw [← compl_Iic, preimage_compl, measurable_set.compl_iff],
  assumption
end

lemma measurable_of_Ici {f : δ → α} (hf : ∀ x, measurable_set (f ⁻¹' Ici x)) : measurable f :=
begin
  apply measurable_of_Iio,
  simp_rw [← compl_Ici, preimage_compl, measurable_set.compl_iff],
  assumption
end

lemma measurable.is_lub {ι} [encodable ι] {f : ι → δ → α} {g : δ → α} (hf : ∀ i, measurable (f i))
  (hg : ∀ b, is_lub {a | ∃ i, f i b = a} (g b)) :
  measurable g :=
begin
  change ∀ b, is_lub (range $ λ i, f i b) (g b) at hg,
  rw [‹borel_space α›.measurable_eq, borel_eq_generate_from_Ioi α],
  apply measurable_generate_from,
  rintro _ ⟨a, rfl⟩,
  simp_rw [set.preimage, mem_Ioi, lt_is_lub_iff (hg _), exists_range_iff, set_of_exists],
  exact measurable_set.Union (λ i, hf i (is_open_lt' _).measurable_set)
end

private lemma ae_measurable.is_lub_of_nonempty {ι} (hι : nonempty ι)
  {μ : measure δ} [encodable ι] {f : ι → δ → α} {g : δ → α}
  (hf : ∀ i, ae_measurable (f i) μ) (hg : ∀ᵐ b ∂μ, is_lub {a | ∃ i, f i b = a} (g b)) :
  ae_measurable g μ :=
begin
  let p : δ → (ι → α) → Prop := λ x f', is_lub {a | ∃ i, f' i = a} (g x),
  let g_seq := λ x, ite (x ∈ ae_seq_set hf p) (g x) (⟨g x⟩ : nonempty α).some,
  have hg_seq : ∀ b, is_lub {a | ∃ i, ae_seq hf p i b = a} (g_seq b),
  { intro b,
    haveI hα : nonempty α := nonempty.map g ⟨b⟩,
    simp only [ae_seq, g_seq],
    split_ifs,
    { have h_set_eq : {a : α | ∃ (i : ι), (hf i).mk (f i) b = a} = {a : α | ∃ (i : ι), f i b = a},
      { ext x,
        simp_rw [set.mem_set_of_eq, ae_seq.mk_eq_fun_of_mem_ae_seq_set hf h], },
      rw h_set_eq,
      exact ae_seq.fun_prop_of_mem_ae_seq_set hf h, },
    { have h_singleton : {a : α | ∃ (i : ι), hα.some = a} = {hα.some},
      { ext1 x,
        exact ⟨λ hx, hx.some_spec.symm, λ hx, ⟨hι.some, hx.symm⟩⟩, },
      rw h_singleton,
      exact is_lub_singleton, }, },
  refine ⟨g_seq, measurable.is_lub (ae_seq.measurable hf p) hg_seq, _⟩,
  exact (ite_ae_eq_of_measure_compl_zero g (λ x, (⟨g x⟩ : nonempty α).some) (ae_seq_set hf p)
    (ae_seq.measure_compl_ae_seq_set_eq_zero hf hg)).symm,
end

lemma ae_measurable.is_lub {ι} {μ : measure δ} [encodable ι] {f : ι → δ → α} {g : δ → α}
  (hf : ∀ i, ae_measurable (f i) μ) (hg : ∀ᵐ b ∂μ, is_lub {a | ∃ i, f i b = a} (g b)) :
  ae_measurable g μ :=
begin
  by_cases hμ : μ = 0, { rw hμ, exact ae_measurable_zero_measure },
  haveI : μ.ae.ne_bot, { simpa [ne_bot_iff] },
  by_cases hι : nonempty ι, { exact ae_measurable.is_lub_of_nonempty hι hf hg, },
  suffices : ∃ x, g =ᵐ[μ] λ y, g x,
  by { exact ⟨(λ y, g this.some), measurable_const, this.some_spec⟩, },
  have h_empty : ∀ x, {a : α | ∃ (i : ι), f i x = a} = ∅,
  { intro x,
    ext1 y,
    rw [set.mem_set_of_eq, set.mem_empty_eq, iff_false],
    exact λ hi, hι (nonempty_of_exists hi), },
  simp_rw h_empty at hg,
  exact ⟨hg.exists.some, hg.mono (λ y hy, is_lub.unique hy hg.exists.some_spec)⟩,
end

lemma measurable.is_glb {ι} [encodable ι] {f : ι → δ → α} {g : δ → α} (hf : ∀ i, measurable (f i))
  (hg : ∀ b, is_glb {a | ∃ i, f i b = a} (g b)) :
  measurable g :=
begin
  change ∀ b, is_glb (range $ λ i, f i b) (g b) at hg,
  rw [‹borel_space α›.measurable_eq, borel_eq_generate_from_Iio α],
  apply measurable_generate_from,
  rintro _ ⟨a, rfl⟩,
  simp_rw [set.preimage, mem_Iio, is_glb_lt_iff (hg _), exists_range_iff, set_of_exists],
  exact measurable_set.Union (λ i, hf i (is_open_gt' _).measurable_set)
end

private lemma ae_measurable.is_glb_of_nonempty {ι} (hι : nonempty ι)
  {μ : measure δ} [encodable ι] {f : ι → δ → α} {g : δ → α}
  (hf : ∀ i, ae_measurable (f i) μ) (hg : ∀ᵐ b ∂μ, is_glb {a | ∃ i, f i b = a} (g b)) :
  ae_measurable g μ :=
begin
  let p : δ → (ι → α) → Prop := λ x f', is_glb {a | ∃ i, f' i = a} (g x),
  let g_seq := λ x, ite (x ∈ ae_seq_set hf p) (g x) (⟨g x⟩ : nonempty α).some,
  have hg_seq : ∀ b, is_glb {a | ∃ i, ae_seq hf p i b = a} (g_seq b),
  { intro b,
    haveI hα : nonempty α := nonempty.map g ⟨b⟩,
    simp only [ae_seq, g_seq],
    split_ifs,
    { have h_set_eq : {a : α | ∃ (i : ι), (hf i).mk (f i) b = a} = {a : α | ∃ (i : ι), f i b = a},
      { ext x,
        simp_rw [set.mem_set_of_eq, ae_seq.mk_eq_fun_of_mem_ae_seq_set hf h], },
      rw h_set_eq,
      exact ae_seq.fun_prop_of_mem_ae_seq_set hf h, },
    { have h_singleton : {a : α | ∃ (i : ι), hα.some = a} = {hα.some},
      { ext1 x,
        exact ⟨λ hx, hx.some_spec.symm, λ hx, ⟨hι.some, hx.symm⟩⟩, },
      rw h_singleton,
      exact is_glb_singleton, }, },
  refine ⟨g_seq, measurable.is_glb (ae_seq.measurable hf p) hg_seq, _⟩,
  exact (ite_ae_eq_of_measure_compl_zero g (λ x, (⟨g x⟩ : nonempty α).some) (ae_seq_set hf p)
    (ae_seq.measure_compl_ae_seq_set_eq_zero hf hg)).symm,
end

lemma ae_measurable.is_glb {ι} {μ : measure δ} [encodable ι] {f : ι → δ → α} {g : δ → α}
  (hf : ∀ i, ae_measurable (f i) μ) (hg : ∀ᵐ b ∂μ, is_glb {a | ∃ i, f i b = a} (g b)) :
  ae_measurable g μ :=
begin
  by_cases hμ : μ = 0, { rw hμ, exact ae_measurable_zero_measure },
  haveI : μ.ae.ne_bot, { simpa [ne_bot_iff] },
  by_cases hι : nonempty ι, { exact ae_measurable.is_glb_of_nonempty hι hf hg, },
  suffices : ∃ x, g =ᵐ[μ] λ y, g x,
  by { exact ⟨(λ y, g this.some), measurable_const, this.some_spec⟩, },
  have h_empty : ∀ x, {a : α | ∃ (i : ι), f i x = a} = ∅,
  { intro x,
    ext1 y,
    rw [set.mem_set_of_eq, set.mem_empty_eq, iff_false],
    exact λ hi, hι (nonempty_of_exists hi), },
  simp_rw h_empty at hg,
  exact ⟨hg.exists.some, hg.mono (λ y hy, is_glb.unique hy hg.exists.some_spec)⟩,
end

protected lemma monotone.measurable [linear_order β] [order_closed_topology β] {f : β → α}
  (hf : monotone f) : measurable f :=
suffices h : ∀ x, ord_connected (f ⁻¹' Ioi x),
  from measurable_of_Ioi (λ x, (h x).measurable_set),
λ x, ord_connected_def.mpr (λ a ha b hb c hc, lt_of_lt_of_le ha (hf hc.1))

lemma ae_measurable_restrict_of_monotone_on [linear_order β] [order_closed_topology β]
  {μ : measure β} {s : set β} (hs : measurable_set s) {f : β → α} (hf : monotone_on f s) :
  ae_measurable f (μ.restrict s) :=
have this : monotone (f ∘ coe : s → α), from λ ⟨x, hx⟩ ⟨y, hy⟩ (hxy : x ≤ y), hf hx hy hxy,
ae_measurable_restrict_of_measurable_subtype hs this.measurable

protected lemma antitone.measurable [linear_order β] [order_closed_topology β] {f : β → α}
  (hf : antitone f) :
  measurable f :=
@monotone.measurable (order_dual α) β _ _ ‹_› _ _ _ _ _ ‹_› _ _ _ hf

lemma ae_measurable_restrict_of_antitone_on [linear_order β] [order_closed_topology β]
  {μ : measure β} {s : set β} (hs : measurable_set s) {f : β → α} (hf : antitone_on f s) :
  ae_measurable f (μ.restrict s) :=
@ae_measurable_restrict_of_monotone_on (order_dual α) β _ _ ‹_› _ _ _ _ _ ‹_› _ _ _ _ hs _ hf

end linear_order

@[measurability]
lemma measurable.supr_Prop {α} [measurable_space α] [complete_lattice α]
  (p : Prop) {f : δ → α} (hf : measurable f) :
  measurable (λ b, ⨆ h : p, f b) :=
classical.by_cases
  (assume h : p, begin convert hf, funext, exact supr_pos h end)
  (assume h : ¬p, begin convert measurable_const, funext, exact supr_neg h end)

@[measurability]
lemma measurable.infi_Prop {α} [measurable_space α] [complete_lattice α]
  (p : Prop) {f : δ → α} (hf : measurable f) :
  measurable (λ b, ⨅ h : p, f b) :=
classical.by_cases
  (assume h : p, begin convert hf, funext, exact infi_pos h end )
  (assume h : ¬p, begin convert measurable_const, funext, exact infi_neg h end)

section complete_linear_order

variables [complete_linear_order α] [order_topology α] [second_countable_topology α]

@[measurability]
lemma measurable_supr {ι} [encodable ι] {f : ι → δ → α} (hf : ∀ i, measurable (f i)) :
  measurable (λ b, ⨆ i, f i b) :=
measurable.is_lub hf $ λ b, is_lub_supr

@[measurability]
lemma ae_measurable_supr {ι} {μ : measure δ} [encodable ι] {f : ι → δ → α}
  (hf : ∀ i, ae_measurable (f i) μ) :
  ae_measurable (λ b, ⨆ i, f i b) μ :=
ae_measurable.is_lub hf $ (ae_of_all μ (λ b, is_lub_supr))

@[measurability]
lemma measurable_infi {ι} [encodable ι] {f : ι → δ → α} (hf : ∀ i, measurable (f i)) :
  measurable (λ b, ⨅ i, f i b) :=
measurable.is_glb hf $ λ b, is_glb_infi

@[measurability]
lemma ae_measurable_infi {ι} {μ : measure δ} [encodable ι] {f : ι → δ → α}
  (hf : ∀ i, ae_measurable (f i) μ) :
  ae_measurable (λ b, ⨅ i, f i b) μ :=
ae_measurable.is_glb hf $ (ae_of_all μ (λ b, is_glb_infi))

lemma measurable_bsupr {ι} (s : set ι) {f : ι → δ → α} (hs : countable s)
  (hf : ∀ i, measurable (f i)) : measurable (λ b, ⨆ i ∈ s, f i b) :=
by { haveI : encodable s := hs.to_encodable, simp only [supr_subtype'],
     exact measurable_supr (λ i, hf i) }

lemma ae_measurable_bsupr {ι} {μ : measure δ} (s : set ι) {f : ι → δ → α} (hs : countable s)
  (hf : ∀ i, ae_measurable (f i) μ) : ae_measurable (λ b, ⨆ i ∈ s, f i b) μ :=
begin
  haveI : encodable s := hs.to_encodable,
  simp only [supr_subtype'],
  exact ae_measurable_supr (λ i, hf i),
end

lemma measurable_binfi {ι} (s : set ι) {f : ι → δ → α} (hs : countable s)
  (hf : ∀ i, measurable (f i)) : measurable (λ b, ⨅ i ∈ s, f i b) :=
by { haveI : encodable s := hs.to_encodable, simp only [infi_subtype'],
     exact measurable_infi (λ i, hf i) }

lemma ae_measurable_binfi {ι} {μ : measure δ} (s : set ι) {f : ι → δ → α} (hs : countable s)
  (hf : ∀ i, ae_measurable (f i) μ) : ae_measurable (λ b, ⨅ i ∈ s, f i b) μ :=
begin
  haveI : encodable s := hs.to_encodable,
  simp only [infi_subtype'],
  exact ae_measurable_infi (λ i, hf i),
end

/-- `liminf` over a general filter is measurable. See `measurable_liminf` for the version over `ℕ`.
-/
lemma measurable_liminf' {ι ι'} {f : ι → δ → α} {u : filter ι} (hf : ∀ i, measurable (f i))
  {p : ι' → Prop} {s : ι' → set ι} (hu : u.has_countable_basis p s) (hs : ∀ i, (s i).countable) :
  measurable (λ x, liminf u (λ i, f i x)) :=
begin
  simp_rw [hu.to_has_basis.liminf_eq_supr_infi],
  refine measurable_bsupr _ hu.countable _,
  exact λ i, measurable_binfi _ (hs i) hf
end

/-- `limsup` over a general filter is measurable. See `measurable_limsup` for the version over `ℕ`.
-/
lemma measurable_limsup' {ι ι'}  {f : ι → δ → α} {u : filter ι} (hf : ∀ i, measurable (f i))
  {p : ι' → Prop} {s : ι' → set ι} (hu : u.has_countable_basis p s) (hs : ∀ i, (s i).countable) :
  measurable (λ x, limsup u (λ i, f i x)) :=
begin
  simp_rw [hu.to_has_basis.limsup_eq_infi_supr],
  refine measurable_binfi _ hu.countable _,
  exact λ i, measurable_bsupr _ (hs i) hf
end

/-- `liminf` over `ℕ` is measurable. See `measurable_liminf'` for a version with a general filter.
-/
@[measurability]
lemma measurable_liminf {f : ℕ → δ → α} (hf : ∀ i, measurable (f i)) :
  measurable (λ x, liminf at_top (λ i, f i x)) :=
measurable_liminf' hf at_top_countable_basis (λ i, countable_encodable _)

/-- `limsup` over `ℕ` is measurable. See `measurable_limsup'` for a version with a general filter.
-/
@[measurability]
lemma measurable_limsup {f : ℕ → δ → α} (hf : ∀ i, measurable (f i)) :
  measurable (λ x, limsup at_top (λ i, f i x)) :=
measurable_limsup' hf at_top_countable_basis (λ i, countable_encodable _)

end complete_linear_order

section conditionally_complete_linear_order

variables [conditionally_complete_linear_order α] [order_topology α] [second_countable_topology α]

lemma measurable_cSup {ι} {f : ι → δ → α} {s : set ι} (hs : s.countable)
  (hf : ∀ i, measurable (f i)) (bdd : ∀ x, bdd_above ((λ i, f i x) '' s)) :
  measurable (λ x, Sup ((λ i, f i x) '' s)) :=
begin
  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 measurable_set.bInter hs (λ i hi, measurable_set_le (hf i) measurable_const) }
end

end conditionally_complete_linear_order

/-- Convert a `homeomorph` to a `measurable_equiv`. -/
def homemorph.to_measurable_equiv (h : α ≃ₜ β) : α ≃ᵐ β :=
{ to_equiv := h.to_equiv,
  measurable_to_fun := h.continuous_to_fun.measurable,
  measurable_inv_fun := h.continuous_inv_fun.measurable }

end borel_space

instance empty.borel_space : borel_space empty := ⟨borel_eq_top_of_discrete.symm⟩
instance unit.borel_space : borel_space unit := ⟨borel_eq_top_of_discrete.symm⟩
instance bool.borel_space : borel_space bool := ⟨borel_eq_top_of_discrete.symm⟩
instance nat.borel_space : borel_space ℕ := ⟨borel_eq_top_of_discrete.symm⟩
instance int.borel_space : borel_space ℤ := ⟨borel_eq_top_of_discrete.symm⟩
instance rat.borel_space : borel_space ℚ := ⟨borel_eq_top_of_encodable.symm⟩

@[priority 900]
instance is_R_or_C.measurable_space {𝕜 : Type*} [is_R_or_C 𝕜] : measurable_space 𝕜 := borel 𝕜
@[priority 900]
instance is_R_or_C.borel_space {𝕜 : Type*} [is_R_or_C 𝕜] : borel_space 𝕜 := ⟨rfl⟩

/- 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.measurable_space : measurable_space ℝ := borel ℝ
instance real.borel_space : borel_space ℝ := ⟨rfl⟩

instance nnreal.measurable_space : measurable_space ℝ≥0 := subtype.measurable_space
instance nnreal.borel_space : borel_space ℝ≥0 := subtype.borel_space _

instance ennreal.measurable_space : measurable_space ℝ≥0∞ := borel ℝ≥0∞
instance ennreal.borel_space : borel_space ℝ≥0∞ := ⟨rfl⟩

instance ereal.measurable_space : measurable_space ereal := borel ereal
instance ereal.borel_space : borel_space ereal := ⟨rfl⟩

instance complex.measurable_space : measurable_space ℂ := borel ℂ
instance complex.borel_space : borel_space ℂ := ⟨rfl⟩

/-- 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`. -/
lemma measure_eq_measure_preimage_add_measure_tsum_Ico_zpow [measurable_space α] (μ : measure α)
  {f : α → ℝ≥0∞} (hf : measurable f) {s : set α} (hs : measurable_set s) {t : ℝ≥0} (ht : 1 < t) :
  μ s = μ (s ∩ f⁻¹' {0}) + μ (s ∩ f⁻¹' {∞}) + ∑' (n : ℤ), μ (s ∩ f⁻¹' (Ico (t^n) (t^(n+1)))) :=
begin
  have A : μ s = μ (s ∩ f⁻¹' {0}) + μ (s ∩ f⁻¹' (Ioi 0)),
  { 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_distrib_left, this, mem_singleton_iff, mem_inter_eq, and_true,
        mem_union_eq, mem_Ioi, mem_preimage], },
    { apply disjoint_left.2 (λ 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 (measurable_set_singleton _)) },
    { exact hs.inter (hf measurable_set_Ioi) } },
  have B : μ (s ∩ f⁻¹' (Ioi 0)) = μ (s ∩ f⁻¹' {∞}) + μ (s ∩ f⁻¹' (Ioo 0 ∞)),
  { rw ← measure_union,
    { rw ← inter_union_distrib_left,
      congr,
      ext x,
      simp only [mem_singleton_iff, mem_union_eq, 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, with_top.zero_lt_top, not_top_lt, and_false] },
      { simp only [H, H.ne, and_true, false_or] } },
    { apply disjoint_left.2 (λ 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 (measurable_set_singleton _)) },
    { exact hs.inter (hf measurable_set_Ioo) } },
  have C : μ (s ∩ f⁻¹' (Ioo 0 ∞)) = ∑' (n : ℤ), μ (s ∩ f⁻¹' (Ico (t^n) (t^(n+1)))),
  { 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],
    { assume i j,
      simp only [function.on_fun],
      wlog h : i ≤ j := le_total i j using [i j, j i] tactic.skip,
      { assume hij,
        replace hij : i + 1 ≤ j := lt_of_le_of_ne h hij,
        apply disjoint_left.2 (λ 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) hij
        ... ≤ f x : h'x.2.1 },
      { assume hij,
        rw disjoint.comm,
        exact this hij.symm } },
    { assume n,
      exact hs.inter (hf measurable_set_Ico) } },
  rw [A, B, C, add_assoc],
end

section metric_space

variables [metric_space α] [measurable_space α] [opens_measurable_space α]
variables [measurable_space β] {x : α} {ε : ℝ}

open metric

@[measurability]
lemma measurable_set_ball : measurable_set (metric.ball x ε) :=
metric.is_open_ball.measurable_set

@[measurability]
lemma measurable_set_closed_ball : measurable_set (metric.closed_ball x ε) :=
metric.is_closed_ball.measurable_set

@[measurability]
lemma measurable_inf_dist {s : set α} : measurable (λ x, inf_dist x s) :=
(continuous_inf_dist_pt s).measurable

@[measurability]
lemma measurable.inf_dist {f : β → α} (hf : measurable f) {s : set α} :
  measurable (λ x, inf_dist (f x) s) :=
measurable_inf_dist.comp hf

@[measurability]
lemma measurable_inf_nndist {s : set α} : measurable (λ x, inf_nndist x s) :=
(continuous_inf_nndist_pt s).measurable

@[measurability]
lemma measurable.inf_nndist {f : β → α} (hf : measurable f) {s : set α} :
  measurable (λ x, inf_nndist (f x) s) :=
measurable_inf_nndist.comp hf

variables [second_countable_topology α]

@[measurability]
lemma measurable_dist : measurable (λ p : α × α, dist p.1 p.2) :=
continuous_dist.measurable

@[measurability]
lemma measurable.dist {f g : β → α} (hf : measurable f) (hg : measurable g) :
  measurable (λ b, dist (f b) (g b)) :=
(@continuous_dist α _).measurable2 hf hg

@[measurability]
lemma measurable_nndist : measurable (λ p : α × α, nndist p.1 p.2) :=
continuous_nndist.measurable

@[measurability]
lemma measurable.nndist {f g : β → α} (hf : measurable f) (hg : measurable g) :
  measurable (λ b, nndist (f b) (g b)) :=
(@continuous_nndist α _).measurable2 hf hg

end metric_space

section emetric_space

variables [emetric_space α] [measurable_space α] [opens_measurable_space α]
variables [measurable_space β] {x : α} {ε : ℝ≥0∞}

open emetric

@[measurability]
lemma measurable_set_eball : measurable_set (emetric.ball x ε) :=
emetric.is_open_ball.measurable_set

@[measurability]
lemma measurable_edist_right : measurable (edist x) :=
(continuous_const.edist continuous_id).measurable

@[measurability]
lemma measurable_edist_left : measurable (λ y, edist y x) :=
(continuous_id.edist continuous_const).measurable

@[measurability]
lemma measurable_inf_edist {s : set α} : measurable (λ x, inf_edist x s) :=
continuous_inf_edist.measurable

@[measurability]
lemma measurable.inf_edist {f : β → α} (hf : measurable f) {s : set α} :
  measurable (λ x, inf_edist (f x) s) :=
measurable_inf_edist.comp hf

variables [second_countable_topology α]

@[measurability]
lemma measurable_edist : measurable (λ p : α × α, edist p.1 p.2) :=
continuous_edist.measurable

@[measurability]
lemma measurable.edist {f g : β → α} (hf : measurable f) (hg : measurable g) :
  measurable (λ b, edist (f b) (g b)) :=
(@continuous_edist α _).measurable2 hf hg

@[measurability]
lemma ae_measurable.edist {f g : β → α} {μ : measure β}
  (hf : ae_measurable f μ) (hg : ae_measurable g μ) : ae_measurable (λ a, edist (f a) (g a)) μ :=
(@continuous_edist α _).ae_measurable2 hf hg

end emetric_space

namespace real
open measurable_space measure_theory

lemma borel_eq_generate_from_Ioo_rat :
  borel ℝ = generate_from (⋃(a b : ℚ) (h : a < b), {Ioo a b}) :=
is_topological_basis_Ioo_rat.borel_eq_generate_from

lemma is_pi_system_Ioo_rat : @is_pi_system ℝ (⋃ (a b : ℚ) (h : a < b), {Ioo a b})  :=
begin
  convert is_pi_system_Ioo (coe : ℚ → ℝ) (coe : ℚ → ℝ),
  ext x,
  simp [eq_comm]
end

/-- 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 finite_spanning_sets_in_Ioo_rat (μ : measure ℝ) [is_locally_finite_measure μ] :
  μ.finite_spanning_sets_in (⋃ (a b : ℚ) (h : a < b), {Ioo a b}) :=
{ set := λ n, Ioo (-(n + 1)) (n + 1),
  set_mem := λ n,
    begin
      simp only [mem_Union, mem_singleton_iff],
      refine ⟨-(n + 1), n + 1, _, by norm_cast⟩,
      exact (neg_nonpos.2 (@nat.cast_nonneg ℚ _ (n + 1))).trans_lt n.cast_add_one_pos
    end,
  finite := λ n, measure_Ioo_lt_top,
  spanning := Union_eq_univ_iff.2 $ λ 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 _)⟩ }

lemma measure_ext_Ioo_rat {μ ν : measure ℝ} [is_locally_finite_measure μ]
  (h : ∀ a b : ℚ, μ (Ioo a b) = ν (Ioo a b)) : μ = ν :=
(finite_spanning_sets_in_Ioo_rat μ).ext borel_eq_generate_from_Ioo_rat is_pi_system_Ioo_rat $
  by { simp only [mem_Union, mem_singleton_iff], rintro _ ⟨a, b, -, rfl⟩, apply h }

lemma borel_eq_generate_from_Iio_rat :
  borel ℝ = generate_from (⋃ a : ℚ, {Iio a}) :=
begin
  let g : measurable_space ℝ := generate_from (⋃ a : ℚ, {Iio a}),
  refine le_antisymm _ _,
  { rw borel_eq_generate_from_Ioo_rat,
    refine generate_from_le (λ t, _),
    simp only [mem_Union, mem_singleton_iff], rintro ⟨a, b, h, rfl⟩,
    rw (set.ext (λ x, _) : Ioo (a : ℝ) b = (⋃c>a, (Iio c)ᶜ) ∩ Iio b),
    { have hg : ∀ q : ℚ, g.measurable_set' (Iio q) :=
        λ q, generate_measurable.basic (Iio q) (by { simp, exact ⟨_, rfl⟩ }),
      refine @measurable_set.inter _ g _ _ _ (hg _),
      refine @measurable_set.bUnion _ _ g _ _ (countable_encodable _) (λ c h, _),
      exact @measurable_set.compl _ _ g (hg _) },
    { suffices : x < ↑b → (↑a < x ↔ ∃ (i : ℚ), a < i ∧ ↑i ≤ x), by simpa,
      refine λ _, ⟨λ h, _, λ ⟨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 measurable_space.generate_from_le (λ _, _),
    simp only [mem_Union, mem_singleton_iff], rintro ⟨r, rfl⟩, exact measurable_set_Iio }
end

end real

variable [measurable_space α]

@[measurability]
lemma measurable_real_to_nnreal : measurable (real.to_nnreal) :=
nnreal.continuous_of_real.measurable

@[measurability]
lemma measurable.real_to_nnreal {f : α → ℝ} (hf : measurable f) :
  measurable (λ x, real.to_nnreal (f x)) :=
measurable_real_to_nnreal.comp hf

@[measurability]
lemma ae_measurable.real_to_nnreal {f : α → ℝ} {μ : measure α} (hf : ae_measurable f μ) :
  ae_measurable (λ x, real.to_nnreal (f x)) μ :=
measurable_real_to_nnreal.comp_ae_measurable hf

@[measurability]
lemma measurable_coe_nnreal_real : measurable (coe : ℝ≥0 → ℝ) :=
nnreal.continuous_coe.measurable

@[measurability]
lemma measurable.coe_nnreal_real {f : α → ℝ≥0} (hf : measurable f) :
  measurable (λ x, (f x : ℝ)) :=
measurable_coe_nnreal_real.comp hf

@[measurability]
lemma ae_measurable.coe_nnreal_real {f : α → ℝ≥0} {μ : measure α} (hf : ae_measurable f μ) :
  ae_measurable (λ x, (f x : ℝ)) μ :=
measurable_coe_nnreal_real.comp_ae_measurable hf

@[measurability]
lemma measurable_coe_nnreal_ennreal : measurable (coe : ℝ≥0 → ℝ≥0∞) :=
ennreal.continuous_coe.measurable

@[measurability]
lemma measurable.coe_nnreal_ennreal {f : α → ℝ≥0} (hf : measurable f) :
  measurable (λ x, (f x : ℝ≥0∞)) :=
ennreal.continuous_coe.measurable.comp hf

@[measurability]
lemma ae_measurable.coe_nnreal_ennreal {f : α → ℝ≥0} {μ : measure α} (hf : ae_measurable f μ) :
  ae_measurable (λ x, (f x : ℝ≥0∞)) μ :=
ennreal.continuous_coe.measurable.comp_ae_measurable hf

@[measurability]
lemma measurable.ennreal_of_real {f : α → ℝ} (hf : measurable f) :
  measurable (λ x, ennreal.of_real (f x)) :=
ennreal.continuous_of_real.measurable.comp hf

/-- The set of finite `ℝ≥0∞` numbers is `measurable_equiv` to `ℝ≥0`. -/
def measurable_equiv.ennreal_equiv_nnreal : {r : ℝ≥0∞ | r ≠ ∞} ≃ᵐ ℝ≥0 :=
ennreal.ne_top_homeomorph_nnreal.to_measurable_equiv

namespace ennreal

lemma measurable_of_measurable_nnreal {f : ℝ≥0∞ → α}
  (h : measurable (λ p : ℝ≥0, f p)) : measurable f :=
measurable_of_measurable_on_compl_singleton ∞
  (measurable_equiv.ennreal_equiv_nnreal.symm.measurable_comp_iff.1 h)

/-- `ℝ≥0∞` is `measurable_equiv` to `ℝ≥0 ⊕ unit`. -/
def ennreal_equiv_sum : ℝ≥0∞ ≃ᵐ ℝ≥0 ⊕ unit :=
{ measurable_to_fun  := measurable_of_measurable_nnreal measurable_inl,
  measurable_inv_fun := measurable_sum measurable_coe_nnreal_ennreal
    (@measurable_const ℝ≥0∞ unit _ _ ∞),
  .. equiv.option_equiv_sum_punit ℝ≥0 }

open function (uncurry)

lemma measurable_of_measurable_nnreal_prod [measurable_space β] [measurable_space γ]
  {f : ℝ≥0∞ × β → γ} (H₁ : measurable (λ p : ℝ≥0 × β, f (p.1, p.2)))
  (H₂ : measurable (λ x, f (∞, x))) :
  measurable f :=
let e : ℝ≥0∞ × β ≃ᵐ ℝ≥0 × β ⊕ unit × β :=
  (ennreal_equiv_sum.prod_congr (measurable_equiv.refl β)).trans
    (measurable_equiv.sum_prod_distrib _ _ _) in
e.symm.measurable_comp_iff.1 $ measurable_sum H₁ (H₂.comp measurable_id.snd)

lemma measurable_of_measurable_nnreal_nnreal [measurable_space β]
  {f : ℝ≥0∞ × ℝ≥0∞ → β} (h₁ : measurable (λ p : ℝ≥0 × ℝ≥0, f (p.1, p.2)))
  (h₂ : measurable (λ r : ℝ≥0, f (∞, r))) (h₃ : measurable (λ 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₂)

@[measurability]
lemma measurable_of_real : measurable ennreal.of_real :=
ennreal.continuous_of_real.measurable

@[measurability]
lemma measurable_to_real : measurable ennreal.to_real :=
ennreal.measurable_of_measurable_nnreal measurable_coe_nnreal_real

@[measurability]
lemma measurable_to_nnreal : measurable ennreal.to_nnreal :=
ennreal.measurable_of_measurable_nnreal measurable_id

instance : has_measurable_mul₂ ℝ≥0∞ :=
begin
  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 }
end

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

instance : has_measurable_inv ℝ≥0∞ := ⟨ennreal.continuous_inv.measurable⟩

end ennreal

@[measurability]
lemma measurable.ennreal_to_nnreal {f : α → ℝ≥0∞} (hf : measurable f) :
  measurable (λ x, (f x).to_nnreal) :=
ennreal.measurable_to_nnreal.comp hf

@[measurability]
lemma ae_measurable.ennreal_to_nnreal {f : α → ℝ≥0∞} {μ : measure α} (hf : ae_measurable f μ) :
  ae_measurable (λ x, (f x).to_nnreal) μ :=
ennreal.measurable_to_nnreal.comp_ae_measurable hf

lemma measurable_coe_nnreal_ennreal_iff {f : α → ℝ≥0} :
  measurable (λ x, (f x : ℝ≥0∞)) ↔ measurable f :=
⟨λ h, h.ennreal_to_nnreal, λ h, h.coe_nnreal_ennreal⟩

@[measurability]
lemma measurable.ennreal_to_real {f : α → ℝ≥0∞} (hf : measurable f) :
  measurable (λ x, ennreal.to_real (f x)) :=
ennreal.measurable_to_real.comp hf

@[measurability]
lemma ae_measurable.ennreal_to_real {f : α → ℝ≥0∞} {μ : measure α} (hf : ae_measurable f μ) :
  ae_measurable (λ x, ennreal.to_real (f x)) μ :=
ennreal.measurable_to_real.comp_ae_measurable hf

/-- note: `ℝ≥0∞` can probably be generalized in a future version of this lemma. -/
@[measurability]
lemma measurable.ennreal_tsum {ι} [encodable ι] {f : ι → α → ℝ≥0∞} (h : ∀ i, measurable (f i)) :
  measurable (λ x, ∑' i, f i x) :=
by { simp_rw [ennreal.tsum_eq_supr_sum], apply measurable_supr,
  exact λ s, s.measurable_sum (λ i _, h i) }

@[measurability]
lemma measurable.ennreal_tsum' {ι} [encodable ι] {f : ι → α → ℝ≥0∞} (h : ∀ i, measurable (f i)) :
  measurable (∑' i, f i) :=
begin
  convert measurable.ennreal_tsum h,
  ext1 x,
  exact tsum_apply (pi.summable.2 (λ _, ennreal.summable)),
end

@[measurability]
lemma measurable.nnreal_tsum {ι} [encodable ι] {f : ι → α → ℝ≥0} (h : ∀ i, measurable (f i)) :
  measurable (λ x, ∑' i, f i x) :=
begin
  simp_rw [nnreal.tsum_eq_to_nnreal_tsum],
  exact (measurable.ennreal_tsum (λ i, (h i).coe_nnreal_ennreal)).ennreal_to_nnreal,
end

@[measurability]
lemma ae_measurable.ennreal_tsum {ι} [encodable ι] {f : ι → α → ℝ≥0∞} {μ : measure α}
  (h : ∀ i, ae_measurable (f i) μ) :
  ae_measurable (λ x, ∑' i, f i x) μ :=
by { simp_rw [ennreal.tsum_eq_supr_sum], apply ae_measurable_supr,
  exact λ s, finset.ae_measurable_sum s (λ i _, h i) }

@[measurability]
lemma measurable_coe_real_ereal : measurable (coe : ℝ → ereal) :=
continuous_coe_real_ereal.measurable

@[measurability]
lemma measurable.coe_real_ereal {f : α → ℝ} (hf : measurable f) :
  measurable (λ x, (f x : ereal)) :=
measurable_coe_real_ereal.comp hf

@[measurability]
lemma ae_measurable.coe_real_ereal {f : α → ℝ} {μ : measure α} (hf : ae_measurable f μ) :
  ae_measurable (λ x, (f x : ereal)) μ :=
measurable_coe_real_ereal.comp_ae_measurable hf

/-- The set of finite `ereal` numbers is `measurable_equiv` to `ℝ`. -/
def measurable_equiv.ereal_equiv_real : ({⊥, ⊤} : set ereal).compl ≃ᵐ ℝ :=
ereal.ne_bot_top_homeomorph_real.to_measurable_equiv

lemma ereal.measurable_of_measurable_real {f : ereal → α}
  (h : measurable (λ p : ℝ, f p)) : measurable f :=
measurable_of_measurable_on_compl_finite {⊥, ⊤} (by simp)
  (measurable_equiv.ereal_equiv_real.symm.measurable_comp_iff.1 h)

@[measurability]
lemma measurable_ereal_to_real : measurable ereal.to_real :=
ereal.measurable_of_measurable_real (by simpa using measurable_id)

@[measurability]
lemma measurable.ereal_to_real {f : α → ereal} (hf : measurable f) :
  measurable (λ x, (f x).to_real) :=
measurable_ereal_to_real.comp hf

@[measurability]
lemma ae_measurable.ereal_to_real {f : α → ereal} {μ : measure α} (hf : ae_measurable f μ) :
  ae_measurable (λ x, (f x).to_real) μ :=
measurable_ereal_to_real.comp_ae_measurable hf

@[measurability]
lemma measurable_coe_ennreal_ereal : measurable (coe : ℝ≥0∞ → ereal) :=
continuous_coe_ennreal_ereal.measurable

@[measurability]
lemma measurable.coe_ereal_ennreal {f : α → ℝ≥0∞} (hf : measurable f) :
  measurable (λ x, (f x : ereal)) :=
measurable_coe_ennreal_ereal.comp hf

@[measurability]
lemma ae_measurable.coe_ereal_ennreal {f : α → ℝ≥0∞} {μ : measure α} (hf : ae_measurable f μ) :
  ae_measurable (λ x, (f x : ereal)) μ :=
measurable_coe_ennreal_ereal.comp_ae_measurable hf

section normed_group

variables [normed_group α] [opens_measurable_space α] [measurable_space β]

@[measurability]
lemma measurable_norm : measurable (norm : α → ℝ) :=
continuous_norm.measurable

@[measurability]
lemma measurable.norm {f : β → α} (hf : measurable f) : measurable (λ a, norm (f a)) :=
measurable_norm.comp hf

@[measurability]
lemma ae_measurable.norm {f : β → α} {μ : measure β} (hf : ae_measurable f μ) :
  ae_measurable (λ a, norm (f a)) μ :=
measurable_norm.comp_ae_measurable hf

@[measurability]
lemma measurable_nnnorm : measurable (nnnorm : α → ℝ≥0) :=
continuous_nnnorm.measurable

@[measurability]
lemma measurable.nnnorm {f : β → α} (hf : measurable f) : measurable (λ a, nnnorm (f a)) :=
measurable_nnnorm.comp hf

@[measurability]
lemma ae_measurable.nnnorm {f : β → α} {μ : measure β} (hf : ae_measurable f μ) :
  ae_measurable (λ a, nnnorm (f a)) μ :=
measurable_nnnorm.comp_ae_measurable hf

@[measurability]
lemma measurable_ennnorm : measurable (λ x : α, (nnnorm x : ℝ≥0∞)) :=
measurable_nnnorm.coe_nnreal_ennreal

@[measurability]
lemma measurable.ennnorm {f : β → α} (hf : measurable f) :
  measurable (λ a, (nnnorm (f a) : ℝ≥0∞)) :=
hf.nnnorm.coe_nnreal_ennreal

@[measurability]
lemma ae_measurable.ennnorm {f : β → α} {μ : measure β} (hf : ae_measurable f μ) :
  ae_measurable (λ a, (nnnorm (f a) : ℝ≥0∞)) μ :=
measurable_ennnorm.comp_ae_measurable hf

end normed_group

section limits

variables [measurable_space β] [metric_space β] [borel_space β]

open metric

/-- A limit (over a general filter) of measurable `ℝ≥0` valued functions is measurable. -/
lemma measurable_of_tendsto_nnreal' {ι} {f : ι → α → ℝ≥0} {g : α → ℝ≥0} (u : filter ι)
  [ne_bot u] [is_countably_generated u] (hf : ∀ i, measurable (f i)) (lim : tendsto f u (𝓝 g)) :
  measurable g :=
begin
  rcases u.exists_seq_tendsto with ⟨x, hx⟩,
  rw [tendsto_pi_nhds] at lim, rw [← measurable_coe_nnreal_ennreal_iff],
  have : ∀ y, liminf at_top (λ n, (f (x n) y : ℝ≥0∞)) = (g y : ℝ≥0∞) :=
    λ y, ((ennreal.continuous_coe.tendsto (g y)).comp $ (lim y).comp hx).liminf_eq,
  simp only [← this],
  show measurable (λ y, liminf at_top (λ n, (f (x n) y : ℝ≥0∞))),
  exact measurable_liminf (λ n, (hf (x n)).coe_nnreal_ennreal),
end

/-- A sequential limit of measurable `ℝ≥0` valued functions is measurable. -/
lemma measurable_of_tendsto_nnreal {f : ℕ → α → ℝ≥0} {g : α → ℝ≥0}
  (hf : ∀ i, measurable (f i)) (lim : tendsto f at_top (𝓝 g)) : measurable g :=
measurable_of_tendsto_nnreal' at_top hf lim

/-- A limit (over a general filter) of measurable functions valued in a metric space is measurable.
The assumption `hs` can be dropped using `filter.is_countably_generated.has_antitone_basis`, but we
don't need that case yet. -/
lemma measurable_of_tendsto_metric' {ι} {f : ι → α → β} {g : α → β}
  (u : filter ι) [ne_bot u] [is_countably_generated u]
  (hf : ∀ i, measurable (f i)) (lim : tendsto f u (𝓝 g)) :
  measurable g :=
begin
  apply measurable_of_is_closed', intros s h1s h2s h3s,
  have : measurable (λ x, inf_nndist (g x) s),
  { suffices : tendsto (λ i x, inf_nndist (f i x) s) u (𝓝 (λ x, inf_nndist (g x) s)),
      from measurable_of_tendsto_nnreal' u (λ i, (hf i).inf_nndist) this,
    rw [tendsto_pi_nhds] at lim ⊢, intro x,
    exact ((continuous_inf_nndist_pt s).tendsto (g x)).comp (lim x) },
  have h4s : g ⁻¹' s = (λ x, inf_nndist (g x) s) ⁻¹' {0},
  { ext x, simp [h1s, ← h1s.mem_iff_inf_dist_zero h2s, ← nnreal.coe_eq_zero] },
  rw [h4s], exact this (measurable_set_singleton 0),
end

/-- A sequential limit of measurable functions valued in a metric space is measurable. -/
lemma measurable_of_tendsto_metric {f : ℕ → α → β} {g : α → β}
  (hf : ∀ i, measurable (f i)) (lim : tendsto f at_top (𝓝 g)) :
  measurable g :=
measurable_of_tendsto_metric' at_top hf lim

lemma ae_measurable_of_tendsto_metric_ae {μ : measure α} {f : ℕ → α → β} {g : α → β}
  (hf : ∀ n, ae_measurable (f n) μ)
  (h_ae_tendsto : ∀ᵐ x ∂μ, tendsto (λ n, f n x) at_top (𝓝 (g x))) :
  ae_measurable g μ :=
begin
  let p : α → (ℕ → β) → Prop := λ x f', filter.at_top.tendsto (λ n, f' n) (𝓝 (g x)),
  let hp : ∀ᵐ x ∂μ, p x (λ n, f n x), from h_ae_tendsto,
  let ae_seq_lim := λ x, ite (x ∈ ae_seq_set hf p) (g x) (⟨f 0 x⟩ : nonempty β).some,
  refine ⟨ae_seq_lim, _, (ite_ae_eq_of_measure_compl_zero g (λ x, (⟨f 0 x⟩ : nonempty β).some)
    (ae_seq_set hf p) (ae_seq.measure_compl_ae_seq_set_eq_zero hf hp)).symm⟩,
  refine measurable_of_tendsto_metric (@ae_seq.measurable α β _ _ _ f μ hf p) _,
  refine tendsto_pi_nhds.mpr (λ x, _),
  simp_rw [ae_seq, ae_seq_lim],
  split_ifs with hx,
  { simp_rw ae_seq.mk_eq_fun_of_mem_ae_seq_set hf hx,
    exact @ae_seq.fun_prop_of_mem_ae_seq_set α β _ _ _ _ _ _ hf x hx, },
  { exact tendsto_const_nhds, },
end

lemma measurable_of_tendsto_metric_ae {μ : measure α} [μ.is_complete] {f : ℕ → α → β} {g : α → β}
  (hf : ∀ n, measurable (f n))
  (h_ae_tendsto : ∀ᵐ x ∂μ, filter.at_top.tendsto (λ n, f n x) (𝓝 (g x))) :
  measurable g :=
ae_measurable_iff_measurable.mp
  (ae_measurable_of_tendsto_metric_ae (λ i, (hf i).ae_measurable) h_ae_tendsto)

lemma measurable_limit_of_tendsto_metric_ae {μ : measure α} {f : ℕ → α → β}
  (hf : ∀ n, ae_measurable (f n) μ)
  (h_ae_tendsto : ∀ᵐ x ∂μ, ∃ l : β, filter.at_top.tendsto (λ n, f n x) (𝓝 l)) :
  ∃ (f_lim : α → β) (hf_lim_meas : measurable f_lim),
    ∀ᵐ x ∂μ, filter.at_top.tendsto (λ n, f n x) (𝓝 (f_lim x)) :=
begin
  let p : α → (ℕ → β) → Prop := λ x f', ∃ l : β, filter.at_top.tendsto (λ n, f' n) (𝓝 l),
  have hp_mem : ∀ x, x ∈ ae_seq_set hf p → p x (λ n, f n x),
    from λ x hx, ae_seq.fun_prop_of_mem_ae_seq_set hf hx,
  have hμ_compl : μ (ae_seq_set hf p)ᶜ = 0,
    from ae_seq.measure_compl_ae_seq_set_eq_zero hf h_ae_tendsto,
  let f_lim : α → β := λ x, dite (x ∈ ae_seq_set hf p) (λ h, (hp_mem x h).some)
    (λ h, (⟨f 0 x⟩ : nonempty β).some),
  have hf_lim_conv : ∀ x, x ∈ ae_seq_set hf p → filter.at_top.tendsto (λ n, f n x) (𝓝 (f_lim x)),
  { intros x hx_conv,
    simp only [f_lim, hx_conv, dif_pos],
    exact (hp_mem x hx_conv).some_spec, },
  have hf_lim : ∀ x, filter.at_top.tendsto (λ n, ae_seq hf p n x) (𝓝 (f_lim x)),
  { intros x,
    simp only [f_lim, ae_seq],
    split_ifs,
    { rw funext (λ n, ae_seq.mk_eq_fun_of_mem_ae_seq_set hf h n),
      exact (hp_mem x h).some_spec, },
    { exact tendsto_const_nhds, }, },
  have h_ae_tendsto_f_lim : ∀ᵐ x ∂μ, filter.at_top.tendsto (λ n, f n x) (𝓝 (f_lim x)),
  { refine le_antisymm (le_of_eq (measure_mono_null _ hμ_compl)) (zero_le _),
    exact set.compl_subset_compl.mpr (λ x hx, hf_lim_conv x hx), },
  have h_f_lim_meas : measurable f_lim,
    from measurable_of_tendsto_metric (ae_seq.measurable hf p)
      (tendsto_pi_nhds.mpr (λ x, hf_lim x)),
  exact ⟨f_lim, h_f_lim_meas, h_ae_tendsto_f_lim⟩,
end

end limits

namespace continuous_linear_map

variables {𝕜 : Type*} [normed_field 𝕜]
variables {E : Type*} [normed_group E] [normed_space 𝕜 E] [measurable_space E]
variables [opens_measurable_space E]
variables {F : Type*} [normed_group F] [normed_space 𝕜 F] [measurable_space F] [borel_space F]

@[measurability]
protected lemma measurable (L : E →L[𝕜] F) : measurable L :=
L.continuous.measurable

lemma measurable_comp (L : E →L[𝕜] F) {φ : α → E} (φ_meas : measurable φ) :
  measurable (λ (a : α), L (φ a)) :=
L.measurable.comp φ_meas

end continuous_linear_map

namespace continuous_linear_map

variables {𝕜 : Type*} [nondiscrete_normed_field 𝕜]
variables {E : Type*} [normed_group E] [normed_space 𝕜 E]
          {F : Type*} [normed_group F] [normed_space 𝕜 F]

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

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

@[measurability]
lemma measurable_apply [measurable_space F] [borel_space F] (x : E) :
  measurable (λ f : E →L[𝕜] F, f x) :=
(apply 𝕜 F x).continuous.measurable

@[measurability]
lemma measurable_apply' [measurable_space E] [opens_measurable_space E]
  [measurable_space F] [borel_space F] :
  measurable (λ (x : E) (f : E →L[𝕜] F), f x) :=
measurable_pi_lambda _ $ λ f, f.measurable

@[measurability]
lemma measurable_coe [measurable_space F] [borel_space F] :
  measurable (λ (f : E →L[𝕜] F) (x : E), f x) :=
measurable_pi_lambda _ measurable_apply

end continuous_linear_map

section continuous_linear_map_nondiscrete_normed_field

variables {𝕜 : Type*} [nondiscrete_normed_field 𝕜]
variables {E : Type*} [normed_group E] [normed_space 𝕜 E] [measurable_space E] [borel_space E]
variables {F : Type*} [normed_group F] [normed_space 𝕜 F]

@[measurability]
lemma measurable.apply_continuous_linear_map  {φ : α → F →L[𝕜] E} (hφ : measurable φ) (v : F) :
  measurable (λ a, φ a v) :=
(continuous_linear_map.apply 𝕜 E v).measurable.comp hφ

@[measurability]
lemma ae_measurable.apply_continuous_linear_map {φ : α → F →L[𝕜] E} {μ : measure α}
  (hφ : ae_measurable φ μ) (v : F) : ae_measurable (λ a, φ a v) μ :=
(continuous_linear_map.apply 𝕜 E v).measurable.comp_ae_measurable hφ

end continuous_linear_map_nondiscrete_normed_field

section normed_space
variables {𝕜 : Type*} [nondiscrete_normed_field 𝕜] [complete_space 𝕜] [measurable_space 𝕜]
variables [borel_space 𝕜]
variables {E : Type*} [normed_group E] [normed_space 𝕜 E] [measurable_space E] [borel_space E]

lemma measurable_smul_const {f : α → 𝕜} {c : E} (hc : c ≠ 0) :
  measurable (λ x, f x • c) ↔ measurable f :=
(closed_embedding_smul_left hc).measurable_embedding.measurable_comp_iff

lemma ae_measurable_smul_const {f : α → 𝕜} {μ : measure α} {c : E} (hc : c ≠ 0) :
  ae_measurable (λ x, f x • c) μ ↔ ae_measurable f μ :=
(closed_embedding_smul_left hc).measurable_embedding.ae_measurable_comp_iff

end normed_space


/-
Copyright (c) 2019 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.order.filter.bases
import Mathlib.PostPort

universes u_1 u_2 u_3 u_4 u_5 u_6 u_7 u_8

namespace Mathlib

/-!
# Lift filters along filter and set functions
-/

namespace filter

/-- A variant on `bind` using a function `g` taking a set instead of a member of `α`.
This is essentially a push-forward along a function mapping each set to a filter. -/
protected def lift {α : Type u_1} {β : Type u_2} (f : filter α) (g : set α → filter β) : filter β :=
  infi fun (s : set α) => infi fun (H : s ∈ f) => g s

/-- If `(p : ι → Prop, s : ι → set α)` is a basis of a filter `f`, `g` is a monotone function
`set α → filter γ`, and for each `i`, `(pg : β i → Prop, sg : β i → set α)` is a basis
of the filter `g (s i)`, then `(λ (i : ι) (x : β i), p i ∧ pg i x, λ (i : ι) (x : β i), sg i x)`
is a basis of the filter `f.lift g`.

This basis is parametrized by `i : ι` and `x : β i`, so in order to formulate this fact using
`has_basis` one has to use `Σ i, β i` as the index type, see `filter.has_basis.lift`.
This lemma states the corresponding `mem_iff` statement without using a sigma type. -/
theorem has_basis.mem_lift_iff {α : Type u_1} {γ : Type u_3} {ι : Type u_2} {p : ι → Prop} {s : ι → set α} {f : filter α} (hf : has_basis f p s) {β : ι → Type u_4} {pg : (i : ι) → β i → Prop} {sg : (i : ι) → β i → set γ} {g : set α → filter γ} (hg : ∀ (i : ι), has_basis (g (s i)) (pg i) (sg i)) (gm : monotone g) : ∀ {s : set γ}, s ∈ filter.lift f g ↔ ∃ (i : ι), ∃ (hi : p i), ∃ (x : β i), ∃ (hx : pg i x), sg i x ⊆ s := sorry

/-- If `(p : ι → Prop, s : ι → set α)` is a basis of a filter `f`, `g` is a monotone function
`set α → filter γ`, and for each `i`, `(pg : β i → Prop, sg : β i → set α)` is a basis
of the filter `g (s i)`, then `(λ (i : ι) (x : β i), p i ∧ pg i x, λ (i : ι) (x : β i), sg i x)`
is a basis of the filter `f.lift g`.

This basis is parametrized by `i : ι` and `x : β i`, so in order to formulate this fact using
`has_basis` one has to use `Σ i, β i` as the index type. See also `filter.has_basis.mem_lift_iff`
for the corresponding `mem_iff` statement formulated without using a sigma type. -/
theorem has_basis.lift {α : Type u_1} {γ : Type u_3} {ι : Type u_2} {p : ι → Prop} {s : ι → set α} {f : filter α} (hf : has_basis f p s) {β : ι → Type u_4} {pg : (i : ι) → β i → Prop} {sg : (i : ι) → β i → set γ} {g : set α → filter γ} (hg : ∀ (i : ι), has_basis (g (s i)) (pg i) (sg i)) (gm : monotone g) : has_basis (filter.lift f g) (fun (i : sigma fun (i : ι) => β i) => p (sigma.fst i) ∧ pg (sigma.fst i) (sigma.snd i))
  fun (i : sigma fun (i : ι) => β i) => sg (sigma.fst i) (sigma.snd i) := sorry

theorem mem_lift_sets {α : Type u_1} {β : Type u_2} {f : filter α} {g : set α → filter β} (hg : monotone g) {s : set β} : s ∈ filter.lift f g ↔ ∃ (t : set α), ∃ (H : t ∈ f), s ∈ g t := sorry

theorem mem_lift {α : Type u_1} {β : Type u_2} {f : filter α} {g : set α → filter β} {s : set β} {t : set α} (ht : t ∈ f) (hs : s ∈ g t) : s ∈ filter.lift f g :=
  iff.mp le_principal_iff
    ((fun (this : filter.lift f g ≤ principal s) => this)
      (infi_le_of_le t (infi_le_of_le ht (iff.mpr le_principal_iff hs))))

theorem lift_le {α : Type u_1} {β : Type u_2} {f : filter α} {g : set α → filter β} {h : filter β} {s : set α} (hs : s ∈ f) (hg : g s ≤ h) : filter.lift f g ≤ h :=
  infi_le_of_le s (infi_le_of_le hs hg)

theorem le_lift {α : Type u_1} {β : Type u_2} {f : filter α} {g : set α → filter β} {h : filter β} (hh : ∀ (s : set α), s ∈ f → h ≤ g s) : h ≤ filter.lift f g :=
  le_infi fun (s : set α) => le_infi fun (hs : s ∈ f) => hh s hs

theorem lift_mono {α : Type u_1} {β : Type u_2} {f₁ : filter α} {f₂ : filter α} {g₁ : set α → filter β} {g₂ : set α → filter β} (hf : f₁ ≤ f₂) (hg : g₁ ≤ g₂) : filter.lift f₁ g₁ ≤ filter.lift f₂ g₂ :=
  infi_le_infi fun (s : set α) => infi_le_infi2 fun (hs : s ∈ f₂) => Exists.intro (hf hs) (hg s)

theorem lift_mono' {α : Type u_1} {β : Type u_2} {f : filter α} {g₁ : set α → filter β} {g₂ : set α → filter β} (hg : ∀ (s : set α), s ∈ f → g₁ s ≤ g₂ s) : filter.lift f g₁ ≤ filter.lift f g₂ :=
  infi_le_infi fun (s : set α) => infi_le_infi fun (hs : s ∈ f) => hg s hs

theorem tendsto_lift {α : Type u_1} {β : Type u_2} {γ : Type u_3} {f : filter α} {g : set α → filter β} {m : γ → β} {l : filter γ} : tendsto m l (filter.lift f g) ↔ ∀ (s : set α), s ∈ f → tendsto m l (g s) := sorry

theorem map_lift_eq {α : Type u_1} {β : Type u_2} {γ : Type u_3} {f : filter α} {g : set α → filter β} {m : β → γ} (hg : monotone g) : map m (filter.lift f g) = filter.lift f (map m ∘ g) := sorry

theorem comap_lift_eq {α : Type u_1} {β : Type u_2} {γ : Type u_3} {f : filter α} {g : set α → filter β} {m : γ → β} (hg : monotone g) : comap m (filter.lift f g) = filter.lift f (comap m ∘ g) := sorry

theorem comap_lift_eq2 {α : Type u_1} {β : Type u_2} {γ : Type u_3} {f : filter α} {m : β → α} {g : set β → filter γ} (hg : monotone g) : filter.lift (comap m f) g = filter.lift f (g ∘ set.preimage m) := sorry

theorem map_lift_eq2 {α : Type u_1} {β : Type u_2} {γ : Type u_3} {f : filter α} {g : set β → filter γ} {m : α → β} (hg : monotone g) : filter.lift (map m f) g = filter.lift f (g ∘ set.image m) := sorry

theorem lift_comm {α : Type u_1} {β : Type u_2} {γ : Type u_3} {f : filter α} {g : filter β} {h : set α → set β → filter γ} : (filter.lift f fun (s : set α) => filter.lift g (h s)) =
  filter.lift g fun (t : set β) => filter.lift f fun (s : set α) => h s t := sorry

theorem lift_assoc {α : Type u_1} {β : Type u_2} {γ : Type u_3} {f : filter α} {g : set α → filter β} {h : set β → filter γ} (hg : monotone g) : filter.lift (filter.lift f g) h = filter.lift f fun (s : set α) => filter.lift (g s) h := sorry

theorem lift_lift_same_le_lift {α : Type u_1} {β : Type u_2} {f : filter α} {g : set α → set α → filter β} : (filter.lift f fun (s : set α) => filter.lift f (g s)) ≤ filter.lift f fun (s : set α) => g s s := sorry

theorem lift_lift_same_eq_lift {α : Type u_1} {β : Type u_2} {f : filter α} {g : set α → set α → filter β} (hg₁ : ∀ (s : set α), monotone fun (t : set α) => g s t) (hg₂ : ∀ (t : set α), monotone fun (s : set α) => g s t) : (filter.lift f fun (s : set α) => filter.lift f (g s)) = filter.lift f fun (s : set α) => g s s := sorry

theorem lift_principal {α : Type u_1} {β : Type u_2} {g : set α → filter β} {s : set α} (hg : monotone g) : filter.lift (principal s) g = g s :=
  le_antisymm (infi_le_of_le s (infi_le (fun (H : s ∈ principal s) => g s) (set.subset.refl s)))
    (le_infi fun (t : set α) => le_infi fun (hi : t ∈ principal s) => hg hi)

theorem monotone_lift {α : Type u_1} {β : Type u_2} {γ : Type u_3} [preorder γ] {f : γ → filter α} {g : γ → set α → filter β} (hf : monotone f) (hg : monotone g) : monotone fun (c : γ) => filter.lift (f c) (g c) :=
  fun (a b : γ) (h : a ≤ b) => lift_mono (hf h) (hg h)

theorem lift_ne_bot_iff {α : Type u_1} {β : Type u_2} {f : filter α} {g : set α → filter β} (hm : monotone g) : ne_bot (filter.lift f g) ↔ ∀ (s : set α), s ∈ f → ne_bot (g s) := sorry

@[simp] theorem lift_const {α : Type u_1} {β : Type u_2} {f : filter α} {g : filter β} : (filter.lift f fun (x : set α) => g) = g :=
  le_antisymm (lift_le univ_mem_sets (le_refl g)) (le_lift fun (s : set α) (hs : s ∈ f) => le_refl g)

@[simp] theorem lift_inf {α : Type u_1} {β : Type u_2} {f : filter α} {g : set α → filter β} {h : set α → filter β} : (filter.lift f fun (x : set α) => g x ⊓ h x) = filter.lift f g ⊓ filter.lift f h := sorry

@[simp] theorem lift_principal2 {α : Type u_1} {f : filter α} : filter.lift f principal = f := sorry

theorem lift_infi {α : Type u_1} {β : Type u_2} {ι : Sort u_4} {f : ι → filter α} {g : set α → filter β} [hι : Nonempty ι] (hg : ∀ {s t : set α}, g s ⊓ g t = g (s ∩ t)) : filter.lift (infi f) g = infi fun (i : ι) => filter.lift (f i) g := sorry

/-- Specialize `lift` to functions `set α → set β`. This can be viewed as a generalization of `map`.
This is essentially a push-forward along a function mapping each set to a set. -/
protected def lift' {α : Type u_1} {β : Type u_2} (f : filter α) (h : set α → set β) : filter β :=
  filter.lift f (principal ∘ h)

theorem mem_lift' {α : Type u_1} {β : Type u_2} {f : filter α} {h : set α → set β} {t : set α} (ht : t ∈ f) : h t ∈ filter.lift' f h :=
  iff.mp le_principal_iff
    ((fun (this : filter.lift' f h ≤ principal (h t)) => this)
      (infi_le_of_le t (infi_le_of_le ht (le_refl (function.comp principal h t)))))

theorem tendsto_lift' {α : Type u_1} {β : Type u_2} {γ : Type u_3} {f : filter α} {h : set α → set β} {m : γ → β} {l : filter γ} : tendsto m l (filter.lift' f h) ↔ ∀ (s : set α), s ∈ f → filter.eventually (fun (a : γ) => m a ∈ h s) l := sorry

theorem has_basis.lift' {α : Type u_1} {β : Type u_2} {f : filter α} {h : set α → set β} {ι : Type u_3} {p : ι → Prop} {s : ι → set α} (hf : has_basis f p s) (hh : monotone h) : has_basis (filter.lift' f h) p (h ∘ s) := sorry

theorem mem_lift'_sets {α : Type u_1} {β : Type u_2} {f : filter α} {h : set α → set β} (hh : monotone h) {s : set β} : s ∈ filter.lift' f h ↔ ∃ (t : set α), ∃ (H : t ∈ f), h t ⊆ s :=
  mem_lift_sets (monotone.comp monotone_principal hh)

theorem eventually_lift'_iff {α : Type u_1} {β : Type u_2} {f : filter α} {h : set α → set β} (hh : monotone h) {p : β → Prop} : filter.eventually (fun (y : β) => p y) (filter.lift' f h) ↔ ∃ (t : set α), ∃ (H : t ∈ f), ∀ (y : β), y ∈ h t → p y :=
  mem_lift'_sets hh

theorem lift'_le {α : Type u_1} {β : Type u_2} {f : filter α} {g : set α → set β} {h : filter β} {s : set α} (hs : s ∈ f) (hg : principal (g s) ≤ h) : filter.lift' f g ≤ h :=
  lift_le hs hg

theorem lift'_mono {α : Type u_1} {β : Type u_2} {f₁ : filter α} {f₂ : filter α} {h₁ : set α → set β} {h₂ : set α → set β} (hf : f₁ ≤ f₂) (hh : h₁ ≤ h₂) : filter.lift' f₁ h₁ ≤ filter.lift' f₂ h₂ :=
  lift_mono hf fun (s : set α) => iff.mpr principal_mono (hh s)

theorem lift'_mono' {α : Type u_1} {β : Type u_2} {f : filter α} {h₁ : set α → set β} {h₂ : set α → set β} (hh : ∀ (s : set α), s ∈ f → h₁ s ⊆ h₂ s) : filter.lift' f h₁ ≤ filter.lift' f h₂ :=
  infi_le_infi fun (s : set α) => infi_le_infi fun (hs : s ∈ f) => iff.mpr principal_mono (hh s hs)

theorem lift'_cong {α : Type u_1} {β : Type u_2} {f : filter α} {h₁ : set α → set β} {h₂ : set α → set β} (hh : ∀ (s : set α), s ∈ f → h₁ s = h₂ s) : filter.lift' f h₁ = filter.lift' f h₂ :=
  le_antisymm (lift'_mono' fun (s : set α) (hs : s ∈ f) => le_of_eq (hh s hs))
    (lift'_mono' fun (s : set α) (hs : s ∈ f) => le_of_eq (Eq.symm (hh s hs)))

theorem map_lift'_eq {α : Type u_1} {β : Type u_2} {γ : Type u_3} {f : filter α} {h : set α → set β} {m : β → γ} (hh : monotone h) : map m (filter.lift' f h) = filter.lift' f (set.image m ∘ h) := sorry

theorem map_lift'_eq2 {α : Type u_1} {β : Type u_2} {γ : Type u_3} {f : filter α} {g : set β → set γ} {m : α → β} (hg : monotone g) : filter.lift' (map m f) g = filter.lift' f (g ∘ set.image m) :=
  map_lift_eq2 (monotone.comp monotone_principal hg)

theorem comap_lift'_eq {α : Type u_1} {β : Type u_2} {γ : Type u_3} {f : filter α} {h : set α → set β} {m : γ → β} (hh : monotone h) : comap m (filter.lift' f h) = filter.lift' f (set.preimage m ∘ h) := sorry

theorem comap_lift'_eq2 {α : Type u_1} {β : Type u_2} {γ : Type u_3} {f : filter α} {m : β → α} {g : set β → set γ} (hg : monotone g) : filter.lift' (comap m f) g = filter.lift' f (g ∘ set.preimage m) :=
  comap_lift_eq2 (monotone.comp monotone_principal hg)

theorem lift'_principal {α : Type u_1} {β : Type u_2} {h : set α → set β} {s : set α} (hh : monotone h) : filter.lift' (principal s) h = principal (h s) :=
  lift_principal (monotone.comp monotone_principal hh)

theorem lift'_pure {α : Type u_1} {β : Type u_2} {h : set α → set β} {a : α} (hh : monotone h) : filter.lift' (pure a) h = principal (h (singleton a)) := sorry

theorem lift'_bot {α : Type u_1} {β : Type u_2} {h : set α → set β} (hh : monotone h) : filter.lift' ⊥ h = principal (h ∅) :=
  eq.mpr (id (Eq._oldrec (Eq.refl (filter.lift' ⊥ h = principal (h ∅))) (Eq.symm principal_empty)))
    (eq.mpr (id (Eq._oldrec (Eq.refl (filter.lift' (principal ∅) h = principal (h ∅))) (lift'_principal hh)))
      (Eq.refl (principal (h ∅))))

theorem principal_le_lift' {α : Type u_1} {β : Type u_2} {f : filter α} {h : set α → set β} {t : set β} (hh : ∀ (s : set α), s ∈ f → t ⊆ h s) : principal t ≤ filter.lift' f h :=
  le_infi fun (s : set α) => le_infi fun (hs : s ∈ f) => iff.mpr principal_mono (hh s hs)

theorem monotone_lift' {α : Type u_1} {β : Type u_2} {γ : Type u_3} [preorder γ] {f : γ → filter α} {g : γ → set α → set β} (hf : monotone f) (hg : monotone g) : monotone fun (c : γ) => filter.lift' (f c) (g c) :=
  fun (a b : γ) (h : a ≤ b) => lift'_mono (hf h) (hg h)

theorem lift_lift'_assoc {α : Type u_1} {β : Type u_2} {γ : Type u_3} {f : filter α} {g : set α → set β} {h : set β → filter γ} (hg : monotone g) (hh : monotone h) : filter.lift (filter.lift' f g) h = filter.lift f fun (s : set α) => h (g s) := sorry

theorem lift'_lift'_assoc {α : Type u_1} {β : Type u_2} {γ : Type u_3} {f : filter α} {g : set α → set β} {h : set β → set γ} (hg : monotone g) (hh : monotone h) : filter.lift' (filter.lift' f g) h = filter.lift' f fun (s : set α) => h (g s) :=
  lift_lift'_assoc hg (monotone.comp monotone_principal hh)

theorem lift'_lift_assoc {α : Type u_1} {β : Type u_2} {γ : Type u_3} {f : filter α} {g : set α → filter β} {h : set β → set γ} (hg : monotone g) : filter.lift' (filter.lift f g) h = filter.lift f fun (s : set α) => filter.lift' (g s) h :=
  lift_assoc hg

theorem lift_lift'_same_le_lift' {α : Type u_1} {β : Type u_2} {f : filter α} {g : set α → set α → set β} : (filter.lift f fun (s : set α) => filter.lift' f (g s)) ≤ filter.lift' f fun (s : set α) => g s s :=
  lift_lift_same_le_lift

theorem lift_lift'_same_eq_lift' {α : Type u_1} {β : Type u_2} {f : filter α} {g : set α → set α → set β} (hg₁ : ∀ (s : set α), monotone fun (t : set α) => g s t) (hg₂ : ∀ (t : set α), monotone fun (s : set α) => g s t) : (filter.lift f fun (s : set α) => filter.lift' f (g s)) = filter.lift' f fun (s : set α) => g s s :=
  lift_lift_same_eq_lift (fun (s : set α) => monotone.comp monotone_principal (hg₁ s))
    fun (t : set α) => monotone.comp monotone_principal (hg₂ t)

theorem lift'_inf_principal_eq {α : Type u_1} {β : Type u_2} {f : filter α} {h : set α → set β} {s : set β} : filter.lift' f h ⊓ principal s = filter.lift' f fun (t : set α) => h t ∩ s := sorry

theorem lift'_ne_bot_iff {α : Type u_1} {β : Type u_2} {f : filter α} {h : set α → set β} (hh : monotone h) : ne_bot (filter.lift' f h) ↔ ∀ (s : set α), s ∈ f → set.nonempty (h s) := sorry

@[simp] theorem lift'_id {α : Type u_1} {f : filter α} : filter.lift' f id = f :=
  lift_principal2

theorem le_lift' {α : Type u_1} {β : Type u_2} {f : filter α} {h : set α → set β} {g : filter β} (h_le : ∀ (s : set α), s ∈ f → h s ∈ g) : g ≤ filter.lift' f h := sorry

theorem lift_infi' {α : Type u_1} {β : Type u_2} {ι : Sort u_4} {f : ι → filter α} {g : set α → filter β} [Nonempty ι] (hf : directed ge f) (hg : monotone g) : filter.lift (infi f) g = infi fun (i : ι) => filter.lift (f i) g := sorry

theorem lift'_infi {α : Type u_1} {β : Type u_2} {ι : Sort u_4} {f : ι → filter α} {g : set α → set β} [Nonempty ι] (hg : ∀ {s t : set α}, g s ∩ g t = g (s ∩ t)) : filter.lift' (infi f) g = infi fun (i : ι) => filter.lift' (f i) g := sorry

theorem lift'_inf {α : Type u_1} {β : Type u_2} (f : filter α) (g : filter α) {s : set α → set β} (hs : ∀ {t₁ t₂ : set α}, s t₁ ∩ s t₂ = s (t₁ ∩ t₂)) : filter.lift' (f ⊓ g) s = filter.lift' f s ⊓ filter.lift' g s := sorry

theorem comap_eq_lift' {α : Type u_1} {β : Type u_2} {f : filter β} {m : α → β} : comap m f = filter.lift' f (set.preimage m) :=
  filter.ext fun (s : set α) => iff.symm (mem_lift'_sets set.monotone_preimage)

theorem lift'_infi_powerset {α : Type u_1} {ι : Sort u_4} [Nonempty ι] {f : ι → filter α} : filter.lift' (infi f) set.powerset = infi fun (i : ι) => filter.lift' (f i) set.powerset :=
  lift'_infi fun (_x _x_1 : set α) => Eq.symm (set.powerset_inter _x _x_1)

theorem lift'_inf_powerset {α : Type u_1} (f : filter α) (g : filter α) : filter.lift' (f ⊓ g) set.powerset = filter.lift' f set.powerset ⊓ filter.lift' g set.powerset :=
  lift'_inf f g fun (_x _x_1 : set α) => Eq.symm (set.powerset_inter _x _x_1)

theorem eventually_lift'_powerset {α : Type u_1} {f : filter α} {p : set α → Prop} : filter.eventually (fun (s : set α) => p s) (filter.lift' f set.powerset) ↔
  ∃ (s : set α), ∃ (H : s ∈ f), ∀ (t : set α), t ⊆ s → p t :=
  eventually_lift'_iff set.monotone_powerset

theorem eventually_lift'_powerset' {α : Type u_1} {f : filter α} {p : set α → Prop} (hp : ∀ {s t : set α}, s ⊆ t → p t → p s) : filter.eventually (fun (s : set α) => p s) (filter.lift' f set.powerset) ↔ ∃ (s : set α), ∃ (H : s ∈ f), p s := sorry

protected instance lift'_powerset_ne_bot {α : Type u_1} (f : filter α) : ne_bot (filter.lift' f set.powerset) :=
  iff.mpr (lift'_ne_bot_iff set.monotone_powerset) fun (_x : set α) (_x_1 : _x ∈ f) => set.powerset_nonempty

theorem tendsto_lift'_powerset_mono {α : Type u_1} {β : Type u_2} {la : filter α} {lb : filter β} {s : α → set β} {t : α → set β} (ht : tendsto t la (filter.lift' lb set.powerset)) (hst : filter.eventually (fun (x : α) => s x ⊆ t x) la) : tendsto s la (filter.lift' lb set.powerset) := sorry

@[simp] theorem eventually_lift'_powerset_forall {α : Type u_1} {f : filter α} {p : α → Prop} : filter.eventually (fun (s : set α) => ∀ (x : α), x ∈ s → p x) (filter.lift' f set.powerset) ↔
  filter.eventually (fun (x : α) => p x) f := sorry

theorem eventually.lift'_powerset {α : Type u_1} {f : filter α} {p : α → Prop} : filter.eventually (fun (x : α) => p x) f →
  filter.eventually (fun (s : set α) => ∀ (x : α), x ∈ s → p x) (filter.lift' f set.powerset) :=
  iff.mpr eventually_lift'_powerset_forall

@[simp] theorem eventually_lift'_powerset_eventually {α : Type u_1} {f : filter α} {g : filter α} {p : α → Prop} : filter.eventually (fun (s : set α) => filter.eventually (fun (x : α) => x ∈ s → p x) g) (filter.lift' f set.powerset) ↔
  filter.eventually (fun (x : α) => p x) (f ⊓ g) := sorry

theorem prod_def {α : Type u_1} {β : Type u_2} {f : filter α} {g : filter β} : filter.prod f g = filter.lift f fun (s : set α) => filter.lift' g (set.prod s) := sorry

theorem prod_same_eq {α : Type u_1} {f : filter α} : filter.prod f f = filter.lift' f fun (t : set α) => set.prod t t :=
  eq.mpr (id (Eq._oldrec (Eq.refl (filter.prod f f = filter.lift' f fun (t : set α) => set.prod t t)) prod_def))
    (lift_lift'_same_eq_lift' (fun (s : set α) => set.monotone_prod monotone_const monotone_id)
      fun (t : set α) => set.monotone_prod monotone_id monotone_const)

theorem mem_prod_same_iff {α : Type u_1} {f : filter α} {s : set (α × α)} : s ∈ filter.prod f f ↔ ∃ (t : set α), ∃ (H : t ∈ f), set.prod t t ⊆ s := sorry

theorem tendsto_prod_self_iff {α : Type u_1} {β : Type u_2} {f : α × α → β} {x : filter α} {y : filter β} : tendsto f (filter.prod x x) y ↔
  ∀ (W : set β) (H : W ∈ y), ∃ (U : set α), ∃ (H : U ∈ x), ∀ (x x' : α), x ∈ U → x' ∈ U → f (x, x') ∈ W := sorry

theorem prod_lift_lift {α₁ : Type u_5} {α₂ : Type u_6} {β₁ : Type u_7} {β₂ : Type u_8} {f₁ : filter α₁} {f₂ : filter α₂} {g₁ : set α₁ → filter β₁} {g₂ : set α₂ → filter β₂} (hg₁ : monotone g₁) (hg₂ : monotone g₂) : filter.prod (filter.lift f₁ g₁) (filter.lift f₂ g₂) =
  filter.lift f₁ fun (s : set α₁) => filter.lift f₂ fun (t : set α₂) => filter.prod (g₁ s) (g₂ t) := sorry

theorem prod_lift'_lift' {α₁ : Type u_5} {α₂ : Type u_6} {β₁ : Type u_7} {β₂ : Type u_8} {f₁ : filter α₁} {f₂ : filter α₂} {g₁ : set α₁ → set β₁} {g₂ : set α₂ → set β₂} (hg₁ : monotone g₁) (hg₂ : monotone g₂) : filter.prod (filter.lift' f₁ g₁) (filter.lift' f₂ g₂) =
  filter.lift f₁ fun (s : set α₁) => filter.lift' f₂ fun (t : set α₂) => set.prod (g₁ s) (g₂ t) := sorry


/-
Copyright (c) 2021 Scott Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Scott Morrison
-/
import category_theory.eq_to_hom
import combinatorics.quiver.path

/-!
# The category paths on a quiver.
-/

universes v₁ v₂ u₁ u₂

namespace category_theory

section

/--
A type synonym for the category of paths in a quiver.
-/
def paths (V : Type u₁) : Type u₁ := V

instance (V : Type u₁) [inhabited V] : inhabited (paths V) := ⟨(default : V)⟩

variables (V : Type u₁) [quiver.{v₁+1} V]

namespace paths

instance category_paths : category.{max u₁ v₁} (paths V) :=
{ hom := λ (X Y : V), quiver.path X Y,
  id := λ X, quiver.path.nil,
  comp := λ X Y Z f g, quiver.path.comp f g, }

variables {V}

/--
The inclusion of a quiver `V` into its path category, as a prefunctor.
-/
@[simps]
def of : prefunctor V (paths V) :=
{ obj := λ X, X,
  map := λ X Y f, f.to_path, }

local attribute [ext] functor.ext

/-- Two functors out of a path category are equal when they agree on singleton paths. -/
@[ext]
lemma ext_functor {C} [category C]
  {F G : paths V ⥤ C}
  (h_obj : F.obj = G.obj)
  (h : ∀ (a b : V) (e : a ⟶ b), F.map e.to_path =
  eq_to_hom (congr_fun h_obj a) ≫ G.map e.to_path ≫ eq_to_hom (congr_fun h_obj.symm b)) :
  F = G :=
begin
  ext X Y f,
  { induction f with Y' Z' g e ih,
    { erw [F.map_id, G.map_id, category.id_comp, eq_to_hom_trans, eq_to_hom_refl], },
    { erw [F.map_comp g e.to_path, G.map_comp g e.to_path, ih, h],
      simp only [category.id_comp, eq_to_hom_refl, eq_to_hom_trans_assoc, category.assoc], }, },
  { intro X, rw h_obj, }
end

end paths

variables (W : Type u₂) [quiver.{v₂+1} W]

-- A restatement of `prefunctor.map_path_comp` using `f ≫ g` instead of `f.comp g`.
@[simp] lemma prefunctor.map_path_comp' (F : prefunctor V W)
  {X Y Z : paths V} (f : X ⟶ Y) (g : Y ⟶ Z) :
  F.map_path (f ≫ g) = (F.map_path f).comp (F.map_path g) :=
prefunctor.map_path_comp _ _ _

end

section

variables {C : Type u₁} [category.{v₁} C]

open quiver

/-- A path in a category can be composed to a single morphism. -/
@[simp]
def compose_path {X : C} : Π {Y : C} (p : path X Y), X ⟶ Y
| _ path.nil := 𝟙 X
| _ (path.cons p e) := compose_path p ≫ e

@[simp]
lemma compose_path_comp {X Y Z : C} (f : path X Y) (g : path Y Z) :
  compose_path (f.comp g) = compose_path f ≫ compose_path g :=
begin
  induction g with Y' Z' g e ih,
  { simp, },
  { simp [ih], },
end

end

end category_theory